SatSale

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

bitcoind.py (5183B)


      1 import json
      2 import logging
      3 import os
      4 import qrcode
      5 import time
      6 
      7 import config
      8 from utils import btc_amount_format
      9 
     10 
     11 class btcd:
     12     def __init__(self, node_config):
     13         from bitcoinrpc.authproxy import AuthServiceProxy
     14         self.config = node_config
     15 
     16         if self.config['tor_bitcoinrpc_host'] is not None:
     17             from gateways.tor import session
     18             self.session = session
     19         self.is_onchain = True
     20 
     21         if self.config['rpc_cookie_file']:
     22             if os.path.isfile(self.config['rpc_cookie_file']):
     23                 rpc_credentials_str = open(self.config['rpc_cookie_file'], "r").read()
     24                 (username, password) = rpc_credentials_str.split(":")
     25             else:
     26                 raise Exception(
     27                     "rpc_cookie_file {} not found".format(self.config['rpc_cookie_file'])
     28                 )
     29         else:
     30             username = self.config['username']
     31             password = self.config['password']
     32 
     33         for i in range(config.connection_attempts):
     34             if self.config['tor_bitcoinrpc_host'] is None:
     35                 self.tor = False
     36                 connection_str = "http://{}:{}@{}:{}/wallet/{}".format(
     37                     username,
     38                     password,
     39                     self.config['host'],
     40                     self.config['rpcport'],
     41                     self.config['wallet'],
     42                 )
     43                 logging.info(
     44                     "Attempting to connect to Bitcoin node RPC to {}:{} with user {}.".format(
     45                         self.config['host'], self.config['rpcport'], self.config['username']
     46                     )
     47                 )
     48             else:
     49                 self.tor = True
     50                 logging.info(
     51                     "Attempting to contact bitcoind rpc tor hidden service: {}:{}".format(
     52                         self.config['tor_bitcoinrpc_host'], self.config['rpcport']
     53                     )
     54                 )
     55 
     56             try:
     57                 # Normal Connection
     58                 if self.config['tor_bitcoinrpc_host'] is None:
     59                     self.rpc = AuthServiceProxy(connection_str)
     60                     info = self.rpc.getblockchaininfo()
     61                 # Tor Connection
     62                 else:
     63                     info = self.call_tor_bitcoin_rpc("getblockchaininfo", None)
     64 
     65                 logging.info(info)
     66                 logging.info("Successfully contacted bitcoind.")
     67                 break
     68 
     69             except Exception as e:
     70                 logging.error(e)
     71                 if i < 5:
     72                     time.sleep(2)
     73                 else:
     74                     time.sleep(60)
     75                 logging.info(
     76                     "Attempting again... {}/{}...".format(
     77                         i + 1, config.connection_attempts
     78                     )
     79                 )
     80         else:
     81             raise Exception(
     82                 "Could not connect to bitcoind. \
     83                 Check your RPC / port tunneling settings and try again."
     84             )
     85 
     86     def call_tor_bitcoin_rpc(self, method, params):
     87         url = "{}:{}".format(self.config['tor_bitcoinrpc_host'], config.rpcport)
     88         payload = json.dumps({"method": method, "params": params})
     89         headers = {"content-type": "application/json", "cache-control": "no-cache"}
     90         response = self.session.request(
     91             "POST",
     92             url,
     93             data=payload,
     94             headers=headers,
     95             auth=(config.username, config.password),
     96         )
     97         return json.loads(response.text)
     98 
     99     def create_qr(self, uuid, address, value):
    100         qr_str = "bitcoin:{}?amount={}&label={}".format(
    101             address, btc_amount_format(value), uuid
    102         )
    103 
    104         img = qrcode.make(qr_str)
    105         img.save("static/qr_codes/{}.png".format(uuid))
    106         return
    107 
    108     def check_payment(self, uuid):
    109         if not self.tor:
    110             transactions = self.rpc.listtransactions(uuid)
    111         else:
    112             transactions = self.call_tor_bitcoin_rpc("listtransactions", [uuid])["result"]
    113 
    114         conf_paid = 0
    115         unconf_paid = 0
    116         for tx in transactions:
    117             if tx["confirmations"] >= config.required_confirmations:
    118                 conf_paid += tx["amount"]
    119             else:
    120                 unconf_paid += tx["amount"]
    121 
    122         return conf_paid, unconf_paid
    123 
    124     def get_address(self, amount, label, expiry):
    125         for i in range(config.connection_attempts):
    126             try:
    127                 if not self.tor:
    128                     address = self.rpc.getnewaddress(label)
    129                 else:
    130                     address = self.call_tor_bitcoin_rpc("getnewaddress", [label])["result"]
    131 
    132                 return address, None
    133 
    134             except Exception as e:
    135                 logging.error(e)
    136                 if i < 5:
    137                     time.sleep(2)
    138                 else:
    139                     time.sleep(60)
    140                 logging.info(
    141                     "Attempting again... {}/{}...".format(
    142                         i + 1, config.connection_attempts
    143                     )
    144                 )
    145             if config.connection_attempts - i == 1:
    146                 logging.info("Reconnecting...")
    147                 self.__init__()
    148         return None