@@ -115,6 +115,27 @@ class InWarmupError(JSONRPCError):
115
115
RPC_ERROR_CODE = - 28
116
116
117
117
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
+
118
139
class BaseProxy (object ):
119
140
"""Base JSON-RPC proxy class. Contains only private methods; do not use
120
141
directly."""
@@ -123,6 +144,7 @@ def __init__(self,
123
144
service_url = None ,
124
145
service_port = None ,
125
146
btc_conf_file = None ,
147
+ btc_conf_file_contents = None ,
126
148
timeout = DEFAULT_HTTP_TIMEOUT ,
127
149
connection = None ):
128
150
@@ -132,6 +154,15 @@ def __init__(self,
132
154
self .__conn = None
133
155
authpair = None
134
156
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
+
135
166
if service_url is None :
136
167
# Figure out the path to the bitcoin.conf file
137
168
if btc_conf_file is None :
@@ -145,44 +176,81 @@ def __init__(self,
145
176
146
177
# Bitcoin Core accepts empty rpcuser, not specified in btc_conf_file
147
178
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
163
211
164
212
if service_port is None :
165
213
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' ])
182
214
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' )
183
249
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 ))
186
254
else :
187
255
url = urlparse .urlparse (service_url )
188
256
authpair = "%s:%s" % (url .username , url .password )
0 commit comments