2 # Copyright (c) 2017 The Bitcoin Core developers
3 # Distributed under the MIT software license, see the accompanying
4 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 """Class for bitcoind node under test"""
19 from .authproxy
import JSONRPCException
22 """A class for representing a bitcoind node under test.
26 - state about the node (whether it's running, etc)
27 - a Python subprocess.Popen object representing the running process
28 - an RPC connection to the node
30 To make things easier for the test writer, a bit of magic is happening under the covers.
31 Any unrecognised messages will be dispatched to the RPC connection."""
33 def __init__(self
, i
, dirname
, extra_args
, rpchost
, timewait
, binary
, stderr
, mocktime
, coverage_dir
):
35 self
.datadir
= os
.path
.join(dirname
, "node" + str(i
))
36 self
.rpchost
= rpchost
38 self
.rpc_timeout
= timewait
40 # Wait for up to 60 seconds for the RPC server to respond
43 self
.binary
= os
.getenv("BITCOIND", "bitcoind")
47 self
.coverage_dir
= coverage_dir
48 # Most callers will just need to add extra args to the standard list below. For those callers that need more flexibity, they can just set the args property directly.
49 self
.extra_args
= extra_args
50 self
.args
= [self
.binary
, "-datadir=" + self
.datadir
, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", "-mocktime=" + str(mocktime
), "-uacomment=testnode%d" % i
]
54 self
.rpc_connected
= False
57 self
.log
= logging
.getLogger('TestFramework.node%d' % i
)
59 def __getattr__(self
, *args
, **kwargs
):
60 """Dispatches any unrecognised messages to the RPC connection."""
61 assert self
.rpc_connected
and self
.rpc
is not None, "Error: no RPC connection"
62 return self
.rpc
.__getattr
__(*args
, **kwargs
)
66 self
.process
= subprocess
.Popen(self
.args
+ self
.extra_args
, stderr
=self
.stderr
)
68 self
.log
.debug("bitcoind started, waiting for RPC to come up")
70 def wait_for_rpc_connection(self
):
71 """Sets up an RPC connection to the bitcoind process. Returns False if unable to connect."""
72 # Poll at a rate of four times per second
74 for _
in range(poll_per_s
* self
.rpc_timeout
):
75 assert self
.process
.poll() is None, "bitcoind exited with status %i during initialization" % self
.process
.returncode
77 self
.rpc
= get_rpc_proxy(rpc_url(self
.datadir
, self
.index
, self
.rpchost
), self
.index
, timeout
=self
.rpc_timeout
, coveragedir
=self
.coverage_dir
)
78 self
.rpc
.getblockcount()
79 # If the call to getblockcount() succeeds then the RPC connection is up
80 self
.rpc_connected
= True
81 self
.url
= self
.rpc
.url
82 self
.log
.debug("RPC successfully started")
85 if e
.errno
!= errno
.ECONNREFUSED
: # Port not yet open?
86 raise # unknown IO error
87 except JSONRPCException
as e
: # Initialization phase
88 if e
.error
['code'] != -28: # RPC in warmup?
89 raise # unknown JSON RPC exception
90 except ValueError as e
: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting
91 if "No RPC credentials" not in str(e
):
93 time
.sleep(1.0 / poll_per_s
)
94 raise AssertionError("Unable to connect to bitcoind")
96 def get_wallet_rpc(self
, wallet_name
):
97 assert self
.rpc_connected
99 wallet_path
= "wallet/%s" % wallet_name
100 return self
.rpc
/ wallet_path
106 self
.log
.debug("Stopping node")
109 except http
.client
.CannotSendRequest
:
110 self
.log
.exception("Unable to stop node.")
112 def is_node_stopped(self
):
113 """Checks whether the node has stopped.
115 Returns True if the node has stopped. False otherwise.
116 This method is responsible for freeing resources (self.process)."""
119 return_code
= self
.process
.poll()
120 if return_code
is not None:
121 # process has stopped. Assert that it didn't return an error code.
122 assert_equal(return_code
, 0)
125 self
.log
.debug("Node stopped")
129 def node_encrypt_wallet(self
, passphrase
):
130 """"Encrypts the wallet.
132 This causes bitcoind to shutdown, so this method takes
133 care of cleaning up resources."""
134 self
.encryptwallet(passphrase
)
135 while not self
.is_node_stopped():
138 self
.rpc_connected
= False