9
9
10
10
from test_framework import BitcoinTestFramework
11
11
from util import *
12
+ from struct import *
13
+ import binascii
12
14
import json
15
+ import StringIO
13
16
14
17
try :
15
18
import http .client as httplib
20
23
except ImportError :
21
24
import urlparse
22
25
23
- def http_get_call (host , port , path , response_object = 0 ):
26
+ def deser_uint256 (f ):
27
+ r = 0
28
+ for i in range (8 ):
29
+ t = unpack (b"<I" , f .read (4 ))[0 ]
30
+ r += t << (i * 32 )
31
+ return r
32
+
33
+ #allows simple http get calls with a request body
34
+ def http_get_call (host , port , path , requestdata = '' , response_object = 0 ):
24
35
conn = httplib .HTTPConnection (host , port )
25
- conn .request ('GET' , path )
36
+ conn .request ('GET' , path , requestdata )
26
37
27
38
if response_object :
28
39
return conn .getresponse ()
29
40
30
41
return conn .getresponse ().read ()
31
42
32
-
33
43
class RESTTest (BitcoinTestFramework ):
34
44
FORMAT_SEPARATOR = "."
35
45
46
+ def setup_chain (self ):
47
+ print ("Initializing test directory " + self .options .tmpdir )
48
+ initialize_chain_clean (self .options .tmpdir , 3 )
49
+
50
+ def setup_network (self , split = False ):
51
+ self .nodes = start_nodes (3 , self .options .tmpdir )
52
+ connect_nodes_bi (self .nodes ,0 ,1 )
53
+ connect_nodes_bi (self .nodes ,1 ,2 )
54
+ connect_nodes_bi (self .nodes ,0 ,2 )
55
+ self .is_network_split = False
56
+ self .sync_all ()
57
+
36
58
def run_test (self ):
37
59
url = urlparse .urlparse (self .nodes [0 ].url )
60
+ print "Mining blocks..."
61
+
62
+ self .nodes [0 ].generate (1 )
63
+ self .sync_all ()
64
+ self .nodes [2 ].generate (100 )
65
+ self .sync_all ()
66
+
67
+ assert_equal (self .nodes [0 ].getbalance (), 50 )
68
+
69
+ txid = self .nodes [0 ].sendtoaddress (self .nodes [1 ].getnewaddress (), 0.1 )
70
+ self .sync_all ()
71
+ self .nodes [2 ].generate (1 )
72
+ self .sync_all ()
73
+ bb_hash = self .nodes [0 ].getbestblockhash ()
74
+
75
+ assert_equal (self .nodes [1 ].getbalance (), Decimal ("0.1" )) #balance now should be 0.1 on node 1
76
+
77
+ # load the latest 0.1 tx over the REST API
78
+ json_string = http_get_call (url .hostname , url .port , '/rest/tx/' + txid + self .FORMAT_SEPARATOR + "json" )
79
+ json_obj = json .loads (json_string )
80
+ vintx = json_obj ['vin' ][0 ]['txid' ] # get the vin to later check for utxo (should be spent by then)
81
+ # get n of 0.1 outpoint
82
+ n = 0
83
+ for vout in json_obj ['vout' ]:
84
+ if vout ['value' ] == 0.1 :
85
+ n = vout ['n' ]
86
+
87
+
88
+ ######################################
89
+ # GETUTXOS: query a unspent outpoint #
90
+ ######################################
91
+ json_request = '{"checkmempool":true,"outpoints":[{"txid":"' + txid + '","n":' + str (n )+ '}]}'
92
+ json_string = http_get_call (url .hostname , url .port , '/rest/getutxos' + self .FORMAT_SEPARATOR + 'json' , json_request )
93
+ json_obj = json .loads (json_string )
94
+
95
+ #check chainTip response
96
+ assert_equal (json_obj ['chaintipHash' ], bb_hash )
97
+
98
+ #make sure there is one utxo
99
+ assert_equal (len (json_obj ['utxos' ]), 1 )
100
+ assert_equal (json_obj ['utxos' ][0 ]['value' ], 0.1 )
101
+
102
+
103
+ ################################################
104
+ # GETUTXOS: now query a already spent outpoint #
105
+ ################################################
106
+ json_request = '{"checkmempool":true,"outpoints":[{"txid":"' + vintx + '","n":0}]}'
107
+ json_string = http_get_call (url .hostname , url .port , '/rest/getutxos' + self .FORMAT_SEPARATOR + 'json' , json_request )
108
+ json_obj = json .loads (json_string )
109
+
110
+ #check chainTip response
111
+ assert_equal (json_obj ['chaintipHash' ], bb_hash )
112
+
113
+ #make sure there is no utox in the response because this oupoint has been spent
114
+ assert_equal (len (json_obj ['utxos' ]), 0 )
115
+
116
+ #check bitmap
117
+ assert_equal (json_obj ['bitmap' ], "0" )
118
+
119
+
120
+ ##################################################
121
+ # GETUTXOS: now check both with the same request #
122
+ ##################################################
123
+ json_request = '{"checkmempool":true,"outpoints":[{"txid":"' + txid + '","n":' + str (n )+ '},{"txid":"' + vintx + '","n":0}]}'
124
+ json_string = http_get_call (url .hostname , url .port , '/rest/getutxos' + self .FORMAT_SEPARATOR + 'json' , json_request )
125
+ json_obj = json .loads (json_string )
126
+ assert_equal (len (json_obj ['utxos' ]), 1 )
127
+ assert_equal (json_obj ['bitmap' ], "10" )
128
+
129
+ #test binary response
38
130
bb_hash = self .nodes [0 ].getbestblockhash ()
39
131
132
+ binaryRequest = b'\x01 \x02 '
133
+ binaryRequest += binascii .unhexlify (txid )
134
+ binaryRequest += pack ("i" , n );
135
+ binaryRequest += binascii .unhexlify (vintx );
136
+ binaryRequest += pack ("i" , 0 );
137
+
138
+ bin_response = http_get_call (url .hostname , url .port , '/rest/getutxos' + self .FORMAT_SEPARATOR + 'bin' , binaryRequest )
139
+
140
+ output = StringIO .StringIO ()
141
+ output .write (bin_response )
142
+ output .seek (0 )
143
+ chainHeight = unpack ("i" , output .read (4 ))[0 ]
144
+ hashFromBinResponse = hex (deser_uint256 (output ))[2 :].zfill (65 ).rstrip ("L" )
145
+
146
+ assert_equal (bb_hash , hashFromBinResponse ) #check if getutxo's chaintip during calculation was fine
147
+ assert_equal (chainHeight , 102 ) #chain height must be 102
148
+
149
+
150
+ ############################
151
+ # GETUTXOS: mempool checks #
152
+ ############################
153
+
154
+ # do a tx and don't sync
155
+ txid = self .nodes [0 ].sendtoaddress (self .nodes [1 ].getnewaddress (), 0.1 )
156
+ json_string = http_get_call (url .hostname , url .port , '/rest/tx/' + txid + self .FORMAT_SEPARATOR + "json" )
157
+ json_obj = json .loads (json_string )
158
+ vintx = json_obj ['vin' ][0 ]['txid' ] # get the vin to later check for utxo (should be spent by then)
159
+ # get n of 0.1 outpoint
160
+ n = 0
161
+ for vout in json_obj ['vout' ]:
162
+ if vout ['value' ] == 0.1 :
163
+ n = vout ['n' ]
164
+
165
+ json_request = '{"checkmempool":false,"outpoints":[{"txid":"' + txid + '","n":' + str (n )+ '}]}'
166
+ json_string = http_get_call (url .hostname , url .port , '/rest/getutxos' + self .FORMAT_SEPARATOR + 'json' , json_request )
167
+ json_obj = json .loads (json_string )
168
+ assert_equal (len (json_obj ['utxos' ]), 0 ) #there should be a outpoint because it has just added to the mempool
169
+
170
+ json_request = '{"checkmempool":true,"outpoints":[{"txid":"' + txid + '","n":' + str (n )+ '}]}'
171
+ json_string = http_get_call (url .hostname , url .port , '/rest/getutxos' + self .FORMAT_SEPARATOR + 'json' , json_request )
172
+ json_obj = json .loads (json_string )
173
+ assert_equal (len (json_obj ['utxos' ]), 1 ) #there should be a outpoint because it has just added to the mempool
174
+
175
+ #do some invalid requests
176
+ json_request = '{"checkmempool'
177
+ response = http_get_call (url .hostname , url .port , '/rest/getutxos' + self .FORMAT_SEPARATOR + 'json' , json_request , True )
178
+ assert_equal (response .status , 500 ) #must be a 500 because we send a invalid json request
179
+
180
+ json_request = '{"checkmempool'
181
+ response = http_get_call (url .hostname , url .port , '/rest/getutxos' + self .FORMAT_SEPARATOR + 'bin' , json_request , True )
182
+ assert_equal (response .status , 500 ) #must be a 500 because we send a invalid bin request
183
+
184
+ #test limits
185
+ json_request = '{"checkmempool":true,"outpoints":['
186
+ for x in range (0 , 200 ):
187
+ json_request += '{"txid":"' + txid + '","n":' + str (n )+ '},'
188
+ json_request = json_request .rstrip ("," )
189
+ json_request += "]}" ;
190
+ response = http_get_call (url .hostname , url .port , '/rest/getutxos' + self .FORMAT_SEPARATOR + 'json' , json_request , True )
191
+ assert_equal (response .status , 500 ) #must be a 500 because we exceeding the limits
192
+
193
+ json_request = '{"checkmempool":true,"outpoints":['
194
+ for x in range (0 , 90 ):
195
+ json_request += '{"txid":"' + txid + '","n":' + str (n )+ '},'
196
+ json_request = json_request .rstrip ("," )
197
+ json_request += "]}" ;
198
+ response = http_get_call (url .hostname , url .port , '/rest/getutxos' + self .FORMAT_SEPARATOR + 'json' , json_request , True )
199
+ assert_equal (response .status , 200 ) #must be a 500 because we exceeding the limits
200
+
201
+ self .nodes [0 ].generate (1 ) #generate block to not affect upcomming tests
202
+ self .sync_all ()
203
+
204
+ ################
205
+ # /rest/block/ #
206
+ ################
207
+
40
208
# check binary format
41
- response = http_get_call (url .hostname , url .port , '/rest/block/' + bb_hash + self .FORMAT_SEPARATOR + "bin" , True )
209
+ response = http_get_call (url .hostname , url .port , '/rest/block/' + bb_hash + self .FORMAT_SEPARATOR + "bin" , "" , True )
42
210
assert_equal (response .status , 200 )
43
211
assert_greater_than (int (response .getheader ('content-length' )), 80 )
44
212
response_str = response .read ()
45
213
46
214
# compare with block header
47
- response_header = http_get_call (url .hostname , url .port , '/rest/headers/1/' + bb_hash + self .FORMAT_SEPARATOR + "bin" , True )
215
+ response_header = http_get_call (url .hostname , url .port , '/rest/headers/1/' + bb_hash + self .FORMAT_SEPARATOR + "bin" , "" , True )
48
216
assert_equal (response_header .status , 200 )
49
217
assert_equal (int (response_header .getheader ('content-length' )), 80 )
50
218
response_header_str = response_header .read ()
51
219
assert_equal (response_str [0 :80 ], response_header_str )
52
220
53
221
# check block hex format
54
- response_hex = http_get_call (url .hostname , url .port , '/rest/block/' + bb_hash + self .FORMAT_SEPARATOR + "hex" , True )
222
+ response_hex = http_get_call (url .hostname , url .port , '/rest/block/' + bb_hash + self .FORMAT_SEPARATOR + "hex" , "" , True )
55
223
assert_equal (response_hex .status , 200 )
56
224
assert_greater_than (int (response_hex .getheader ('content-length' )), 160 )
57
225
response_hex_str = response_hex .read ()
58
226
assert_equal (response_str .encode ("hex" )[0 :160 ], response_hex_str [0 :160 ])
59
227
60
228
# compare with hex block header
61
- response_header_hex = http_get_call (url .hostname , url .port , '/rest/headers/1/' + bb_hash + self .FORMAT_SEPARATOR + "hex" , True )
229
+ response_header_hex = http_get_call (url .hostname , url .port , '/rest/headers/1/' + bb_hash + self .FORMAT_SEPARATOR + "hex" , "" , True )
62
230
assert_equal (response_header_hex .status , 200 )
63
231
assert_greater_than (int (response_header_hex .getheader ('content-length' )), 160 )
64
232
response_header_hex_str = response_header_hex .read ()
@@ -77,9 +245,11 @@ def run_test(self):
77
245
assert_equal (json_obj ['txid' ], tx_hash )
78
246
79
247
# check hex format response
80
- hex_string = http_get_call (url .hostname , url .port , '/rest/tx/' + tx_hash + self .FORMAT_SEPARATOR + "hex" , True )
248
+ hex_string = http_get_call (url .hostname , url .port , '/rest/tx/' + tx_hash + self .FORMAT_SEPARATOR + "hex" , "" , True )
81
249
assert_equal (hex_string .status , 200 )
82
250
assert_greater_than (int (response .getheader ('content-length' )), 10 )
251
+
252
+
83
253
84
254
# check block tx details
85
255
# let's make 3 tx and mine them on node 1
0 commit comments