Пример #1
0
def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
    """
    Start a bitcoind and return RPC connection to it
    """
    datadir = os.path.join(dirname, "node"+str(i))
    if binary is None:
        binary = os.getenv("BITCOIND", "bitcoind")
    args = [ binary, "-datadir="+datadir, "-keypool=1", "-discover=0", "-rest" ]
    if extra_args is not None: args.extend(extra_args)
    bitcoind_processes[i] = subprocess.Popen(args)
    devnull = open(os.devnull, "w")
    if os.getenv("PYTHON_DEBUG", ""):
        print "start_node: bitcoind started, calling bitcoin-cli -rpcwait getblockcount"
    subprocess.check_call([ os.getenv("BITCOINCLI", "bitcoin-cli"), "-datadir="+datadir] +
                          _rpchost_to_args(rpchost)  +
                          ["-rpcwait", "getblockcount"], stdout=devnull)
    if os.getenv("PYTHON_DEBUG", ""):
        print "start_node: calling bitcoin-cli -rpcwait getblockcount returned"
    devnull.close()
    url = "http://*****:*****@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i))
    if timewait is not None:
        proxy = AuthServiceProxy(url, timeout=timewait)
    else:
        proxy = AuthServiceProxy(url)
    proxy.url = url # store URL on proxy for info
    return proxy
Пример #2
0
def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None):
    """
    Start a komodod and return RPC connection to it
    """
    datadir = os.path.join(dirname, "node"+str(i))
    # creating special config in case of cryptocondition asset chain test
    if extra_args[0] == '-ac_name=REGTEST':
        configpath = datadir + "/REGTEST.conf"
        with open(configpath, "w+") as config:
            config.write("regtest=1\n")
            config.write("rpcuser=rt\n")
            config.write("rpcpassword=rt\n")
            port = extra_args[3]
            config.write("rpcport=" + (port[9:]) + "\n")
            config.write("server=1\n")
            config.write("txindex=1\n")
            config.write("rpcworkqueue=256\n")
            config.write("rpcallowip=127.0.0.1\n")
            config.write("bind=127.0.0.1\n")
            config.write("rpcbind=127.0.0.1")
    if binary is None:
        binary = os.getenv("BITCOIND", "komodod")
    args = [ binary, "-datadir="+datadir, "-keypool=1", "-discover=0", "-rest" ]
    if extra_args is not None: args.extend(extra_args)
    #print("args=" + ' '.join(args))
    bitcoind_processes[i] = subprocess.Popen(args)
    devnull = open("/dev/null", "w+")

    cmd = os.getenv("BITCOINCLI", "komodo-cli")
    print("cmd=" + cmd)
    cmd_args = ' '.join(extra_args) + " -rpcwait getblockcount "
    if os.getenv("PYTHON_DEBUG", ""):
        print "start_node: komodod started, calling : " + cmd + " " + cmd_args
    strcmd = cmd + " " + cmd_args

    print("Running " + strcmd)
    import time
    time.sleep(2)
    subprocess.check_call(strcmd, shell=True);
    #subprocess.check_call([ os.getenv("BITCOINCLI", "komodo-cli"), "-datadir="+datadir] +
    #                      _rpchost_to_args(rpchost)  +
    #                      ["-rpcwait", "-rpcport=6438", "getblockcount"], stdout=devnull)
    if os.getenv("PYTHON_DEBUG", ""):
        print "start_node: calling komodo-cli -rpcwait getblockcount returned"
    devnull.close()
    port = extra_args[3]
    url = "http://*****:*****@%s:%d" % (rpchost or '127.0.0.1', int(port[9:]))
    print("connecting to " + url)
    if timewait is not None:
        proxy = AuthServiceProxy(url, timeout=timewait)
    else:
        proxy = AuthServiceProxy(url)
    print("created proxy")
    proxy.url = url # store URL on proxy for info
    return proxy
Пример #3
0
def initialize_chain(test_dir):
    """
    Create (or copy from cache) a 200-block-long chain and
    4 wallets.
    bitcoind and bitcoin-cli must be in search path.
    """

    if not os.path.isdir(os.path.join("cache", "node0")):
        devnull = open("/dev/null", "w+")
        # Create cache directories, run bitcoinds:
        for i in range(4):
            datadir=initialize_datadir("cache", i)
            args = [ os.getenv("BITCOIND", "bitcoind"), "-keypool=1", "-datadir="+datadir, "-discover=0" ]
            if i > 0:
                args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
            bitcoind_processes[i] = subprocess.Popen(args)
            if os.getenv("PYTHON_DEBUG", ""):
                print "initialize_chain: bitcoind started, calling bitcoin-cli -rpcwait getblockcount"
            subprocess.check_call([ os.getenv("BITCOINCLI", "bitcoin-cli"), "-datadir="+datadir,
                                    "-rpcwait", "getblockcount"], stdout=devnull)
            if os.getenv("PYTHON_DEBUG", ""):
                print "initialize_chain: bitcoin-cli -rpcwait getblockcount completed"
        devnull.close()
        rpcs = []
        for i in range(4):
            try:
                url = "http://*****:*****@127.0.0.1:%d"%(rpc_port(i),)
                rpcs.append(AuthServiceProxy(url))
            except:
                sys.stderr.write("Error connecting to "+url+"\n")
                sys.exit(1)

        # Create a 200-block-long chain; each of the 4 nodes
        # gets 25 mature blocks and 25 immature.
        # blocks are created with timestamps 10 minutes apart, starting
        # at 1 Jan 2014
        block_time = 1388534400
        for i in range(2):
            for peer in range(4):
                for j in range(25):
                    set_node_times(rpcs, block_time)
                    rpcs[peer].generate(1)
                    block_time += 10*60
                # Must sync before next peer starts generating blocks
                sync_blocks(rpcs)

        # Shut them down, and clean up cache directories:
        stop_nodes(rpcs)
        wait_bitcoinds()
        for i in range(4):
            os.remove(log_filename("cache", i, "debug.log"))
            os.remove(log_filename("cache", i, "db.log"))
            os.remove(log_filename("cache", i, "peers.dat"))
            os.remove(log_filename("cache", i, "fee_estimates.dat"))

    for i in range(4):
        from_dir = os.path.join("cache", "node"+str(i))
        to_dir = os.path.join(test_dir,  "node"+str(i))
        shutil.copytree(from_dir, to_dir)
        initialize_datadir(test_dir, i) # Overwrite port/rpcport in asofe.conf
Пример #4
0
 def __init__(self, settings):
     self.bitcoind = AuthServiceProxy(settings['rpc_url'])
     self.current_address = ""
     self.exchange_rate = 0.0
     self.exchange_rate_source = ""
     self.currency = settings['exchange_rate_ticker']['currency']
     self.singleScreenMode = settings['single-screen-mode']
 def __init__(self, settings):
     self.bitcoind = AuthServiceProxy(settings['rpc_url'])
     self.candy_price = settings['candy_price']
     self.candy_currency = settings['candy_currency']
     self.arduino_port = settings['arduino_port']
     self.current_address = ""
     self.exchange_rate = 0.0
     self.exchange_rate_source = ""
Пример #6
0
def start_bitcoind(bitcoind_path):
    datadir = tempfile.mkdtemp()
    bitcoind_proc = subprocess.Popen([bitcoind_path, '-regtest', '-datadir=' + datadir, '-noprinttoconsole', '-fallbackfee=0.0002'])

    def cleanup_bitcoind():
        bitcoind_proc.kill()
        shutil.rmtree(datadir)
    atexit.register(cleanup_bitcoind)
    # Wait for cookie file to be created
    while not os.path.exists(datadir + '/regtest/.cookie'):
        time.sleep(0.5)
    # Read .cookie file to get user and pass
    with open(datadir + '/regtest/.cookie') as f:
        userpass = f.readline().lstrip().rstrip()
    rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(userpass))

    # Wait for bitcoind to be ready
    ready = False
    while not ready:
        try:
            rpc.getblockchaininfo()
            ready = True
        except JSONRPCException:
            time.sleep(0.5)
            pass

    # Make sure there are blocks and coins available
    rpc.generatetoaddress(101, rpc.getnewaddress())
    return (rpc, userpass)
 def __init__(self, settings):
     self.bitcoind = AuthServiceProxy(settings['rpc_url'])
     self.current_address = ""
     self.expected_amount = ""
     self.exchange_rate = 0.0
     self.exchange_rate_source = ""
     self.currency = settings['exchange_rate_ticker']['currency']
     self.single_screen_mode = settings['single_screen_mode']
     self.green_addresses = settings['green_addresses']
Пример #8
0
    def start(self):
        def get_free_port():
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.bind(("", 0))
            s.listen(1)
            port = s.getsockname()[1]
            s.close()
            return port

        self.p2p_port = get_free_port()
        self.rpc_port = get_free_port()

        self.bitcoind_proc = subprocess.Popen([
            self.bitcoind_path, "-regtest", f"-datadir={self.datadir}",
            "-noprinttoconsole", "-fallbackfee=0.0002", "-keypool=1",
            f"-port={self.p2p_port}", f"-rpcport={self.rpc_port}"
        ])

        atexit.register(self.cleanup)

        # Wait for cookie file to be created
        cookie_path = os.path.join(self.datadir, "regtest", ".cookie")
        while not os.path.exists(cookie_path):
            time.sleep(0.5)
        # Read .cookie file to get user and pass
        with open(cookie_path) as f:
            self.userpass = f.readline().lstrip().rstrip()
        self.rpc_url = f"http://{self.userpass}@127.0.0.1:{self.rpc_port}"
        self.rpc = AuthServiceProxy(self.rpc_url)

        # Wait for bitcoind to be ready
        ready = False
        while not ready:
            try:
                self.rpc.getblockchaininfo()
                ready = True
            except JSONRPCException:
                time.sleep(0.5)
                pass

        # Make sure there are blocks and coins available
        self.rpc.createwallet(wallet_name="supply")
        self.wrpc = self.get_wallet_rpc("supply")
        self.wrpc.generatetoaddress(101, self.wrpc.getnewaddress())
 def __init__(self, settings, nfc_broadcast):
     self.nfc_broadcast = nfc_broadcast
     self.bitcoind = AuthServiceProxy(settings['rpc_url'])
     self.current_address = ""
     self.exchange_rate = 0.0
     self.exchange_rate_source = ""
     self.currency = settings['exchange_rate_ticker']['currency']
     self.single_screen_mode = settings['single_screen_mode']
     self.green_addresses = settings['green_addresses']
     self.bt_addr = None
Пример #10
0
 def run_allowip_test(self, allow_ips, rpchost, rpcport):
     '''
     Start a node with rpcwallow IP, and request getinfo
     at a non-localhost IP.
     '''
     base_args = ['-disablewallet', '-nolisten'
                  ] + ['-rpcallowip=' + x for x in allow_ips]
     nodes = start_nodes(1, self.options.tmpdir, [base_args])
     try:
         # connect to node through non-loopback interface
         url = "http://*****:*****@%s:%d" % (
             rpchost,
             rpcport,
         )
         node = AuthServiceProxy(url)
         node.getinfo()
     finally:
         node = None  # make sure connection will be garbage collected and closed
         stop_nodes(nodes)
         wait_bitcoinds()
Пример #11
0
def start_node(i,
               dirname,
               extra_args=None,
               rpchost=None,
               timewait=None,
               binary=None):
    """
    Start a zend and return RPC connection to it
    """
    datadir = os.path.join(dirname, "node" + str(i))
    if binary is None:
        # ZEN_MOD_START
        binary = os.getenv("BITCOIND", "zend")
# ZEN_MOD_END
    args = [
        binary, "-datadir=" + datadir, "-keypool=1", "-discover=0", "-rest"
    ]
    if extra_args is not None: args.extend(extra_args)
    bitcoind_processes[i] = subprocess.Popen(args)
    devnull = open("/dev/null", "w+")
    # ZEN_MOD_START
    if os.getenv("PYTHON_DEBUG", ""):
        print "start_node: zend started, calling zen-cli -rpcwait getblockcount"
    subprocess.check_call(
        [os.getenv("BITCOINCLI", "zen-cli"), "-datadir=" + datadir] +
        _rpchost_to_args(rpchost) + ["-rpcwait", "getblockcount"],
        stdout=devnull)
    if os.getenv("PYTHON_DEBUG", ""):
        print "start_node: calling zen-cli -rpcwait getblockcount returned"


# ZEN_MOD_END
    devnull.close()
    url = "http://*****:*****@%s:%d" % (rpchost or '127.0.0.1', rpc_port(i))
    if timewait is not None:
        proxy = AuthServiceProxy(url, timeout=timewait)
    else:
        proxy = AuthServiceProxy(url)
    proxy.url = url  # store URL on proxy for info
    return proxy
Пример #12
0
    def __init__(self, options, instance_name):
        self.options = options
        self.instance_name = instance_name
        handlers = [
            (r"/api/receive", ReceiveHandler),
            (r"/api/walletnotify/(?P<txid>[^\/]+)", WalletNotifyHandler),
            (r"/api/blocknotify/(?P<hash>[^\/]+)", BlockNotifyHandler),
        ]
        settings = dict(cookie_secret='cookie_secret')
        tornado.web.Application.__init__(self, handlers, **settings)

        input_log_file_handler = logging.handlers.TimedRotatingFileHandler(
            self.options.log, when='MIDNIGHT')
        formatter = logging.Formatter('%(asctime)s - %(message)s')
        input_log_file_handler.setFormatter(formatter)

        self.bitcoind = AuthServiceProxy(self.options.rpc_url)
        self.paytxfee = self.bitcoind.getinfo()['paytxfee']

        self.replay_logger = logging.getLogger(self.instance_name)
        self.replay_logger.setLevel(logging.DEBUG)
        self.replay_logger.addHandler(input_log_file_handler)
        self.replay_logger.info('START')

        ch = logging.StreamHandler(sys.stdout)
        ch.setLevel(logging.DEBUG)
        ch.setFormatter(
            logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
        self.replay_logger.addHandler(ch)

        from models import Base, db_bootstrap
        engine = create_engine(self.options.db_engine,
                               echo=self.options.db_echo)
        Base.metadata.create_all(engine)
        self.db_session = scoped_session(sessionmaker(bind=engine))
        db_bootstrap(self.db_session)

        self.log_start_data()
Пример #13
0
 def setUp(self):
     self.rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(self.rpc_userpass))
     if '{}_test'.format(self.full_type) not in self.rpc.listwallets():
         self.rpc.createwallet('{}_test'.format(self.full_type), True)
     self.wrpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/{}_test'.format(self.rpc_userpass, self.full_type))
     self.wpk_rpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/'.format(self.rpc_userpass))
     if '--testnet' not in self.dev_args:
         self.dev_args.append('--testnet')
     self.emulator.start()
Пример #14
0
 def __init__(self):
     # load config:
     Config = ConfigParser.ConfigParser(allow_no_value = True)
     Config.read('config.cfg')
     network = Config.get('Global','network')
     rpcusername = Config.get(network,'rpcusername')
     rpcpassword = Config.get(network,'rpcpassword')
     rpcport = Config.getint(network,'rpcport')
     rpchostip = Config.get(network,'rpchostip')
     self.plotpath = str(Config.get(network,'htmlpath'))
     self.block_window = Config.getint(network,'block_window')
     self.block_domain = Config.getint(network,'block_domain')
     # set rpc:
     self.rpc = AuthServiceProxy('http://'+rpcusername+':'+rpcpassword+'@'+
             rpchostip+':'+str(rpcport))
Пример #15
0
def get_rpc_proxy(url, node_number, timeout=None):
    """
    Args:
        url (str): URL of the RPC server to call
        node_number (int): the node number (or id) that this calls to

    Kwargs:
        timeout (int): HTTP timeout in seconds

    Returns:
        AuthServiceProxy. convenience object for making RPC calls.

    """
    proxy_kwargs = {}
    if timeout is not None:
        proxy_kwargs['timeout'] = timeout

    proxy = AuthServiceProxy(url, **proxy_kwargs)
    proxy.url = url  # store URL on proxy for info

    coverage_logfile = coverage.get_filename(
        COVERAGE_DIR, node_number) if COVERAGE_DIR else None

    return coverage.AuthServiceProxyWrapper(proxy, coverage_logfile)
Пример #16
0
def initialize_chain(test_dir):
    """
    Create (or copy from cache) a 200-block-long chain and
    4 wallets.
    zend and zen-cli must be in search path.
    """
    if os.path.isdir(os.path.join("cache", "node0")):
        if os.stat("cache").st_mtime + (60 * 60) < time.time():
            print("initialize_chain(): Removing stale cache")
            shutil.rmtree("cache")
            
    if not os.path.isdir(os.path.join("cache", "node0")):
        devnull = open("/dev/null", "w+")
        # Create cache directories, run bitcoinds:
        for i in range(4):
            datadir=initialize_datadir("cache", i)
            args = [ os.getenv("BITCOIND", "zend"), "-keypool=1", "-datadir="+datadir, "-discover=0", "-rpcservertimeout=600" ]
            if i > 0:
                args.append("-connect=127.0.0.1:"+str(p2p_port(0)))
            bitcoind_processes[i] = subprocess.Popen(args)
            if os.getenv("PYTHON_DEBUG", ""):
                print "initialize_chain: zend started, calling zen-cli -rpcwait getblockcount"
            subprocess.check_call([ os.getenv("BITCOINCLI", "zen-cli"), "-datadir="+datadir,
                                    "-rpcwait", "getblockcount"], stdout=devnull)
            if os.getenv("PYTHON_DEBUG", ""):
                print "initialize_chain: zen-cli -rpcwait getblockcount completed"
        devnull.close()
        rpcs = []
        for i in range(4):
            try:
                url = "http://*****:*****@127.0.0.1:%d"%(rpc_port(i),)
                rpcs.append(AuthServiceProxy(url))
            except:
                sys.stderr.write("Error connecting to "+url+"\n")
                sys.exit(1)

        # Create a 200-block-long chain; each of the 4 nodes
        # gets 25 mature blocks and 25 immature.
        # blocks are created with timestamps 10 minutes apart, starting
        # at Fri, 12 May 2017 00:15:50 GMT (genesis block time)
        # block_time = 1494548150
        block_time = int(time.time()) - (200 * 150) # 200 is number of blocks and 150 is blocktime target spacing 150 / 60 = 2.5 min
        for i in range(2):
            for peer in range(4):
                for j in range(25):
                    set_node_times(rpcs, block_time)
                    rpcs[peer].generate(1)
                    # block_time += 10*60 # this was BTC target spacing ??
                    block_time += 150   # ZEN blocktime target spacing
                # Must sync before next peer starts generating blocks
                sync_blocks(rpcs)
        # Check that local time isn't going backwards                
        assert_greater_than(time.time() + 1, block_time)
                
        # Shut them down, and clean up cache directories:
        stop_nodes(rpcs)
        wait_bitcoinds()
        for i in range(4):
            os.remove(log_filename("cache", i, "debug.log"))
            os.remove(log_filename("cache", i, "db.log"))
            os.remove(log_filename("cache", i, "peers.dat"))
            os.remove(log_filename("cache", i, "fee_estimates.dat"))

    for i in range(4):
        from_dir = os.path.join("cache", "node"+str(i))
        to_dir = os.path.join(test_dir,  "node"+str(i))
        shutil.copytree(from_dir, to_dir)
        initialize_datadir(test_dir, i) # Overwrite port/rpcport in zen.conf
class Controller:
    def __init__(self, settings):
        self.bitcoind = AuthServiceProxy(settings['rpc_url'])
        self.current_address = ""
        self.expected_amount = ""
        self.exchange_rate = 0.0
        self.exchange_rate_source = ""
        self.currency = settings['exchange_rate_ticker']['currency']
        self.single_screen_mode = settings['single_screen_mode']
        self.green_addresses = settings['green_addresses']

    def run(self):
        self.app = QtGui.QApplication([])

        font = self.app.font()
        font.setPointSize(12)
        self.app.setFont(font)

        self.app.connect(self.app, QtCore.SIGNAL('_new_transaction_received(PyQt_PyObject)'),
                self._new_transaction_received)
        self.app.connect(self.app, QtCore.SIGNAL('_exchange_rate_updated(PyQt_PyObject)'),
                self._exchange_rate_updated)

        self.merchant_gui = MerchantGUI(self, self.currency)
        self.merchant_gui.show()
        self.customer_display = CustomerDisplay(os.environ['POS'] + '/data/customer_display.html', self.single_screen_mode)
        if not self.single_screen_mode:
            self.customer_display.show()
        self.app.exec_()

    def init_new_transaction(self, amount, currency):
        if self.single_screen_mode:
            self.customer_display.show()
            if not self.customer_display.isFullScreen():
                self.customer_display.showFullScreen()
        if currency != "BTC":
            cur_amount = amount
            if self.exchange_rate != 0:
                amount = round(cur_amount / self.exchange_rate, 8)
            else:
                amount = 0

            conversion = '["%.2f %s", "%.4f %s", "%s"]' % (cur_amount, 
                            currency, self.exchange_rate, currency,
                            self.exchange_rate_source)
        else:
            conversion = '-1'

        self.current_address = self.bitcoind.getnewaddress("Point of Sale")
        self.merchant_gui.update_status("Looking for a transaction to %s..." %
                self.current_address)

        amount_str = self.format_btc_amount(amount)
        self.expected_amount = '%s BTC' % amount_str
        imgdata = self.create_img_data(self.current_address, amount_str)
        js = 'show_payment_info("%s", %s, "%s", "%s")' % \
                (self.expected_amount, conversion,
                        self.current_address, imgdata)

        self.customer_display.evaluate_java_script(js)

    def create_img_data(self, address, amount_str):
        (_, size, img) = qrencode.encode("bitcoin:%s?amount=%s&label=" %
                (address, amount_str))
        if size < 400: img = img.resize((400, 400), Image.NEAREST)

        buf = StringIO()
        img.save(buf, format='PNG')
        imgdata = "data:image/png,%s" % urllib.quote(buf.getvalue())
        return imgdata

    def format_btc_amount(self, amount):
        s = "%.8f" % amount
        return re.sub("\.?0+$", "", s)

    # this is thread-safe, as long as it is called from a QThread
    def new_transaction_received(self, txid):
        if not hasattr(self, 'app'): return  # not yet read
        # emit signal, so we can process this on the Qt GUI thread
        self.app.emit(QtCore.SIGNAL('_new_transaction_received(PyQt_PyObject)'),
                txid)

    def _new_transaction_received(self, txid):
        # check if we are waiting for a payment
        if self.current_address == "": return

        # check if the txid looks sane before passing it
        # to bitcoind (for security reasons; might be overly
        # paranoid, but can't hurt)
        if re.search("^[a-f0-9]*$", txid) == None: return

        tx_info = self.bitcoind.gettransaction(txid)
        address_found = False
        for detail in tx_info['details']:
            if self.current_address == detail['address']:
                amount_received = detail['amount']
                address_found = True
        if not address_found: return

        msg = "Transaction to %s with amount %s (of %s expected) received." % (self.current_address, amount_received, self.expected_amount)
        (from_green_address, green_address_msg) = self.green_address_check(txid)
        if from_green_address: msg += " " + green_address_msg

        self.merchant_gui.update_status(msg)
        self.customer_display.evaluate_java_script('show_payment_received()')
        self.current_address = ""

    def green_address_check(self, txid):
        found = False
        msg = ""

        origins = self.get_origins(txid)
        for origin in origins:
            if origin in self.green_addresses:
                found = True
                msg = self.green_addresses[origin]
                break

        return (found, msg)

    def get_origins(self, txid):
        try:
            origins = []
            raw_tx = self.bitcoind.getrawtransaction(txid, 1)
            vins = raw_tx['vin']
            for vin in vins:
                raw_tx = self.bitcoind.getrawtransaction(vin['txid'], 1)
                for vout in raw_tx['vout']:
                    if vin['vout'] == vout['n']:
                        origins.extend(vout['scriptPubKey']['addresses'])
            return origins
        except JSONRPCException:
            return []

    def toggle_fullscreen_mode(self):
        if not self.customer_display.isFullScreen():
            self.customer_display.showFullScreen()
        else:
            self.customer_display.showNormal()

    def clear_customer_display(self):
        self.customer_display.evaluate_java_script('show_idle()')

    # this is thread-safe, as long as it is called from a QThread
    def exchange_rate_updated(self, rate, source):
        if not hasattr(self, 'app'): return  # not yet read
        self.app.emit(QtCore.SIGNAL('_exchange_rate_updated(PyQt_PyObject)'),
                (rate, source))

    def _exchange_rate_updated(self, data):
        (self.exchange_rate, self.exchange_rate_source) = data
        self.merchant_gui.update_exchange_rate(self.exchange_rate)
Пример #18
0
class UpMyFee():
    def __init__(self, service_url, wallet_unlock_timeout):
        self.wallet_unlock_timeout = wallet_unlock_timeout
        self.api = AuthServiceProxy(service_url=service_url, verify=False)

    def get_tx_amount(self, txid):
        return self.api.gettransaction(txid)['amount']

    def get_new_tx(self, orig_tx, payer, to, fee):
        new_amount = 0
        orig_amount = 0

        if len(orig_tx['vout']) > 2:
            raise BaseException('Multiaddresses is NOT supported')

        orig_vins = [{
            'txid': t['txid'],
            'vout': t['vout']
        } for t in orig_tx['vin']]
        vins_sum_amounts = sum(
            [self.get_tx_amount(t['txid']) for t in orig_vins])

        orig_vout = orig_tx['vout']
        vouts_sum_amounts = sum(v['value'] for v in orig_vout)

        orig_fee = vins_sum_amounts - vouts_sum_amounts

        if orig_fee >= fee:
            raise BaseException('New tx fee should be more than the original!')

        for v in orig_vout:
            addresses = v['scriptPubKey']['addresses']
            if len(addresses) > 1:
                raise BaseException('Multiaddresses is NOT supported')

        if payer not in [v['scriptPubKey']['addresses'][0] for v in orig_vout]:
            raise BaseException('Payer address not in transaction')

        fee_diff = fee - orig_fee

        new_vouts = {}

        for vout in orig_vout:
            addr = vout['scriptPubKey']['addresses'][0]
            amount = vout['value']

            if addr == payer:
                orig_amount = amount
                amount -= fee_diff
                new_amount = amount
                new_vouts[to] = new_amount
            else:
                new_vouts[addr] = amount

        if new_amount <= Decimal(0):
            raise BaseException('New fee is very big!')

        return orig_vins, new_vouts, orig_fee, fee_diff, orig_amount, new_amount

    def get_user_confirm(self, payer, to, txid, fee, orig_fee, fee_diff,
                         orig_amount, new_amount):
        print("Transaction ID:\t%s" % txid)
        print("Payer address:\t%s" % payer)
        print("New recipient:\t%s" % to)
        print("Orig fee:\t%s" % orig_fee)
        print("New fee:\t%s" % fee)
        print("Diff fee:\t%s" % fee_diff)
        print("Orig amount:\t%s" % orig_amount)
        print("New amount:\t%s" % new_amount)

        user_result = input("All is correct? (yes/no): ")
        if user_result != "yes":
            print('Exit.')
            return False

        return True

    def change_fee(self, payer, to, txid, fee, debug):
        orig_rawtx = self.api.getrawtransaction(txid)
        orig_tx = self.api.decoderawtransaction(orig_rawtx)

        vin, vout, orig_fee, fee_diff, orig_amount, new_amount = self.get_new_tx(
            orig_tx, payer, to, fee)

        new_rawtx = self.api.createrawtransaction(vin, vout)
        new_tx = self.api.decoderawtransaction(new_rawtx)

        if debug:
            pprint(new_tx)

        if not self.get_user_confirm(payer, to, txid, fee, orig_fee, fee_diff,
                                     orig_amount, new_amount):
            return False

        passphrase = input("Please enter the wallet passphrase: ")

        self.api.walletpassphrase(passphrase, self.wallet_unlock_timeout)

        tx_sign_result = self.api.signrawtransaction(new_rawtx)
        if not tx_sign_result['complete']:
            raise BaseException('Error sign transaction: %s' %
                                str(tx_sign_result))

        tx_signed_hex = tx_sign_result['hex']
        tx_signed = self.api.decoderawtransaction(tx_signed_hex)

        if debug:
            pprint(tx_signed)

        print('HEX of signed transaction: ')
        print(print(tx_signed_hex))
        print(
            'You can decode and broadcast transaction use https://blockchain.info/pushtx'
        )

        user_result = input(
            "Broadcast transaction using your Bitcoin node? (yes/no): ")
        if user_result != "yes":
            print('Exit.')
            return False

        sent_txid = self.api.sendrawtransaction(tx_signed_hex)
        print('New TxID: %s' % sent_txid)
Пример #19
0
class TestSignTx(DeviceTestCase):
    def setUp(self):
        self.rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(self.rpc_userpass))
        if '{}_test'.format(self.full_type) not in self.rpc.listwallets():
            self.rpc.createwallet('{}_test'.format(self.full_type), True)
        self.wrpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/{}_test'.format(self.rpc_userpass, self.full_type))
        self.wpk_rpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/'.format(self.rpc_userpass))
        if '--testnet' not in self.dev_args:
            self.dev_args.append('--testnet')
        self.emulator.start()

    def tearDown(self):
        self.emulator.stop()

    def _generate_and_finalize(self, unknown_inputs, psbt):
        if not unknown_inputs:
            # Just do the normal signing process to test "all inputs" case
            sign_res = self.do_command(self.dev_args + ['signtx', psbt['psbt']])
            finalize_res = self.wrpc.finalizepsbt(sign_res['psbt'])
        else:
            # Sign only input one on first pass
            # then rest on second pass to test ability to successfully
            # ignore inputs that are not its own. Then combine both
            # signing passes to ensure they are actually properly being
            # partially signed at each step.
            first_psbt = PSBT()
            first_psbt.deserialize(psbt['psbt'])
            second_psbt = PSBT()
            second_psbt.deserialize(psbt['psbt'])

            # Blank master fingerprint to make hww fail to sign
            # Single input PSBTs will be fully signed by first signer
            for psbt_input in first_psbt.inputs[1:]:
                for pubkey, path in psbt_input.hd_keypaths.items():
                    psbt_input.hd_keypaths[pubkey] = (0,) + path[1:]
            for pubkey, path in second_psbt.inputs[0].hd_keypaths.items():
                second_psbt.inputs[0].hd_keypaths[pubkey] = (0,) + path[1:]

            single_input = len(first_psbt.inputs) == 1

            # Process the psbts
            first_psbt = first_psbt.serialize()
            second_psbt = second_psbt.serialize()

            # First will always have something to sign
            first_sign_res = self.do_command(self.dev_args + ['signtx', first_psbt])
            self.assertTrue(single_input == self.wrpc.finalizepsbt(first_sign_res['psbt'])['complete'])
            # Second may have nothing to sign (1 input case)
            # and also may throw an error(e.g., ColdCard)
            second_sign_res = self.do_command(self.dev_args + ['signtx', second_psbt])
            if 'psbt' in second_sign_res:
                self.assertTrue(not self.wrpc.finalizepsbt(second_sign_res['psbt'])['complete'])
                combined_psbt = self.wrpc.combinepsbt([first_sign_res['psbt'], second_sign_res['psbt']])

            else:
                self.assertTrue('error' in second_sign_res)
                combined_psbt = first_sign_res['psbt']

            finalize_res = self.wrpc.finalizepsbt(combined_psbt)
            self.assertTrue(finalize_res['complete'])
            self.assertTrue(self.wrpc.testmempoolaccept([finalize_res['hex']])[0]["allowed"])
        return finalize_res['hex']

    def _test_signtx(self, input_type, multisig, external):
        # Import some keys to the watch only wallet and send coins to them
        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--sh_wpkh', '30', '40'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--sh_wpkh', '--internal', '30', '40'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        sh_wpkh_addr = self.wrpc.getnewaddress('', 'p2sh-segwit')
        wpkh_addr = self.wrpc.getnewaddress('', 'bech32')
        pkh_addr = self.wrpc.getnewaddress('', 'legacy')
        self.wrpc.importaddress(wpkh_addr)
        self.wrpc.importaddress(pkh_addr)

        # pubkeys to construct 2-of-3 multisig descriptors for import
        sh_wpkh_info = self.wrpc.getaddressinfo(sh_wpkh_addr)
        wpkh_info = self.wrpc.getaddressinfo(wpkh_addr)
        pkh_info = self.wrpc.getaddressinfo(pkh_addr)

        # Get origin info/key pair so wallet doesn't forget how to
        # sign with keys post-import
        pubkeys = [sh_wpkh_info['desc'][8:-11],
                   wpkh_info['desc'][5:-10],
                   pkh_info['desc'][4:-10]]

        # Get the descriptors with their checksums
        sh_multi_desc = self.wrpc.getdescriptorinfo('sh(sortedmulti(2,' + pubkeys[0] + ',' + pubkeys[1] + ',' + pubkeys[2] + '))')['descriptor']
        sh_wsh_multi_desc = self.wrpc.getdescriptorinfo('sh(wsh(sortedmulti(2,' + pubkeys[0] + ',' + pubkeys[1] + ',' + pubkeys[2] + ')))')['descriptor']
        wsh_multi_desc = self.wrpc.getdescriptorinfo('wsh(sortedmulti(2,' + pubkeys[2] + ',' + pubkeys[1] + ',' + pubkeys[0] + '))')['descriptor']

        sh_multi_import = {'desc': sh_multi_desc, "timestamp": "now", "label": "shmulti"}
        sh_wsh_multi_import = {'desc': sh_wsh_multi_desc, "timestamp": "now", "label": "shwshmulti"}
        # re-order pubkeys to allow import without "already have private keys" error
        wsh_multi_import = {'desc': wsh_multi_desc, "timestamp": "now", "label": "wshmulti"}
        multi_result = self.wrpc.importmulti([sh_multi_import, sh_wsh_multi_import, wsh_multi_import])
        self.assertTrue(multi_result[0]['success'])
        self.assertTrue(multi_result[1]['success'])
        self.assertTrue(multi_result[2]['success'])

        sh_multi_addr = self.wrpc.getaddressesbylabel("shmulti").popitem()[0]
        sh_wsh_multi_addr = self.wrpc.getaddressesbylabel("shwshmulti").popitem()[0]
        wsh_multi_addr = self.wrpc.getaddressesbylabel("wshmulti").popitem()[0]

        in_amt = 3
        out_amt = in_amt // 3
        number_inputs = 0
        # Single-sig
        if input_type == 'segwit' or input_type == 'all':
            self.wpk_rpc.sendtoaddress(sh_wpkh_addr, in_amt)
            self.wpk_rpc.sendtoaddress(wpkh_addr, in_amt)
            number_inputs += 2
        if input_type == 'legacy' or input_type == 'all':
            self.wpk_rpc.sendtoaddress(pkh_addr, in_amt)
            number_inputs += 1
        # Now do segwit/legacy multisig
        if multisig:
            if input_type == 'legacy' or input_type == 'all':
                self.wpk_rpc.sendtoaddress(sh_multi_addr, in_amt)
                number_inputs += 1
            if input_type == 'segwit' or input_type == 'all':
                self.wpk_rpc.sendtoaddress(wsh_multi_addr, in_amt)
                self.wpk_rpc.sendtoaddress(sh_wsh_multi_addr, in_amt)
                number_inputs += 2

        self.wpk_rpc.generatetoaddress(6, self.wpk_rpc.getnewaddress())

        # Spend different amounts, requiring 1 to 3 inputs
        for i in range(number_inputs):
            # Create a psbt spending the above
            if i == number_inputs - 1:
                self.assertTrue((i + 1) * in_amt == self.wrpc.getbalance("*", 0, True))
            psbt = self.wrpc.walletcreatefundedpsbt([], [{self.wpk_rpc.getnewaddress('', 'legacy'): (i + 1) * out_amt}, {self.wpk_rpc.getnewaddress('', 'p2sh-segwit'): (i + 1) * out_amt}, {self.wpk_rpc.getnewaddress('', 'bech32'): (i + 1) * out_amt}], 0, {'includeWatching': True, 'subtractFeeFromOutputs': [0, 1, 2]}, True)

            if external:
                # Sign with unknown inputs in two steps
                self._generate_and_finalize(True, psbt)
            # Sign all inputs all at once
            final_tx = self._generate_and_finalize(False, psbt)

        # Send off final tx to sweep the wallet
        self.wrpc.sendrawtransaction(final_tx)

    # Test wrapper to avoid mixed-inputs signing for Ledger
    def test_signtx(self):
        supports_mixed = {'coldcard', 'trezor_1', 'digitalbitbox', 'keepkey'}
        supports_multisig = {'ledger', 'trezor_1', 'digitalbitbox', 'keepkey', 'coldcard', 'trezor_t'}
        supports_external = {'ledger', 'trezor_1', 'digitalbitbox', 'keepkey', 'coldcard'}
        if self.full_type not in supports_mixed:
            self._test_signtx("legacy", self.full_type in supports_multisig, self.full_type in supports_external)
            self._test_signtx("segwit", self.full_type in supports_multisig, self.full_type in supports_external)
        else:
            self._test_signtx("all", self.full_type in supports_multisig, self.full_type in supports_external)

    # Make a huge transaction which might cause some problems with different interfaces
    def test_big_tx(self):
        # make a huge transaction that is unrelated to the hardware wallet
        outputs = []
        num_inputs = 60
        for i in range(0, num_inputs):
            outputs.append({self.wpk_rpc.getnewaddress('', 'legacy'): 0.001})
        psbt = self.wpk_rpc.walletcreatefundedpsbt([], outputs, 0, {}, True)['psbt']
        psbt = self.wpk_rpc.walletprocesspsbt(psbt)['psbt']
        tx = self.wpk_rpc.finalizepsbt(psbt)['hex']
        txid = self.wpk_rpc.sendrawtransaction(tx)
        inputs = []
        for i in range(0, num_inputs):
            inputs.append({'txid': txid, 'vout': i})
        psbt = self.wpk_rpc.walletcreatefundedpsbt(inputs, [{self.wpk_rpc.getnewaddress('', 'legacy'): 0.001 * num_inputs}], 0, {'subtractFeeFromOutputs': [0]}, True)['psbt']
        # For cli, this should throw an exception
        try:
            result = self.do_command(self.dev_args + ['signtx', psbt])
            if self.interface == 'cli':
                self.fail('Big tx did not cause CLI to error')
            if self.type == 'coldcard':
                self.assertEqual(result['code'], -7)
            else:
                self.assertNotIn('code', result)
                self.assertNotIn('error', result)
        except OSError:
            if self.interface == 'cli':
                pass
Пример #20
0
class Controller:
    def __init__(self, settings, nfc_broadcast):
        self.nfc_broadcast = nfc_broadcast
        self.bitcoind = AuthServiceProxy(settings['rpc_url'])
        self.current_address = ""
        self.exchange_rate = 0.0
        self.exchange_rate_source = ""
        self.currency = settings['exchange_rate_ticker']['currency']
        self.single_screen_mode = settings['single_screen_mode']
        self.green_addresses = settings['green_addresses']
        self.bt_addr = None

    def run(self):
        self.app = QtGui.QApplication([])

        font = self.app.font()
        font.setPointSize(12)
        self.app.setFont(font)

        self.app.connect(
            self.app,
            QtCore.SIGNAL('_new_transaction_received(PyQt_PyObject)'),
            self._new_transaction_received)
        self.app.connect(
            self.app, QtCore.SIGNAL('_exchange_rate_updated(PyQt_PyObject)'),
            self._exchange_rate_updated)

        self.merchant_gui = MerchantGUI(self, self.currency)
        self.merchant_gui.show()
        self.customer_display = CustomerDisplay('data/customer_display.html',
                                                self.single_screen_mode)
        if not self.single_screen_mode:
            self.customer_display.show()
        self.app.exec_()

    def init_new_transaction(self, amount, currency):
        if self.single_screen_mode:
            self.customer_display.show()
            if not self.customer_display.isFullScreen():
                self.customer_display.showFullScreen()
        if currency != "BTC":
            cur_amount = amount
            if self.exchange_rate != 0:
                amount = round(cur_amount / self.exchange_rate, 8)
            else:
                amount = 0

            conversion = '["%.2f %s", "%.4f %s", "%s"]' % (
                cur_amount, currency, self.exchange_rate, currency,
                self.exchange_rate_source)
        else:
            conversion = '-1'

        self.current_address = self.bitcoind.getnewaddress("Point of Sale")
        self.merchant_gui.update_status("Looking for a transaction to %s..." %
                                        self.current_address)

        amount_str = self.format_btc_amount(amount)
        btc_uri = self.create_btc_uri(self.current_address, amount_str,
                                      self.bt_addr)
        imgdata = self.create_img_data(btc_uri)
        js = 'show_payment_info("%s", %s, "%s", "%s")' % \
                ('%s BTC' % amount_str, conversion,
                        self.current_address, imgdata)

        self.customer_display.evaluate_java_script(js)
        self.nfc_broadcast.set_btc_uri(btc_uri)

    def create_btc_uri(self, address, amount_str, bt_addr):
        btc_uri = "bitcoin:%s?amount=%s" % (address, amount_str)
        if bt_addr != None:
            bt_addr_stripped = bt_addr.translate(None, ':')
            btc_uri += "&bt=%s" % bt_addr_stripped
        return btc_uri

    def create_img_data(self, btc_uri):
        (_, size, img) = qrencode.encode(btc_uri)
        if size < 400: img = img.resize((400, 400), Image.NEAREST)

        buf = StringIO()
        img.save(buf, format='PNG')
        imgdata = "data:image/png,%s" % urllib.quote(buf.getvalue())
        return imgdata

    def format_btc_amount(self, amount):
        s = "%.8f" % amount
        return re.sub("\.?0+$", "", s)

    # this is thread-safe, as long as it is called from a QThread
    def new_transaction_received(self, txid):
        if not hasattr(self, 'app'): return  # not yet read
        # emit signal, so we can process this on the Qt GUI thread
        self.app.emit(
            QtCore.SIGNAL('_new_transaction_received(PyQt_PyObject)'), txid)

    def _new_transaction_received(self, txid):
        # check if we are waiting for a payment
        if self.current_address == "": return

        # check if the txid looks sane before passing it
        # to bitcoind (for security reasons; might be overly
        # paranoid, but can't hurt)
        if re.search("^[a-f0-9]*$", txid) == None: return

        tx_info = self.bitcoind.gettransaction(txid)
        output_addresses = []
        for detail in tx_info['details']:
            output_addresses.append(detail['address'])
        if self.current_address not in output_addresses: return

        msg = "Transaction to %s received." % self.current_address
        (from_green_address,
         green_address_msg) = self.green_address_check(txid)
        if from_green_address: msg += " " + green_address_msg

        self.merchant_gui.update_status(msg)
        self.customer_display.evaluate_java_script('show_payment_received()')
        self.current_address = ""

    def bluetooth_available(self, bt_addr):
        self.bt_addr = bt_addr

    def new_transaction_via_bluetooth(self, tx):
        try:
            self.bitcoind.sendrawtransaction(tx)
        except JSONRPCException:
            # ignore, if this did not work - we might
            # have already received the transaction in
            # a different way
            pass

    def green_address_check(self, txid):
        found = False
        msg = ""

        origins = self.get_origins(txid)
        for origin in origins:
            if origin in self.green_addresses:
                found = True
                msg = self.green_addresses[origin]
                break

        return (found, msg)

    def get_origins(self, txid):
        try:
            origins = []
            raw_tx = self.bitcoind.getrawtransaction(txid, 1)
            vins = raw_tx['vin']
            for vin in vins:
                raw_tx = self.bitcoind.getrawtransaction(vin['txid'], 1)
                for vout in raw_tx['vout']:
                    if vin['vout'] == vout['n']:
                        origins.extend(vout['scriptPubKey']['addresses'])
            return origins
        except JSONRPCException:
            return []

    def toggle_fullscreen_mode(self):
        if not self.customer_display.isFullScreen():
            self.customer_display.showFullScreen()
        else:
            self.customer_display.showNormal()

    def clear_customer_display(self):
        self.customer_display.evaluate_java_script('show_idle()')
        self.merchant_gui.update_status("System ready.")

    # this is thread-safe, as long as it is called from a QThread
    def exchange_rate_updated(self, rate, source):
        if not hasattr(self, 'app'): return  # not yet read
        self.app.emit(QtCore.SIGNAL('_exchange_rate_updated(PyQt_PyObject)'),
                      (rate, source))

    def _exchange_rate_updated(self, data):
        (self.exchange_rate, self.exchange_rate_source) = data
        self.merchant_gui.update_exchange_rate(self.exchange_rate)
Пример #21
0
class myrstat(object):

    plotpath = None
    rpc = None
    block_window = None
    block_domain = None

    algos = []
    diffs = []
    heights = []
    versions = []
    bip9bits = []
    sizes = []
    times = []
    txnums = []

    blocklist = []

    algolist = ['sha256d', 'scrypt', 'groestl', 'yescrypt', 'argon2d']
    colorlist = ['#8ecf1d', '#2db6db', '#d7370c', '#ffe21b', '#8f3c85']
    figsize = (8, 6)
    lw = 2.0

    def __init__(self):
        # load config:
        Config = ConfigParser.ConfigParser(allow_no_value=True)
        Config.read('config.cfg')
        network = Config.get('Global', 'network')
        rpcusername = Config.get(network, 'rpcusername')
        rpcpassword = Config.get(network, 'rpcpassword')
        rpcport = Config.getint(network, 'rpcport')
        rpchostip = Config.get(network, 'rpchostip')
        self.plotpath = str(Config.get(network, 'htmlpath'))
        self.block_window = Config.getint(network, 'block_window')
        self.block_domain = Config.getint(network, 'block_domain')
        # set rpc:
        self.rpc = AuthServiceProxy('http://' + rpcusername + ':' +
                                    rpcpassword + '@' + rpchostip + ':' +
                                    str(rpcport))

    def run(self):
        self.getdata()
        self.getblockwindowlist()
        self.plotalgos()
        self.plotalgodiffs()
        self.plotversionma_algo()
        self.plotversionma()

    def get_moving_average_for_algo(self, algo, dlist, value, bip9=False):
        """Given an algo, give moving average percentage of value. Here bip9 is
        actually the bit signaling + 1"""
        # first get data for the algo:
        da = self.get_data_for_algo(algo, dlist, start=0)
        h = self.get_data_for_algo(algo, self.heights, start=0)
        pct = []
        # loop through data to get list that match targets:
        for i, ds in enumerate(da):
            (x, y) = self.get_data_for_window(h, da, h[i] - self.block_window,
                                              h[i])
            domain_length = len(x)
            c = 0
            for tmp in y:
                if bip9:
                    # in this case, value is the bit we are seeking
                    tmp = bin(tmp)
                    if (tmp[0] != '-') and (len(tmp) >= value + 2):
                        if tmp[-value] == '1':
                            c += 1
                else:
                    if tmp == value: c += 1
            if (domain_length == 0):
                pct.append(0.)
            else:
                pct.append(float(c) / float(domain_length) * 100.)
        return pct

    def get_moving_average(self, dlist, value, bip9=False):
        """Give moving average percentage of value. Here bip9 is actually the 
        bit signaling + 1"""
        # first get data for the algo:
        da = dlist
        h = self.heights
        pct = []
        # loop through data to get list that match targets:
        for i, ds in enumerate(da):
            (x, y) = self.get_data_for_window(h, da, h[i] - self.block_window,
                                              h[i])
            domain_length = len(x)
            c = 0
            for tmp in y:
                if bip9:
                    # in this case, value is the bit we are seeking
                    tmp = bin(tmp)
                    if (tmp[0] != '-') and (len(tmp) >= value + 2):
                        if tmp[-value] == '1':
                            c += 1
                else:
                    if tmp == value: c += 1
            if (domain_length == 0):
                pct.append(0.)
            else:
                pct.append(float(c) / float(domain_length) * 100.)
        return pct

    def getdata(self):
        """Get data via rpc."""
        info = self.rpc.getblockchaininfo()
        block_height = info['blocks']
        block_min = block_height - self.block_domain - self.block_window
        for bh in xrange(block_min, block_height + 1, 1):
            bhash = self.rpc.getblockhash(bh)
            block = self.rpc.getblock(bhash)
            self.algos.append(block['pow_algo'])
            self.diffs.append(block['difficulty'])
            self.heights.append(block['height'])
            self.versions.append((block['version'] & 255))
            self.sizes.append(block['size'])
            self.times.append(block['time'])
            self.txnums.append(len(block['tx']))
            if ((block['version'] & 0xFF000000) == 536870912):
                self.bip9bits.append((block['version'] & 0x000000FF))
            else:
                self.bip9bits.append(-1)

    def get_data_for_window(self, x, y, xmin, xmax):
        """Return a list of y values in x that are between xmin and xmax."""
        yi = []
        xi = []
        for i, tmp in enumerate(x):
            if (tmp >= xmin) and (tmp <= xmax):
                yi.append(y[i])
                xi.append(x[i])
        return (xi, yi)

    def moving_average_pct(self, raw, tgt):
        """generate a subset of data based on looking back by block_window."""
        d = []
        for i in xrange(self.block_window,
                        self.block_domain + self.block_window + 1):
            count = 0.
            for k in xrange(0, self.block_window):
                if (raw[i - k] == tgt): count += 1
            d.append(count / self.block_window * 100.)
        return d

    def getblockwindowlist(self):
        """Gets the block list for plotting."""
        for i in xrange(self.block_window,
                        self.block_domain + self.block_window + 1):
            self.blocklist.append(self.heights[i])

    def get_data_for_algo(self, algo, dlist, start=0):
        """Get the list corresponding to the algo."""
        d = []
        for i in xrange(start, self.block_domain + self.block_window + 1):
            if (self.algos[i] == algo):
                d.append(dlist[i])
        return d

    def plotalgos(self):
        """plots aglos"""
        figure(figsize=self.figsize)
        for i, algo in enumerate(self.algolist):
            d = self.moving_average_pct(self.algos, algo)
            plt.plot(self.blocklist,
                     d,
                     '-',
                     color=self.colorlist[i],
                     label=algo,
                     linewidth=self.lw)
            plt.hold('on')
            plt.grid('on')
            ax = plt.gca()
            ax.get_xaxis().set_minor_locator(ticker.AutoMinorLocator())
            ax.get_yaxis().set_minor_locator(ticker.AutoMinorLocator())
            ax.set_xlim([self.blocklist[0], self.blocklist[-1]])
            ax.grid(b=True,
                    which='major',
                    color='#a0a0a0',
                    linestyle='-',
                    linewidth=1.0)
            ax.grid(b=True,
                    which='minor',
                    color='#dcdcdc',
                    linestyle='-',
                    linewidth=0.5)
            ax.get_xaxis().get_major_formatter().set_scientific(False)
            ax.get_xaxis().get_major_formatter().set_useOffset(False)
            ax.set_xlabel('Block Number')
            ax.set_ylabel('% of Blocks')
        ax.set_title('Block % for Mining Algorithms')
        legend(self.algolist, loc=0, prop={'size': 8})
        savefig(self.plotpath + 'algohist.png', bbox_inches='tight')

    def plotversionma(self):
        """plots block versions"""
        figure(figsize=self.figsize)
        dm1 = self.get_moving_average(self.bip9bits, -1)
        d1 = self.get_moving_average(self.bip9bits, 1, bip9=True)
        d2 = self.get_moving_average(self.bip9bits, 2, bip9=True)
        d3 = self.get_moving_average(self.bip9bits, 3, bip9=True)
        d5 = self.get_moving_average(self.bip9bits, 5, bip9=True)
        d6 = self.get_moving_average(self.bip9bits, 6, bip9=True)
        d7 = self.get_moving_average(self.bip9bits, 7, bip9=True)
        # create an indicator line:
        di = []
        dibip = []
        for i in d1:
            di.append(75.)
        h = self.heights
        # block window:
        bw_calc = h[-1] - (h[-1] % self.block_window)
        bw_x = [
            bw_calc, bw_calc, bw_calc - self.block_window,
            bw_calc - self.block_window, bw_calc
        ]
        bw_y = [0, 100, 100, 0, 0]
        #plt.plot(h,dm1,'-',color='red',label='Legacy Blocks',
        #    linewidth=self.lw)
        #plt.plot(h,d1,'-',color='blue',label='CSV Blocks',
        #    linewidth=self.lw)
        #plt.plot(h,d2,'-',color='magenta',label='segwit Blocks',
        #    linewidth=self.lw)
        plt.plot(h,
                 d3,
                 '-',
                 color='cyan',
                 label='legbit Blocks',
                 linewidth=self.lw)
        #plt.plot(h,d5,'-',color='red',label='reservealgo Blocks',
        #    linewidth=self.lw)
        #plt.plot(h,d6,'-',color='magenta',label='longblocks Blocks',
        #    linewidth=self.lw)
        plt.plot(h,
                 d7,
                 '-',
                 color='blue',
                 label='argon2d Blocks',
                 linewidth=self.lw)
        plt.plot(h,
                 di,
                 '-.',
                 color='green',
                 label='BIP9 Activation Threshold',
                 linewidth=self.lw)
        plt.plot(bw_x,
                 bw_y,
                 '-.',
                 color='orange',
                 label='Block Window',
                 linewidth=self.lw)
        plt.hold('on')
        plt.grid('on')
        ax = plt.gca()
        ax.get_xaxis().set_minor_locator(ticker.AutoMinorLocator())
        ax.grid(b=True,
                which='major',
                color='#a0a0a0',
                linestyle='-',
                linewidth=1.0)
        ax.grid(b=True,
                which='minor',
                color='#dcdcdc',
                linestyle='-',
                linewidth=0.5)
        ax.get_xaxis().get_major_formatter().set_scientific(False)
        ax.get_xaxis().get_major_formatter().set_useOffset(False)
        ax.set_xlim([self.blocklist[0], self.blocklist[-1]])
        ax.set_ylim([-10., 110.])
        ax.set_ylabel('%')
        legend(loc=0, prop={'size': 8})
        ax.set_title('Block Softforks')
        ax.set_xlabel('Block Number')
        savefig(self.plotpath + 'versionma.png', bbox_inches='tight')

    def plotalgodiffs(self):
        figure(figsize=self.figsize)
        for i, algo in enumerate(self.algolist):
            d = self.get_data_for_algo(algo, self.diffs)
            h = self.get_data_for_algo(algo, self.heights)
            plt.subplot(len(self.algolist), 1, i + 1)
            plt.plot(h,
                     d,
                     '-',
                     color=self.colorlist[i],
                     label=algo,
                     linewidth=self.lw)
            plt.hold('on')
            plt.grid('on')
            ax = plt.gca()
            ax.get_xaxis().set_minor_locator(ticker.AutoMinorLocator())
            ax.grid(b=True,
                    which='major',
                    color='#a0a0a0',
                    linestyle='-',
                    linewidth=1.0)
            ax.grid(b=True,
                    which='minor',
                    color='#dcdcdc',
                    linestyle='-',
                    linewidth=0.5)
            ax.get_xaxis().get_major_formatter().set_scientific(False)
            ax.get_xaxis().get_major_formatter().set_useOffset(False)
            ax.set_xlim([self.blocklist[0], self.blocklist[-1]])
            ax.set_ylabel(algo)
            if i == 0: ax.set_title('Mining Difficulty')
            if not i == (len(self.algolist) - 1):
                ax.xaxis.set_ticklabels([])
            else:
                ax.set_xlabel('Block Number')
        savefig(self.plotpath + 'diffhist.png', bbox_inches='tight')

    def plotversionma_algo(self):
        figure(figsize=self.figsize)
        for i, algo in enumerate(self.algolist):
            dm1 = self.get_moving_average_for_algo(algo, self.bip9bits, -1)
            d1 = self.get_moving_average_for_algo(algo,
                                                  self.bip9bits,
                                                  1,
                                                  bip9=True)
            d2 = self.get_moving_average_for_algo(algo,
                                                  self.bip9bits,
                                                  2,
                                                  bip9=True)
            d3 = self.get_moving_average_for_algo(algo,
                                                  self.bip9bits,
                                                  3,
                                                  bip9=True)
            d5 = self.get_moving_average_for_algo(algo,
                                                  self.bip9bits,
                                                  5,
                                                  bip9=True)
            d6 = self.get_moving_average_for_algo(algo,
                                                  self.bip9bits,
                                                  6,
                                                  bip9=True)
            d7 = self.get_moving_average_for_algo(algo,
                                                  self.bip9bits,
                                                  7,
                                                  bip9=True)
            h = self.get_data_for_algo(algo, self.heights)
            plt.subplot(len(self.algolist), 1, i + 1)
            #plt.plot(h,dm1,'-',color='red',label='Legacy Blocks',
            #    linewidth=self.lw)
            #plt.plot(h,d1,'-',color='blue',label='CSV  Blocks',
            #    linewidth=self.lw)
            #plt.plot(h,d2,'-',color='magenta',label='segwit Blocks',
            #    linewidth=self.lw)
            plt.plot(h,
                     d3,
                     '-',
                     color='cyan',
                     label='legbit Blocks',
                     linewidth=self.lw)
            #plt.plot(h,d5,'-',color='red',label='reservealgo Blocks',
            #    linewidth=self.lw)
            #plt.plot(h,d6,'-',color='magenta',label='longblocks Blocks',
            #    linewidth=self.lw)
            plt.plot(h,
                     d7,
                     '-',
                     color='blue',
                     label='argon2d Blocks',
                     linewidth=self.lw)
            plt.hold('on')
            plt.grid('on')
            ax = plt.gca()
            ax.get_xaxis().set_minor_locator(ticker.AutoMinorLocator())
            ax.grid(b=True,
                    which='major',
                    color='#a0a0a0',
                    linestyle='-',
                    linewidth=1.0)
            ax.grid(b=True,
                    which='minor',
                    color='#dcdcdc',
                    linestyle='-',
                    linewidth=0.5)
            ax.get_xaxis().get_major_formatter().set_scientific(False)
            ax.get_xaxis().get_major_formatter().set_useOffset(False)
            ax.set_xlim([self.blocklist[0], self.blocklist[-1]])
            ax.set_ylim([-10., 110.])
            ax.set_ylabel(algo)
            legend(loc=3, prop={'size': 8})
            if i == 0: ax.set_title('Block Softfork %')
            if not i == (len(self.algolist) - 1):
                ax.xaxis.set_ticklabels([])
            else:
                ax.set_xlabel('Block Number')
        savefig(self.plotpath + 'algoversionma.png', bbox_inches='tight')
Пример #22
0
class myrstat(object):

    plotpath = None
    rpc = None
    block_window = None
    block_domain = None

    algos = []
    diffs = []
    heights = []
    versions = []
    bip9bits = []
    sizes = []
    times = []
    txnums = []

    blocklist = []

    algolist = ['NeoScrypt','Argon2d','Lyra2CZ']
    colorlist = ['#8ecf1d','#2db6db','#a654c9']
    figsize=(8,6)
    lw=2.0

    def __init__(self):
        # load config:
        Config = ConfigParser.ConfigParser(allow_no_value = True)
        Config.read('config.cfg')
        network = Config.get('Global','network')
        rpcusername = Config.get(network,'rpcusername')
        rpcpassword = Config.get(network,'rpcpassword')
        rpcport = Config.getint(network,'rpcport')
        rpchostip = Config.get(network,'rpchostip')
        self.plotpath = str(Config.get(network,'htmlpath'))
        self.block_window = Config.getint(network,'block_window')
        self.block_domain = Config.getint(network,'block_domain')
        # set rpc:
        self.rpc = AuthServiceProxy('http://'+rpcusername+':'+rpcpassword+'@'+
                rpchostip+':'+str(rpcport))

    def run(self):
        self.getdata()
        self.getblockwindowlist()
        self.plotalgos()
        self.plotalgodiffs()
       # self.plotversionma_algo()
       # self.plotversionma()

    def get_moving_average_for_algo(self,algo,dlist,value,bip9=False):
        """Given an algo, give moving average percentage of value. Here bip9 is
        actually the bit signaling + 1"""
        # first get data for the algo:
        da = self.get_data_for_algo(algo,dlist,start=0)
        h = self.get_data_for_algo(algo,self.heights,start=0)
        pct = []
        # loop through data to get list that match targets:
        for i,ds in enumerate(da):
            (x,y) = self.get_data_for_window(h,da,h[i]-self.block_window,h[i])
            domain_length=len(x)
            c=0
            for tmp in y:
                if bip9:
                    # in this case, value is the bit we are seeking
                    tmp = bin(tmp)
                    if (tmp[0]!='-') and (len(tmp)>=value+2):
                        if tmp[-value]=='1':
                            c+=1
                else:
                    if tmp==value: c+=1
            if (domain_length==0):
                pct.append(0.)
            else:
                pct.append(float(c)/float(domain_length)*100.)
        return pct
    
    def get_moving_average(self,dlist,value,bip9=False):
        """Give moving average percentage of value. Here bip9 is actually the 
        bit signaling + 1"""
        # first get data for the algo:
        da = dlist
        h = self.heights
        pct = []
        # loop through data to get list that match targets:
        for i,ds in enumerate(da):
            (x,y) = self.get_data_for_window(h,da,h[i]-self.block_window,h[i])
            domain_length=len(x)
            c=0
            for tmp in y:
                if bip9:
                    # in this case, value is the bit we are seeking
                    tmp = bin(tmp)
                    if (tmp[0]!='-') and (len(tmp)>=value+2):
                        if tmp[-value]=='1':
                            c+=1
                else:
                    if tmp==value: c+=1
            if (domain_length==0):
                pct.append(0.)
            else:
                pct.append(float(c)/float(domain_length)*100.)
        return pct

    def getdata(self):
        """Get data via rpc."""
        info = self.rpc.getblockchaininfo()
        block_height = info['blocks']
        block_min = block_height - self.block_domain - self.block_window
        for bh in xrange(block_min,block_height+1,1):
            bhash = self.rpc.getblockhash(bh)
            block = self.rpc.getblock(bhash)
            self.algos.append(block['pow_algo'])
            self.diffs.append(block['difficulty'])
            self.heights.append(block['height'])
            self.versions.append((block['version'] & 255))
            self.sizes.append(block['size'])
            self.times.append(block['time'])
            self.txnums.append(len(block['tx']))
            if ((block['version'] & 0xFF000000) == 536870912):
                self.bip9bits.append((block['version'] & 0x000000FF))
            else:
                self.bip9bits.append(-1)

    def get_data_for_window(self,x,y,xmin,xmax):
        """Return a list of y values in x that are between xmin and xmax."""
        yi = []
        xi = []
        for i,tmp in enumerate(x):
            if (tmp>=xmin) and (tmp<=xmax):
                yi.append(y[i])
                xi.append(x[i])
        return (xi,yi)

    def moving_average_pct(self,raw,tgt):
        """generate a subset of data based on looking back by block_window."""
        d = []
        for i in xrange(self.block_window,
            self.block_domain+self.block_window+1):
            count=0.
            for k in xrange(0,self.block_window):
                if (raw[i-k]==tgt): count+=1
            d.append(count/self.block_window*100.)
        return d

    def getblockwindowlist(self):
        """Gets the block list for plotting."""
        for i in xrange(self.block_window,
            self.block_domain+self.block_window+1):
            self.blocklist.append(self.heights[i])

    def get_data_for_algo(self,algo,dlist,start=0):
        """Get the list corresponding to the algo."""
        d = []
        for i in xrange(start,self.block_domain+self.block_window+1):
            if (self.algos[i]==algo):
                d.append(dlist[i])
        return d

    def plotalgos(self):
        """plots aglos"""
        figure(figsize=self.figsize)
        for i, algo in enumerate(self.algolist):
            d = self.moving_average_pct(self.algos,algo)
            plt.plot(self.blocklist,d,'-',color=self.colorlist[i],label=algo,
                linewidth=self.lw)
            plt.hold('on')
            plt.grid('on')
            ax = plt.gca()
            ax.get_xaxis().set_minor_locator(ticker.AutoMinorLocator())
            ax.get_yaxis().set_minor_locator(ticker.AutoMinorLocator())
            ax.set_xlim([self.blocklist[0], self.blocklist[-1]])
            ax.grid(b=True, which='major', color='#a0a0a0', linestyle='-',
                linewidth=1.0)
            ax.grid(b=True, which='minor', color='#dcdcdc', linestyle='-',
                linewidth=0.5)
            ax.get_xaxis().get_major_formatter().set_scientific(False)
            ax.get_xaxis().get_major_formatter().set_useOffset(False)
            ax.set_xlabel('Block Number')
            ax.set_ylabel('% of Blocks')
        ax.set_title('Block % for Mining Algorithms')
        legend(self.algolist,loc=0,prop={'size':8})
        savefig(self.plotpath+'algohist.png',bbox_inches='tight')

    def plotalgodiffs(self):
        figure(figsize=self.figsize)
        for i, algo in enumerate(self.algolist):
            d = self.get_data_for_algo(algo,self.diffs)
            h = self.get_data_for_algo(algo,self.heights)
            plt.subplot(len(self.algolist),1,i+1)
            plt.plot(h,d,'-',color=self.colorlist[i],label=algo,
                linewidth=self.lw)
            plt.hold('on')
            plt.grid('on')
            ax = plt.gca()
            ax.get_xaxis().set_minor_locator(ticker.AutoMinorLocator())
            ax.grid(b=True, which='major', color='#a0a0a0', linestyle='-',
                linewidth=1.0)
            ax.grid(b=True, which='minor', color='#dcdcdc', linestyle='-',
                linewidth=0.5)
            ax.get_xaxis().get_major_formatter().set_scientific(False)
            ax.get_xaxis().get_major_formatter().set_useOffset(False)
            ax.set_xlim([self.blocklist[0], self.blocklist[-1]])
            ax.set_ylabel(algo)
            if i==0: ax.set_title('Mining Difficulty')
            if not i==(len(self.algolist)-1):
                ax.xaxis.set_ticklabels([])
            else:
                ax.set_xlabel('Block Number')
        savefig(self.plotpath+'diffhist.png',bbox_inches='tight')
Пример #23
0
    args = parser.parse_args()
    args.config = os.path.expanduser(args.config)

    # Get user and password from config
    user = None
    password = None
    if os.path.isfile(args.config):
        with open(args.config, 'r', encoding='utf8') as f:
            for line in f:
                if line.startswith("rpcuser="******"=")[1].strip("\n")
                if line.startswith("rpcpassword="******"=")[1].strip("\n")
    else:
        raise FileNotFoundError("Missing lotus.conf")
    if user is None:
        raise ValueError("Config is missing rpcuser")
    if password is None:
        raise ValueError("Config is missing rpcpassword")

    args.rpc = AuthServiceProxy(service_url='http://{}:{}@{}'.format(
        user, password, args.address),
                                timeout=1200)
    output = main(vars(args))
    if output:
        print(output)
Пример #24
0
class TestDisplayAddress(DeviceTestCase):
    def setUp(self):
        self.rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(
            self.rpc_userpass))
        if '{}_test'.format(self.full_type) not in self.rpc.listwallets():
            self.rpc.createwallet('{}_test'.format(self.full_type), True)
        self.wrpc = AuthServiceProxy(
            'http://{}@127.0.0.1:18443/wallet/{}_test'.format(
                self.rpc_userpass, self.full_type))
        self.wpk_rpc = AuthServiceProxy(
            'http://{}@127.0.0.1:18443/wallet/'.format(self.rpc_userpass))
        if '--testnet' not in self.dev_args:
            self.dev_args.append('--testnet')
        self.emulator.start()

    def test_display_address_bad_args(self):
        result = self.do_command(self.dev_args + [
            'displayaddress', '--sh_wpkh', '--wpkh', '--path',
            'm/49h/1h/0h/0/0'
        ])
        self.assertIn('error', result)
        self.assertIn('code', result)
        self.assertEqual(result['code'], -7)

    def test_display_address_path(self):
        result = self.do_command(
            self.dev_args + ['displayaddress', '--path', 'm/44h/1h/0h/0/0'])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

        result = self.do_command(
            self.dev_args +
            ['displayaddress', '--sh_wpkh', '--path', 'm/49h/1h/0h/0/0'])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

        result = self.do_command(
            self.dev_args +
            ['displayaddress', '--wpkh', '--path', 'm/84h/1h/0h/0/0'])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

    def test_display_address_bad_path(self):
        result = self.do_command(self.dev_args +
                                 ['displayaddress', '--path', 'f'])
        self.assertEquals(result['code'], -7)

    def test_display_address_descriptor(self):
        account_xpub = self.do_command(self.dev_args +
                                       ['getxpub', 'm/84h/1h/0h'])['xpub']
        p2sh_segwit_account_xpub = self.do_command(
            self.dev_args + ['getxpub', 'm/49h/1h/0h'])['xpub']
        legacy_account_xpub = self.do_command(
            self.dev_args + ['getxpub', 'm/44h/1h/0h'])['xpub']

        # Native SegWit address using xpub:
        result = self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'wpkh([' + self.fingerprint +
            '/84h/1h/0h]' + account_xpub + '/0/0)'
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

        # Native SegWit address using hex encoded pubkey:
        result = self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'wpkh([' + self.fingerprint +
            '/84h/1h/0h]' + xpub_to_pub_hex(account_xpub) + '/0/0)'
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

        # P2SH wrapped SegWit address using xpub:
        result = self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'sh(wpkh([' + self.fingerprint +
            '/49h/1h/0h]' + p2sh_segwit_account_xpub + '/0/0))'
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

        # Legacy address
        result = self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'pkh([' + self.fingerprint +
            '/44h/1h/0h]' + legacy_account_xpub + '/0/0)'
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

        # Should check xpub
        result = self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'wpkh([' + self.fingerprint +
            '/84h/1h/0h]' + "not_and_xpub" + '/0/0)'
        ])
        self.assertIn('error', result)
        self.assertIn('code', result)
        self.assertEqual(result['code'], -7)

        # Should check hex pub
        result = self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'wpkh([' + self.fingerprint +
            '/84h/1h/0h]' + "not_and_xpub" + '/0/0)'
        ])
        self.assertIn('error', result)
        self.assertIn('code', result)
        self.assertEqual(result['code'], -7)

        # Should check fingerprint
        self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'wpkh([00000000/84h/1h/0h]' +
            account_xpub + '/0/0)'
        ])
        self.assertIn('error', result)
        self.assertIn('code', result)
        self.assertEqual(result['code'], -7)

    def test_display_address_multisig_path(self):
        supports_multisig = {'trezor_1', 'keepkey', 'coldcard', 'trezor_t'}
        if self.full_type not in supports_multisig:
            return
        # Import some keys to the watch only wallet and get multisig address
        keypool_desc = self.do_command(self.dev_args +
                                       ['getkeypool', '--sh_wpkh', '40', '50'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        keypool_desc = self.do_command(
            self.dev_args +
            ['getkeypool', '--sh_wpkh', '--internal', '40', '50'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        sh_wpkh_addr = self.wrpc.getnewaddress('', 'p2sh-segwit')
        wpkh_addr = self.wrpc.getnewaddress('', 'bech32')
        pkh_addr = self.wrpc.getnewaddress('', 'legacy')
        self.wrpc.importaddress(wpkh_addr)
        self.wrpc.importaddress(pkh_addr)

        # pubkeys to construct 2-of-3 multisig descriptors for import
        sh_wpkh_info = self.wrpc.getaddressinfo(sh_wpkh_addr)
        wpkh_info = self.wrpc.getaddressinfo(wpkh_addr)
        pkh_info = self.wrpc.getaddressinfo(pkh_addr)

        pubkeys = [
            sh_wpkh_info['desc'][8:-11], wpkh_info['desc'][5:-10],
            pkh_info['desc'][4:-10]
        ]

        # Get the descriptors with their checksums
        sh_multi_desc = self.wrpc.getdescriptorinfo('sh(sortedmulti(2,' +
                                                    pubkeys[0] + ',' +
                                                    pubkeys[1] + ',' +
                                                    pubkeys[2] +
                                                    '))')['descriptor']
        sh_wsh_multi_desc = self.wrpc.getdescriptorinfo(
            'sh(wsh(sortedmulti(2,' + pubkeys[0] + ',' + pubkeys[1] + ',' +
            pubkeys[2] + ')))')['descriptor']
        wsh_multi_desc = self.wrpc.getdescriptorinfo('wsh(sortedmulti(2,' +
                                                     pubkeys[2] + ',' +
                                                     pubkeys[1] + ',' +
                                                     pubkeys[0] +
                                                     '))')['descriptor']

        sh_multi_import = {
            'desc': sh_multi_desc,
            "timestamp": "now",
            "label": "shmulti-display"
        }
        sh_wsh_multi_import = {
            'desc': sh_wsh_multi_desc,
            "timestamp": "now",
            "label": "shwshmulti-display"
        }
        # re-order pubkeys to allow import without "already have private keys" error
        wsh_multi_import = {
            'desc': wsh_multi_desc,
            "timestamp": "now",
            "label": "wshmulti-display"
        }
        multi_result = self.wrpc.importmulti(
            [sh_multi_import, sh_wsh_multi_import, wsh_multi_import])
        self.assertTrue(multi_result[0]['success'])
        self.assertTrue(multi_result[1]['success'])
        self.assertTrue(multi_result[2]['success'])

        sh_multi_addr = self.wrpc.getaddressesbylabel(
            "shmulti-display").popitem()[0]
        sh_wsh_multi_addr = self.wrpc.getaddressesbylabel(
            "shwshmulti-display").popitem()[0]
        wsh_multi_addr = self.wrpc.getaddressesbylabel(
            "wshmulti-display").popitem()[0]

        sh_multi_addr_redeem_script = self.wrpc.getaddressinfo(
            sh_multi_addr)['hex']
        sh_wsh_multi_addr_redeem_script = self.wrpc.getaddressinfo(
            sh_multi_addr)['hex']
        wsh_multi_addr_redeem_script = self.wrpc.getaddressinfo(
            sh_multi_addr)['hex']

        path = pubkeys[2][1:24] + ',' + pubkeys[1][1:24] + ',' + pubkeys[0][
            1:24]
        # need to replace `'` with `h` for stdin option to work
        path = path.replace("'", "h")

        # legacy
        result = self.do_command(self.dev_args + [
            'displayaddress', '--path', path, '--redeem_script',
            sh_multi_addr_redeem_script
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)
        self.assertEqual(sh_multi_addr, result['address'])

        # wrapped segwit
        result = self.do_command(self.dev_args + [
            'displayaddress', '--sh_wpkh', '--path', path, '--redeem_script',
            sh_wsh_multi_addr_redeem_script
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)
        self.assertEqual(sh_wsh_multi_addr, result['address'])

        # native setwit
        result = self.do_command(self.dev_args + [
            'displayaddress', '--wpkh', '--path', path, '--redeem_script',
            wsh_multi_addr_redeem_script
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)
        # removes prefix and checksum since regtest gives
        # prefix `bcrt` on Bitcoin Core while wallets return testnet `tb` prefix
        self.assertEqual(wsh_multi_addr[4:58], result['address'][2:56])

    def test_display_address_multisig_descriptor(self):
        supports_multisig = {'trezor_1', 'keepkey', 'coldcard', 'trezor_t'}
        if self.full_type not in supports_multisig:
            return
        # Import some keys to the watch only wallet and get multisig address
        keypool_desc = self.do_command(self.dev_args +
                                       ['getkeypool', '--sh_wpkh', '50', '60'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        keypool_desc = self.do_command(
            self.dev_args +
            ['getkeypool', '--sh_wpkh', '--internal', '50', '60'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        sh_wpkh_addr = self.wrpc.getnewaddress('', 'p2sh-segwit')
        wpkh_addr = self.wrpc.getnewaddress('', 'bech32')
        pkh_addr = self.wrpc.getnewaddress('', 'legacy')
        self.wrpc.importaddress(wpkh_addr)
        self.wrpc.importaddress(pkh_addr)

        # pubkeys to construct 2-of-3 multisig descriptors for import
        sh_wpkh_info = self.wrpc.getaddressinfo(sh_wpkh_addr)
        wpkh_info = self.wrpc.getaddressinfo(wpkh_addr)
        pkh_info = self.wrpc.getaddressinfo(pkh_addr)

        pubkeys = [
            sh_wpkh_info['desc'][8:-11], wpkh_info['desc'][5:-10],
            pkh_info['desc'][4:-10]
        ]

        # Get the descriptors with their checksums
        sh_multi_desc = self.wrpc.getdescriptorinfo('sh(sortedmulti(2,' +
                                                    pubkeys[0] + ',' +
                                                    pubkeys[1] + ',' +
                                                    pubkeys[2] +
                                                    '))')['descriptor']
        sh_wsh_multi_desc = self.wrpc.getdescriptorinfo(
            'sh(wsh(sortedmulti(2,' + pubkeys[0] + ',' + pubkeys[1] + ',' +
            pubkeys[2] + ')))')['descriptor']
        wsh_multi_desc = self.wrpc.getdescriptorinfo('wsh(sortedmulti(2,' +
                                                     pubkeys[2] + ',' +
                                                     pubkeys[1] + ',' +
                                                     pubkeys[0] +
                                                     '))')['descriptor']

        sh_multi_import = {
            'desc': sh_multi_desc,
            "timestamp": "now",
            "label": "shmulti-display-desc"
        }
        sh_wsh_multi_import = {
            'desc': sh_wsh_multi_desc,
            "timestamp": "now",
            "label": "shwshmulti-display-desc"
        }
        # re-order pubkeys to allow import without "already have private keys" error
        wsh_multi_import = {
            'desc': wsh_multi_desc,
            "timestamp": "now",
            "label": "wshmulti-display-desc"
        }
        multi_result = self.wrpc.importmulti(
            [sh_multi_import, sh_wsh_multi_import, wsh_multi_import])
        self.assertTrue(multi_result[0]['success'])
        self.assertTrue(multi_result[1]['success'])
        self.assertTrue(multi_result[2]['success'])

        sh_multi_addr = self.wrpc.getaddressesbylabel(
            "shmulti-display-desc").popitem()[0]
        sh_wsh_multi_addr = self.wrpc.getaddressesbylabel(
            "shwshmulti-display-desc").popitem()[0]
        wsh_multi_addr = self.wrpc.getaddressesbylabel(
            "wshmulti-display-desc").popitem()[0]

        # need to replace `'` with `h` and to remove checksome for the stdin option to work
        sh_multi_desc = sh_multi_desc.replace("'", "h").split('#')[0]
        sh_wsh_multi_desc = sh_wsh_multi_desc.replace("'", "h").split('#')[0]
        wsh_multi_desc = wsh_multi_desc.replace("'", "h").split('#')[0]

        # legacy
        result = self.do_command(self.dev_args +
                                 ['displayaddress', '--desc', sh_multi_desc])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)
        self.assertEqual(sh_multi_addr, result['address'])

        # wrapped segwit
        result = self.do_command(
            self.dev_args + ['displayaddress', '--desc', sh_wsh_multi_desc])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)
        self.assertEqual(sh_wsh_multi_addr, result['address'])

        # native setwit
        result = self.do_command(self.dev_args +
                                 ['displayaddress', '--desc', wsh_multi_desc])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)
        # removes prefix and checksum since regtest gives
        # prefix `bcrt` on Bitcoin Core while wallets return testnet `tb` prefix
        self.assertEqual(wsh_multi_addr[4:58], result['address'][2:56])
Пример #25
0
class ApiReceiveApplication(tornado.web.Application):
    def __init__(self, options, instance_name):
        self.options = options
        self.instance_name = instance_name
        handlers = [
            (r"/api/receive", ReceiveHandler),
            (r"/api/walletnotify/(?P<txid>[^\/]+)", WalletNotifyHandler),
            (r"/api/blocknotify/(?P<hash>[^\/]+)", BlockNotifyHandler),
        ]
        settings = dict(cookie_secret='cookie_secret')
        tornado.web.Application.__init__(self, handlers, **settings)

        input_log_file_handler = logging.handlers.TimedRotatingFileHandler(
            self.options.log, when='MIDNIGHT')
        formatter = logging.Formatter('%(asctime)s - %(message)s')
        input_log_file_handler.setFormatter(formatter)

        self.bitcoind = AuthServiceProxy(self.options.rpc_url)
        self.paytxfee = self.bitcoind.getinfo()['paytxfee']

        self.replay_logger = logging.getLogger(self.instance_name)
        self.replay_logger.setLevel(logging.DEBUG)
        self.replay_logger.addHandler(input_log_file_handler)
        self.replay_logger.info('START')

        ch = logging.StreamHandler(sys.stdout)
        ch.setLevel(logging.DEBUG)
        ch.setFormatter(
            logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
        self.replay_logger.addHandler(ch)

        from models import Base, db_bootstrap
        engine = create_engine(self.options.db_engine,
                               echo=self.options.db_echo)
        Base.metadata.create_all(engine)
        self.db_session = scoped_session(sessionmaker(bind=engine))
        db_bootstrap(self.db_session)

        self.log_start_data()

    def invoke_callback_url(self, forwarding_address):
        url = forwarding_address.get_callback_url()
        self.log('EXECUTE', 'curl ' + url)
        context = ssl._create_unverified_context()
        http_client = httpclient.AsyncHTTPClient(defaults=dict(
            ssl_options=context))
        http_client.fetch(
            url, partial(self.on_handle_callback_url, forwarding_address.id))

    def on_handle_callback_url(self, forwarding_address_id, response):
        from models import ForwardingAddress
        forwarding_address = ForwardingAddress.get_by_id(
            self.db_session, forwarding_address_id)

        if response.error:
            self.log('ERROR', str(response.error))
            forwarding_address.callback_number_of_errors += 1
            self.db_session.add(forwarding_address)
            self.db_session.commit()
        else:
            if response.body == '*ok*':
                forwarding_address.is_confirmed_by_client = True
                self.db_session.add(forwarding_address)
                self.db_session.commit()

    def log(self, command, key, value=None):
        #if len(logging.getLogger().handlers):
        #  logging.getLogger().handlers = []  # workaround to avoid stdout logging from the root logger

        log_msg = command + ',' + key
        if value:
            try:
                log_msg += ',' + value
            except Exception as e:
                try:
                    log_msg += ',' + str(value)
                except Exception as e:
                    try:
                        log_msg += ',' + str(value)
                    except Exception as e:
                        log_msg += ', [object]'

        self.replay_logger.info(log_msg)

    def log_start_data(self):
        self.log('PARAM', 'BEGIN')
        self.log('PARAM', 'port', self.options.port)
        self.log('PARAM', 'log', self.options.log)
        self.log('PARAM', 'db_echo', self.options.db_echo)
        self.log('PARAM', 'db_engine', self.options.db_engine)
        self.log('PARAM', 'rpc_url', self.options.rpc_url)
        self.log('PARAM', 'END')

        from models import ForwardingAddress
        fwd_address_list = self.db_session.query(ForwardingAddress)
        for fwd_address in fwd_address_list:
            self.log('DB_ENTITY', 'FORWARDING_ADDRESS', fwd_address)

        bitcoin_info = self.bitcoind.getinfo()
        self.log('INFO', 'BITCOIND_GETINFO', str(bitcoin_info))

    def clean_up(self):
        pass
Пример #26
0
sys.path.append(auth)
from authproxy import AuthServiceProxy

parser = argparse.ArgumentParser()
parser.add_argument('datadir')
parser.add_argument('txcount', type=int)
args = parser.parse_args()

# Wait for cookie file to be created
while not os.path.exists(args.datadir + '/regtest/.cookie'):
    time.sleep(0.5)

# Read .cookie file to get user and pass
with open(args.datadir + '/regtest/.cookie') as f:
    userpass = f.readline().lstrip().rstrip()
rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(userpass))

# Wait for bitcoind to be ready
ready: bool = False
while not ready:
    try:
        rpc.getblockchaininfo()
        ready = True
    except Exception:
        time.sleep(0.5)
        pass
print('bitcoind ready')

for item in rpc.listwalletdir()['wallets']:
    if 'big' == item['name']:
        break
Пример #27
0
 def setup_wallets(self):
     wallet_name = '{}_{}_test'.format(self.full_type, self.id())
     self.rpc.createwallet(wallet_name=wallet_name, disable_private_keys=True, descriptors=True)
     self.wrpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/{}'.format(self.rpc_userpass, wallet_name))
     self.wpk_rpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/supply'.format(self.rpc_userpass))
Пример #28
0
def initialize_chain(test_dir):
    """
    Create (or copy from cache) a 200-block-long chain and
    4 wallets.
    bitcoind and bitcoin-cli must be in search path.
    """

    # Due to the consensus change fix for the timejacking attack, we need to
    # ensure that the cache is pretty fresh. Specifically, we need the median
    # time past of the chain tip of the cache to be no more than 90 minutes
    # behind the current local time, or else mined blocks will be rejected by
    # all nodes, halting the test. With Sapling active by default, this requires
    # the chain tip itself to be no more than 75 minutes behind the current
    # local time.
    #
    # We address this here, by regenerating the cache if it is more than 60
    # minutes old. This gives 15 minutes of slack initially that an RPC test has
    # to complete in, if it is started right at the oldest cache time. Within an
    # individual test, the first five calls to `generate` will each advance the
    # median time past of the chain tip by 2.5 minutes (with Sapling active by
    # default). Therefore, if the logic between the completion of any two
    # adjacent calls to `generate` within a test takes longer than 2.5 minutes,
    # the excess will subtract from the slack.
    if os.path.isdir(os.path.join("cache", "node0")):
        if os.stat("cache").st_mtime + (60 * 60) < time.time():
            print("initialize_chain(): Removing stale cache")
            shutil.rmtree("cache")

    if not os.path.isdir(os.path.join("cache", "node0")):
        devnull = open("/dev/null", "w+")
        # Create cache directories, run bitcoinds:
        for i in range(4):
            datadir = initialize_datadir("cache", i)
            args = [
                os.getenv("BITCOIND", "bitcoind"), "-keypool=1",
                "-datadir=" + datadir, "-discover=0"
            ]
            if i > 0:
                args.append("-connect=127.0.0.1:" + str(p2p_port(0)))
            bitcoind_processes[i] = subprocess.Popen(args)
            if os.getenv("PYTHON_DEBUG", ""):
                print "initialize_chain: bitcoind started, calling bitcoin-cli -rpcwait getblockcount"
            subprocess.check_call([
                os.getenv("BITCOINCLI", "bitcoin-cli"), "-datadir=" + datadir,
                "-rpcwait", "getblockcount"
            ],
                                  stdout=devnull)
            if os.getenv("PYTHON_DEBUG", ""):
                print "initialize_chain: bitcoin-cli -rpcwait getblockcount completed"
        devnull.close()
        rpcs = []
        for i in range(4):
            try:
                url = "http://*****:*****@127.0.0.1:%d" % (rpc_port(i), )
                rpcs.append(AuthServiceProxy(url))
            except:
                sys.stderr.write("Error connecting to " + url + "\n")
                sys.exit(1)

        # Create a 200-block-long chain; each of the 4 nodes
        # gets 25 mature blocks and 25 immature.
        # Blocks are created with timestamps 2.5 minutes apart (matching the
        # chain defaulting above to Sapling active), starting 200 * 2.5 minutes
        # before the current time.
        block_time = int(
            time.time()) - (200 * PRE_BUTTERCUP_BLOCK_TARGET_SPACING)
        for i in range(2):
            for peer in range(4):
                for j in range(25):
                    #set_node_times(rpcs, block_time)
                    rpcs[peer].generate(1)
                    block_time += PRE_BUTTERCUP_BLOCK_TARGET_SPACING
                # Must sync before next peer starts generating blocks
                sync_blocks(rpcs)
        # Check that local time isn't going backwards
        assert_greater_than(time.time() + 1, block_time)

        # Shut them down, and clean up cache directories:
        stop_nodes(rpcs)
        wait_bitcoinds()
        for i in range(4):
            os.remove(log_filename("cache", i, "debug.log"))
            os.remove(log_filename("cache", i, "db.log"))
            os.remove(log_filename("cache", i, "peers.dat"))
            os.remove(log_filename("cache", i, "fee_estimates.dat"))

    for i in range(4):
        from_dir = os.path.join("cache", "node" + str(i))
        to_dir = os.path.join(test_dir, "node" + str(i))
        shutil.copytree(from_dir, to_dir)
        initialize_datadir(test_dir, i)  # Overwrite port/rpcport in zcash.conf
Пример #29
0
class Watcher(Process):
    def __init__(self, url, userpass, rpccookiefile, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.buf = b""
        self.id = 0
        self.userpass = userpass
        self.signals = None
        self.last_log_time = time.time()

        # Parse the URL
        self.purl = urlparse(url)
        if self.purl.scheme != "stratum+tcp":
            raise ValueError(
                f"Unrecognized scheme {self.purl.scheme}, only 'stratum+tcp' is allowed"
            )
        if self.purl.hostname is None:
            raise ValueError(f"No hostname provided")
        if self.purl.port is None:
            raise ValueError(f"No port provided")
        if self.purl.path != "":
            raise ValueError(
                f"URL has a path {self.purl.path}, this is not valid")

        # Get the RPC cookie
        cookie_filepath = os.path.abspath(os.path.expanduser(rpccookiefile))
        with open(cookie_filepath, "r") as f:
            self.rpc_userpass = f.readline()

        # Open RPC connection
        self.rpc = AuthServiceProxy(
            f"http://{self.rpc_userpass}@localhost:8332")
        self.last_seen_blockhash = self.rpc.getbestblockhash()

        self.init_socket()

    def init_socket(self):
        # Make the socket
        self.sock = socket.socket()
        self.sock.settimeout(600)

    def close(self):
        try:
            self.sock.shutdown(socket.SHUT_RDWR)
        except OSError:
            pass
        self.sock.close()
        LOG.debug(f"Disconnected from {urlunparse(self.purl)}")

    def get_msg(self):
        while True:
            split_buf = self.buf.split(b"\n", maxsplit=1)
            r = split_buf[0]
            try:
                resp = json.loads(r)

                # Remove r from the buffer
                if len(split_buf) == 2:
                    self.buf = split_buf[1]
                else:
                    self.buf = b""

                # Decoded, so return this message
                return resp
            except json.JSONDecodeError:
                # Failed to decode, maybe missing, so try to get more
                new_buf = self.sock.recv(4096)
                if len(new_buf) == 0:
                    raise EOFError("Socket EOF received")
                self.buf += new_buf

    def send_jsonrpc(self, method, params):
        # Build the jsonrpc request
        data = {
            "jsonrpc": "2.0",
            "id": self.id,
            "method": method,
            "params": params,
        }
        self.id += 1

        # Send the jsonrpc request
        LOG.debug(f"Sending: {data}")
        json_data = json.dumps(data) + "\n"
        self.sock.send(json_data.encode())

        # Get the jsonrpc reqponse
        resp = self.get_msg()
        LOG.debug(f"Received: {resp}")

    def get_stratum_work(self):
        # Open TCP connection to the server
        self.sock.connect((self.purl.hostname, self.purl.port))
        LOG.debug(f"Connected to server {urlunparse(self.purl)}")

        # Subscribe to mining notifications
        self.send_jsonrpc("mining.subscribe", ["StratumWatcher/0.1"])
        LOG.debug(f"Subscribed to pool notifications")

        # Authorize with the pool
        self.send_jsonrpc("mining.authorize", self.userpass.split(":"))
        LOG.debug(f"Authed with the pool")

        # Wait for notifications
        while True:
            try:
                n = self.get_msg()
            except Exception as e:
                LOG.debug(f"Received exception for {self.purl.hostname}: {e}")
                break
            LOG.debug(f"Received notification: {n}")

            # Check the notification for mining.notify
            if "method" in n and n["method"] == "mining.notify":
                # Get the previous block hash
                prev_bh_stratum = struct.unpack("<IIIIIIII",
                                                bytes.fromhex(n["params"][1]))
                prev_bh = struct.pack(
                    "<IIIIIIII",
                    prev_bh_stratum[7],
                    prev_bh_stratum[6],
                    prev_bh_stratum[5],
                    prev_bh_stratum[4],
                    prev_bh_stratum[3],
                    prev_bh_stratum[2],
                    prev_bh_stratum[1],
                    prev_bh_stratum[0],
                ).hex()

                # Check that this is Bitcoin
                if prev_bh != self.last_seen_blockhash:
                    # If the blockhash doesn't match what we've cached, ask bitcoind
                    try:
                        self.rpc.getblockheader(prev_bh)
                        self.last_seen_blockhash = prev_bh
                    except JSONRPCException:
                        LOG.debug(f"Received non-Bitcoin work, ignoring")
                        continue

                # Check for taproot versionbits
                block_ver_hex = n["params"][5]
                block_ver = int.from_bytes(bytes.fromhex(block_ver_hex),
                                           byteorder="big")
                if block_ver & (1 << 2):
                    if self.signals is None:
                        LOG.info(
                            f"✅ Signaling initially: {self.purl.hostname}:{self.purl.port}"
                        )
                        self.last_log_time = time.time()
                    elif not self.signals:
                        LOG.info(
                            f"✅ Now signaling: {self.purl.hostname}:{self.purl.port}"
                        )
                        self.last_log_time = time.time()
                    elif time.time() - self.last_log_time > 300:
                        LOG.info(
                            f"✅ Still signaling: {self.purl.hostname}:{self.purl.port}"
                        )
                        self.last_log_time = time.time()
                    LOG.debug(
                        f"Issued new work that SIGNALS ✅ for Taproot from {self.purl.hostname}:{self.purl.port}"
                    )
                    self.signals = True
                else:
                    if self.signals is None:
                        LOG.info(
                            f"❌ Not signaling initially: {self.purl.hostname}:{self.purl.port}"
                        )
                        self.last_log_time = time.time()
                    elif self.signals:
                        LOG.info(
                            f"❌ Stopped signaling: {self.purl.hostname}:{self.purl.port}"
                        )
                        self.last_log_time = time.time()
                    elif time.time() - self.last_log_time > 300:
                        LOG.info(
                            f"❌ Still not signaling: {self.purl.hostname}:{self.purl.port}"
                        )
                        self.last_log_time = time.time()
                    LOG.debug(
                        f"Issued new work that DOES NOT SIGNAL ❌ for Taproot from {self.purl.hostname}:{self.purl.port}"
                    )
                    self.signals = False

    def run(self):
        # If there is a socket exception, retry
        while True:
            try:
                self.get_stratum_work()
            except (ConnectionRefusedError, EOFError, socket.timeout):
                pass
            self.close()
            self.init_socket()
Пример #30
0
import random
import urllib.request
import json
import re
import sys

# Requires running Core RPC server on standard mainnet RPC port
if len(sys.argv) < 7:
    raise Exception(
        'feeloop.py <RPC username> <RPC password> <oauth1> <oauth2> <token1> <token2>'
    )

while True:
    bitcoin_req = "http://" + sys.argv[1] + ":" + sys.argv[
        2] + "@127.0.0.1:8332"
    bitcoin = AuthServiceProxy(bitcoin_req)

    def get_rounded_feerate(result):
        rate = str(int(result * 1000000) / 10.0) + " sat/byte "
        if len(re.split("\.", rate)[0]) == 1:
            rate = " " + rate
        return rate

    try:
        mempool_info = bitcoin.getmempoolinfo()
        nextblock = [
            "Next: ",
            bitcoin.estimatesmartfee(1, "ECONOMICAL")["feerate"]
        ]
        hour = ["1h:   ", bitcoin.estimatesmartfee(6, "ECONOMICAL")["feerate"]]
        six_hours = [
Пример #31
0
 def get_wallet_rpc(self, wallet):
     url = self.rpc_url + f"/wallet/{wallet}"
     return AuthServiceProxy(url)
Пример #32
0
def start_node(i,
               dirname,
               extra_args=None,
               rpchost=None,
               timewait=None,
               binary=None):
    """
    Start a komodod and return RPC connection to it
    """
    datadir = os.path.join(dirname, "node" + str(i))
    # creating special config in case of cryptocondition asset chain test
    if extra_args[0] == '-ac_name=REGTEST':
        configpath = datadir + "/REGTEST.conf"
        with open(configpath, "w+") as config:
            config.write("regtest=1\n")
            config.write("rpcuser=rt\n")
            config.write("rpcpassword=rt\n")
            port = extra_args[3]
            config.write("rpcport=" + (port[9:]) + "\n")
            config.write("server=1\n")
            config.write("txindex=1\n")
            config.write("rpcworkqueue=256\n")
            config.write("rpcallowip=127.0.0.1\n")
            config.write("bind=127.0.0.1\n")
            config.write("rpcbind=127.0.0.1")
    if binary is None:
        binary = os.getenv("BITCOIND", "komodod")
    args = [
        binary, "-datadir=" + datadir, "-keypool=1", "-discover=0", "-rest"
    ]
    if extra_args is not None: args.extend(extra_args)
    #print("args=" + ' '.join(args))
    bitcoind_processes[i] = subprocess.Popen(args)
    devnull = open("/dev/null", "w+")

    cmd = os.getenv("BITCOINCLI", "komodo-cli")
    print("cmd=" + cmd)
    cmd_args = ' '.join(extra_args) + " -rpcwait getblockcount "
    if os.getenv("PYTHON_DEBUG", ""):
        print "start_node: komodod started, calling : " + cmd + " " + cmd_args
    strcmd = cmd + " " + cmd_args

    print("Running " + strcmd)
    import time
    time.sleep(2)
    subprocess.check_call(strcmd, shell=True)
    #subprocess.check_call([ os.getenv("BITCOINCLI", "komodo-cli"), "-datadir="+datadir] +
    #                      _rpchost_to_args(rpchost)  +
    #                      ["-rpcwait", "-rpcport=6438", "getblockcount"], stdout=devnull)
    if os.getenv("PYTHON_DEBUG", ""):
        print "start_node: calling komodo-cli -rpcwait getblockcount returned"
    devnull.close()
    port = extra_args[3]
    url = "http://*****:*****@%s:%d" % (rpchost or '127.0.0.1', int(port[9:]))
    print("connecting to " + url)
    if timewait is not None:
        proxy = AuthServiceProxy(url, timeout=timewait)
    else:
        proxy = AuthServiceProxy(url)
    print("created proxy")
    proxy.url = url  # store URL on proxy for info
    return proxy
Пример #33
0
 def __init__(self, service_url, wallet_unlock_timeout):
     self.wallet_unlock_timeout = wallet_unlock_timeout
     self.api = AuthServiceProxy(service_url=service_url, verify=False)
Пример #34
0
class TestGetKeypool(DeviceTestCase):
    def setUp(self):
        self.rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(self.rpc_userpass))
        if '{}_test'.format(self.full_type) not in self.rpc.listwallets():
            self.rpc.createwallet('{}_test'.format(self.full_type), True)
        self.wrpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/{}_test'.format(self.rpc_userpass, self.full_type))
        self.wpk_rpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/'.format(self.rpc_userpass))
        if '--testnet' not in self.dev_args:
            self.dev_args.append('--testnet')
        self.emulator.start()

    def tearDown(self):
        self.emulator.stop()

    def test_getkeypool_bad_args(self):
        result = self.do_command(self.dev_args + ['getkeypool', '--sh_wpkh', '--wpkh', '0', '20'])
        self.assertIn('error', result)
        self.assertIn('code', result)
        self.assertEqual(result['code'], -7)

    def test_getkeypool(self):
        non_keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--nokeypool', '0', '20'])
        import_result = self.wpk_rpc.importmulti(non_keypool_desc)
        self.assertTrue(import_result[0]['success'])

        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '0', '20'])
        import_result = self.wpk_rpc.importmulti(keypool_desc)
        self.assertFalse(import_result[0]['success'])

        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        for i in range(0, 21):
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getnewaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/44'/1'/0'/0/{}".format(i))
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getrawchangeaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/44'/1'/0'/1/{}".format(i))

        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--sh_wpkh', '0', '20'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        for i in range(0, 21):
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getnewaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/49'/1'/0'/0/{}".format(i))
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getrawchangeaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/49'/1'/0'/1/{}".format(i))

        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--wpkh', '0', '20'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        for i in range(0, 21):
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getnewaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/84'/1'/0'/0/{}".format(i))
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getrawchangeaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/84'/1'/0'/1/{}".format(i))

        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--sh_wpkh', '--account', '3', '0', '20'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        for i in range(0, 21):
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getnewaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/49'/1'/3'/0/{}".format(i))
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getrawchangeaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/49'/1'/3'/1/{}".format(i))
        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--wpkh', '--account', '3', '0', '20'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        for i in range(0, 21):
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getnewaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/84'/1'/3'/0/{}".format(i))
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getrawchangeaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/84'/1'/3'/1/{}".format(i))

        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--path', 'm/0h/0h/4h/*', '0', '20'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        for i in range(0, 21):
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getnewaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/0'/0'/4'/{}".format(i))

        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--path', '/0h/0h/4h/*', '0', '20'])
        self.assertEqual(keypool_desc['error'], 'Path must start with m/')
        self.assertEqual(keypool_desc['code'], -7)
        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--path', 'm/0h/0h/4h/', '0', '20'])
        self.assertEqual(keypool_desc['error'], 'Path must end with /*')
        self.assertEqual(keypool_desc['code'], -7)
        "Default: ~/.bitcoin/bitcoin.conf")
    args = parser.parse_args()
    args.config = os.path.expanduser(args.config)

    # Get user and password from config
    user = None
    password = None
    if os.path.isfile(args.config):
        with open(args.config, 'r', encoding='utf8') as f:
            for line in f:
                if line.startswith("rpcuser="******"=")[1].strip("\n")
                if line.startswith("rpcpassword="******"=")[1].strip("\n")
    else:
        raise FileNotFoundError("Missing bitcoin.conf")
    if user is None:
        raise ValueError("Config is missing rpcuser")
    if password is None:
        raise ValueError("Config is missing rpcpassword")

    args.rpc = AuthServiceProxy('http://{}:{}@{}'.format(
        user, password, args.address))
    output = main(vars(args))
    if output:
        print(output)
Пример #36
0
 def setUp(self):
     self.rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(self.rpc_userpass))
     if '--testnet' not in self.dev_args:
         self.dev_args.append('--testnet')
     self.emulator.start()
Пример #37
0
class Controller:
    def __init__(self, settings):
        self.bitcoind = AuthServiceProxy(settings['rpc_url'])
        self.current_address = ""
        self.exchange_rate = 0.0
        self.exchange_rate_source = ""
        self.currency = settings['exchange_rate_ticker']['currency']
        self.singleScreenMode = settings['single-screen-mode']

    def run(self):
        self.app = QtGui.QApplication([])

        font = self.app.font()
        font.setPointSize(12)
        self.app.setFont(font)

        self.app.connect(
            self.app,
            QtCore.SIGNAL('_new_transaction_received(PyQt_PyObject)'),
            self._new_transaction_received)
        self.app.connect(
            self.app, QtCore.SIGNAL('_exchange_rate_updated(PyQt_PyObject)'),
            self._exchange_rate_updated)

        self.merchant_gui = MerchantGUI(self, self.currency)
        self.merchant_gui.show()
        self.customer_display = CustomerDisplay('data/customer_display.html',
                                                self.singleScreenMode)
        if not self.singleScreenMode:
            self.customer_display.show()
        self.app.exec_()

    def init_new_transaction(self, amount, currency):
        if self.singleScreenMode:
            self.customer_display.show()
            if not self.customer_display.isFullScreen():
                self.customer_display.showFullScreen()
        if currency != "BTC":
            cur_amount = amount
            if self.exchange_rate != 0:
                amount = round(cur_amount / self.exchange_rate, 8)
            else:
                amount = 0

            conversion = '["%.2f %s", "%.4f %s", "%s"]' % (
                cur_amount, currency, self.exchange_rate,
                self.exchange_rate_source, currency)
        else:
            conversion = '-1'

        self.current_address = self.bitcoind.getnewaddress("Point of Sale")
        self.merchant_gui.update_status("Looking for a transaction to %s..." %
                                        self.current_address)

        amount_str = self.format_btc_amount(amount)
        imgdata = self.create_img_data(self.current_address, amount_str)
        js = 'show_payment_info("%s", %s, "%s", "%s")' % \
                ('%s BTC' % amount_str, conversion,
                        self.current_address, imgdata)

        self.customer_display.evaluate_java_script(js)

    def create_img_data(self, address, amount_str):
        (_, size, img) = qrencode.encode("bitcoin:%s?amount=%s&label=" %
                                         (address, amount_str))
        if size < 400: img = img.resize((400, 400), Image.NEAREST)

        buf = StringIO()
        img.save(buf, format='PNG')
        imgdata = "data:image/png,%s" % urllib.quote(buf.getvalue())
        return imgdata

    def format_btc_amount(self, amount):
        s = "%.8f" % amount
        return re.sub("\.?0+$", "", s)

    # this is thread-safe, as long as it is called from a QThread
    def new_transaction_received(self, txid, output_addresses,
                                 from_green_address, green_address_msg):
        # emit signal, so we can process this on the Qt GUI thread
        self.app.emit(
            QtCore.SIGNAL('_new_transaction_received(PyQt_PyObject)'),
            (txid, output_addresses, from_green_address, green_address_msg))

    def _new_transaction_received(self, data):
        (_, output_addresses, from_green_address, green_address_msg) = data
        if self.current_address != "" and self.current_address in output_addresses:
            msg = "Transaction to %s received." % self.current_address
            if from_green_address: msg += " " + green_address_msg

            self.merchant_gui.update_status(msg)
            self.customer_display.evaluate_java_script(
                'show_payment_received()')
            self.current_address = ""

    def toggle_fullscreen_mode(self):
        if not self.customer_display.isFullScreen():
            self.customer_display.showFullScreen()
        else:
            self.customer_display.showNormal()

    def clear_customer_display(self):
        self.customer_display.evaluate_java_script('show_idle()')

    # this is thread-safe, as long as it is called from a QThread
    def exchange_rate_updated(self, rate, source):
        self.app.emit(QtCore.SIGNAL('_exchange_rate_updated(PyQt_PyObject)'),
                      (rate, source))

    def _exchange_rate_updated(self, data):
        (self.exchange_rate, self.exchange_rate_source) = data
        self.merchant_gui.update_exchange_rate(self.exchange_rate)
Пример #38
0
import logging
from typing import Tuple

from authproxy import AuthServiceProxy
from block import Block
from mempool import Mempool
from private import rpc_user, rpc_password

logger = logging.getLogger(__name__)
logging.getLogger("BitcoinRPC").setLevel(logging.INFO)

rpc = AuthServiceProxy("http://%s:%[email protected]:8332" %
                       (rpc_user, rpc_password))


def fetch_synced() -> Tuple[dict, Block, Block, Mempool]:
    """
    Fetches various data from Bitcoin Core RPC.
    Will check that tip_height before and after the fetches match, if they don't a block
     was found between calls and try again.
    """
    tip_height, _height_check = 0, 1
    previous, tip, blocktemplate, mempool = None, None, None, None
    mempool_ok = False

    while not tip_height == _height_check and not mempool_ok:
        tip_height = rpc.getblockcount()
        tip_hash = rpc.getbestblockhash()

        # First get blocktemplate as it's a subset of mempool
        blocktemplate = Block.from_blocktemplate(
Пример #39
0
class Controller:
    def __init__(self, settings):
        self.bitcoind = AuthServiceProxy(settings['rpc_url'])
        self.current_address = ""
        self.exchange_rate = 0.0
        self.exchange_rate_source = ""
        self.currency = settings['exchange_rate_ticker']['currency']
        self.singleScreenMode = settings['single-screen-mode']

    def run(self):
        self.app = QtGui.QApplication([])

        font = self.app.font()
        font.setPointSize(12)
        self.app.setFont(font)

        self.app.connect(self.app, QtCore.SIGNAL('_new_transaction_received(PyQt_PyObject)'),
                self._new_transaction_received)
        self.app.connect(self.app, QtCore.SIGNAL('_exchange_rate_updated(PyQt_PyObject)'),
                self._exchange_rate_updated)

        self.merchant_gui = MerchantGUI(self, self.currency)
        self.merchant_gui.show()
        self.customer_display = CustomerDisplay('data/customer_display.html', self.singleScreenMode)
        if not self.singleScreenMode:
            self.customer_display.show()
        self.app.exec_()

    def init_new_transaction(self, amount, currency):
        if self.singleScreenMode:
            self.customer_display.show()
            if not self.customer_display.isFullScreen():
                self.customer_display.showFullScreen()
        if currency != "BTC":
            cur_amount = amount
            if self.exchange_rate != 0:
                amount = round(cur_amount / self.exchange_rate, 8)
            else:
                amount = 0

            conversion = '["%.2f %s", "%.4f %s", "%s"]' % (cur_amount, 
                            currency, self.exchange_rate, self.exchange_rate_source,
                            currency)
        else:
            conversion = '-1'

        self.current_address = self.bitcoind.getnewaddress("Point of Sale")
        self.merchant_gui.update_status("Looking for a transaction to %s..." %
                self.current_address)

        amount_str = self.format_btc_amount(amount)
        imgdata = self.create_img_data(self.current_address, amount_str)
        js = 'show_payment_info("%s", %s, "%s", "%s")' % \
                ('%s BTC' % amount_str, conversion,
                        self.current_address, imgdata)

        self.customer_display.evaluate_java_script(js)

    def create_img_data(self, address, amount_str):
        (_, size, img) = qrencode.encode("bitcoin:%s?amount=%s&label=" %
                (address, amount_str))
        if size < 400: img = img.resize((400, 400), Image.NEAREST)

        buf = StringIO()
        img.save(buf, format='PNG')
        imgdata = "data:image/png,%s" % urllib.quote(buf.getvalue())
        return imgdata

    def format_btc_amount(self, amount):
        s = "%.8f" % amount
        return re.sub("\.?0+$", "", s)

    # this is thread-safe, as long as it is called from a QThread
    def new_transaction_received(self, txid, output_addresses,
            from_green_address, green_address_msg):
        # emit signal, so we can process this on the Qt GUI thread
        self.app.emit(QtCore.SIGNAL('_new_transaction_received(PyQt_PyObject)'),
                (txid, output_addresses, from_green_address, green_address_msg))

    def _new_transaction_received(self, data):
        (_, output_addresses, from_green_address, green_address_msg) = data
        if self.current_address != "" and self.current_address in output_addresses:
            msg = "Transaction to %s received." % self.current_address
            if from_green_address: msg += " " + green_address_msg

            self.merchant_gui.update_status(msg)
            self.customer_display.evaluate_java_script('show_payment_received()')
            self.current_address = ""

    def toggle_fullscreen_mode(self):
        if not self.customer_display.isFullScreen():
            self.customer_display.showFullScreen()
        else:
            self.customer_display.showNormal()

    def clear_customer_display(self):
        self.customer_display.evaluate_java_script('show_idle()')

    # this is thread-safe, as long as it is called from a QThread
    def exchange_rate_updated(self, rate, source):
        self.app.emit(QtCore.SIGNAL('_exchange_rate_updated(PyQt_PyObject)'),
                (rate, source))

    def _exchange_rate_updated(self, data):
        (self.exchange_rate, self.exchange_rate_source) = data
        self.merchant_gui.update_exchange_rate(self.exchange_rate)