4
4
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
5
"""Test bitcoin-wallet."""
6
6
7
+ import hashlib
8
+ import os
9
+ import stat
7
10
import subprocess
8
11
import textwrap
9
12
10
13
from test_framework .test_framework import BitcoinTestFramework
11
14
from test_framework .util import assert_equal
12
15
16
+ BUFFER_SIZE = 16 * 1024
17
+
13
18
class ToolWalletTest (BitcoinTestFramework ):
14
19
def set_test_params (self ):
15
20
self .num_nodes = 1
@@ -33,9 +38,27 @@ def assert_raises_tool_error(self, error, *args):
33
38
def assert_tool_output (self , output , * args ):
34
39
p = self .bitcoin_wallet_process (* args )
35
40
stdout , stderr = p .communicate ()
36
- assert_equal (p .poll (), 0 )
37
41
assert_equal (stderr , '' )
38
42
assert_equal (stdout , output )
43
+ assert_equal (p .poll (), 0 )
44
+
45
+ def wallet_shasum (self ):
46
+ h = hashlib .sha1 ()
47
+ mv = memoryview (bytearray (BUFFER_SIZE ))
48
+ with open (self .wallet_path , 'rb' , buffering = 0 ) as f :
49
+ for n in iter (lambda : f .readinto (mv ), 0 ):
50
+ h .update (mv [:n ])
51
+ return h .hexdigest ()
52
+
53
+ def wallet_timestamp (self ):
54
+ return os .path .getmtime (self .wallet_path )
55
+
56
+ def wallet_permissions (self ):
57
+ return oct (os .lstat (self .wallet_path ).st_mode )[- 3 :]
58
+
59
+ def log_wallet_timestamp_comparison (self , old , new ):
60
+ result = 'unchanged' if new == old else 'increased!'
61
+ self .log .debug ('Wallet file timestamp {}' .format (result ))
39
62
40
63
def test_invalid_tool_commands_and_args (self ):
41
64
self .log .info ('Testing that various invalid commands raise with specific error messages' )
@@ -51,6 +74,18 @@ def test_tool_wallet_info(self):
51
74
# Stop the node to close the wallet to call the info command.
52
75
self .stop_node (0 )
53
76
self .log .info ('Calling wallet tool info, testing output' )
77
+ #
78
+ # TODO: Wallet tool info should work with wallet file permissions set to
79
+ # read-only without raising:
80
+ # "Error loading wallet.dat. Is wallet being used by another process?"
81
+ # The following lines should be uncommented and the tests still succeed:
82
+ #
83
+ # self.log.debug('Setting wallet file permissions to 400 (read-only)')
84
+ # os.chmod(self.wallet_path, stat.S_IRUSR)
85
+ # assert(self.wallet_permissions() in ['400', '666']) # Sanity check. 666 because Appveyor.
86
+ # shasum_before = self.wallet_shasum()
87
+ timestamp_before = self .wallet_timestamp ()
88
+ self .log .debug ('Wallet file timestamp before calling info: {}' .format (timestamp_before ))
54
89
out = textwrap .dedent ('''\
55
90
Wallet info
56
91
===========
@@ -61,6 +96,20 @@ def test_tool_wallet_info(self):
61
96
Address Book: 3
62
97
''' )
63
98
self .assert_tool_output (out , '-wallet=wallet.dat' , 'info' )
99
+ timestamp_after = self .wallet_timestamp ()
100
+ self .log .debug ('Wallet file timestamp after calling info: {}' .format (timestamp_after ))
101
+ self .log_wallet_timestamp_comparison (timestamp_before , timestamp_after )
102
+ self .log .debug ('Setting wallet file permissions back to 600 (read/write)' )
103
+ os .chmod (self .wallet_path , stat .S_IRUSR | stat .S_IWUSR )
104
+ assert (self .wallet_permissions () in ['600' , '666' ]) # Sanity check. 666 because Appveyor.
105
+ #
106
+ # TODO: Wallet tool info should not write to the wallet file.
107
+ # The following lines should be uncommented and the tests still succeed:
108
+ #
109
+ # assert_equal(timestamp_before, timestamp_after)
110
+ # shasum_after = self.wallet_shasum()
111
+ # assert_equal(shasum_before, shasum_after)
112
+ # self.log.debug('Wallet file shasum unchanged\n')
64
113
65
114
def test_tool_wallet_info_after_transaction (self ):
66
115
"""
@@ -73,6 +122,9 @@ def test_tool_wallet_info_after_transaction(self):
73
122
self .stop_node (0 )
74
123
75
124
self .log .info ('Calling wallet tool info after generating a transaction, testing output' )
125
+ shasum_before = self .wallet_shasum ()
126
+ timestamp_before = self .wallet_timestamp ()
127
+ self .log .debug ('Wallet file timestamp before calling info: {}' .format (timestamp_before ))
76
128
out = textwrap .dedent ('''\
77
129
Wallet info
78
130
===========
@@ -83,9 +135,22 @@ def test_tool_wallet_info_after_transaction(self):
83
135
Address Book: 3
84
136
''' )
85
137
self .assert_tool_output (out , '-wallet=wallet.dat' , 'info' )
138
+ shasum_after = self .wallet_shasum ()
139
+ timestamp_after = self .wallet_timestamp ()
140
+ self .log .debug ('Wallet file timestamp after calling info: {}' .format (timestamp_after ))
141
+ self .log_wallet_timestamp_comparison (timestamp_before , timestamp_after )
142
+ #
143
+ # TODO: Wallet tool info should not write to the wallet file.
144
+ # This assertion should be uncommented and succeed:
145
+ # assert_equal(timestamp_before, timestamp_after)
146
+ assert_equal (shasum_before , shasum_after )
147
+ self .log .debug ('Wallet file shasum unchanged\n ' )
86
148
87
149
def test_tool_wallet_create_on_existing_wallet (self ):
88
150
self .log .info ('Calling wallet tool create on an existing wallet, testing output' )
151
+ shasum_before = self .wallet_shasum ()
152
+ timestamp_before = self .wallet_timestamp ()
153
+ self .log .debug ('Wallet file timestamp before calling create: {}' .format (timestamp_before ))
89
154
out = textwrap .dedent ('''\
90
155
Topping up keypool...
91
156
Wallet info
@@ -97,21 +162,41 @@ def test_tool_wallet_create_on_existing_wallet(self):
97
162
Address Book: 0
98
163
''' )
99
164
self .assert_tool_output (out , '-wallet=foo' , 'create' )
165
+ shasum_after = self .wallet_shasum ()
166
+ timestamp_after = self .wallet_timestamp ()
167
+ self .log .debug ('Wallet file timestamp after calling create: {}' .format (timestamp_after ))
168
+ self .log_wallet_timestamp_comparison (timestamp_before , timestamp_after )
169
+ assert_equal (timestamp_before , timestamp_after )
170
+ assert_equal (shasum_before , shasum_after )
171
+ self .log .debug ('Wallet file shasum unchanged\n ' )
100
172
101
173
def test_getwalletinfo_on_different_wallet (self ):
102
174
self .log .info ('Starting node with arg -wallet=foo' )
103
175
self .start_node (0 , ['-wallet=foo' ])
104
176
105
177
self .log .info ('Calling getwalletinfo on a different wallet ("foo"), testing output' )
178
+ shasum_before = self .wallet_shasum ()
179
+ timestamp_before = self .wallet_timestamp ()
180
+ self .log .debug ('Wallet file timestamp before calling getwalletinfo: {}' .format (timestamp_before ))
106
181
out = self .nodes [0 ].getwalletinfo ()
107
182
self .stop_node (0 )
108
183
184
+ shasum_after = self .wallet_shasum ()
185
+ timestamp_after = self .wallet_timestamp ()
186
+ self .log .debug ('Wallet file timestamp after calling getwalletinfo: {}' .format (timestamp_after ))
187
+
109
188
assert_equal (0 , out ['txcount' ])
110
189
assert_equal (1000 , out ['keypoolsize' ])
111
190
assert_equal (1000 , out ['keypoolsize_hd_internal' ])
112
191
assert_equal (True , 'hdseedid' in out )
113
192
193
+ self .log_wallet_timestamp_comparison (timestamp_before , timestamp_after )
194
+ assert_equal (timestamp_before , timestamp_after )
195
+ assert_equal (shasum_after , shasum_before )
196
+ self .log .debug ('Wallet file shasum unchanged\n ' )
197
+
114
198
def run_test (self ):
199
+ self .wallet_path = os .path .join (self .nodes [0 ].datadir , 'regtest' , 'wallets' , 'wallet.dat' )
115
200
self .test_invalid_tool_commands_and_args ()
116
201
# Warning: The following tests are order-dependent.
117
202
self .test_tool_wallet_info ()
0 commit comments