@@ -115,6 +115,27 @@ class InWarmupError(JSONRPCError):
115115 RPC_ERROR_CODE = - 28
116116
117117
118+ def split_hostport (hostport ):
119+ r = hostport .rsplit (':' , maxsplit = 1 )
120+ if len (r ) == 1 :
121+ return (hostport , None )
122+
123+ maybe_host , maybe_port = r
124+
125+ if ':' in maybe_host :
126+ if not (maybe_host .startswith ('[' ) and maybe_host .endswith (']' )):
127+ return (hostport , None )
128+
129+ if not maybe_port .isdigit ():
130+ return (hostport , None )
131+
132+ port = int (maybe_port )
133+ if port > 0 and port < 0x10000 :
134+ return (maybe_host , port )
135+
136+ return (hostport , None )
137+
138+
118139class BaseProxy (object ):
119140 """Base JSON-RPC proxy class. Contains only private methods; do not use
120141 directly."""
@@ -123,6 +144,7 @@ def __init__(self,
123144 service_url = None ,
124145 service_port = None ,
125146 btc_conf_file = None ,
147+ btc_conf_file_contents = None ,
126148 timeout = DEFAULT_HTTP_TIMEOUT ,
127149 connection = None ):
128150
@@ -132,6 +154,15 @@ def __init__(self,
132154 self .__conn = None
133155 authpair = None
134156
157+ network_id = 'main'
158+ extraname = ''
159+ if bitcoin .params .NAME == 'testnet' :
160+ network_id = 'test'
161+ extraname = 'testnet3'
162+ elif bitcoin .params .NAME == 'regtest' :
163+ network_id = 'regtest'
164+ extraname = 'regtest'
165+
135166 if service_url is None :
136167 # Figure out the path to the bitcoin.conf file
137168 if btc_conf_file is None :
@@ -145,44 +176,81 @@ def __init__(self,
145176
146177 # Bitcoin Core accepts empty rpcuser, not specified in btc_conf_file
147178 conf = {'rpcuser' : "" }
148-
149- # Extract contents of bitcoin.conf to build service_url
150- try :
151- with open (btc_conf_file , 'r' ) as fd :
152- for line in fd .readlines ():
153- if '#' in line :
154- line = line [:line .index ('#' )]
155- if '=' not in line :
156- continue
157- k , v = line .split ('=' , 1 )
158- conf [k .strip ()] = v .strip ()
159-
160- # Treat a missing bitcoin.conf as though it were empty
161- except FileNotFoundError :
162- pass
179+ section = ''
180+
181+ def process_line (line : str ) -> None :
182+ nonlocal section
183+
184+ if '#' in line :
185+ line = line [:line .index ('#' )]
186+ line = line .strip ()
187+ if not line :
188+ return
189+ if line [0 ] == '[' and line [- 1 ] == ']' :
190+ section = line [1 :- 1 ] + '.'
191+ return
192+ if '=' not in line :
193+ return
194+ k , v = line .split ('=' , 1 )
195+ conf [section + k .strip ()] = v .strip ()
196+
197+ if btc_conf_file_contents is not None :
198+ buf = btc_conf_file_contents
199+ while '\n ' in buf :
200+ line , buf = buf .split ('\n ' , 1 )
201+ process_line (line )
202+ else :
203+ # Extract contents of bitcoin.conf to build service_url
204+ try :
205+ with open (btc_conf_file , 'r' ) as fd :
206+ for line in fd .readlines ():
207+ process_line (line )
208+ # Treat a missing bitcoin.conf as though it were empty
209+ except FileNotFoundError :
210+ pass
163211
164212 if service_port is None :
165213 service_port = bitcoin .params .RPC_PORT
166- conf ['rpcport' ] = int (conf .get ('rpcport' , service_port ))
167- conf ['rpchost' ] = conf .get ('rpcconnect' , 'localhost' )
168-
169- service_url = ('%s://%s:%d' %
170- ('http' , conf ['rpchost' ], conf ['rpcport' ]))
171-
172- cookie_dir = conf .get ('datadir' , os .path .dirname (btc_conf_file ))
173- if bitcoin .params .NAME != "mainnet" :
174- cookie_dir = os .path .join (cookie_dir , bitcoin .params .NAME )
175- cookie_file = os .path .join (cookie_dir , ".cookie" )
176- try :
177- with open (cookie_file , 'r' ) as fd :
178- authpair = fd .read ()
179- except IOError as err :
180- if 'rpcpassword' in conf :
181- authpair = "%s:%s" % (conf ['rpcuser' ], conf ['rpcpassword' ])
182214
215+ (host , port ) = split_hostport (
216+ conf .get (network_id + '.rpcconnect' ,
217+ conf .get ('rpcconnect' , 'localhost' )))
218+
219+ port = int (conf .get (network_id + '.rpcport' ,
220+ conf .get ('rpcport' , port or service_port )))
221+ service_url = ('%s://%s:%d' % ('http' , host , port ))
222+
223+ cookie_dir = conf .get (network_id + '.datadir' ,
224+ conf .get ('datadir' ,
225+ None if btc_conf_file is None
226+ else os .path .dirname (btc_conf_file )))
227+ io_err = None
228+ if cookie_dir is not None :
229+ cookie_dir = os .path .join (cookie_dir , extraname )
230+ cookie_file = os .path .join (cookie_dir , ".cookie" )
231+ try :
232+ with open (cookie_file , 'r' ) as fd :
233+ authpair = fd .read ()
234+ except IOError as err :
235+ io_err = err
236+
237+ if authpair is None :
238+ if network_id + '.rpcpassword' in conf :
239+ authpair = "%s:%s" % (
240+ conf .get (network_id + '.rpcuser' , '' ),
241+ conf [network_id + '.rpcpassword' ])
242+ elif 'rpcpassword' in conf :
243+ authpair = "%s:%s" % (conf .get ('rpcuser' , '' ),
244+ conf ['rpcpassword' ])
245+ elif io_err is None :
246+ raise ValueError (
247+ 'Cookie dir is not known and rpcpassword is not '
248+ 'specified in btc_conf_file_contents' )
183249 else :
184- raise ValueError ('Cookie file unusable (%s) and rpcpassword not specified in the configuration file: %r' % (err , btc_conf_file ))
185-
250+ raise ValueError (
251+ 'Cookie file unusable (%s) and rpcpassword '
252+ 'not specified in the configuration file: %r'
253+ % (io_err , btc_conf_file ))
186254 else :
187255 url = urlparse .urlparse (service_url )
188256 authpair = "%s:%s" % (url .username , url .password )
0 commit comments