diff options
Diffstat (limited to 'qa')
-rwxr-xr-x | qa/rpc-tests/fundrawtransaction.py | 16 | ||||
-rwxr-xr-x | qa/rpc-tests/p2p-acceptblock.py | 87 | ||||
-rwxr-xr-x | qa/rpc-tests/rest.py | 3 | ||||
-rwxr-xr-x | qa/rpc-tests/test_framework/comptool.py | 4 | ||||
-rwxr-xr-x | qa/rpc-tests/wallet.py | 66 |
5 files changed, 145 insertions, 31 deletions
diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py index deaf8b68fd..fc29789218 100755 --- a/qa/rpc-tests/fundrawtransaction.py +++ b/qa/rpc-tests/fundrawtransaction.py @@ -535,6 +535,22 @@ class RawTransactionsTest(BitcoinTestFramework): self.sync_all() assert_equal(oldBalance+Decimal('50.19000000'), self.nodes[0].getbalance()) #0.19+block reward + ##################################################### + # test fundrawtransaction with OP_RETURN and no vin # + ##################################################### + + rawtx = "0100000000010000000000000000066a047465737400000000" + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + + assert_equal(len(dec_tx['vin']), 0) + assert_equal(len(dec_tx['vout']), 1) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + + assert_greater_than(len(dec_tx['vin']), 0) # at least one vin + assert_equal(len(dec_tx['vout']), 2) # one change output added + ################################################## # test a fundrawtransaction using only watchonly # diff --git a/qa/rpc-tests/p2p-acceptblock.py b/qa/rpc-tests/p2p-acceptblock.py index fcdd1e1b99..83c03eeb78 100755 --- a/qa/rpc-tests/p2p-acceptblock.py +++ b/qa/rpc-tests/p2p-acceptblock.py @@ -40,6 +40,11 @@ The test: it's missing an intermediate block. Node1 should reorg to this longer chain. +4b.Send 288 more blocks on the longer chain. + Node0 should process all but the last block (too far ahead in height). + Send all headers to Node1, and then send the last block in that chain. + Node1 should accept the block because it's coming from a whitelisted peer. + 5. Send a duplicate of the block in #3 to Node0. Node0 should not process the block because it is unrequested, and stay on the shorter chain. @@ -59,6 +64,8 @@ class TestNode(NodeConnCB): NodeConnCB.__init__(self) self.create_callback_map() self.connection = None + self.ping_counter = 1 + self.last_pong = msg_pong() def add_connection(self, conn): self.connection = conn @@ -82,6 +89,24 @@ class TestNode(NodeConnCB): def send_message(self, message): self.connection.send_message(message) + def on_pong(self, conn, message): + self.last_pong = message + + # Sync up with the node after delivery of a block + def sync_with_ping(self, timeout=30): + self.connection.send_message(msg_ping(nonce=self.ping_counter)) + received_pong = False + sleep_time = 0.05 + while not received_pong and timeout > 0: + time.sleep(sleep_time) + timeout -= sleep_time + with mininode_lock: + if self.last_pong.nonce == self.ping_counter: + received_pong = True + self.ping_counter += 1 + return received_pong + + class AcceptBlockTest(BitcoinTestFramework): def add_options(self, parser): parser.add_option("--testbinary", dest="testbinary", @@ -126,13 +151,15 @@ class AcceptBlockTest(BitcoinTestFramework): # 2. Send one block that builds on each tip. # This should be accepted. blocks_h2 = [] # the height 2 blocks on each node's chain + block_time = time.time() + 1 for i in xrange(2): - blocks_h2.append(create_block(tips[i], create_coinbase(), time.time()+1)) + blocks_h2.append(create_block(tips[i], create_coinbase(), block_time)) blocks_h2[i].solve() + block_time += 1 test_node.send_message(msg_block(blocks_h2[0])) white_node.send_message(msg_block(blocks_h2[1])) - time.sleep(1) + [ x.sync_with_ping() for x in [test_node, white_node] ] assert_equal(self.nodes[0].getblockcount(), 2) assert_equal(self.nodes[1].getblockcount(), 2) print "First height 2 block accepted by both nodes" @@ -145,7 +172,7 @@ class AcceptBlockTest(BitcoinTestFramework): test_node.send_message(msg_block(blocks_h2f[0])) white_node.send_message(msg_block(blocks_h2f[1])) - time.sleep(1) # Give time to process the block + [ x.sync_with_ping() for x in [test_node, white_node] ] for x in self.nodes[0].getchaintips(): if x['hash'] == blocks_h2f[0].hash: assert_equal(x['status'], "headers-only") @@ -164,7 +191,7 @@ class AcceptBlockTest(BitcoinTestFramework): test_node.send_message(msg_block(blocks_h3[0])) white_node.send_message(msg_block(blocks_h3[1])) - time.sleep(1) + [ x.sync_with_ping() for x in [test_node, white_node] ] # Since the earlier block was not processed by node0, the new block # can't be fully validated. for x in self.nodes[0].getchaintips(): @@ -182,6 +209,45 @@ class AcceptBlockTest(BitcoinTestFramework): assert_equal(self.nodes[1].getblockcount(), 3) print "Successfully reorged to length 3 chain from whitelisted peer" + # 4b. Now mine 288 more blocks and deliver; all should be processed but + # the last (height-too-high) on node0. Node1 should process the tip if + # we give it the headers chain leading to the tip. + tips = blocks_h3 + headers_message = msg_headers() + all_blocks = [] # node0's blocks + for j in xrange(2): + for i in xrange(288): + next_block = create_block(tips[j].sha256, create_coinbase(), tips[j].nTime+1) + next_block.solve() + if j==0: + test_node.send_message(msg_block(next_block)) + all_blocks.append(next_block) + else: + headers_message.headers.append(CBlockHeader(next_block)) + tips[j] = next_block + + time.sleep(2) + for x in all_blocks: + try: + self.nodes[0].getblock(x.hash) + if x == all_blocks[287]: + raise AssertionError("Unrequested block too far-ahead should have been ignored") + except: + if x == all_blocks[287]: + print "Unrequested block too far-ahead not processed" + else: + raise AssertionError("Unrequested block with more work should have been accepted") + + headers_message.headers.pop() # Ensure the last block is unrequested + white_node.send_message(headers_message) # Send headers leading to tip + white_node.send_message(msg_block(tips[1])) # Now deliver the tip + try: + white_node.sync_with_ping() + self.nodes[1].getblock(tips[1].hash) + print "Unrequested block far ahead of tip accepted from whitelisted peer" + except: + raise AssertionError("Unrequested block from whitelisted peer not accepted") + # 5. Test handling of unrequested block on the node that didn't process # Should still not be processed (even though it has a child that has more # work). @@ -192,7 +258,7 @@ class AcceptBlockTest(BitcoinTestFramework): # the node processes it and incorrectly advances the tip). # But this would be caught later on, when we verify that an inv triggers # a getdata request for this block. - time.sleep(1) + test_node.sync_with_ping() assert_equal(self.nodes[0].getblockcount(), 2) print "Unrequested block that would complete more-work chain was ignored" @@ -204,21 +270,20 @@ class AcceptBlockTest(BitcoinTestFramework): test_node.last_getdata = None test_node.send_message(msg_inv([CInv(2, blocks_h3[0].sha256)])) - time.sleep(1) + test_node.sync_with_ping() with mininode_lock: getdata = test_node.last_getdata - # Check that the getdata is for the right block - assert_equal(len(getdata.inv), 1) + # Check that the getdata includes the right block assert_equal(getdata.inv[0].hash, blocks_h2f[0].sha256) print "Inv at tip triggered getdata for unprocessed block" # 7. Send the missing block for the third time (now it is requested) test_node.send_message(msg_block(blocks_h2f[0])) - time.sleep(1) - assert_equal(self.nodes[0].getblockcount(), 3) - print "Successfully reorged to length 3 chain from non-whitelisted peer" + test_node.sync_with_ping() + assert_equal(self.nodes[0].getblockcount(), 290) + print "Successfully reorged to longer chain from non-whitelisted peer" [ c.disconnect_node() for c in connections ] diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py index 1a2d326cc3..b0cde7268e 100755 --- a/qa/rpc-tests/rest.py +++ b/qa/rpc-tests/rest.py @@ -14,6 +14,7 @@ from struct import * import binascii import json import StringIO +import decimal try: import http.client as httplib @@ -243,7 +244,7 @@ class RESTTest (BitcoinTestFramework): response_header_json = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"json", "", True) assert_equal(response_header_json.status, 200) response_header_json_str = response_header_json.read() - json_obj = json.loads(response_header_json_str) + json_obj = json.loads(response_header_json_str, parse_float=decimal.Decimal) assert_equal(len(json_obj), 1) #ensure that there is one header in the json response assert_equal(json_obj[0]['hash'], bb_hash) #request/response hash should be the same diff --git a/qa/rpc-tests/test_framework/comptool.py b/qa/rpc-tests/test_framework/comptool.py index 23a979250c..7fb31d4a06 100755 --- a/qa/rpc-tests/test_framework/comptool.py +++ b/qa/rpc-tests/test_framework/comptool.py @@ -122,8 +122,8 @@ class TestNode(NodeConnCB): # or false, then only the last tx is tested against outcome.) class TestInstance(object): - def __init__(self, objects=[], sync_every_block=True, sync_every_tx=False): - self.blocks_and_transactions = objects + def __init__(self, objects=None, sync_every_block=True, sync_every_tx=False): + self.blocks_and_transactions = objects if objects else [] self.sync_every_block = sync_every_block self.sync_every_tx = sync_every_tx diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 46dc7765b6..f9ec6f429b 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -4,11 +4,11 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. # -# Exercise the wallet. Ported from wallet.sh. +# Exercise the wallet. Ported from wallet.sh. # Does the following: # a) creates 3 nodes, with an empty chain (no blocks). # b) node0 mines a block -# c) node1 mines 101 blocks, so now nodes 0 and 1 have 50btc, node2 has none. +# c) node1 mines 101 blocks, so now nodes 0 and 1 have 50btc, node2 has none. # d) node0 sends 21 btc to node2, in two transactions (11 btc, then 10 btc). # e) node0 mines a block, collects the fee on the second transaction # f) node1 mines 100 blocks, to mature node0's just-mined block @@ -75,14 +75,14 @@ class WalletTest (BitcoinTestFramework): assert_equal(self.nodes[2].getbalance(), 21) # Node0 should have two unspent outputs. - # Create a couple of transactions to send them to node2, submit them through - # node1, and make sure both node0 and node2 pick them up properly: + # Create a couple of transactions to send them to node2, submit them through + # node1, and make sure both node0 and node2 pick them up properly: node0utxos = self.nodes[0].listunspent(1) assert_equal(len(node0utxos), 2) # create both transactions txns_to_send = [] - for utxo in node0utxos: + for utxo in node0utxos: inputs = [] outputs = {} inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]}) @@ -149,27 +149,27 @@ class WalletTest (BitcoinTestFramework): sync_mempools(self.nodes) assert(txid1 in self.nodes[3].getrawmempool()) - + #check if we can list zero value tx as available coins #1. create rawtx - #2. hex-changed one output to 0.0 + #2. hex-changed one output to 0.0 #3. sign and send #4. check if recipient (node0) can list the zero value tx usp = self.nodes[1].listunspent() inputs = [{"txid":usp[0]['txid'], "vout":usp[0]['vout']}] outputs = {self.nodes[1].getnewaddress(): 49.998, self.nodes[0].getnewaddress(): 11.11} - + rawTx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") #replace 11.11 with 0.0 (int32) decRawTx = self.nodes[1].decoderawtransaction(rawTx) signedRawTx = self.nodes[1].signrawtransaction(rawTx) decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex']) zeroValueTxid= decRawTx['txid'] sendResp = self.nodes[1].sendrawtransaction(signedRawTx['hex']) - + self.sync_all() self.nodes[1].generate(1) #mine a block self.sync_all() - + unspentTxs = self.nodes[0].listunspent() #zero value tx must be in listunspents output found = False for uTx in unspentTxs: @@ -177,7 +177,7 @@ class WalletTest (BitcoinTestFramework): found = True assert_equal(uTx['amount'], Decimal('0.00000000')); assert(found) - + #do some -walletbroadcast tests stop_nodes(self.nodes) wait_bitcoinds() @@ -192,17 +192,17 @@ class WalletTest (BitcoinTestFramework): self.nodes[1].generate(1) #mine a block, tx should not be in there self.sync_all() assert_equal(self.nodes[2].getbalance(), Decimal('59.99800000')); #should not be changed because tx was not broadcasted - + #now broadcast from another node, mine a block, sync, and check the balance self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex']) self.nodes[1].generate(1) self.sync_all() txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) assert_equal(self.nodes[2].getbalance(), Decimal('61.99800000')); #should not be - + #create another tx txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2); - + #restart the nodes with -walletbroadcast=1 stop_nodes(self.nodes) wait_bitcoinds() @@ -211,12 +211,44 @@ class WalletTest (BitcoinTestFramework): connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) sync_blocks(self.nodes) - + self.nodes[0].generate(1) sync_blocks(self.nodes) - + #tx should be added to balance because after restarting the nodes tx should be broadcastet assert_equal(self.nodes[2].getbalance(), Decimal('63.99800000')); #should not be - + + #send a tx with value in a string (PR#6380 +) + txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2") + txObj = self.nodes[0].gettransaction(txId) + assert_equal(txObj['amount'], Decimal('-2.00000000')) + + txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001") + txObj = self.nodes[0].gettransaction(txId) + assert_equal(txObj['amount'], Decimal('-0.00010000')) + + #check if JSON parser can handle scientific notation in strings + txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1e-4") + txObj = self.nodes[0].gettransaction(txId) + assert_equal(txObj['amount'], Decimal('-0.00010000')) + + #this should fail + errorString = "" + try: + txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1f-4") + except JSONRPCException,e: + errorString = e.error['message'] + + assert_equal("Invalid amount" in errorString, True); + + errorString = "" + try: + self.nodes[0].generate("2") #use a string to as block amount parameter must fail because it's not interpreted as amount + except JSONRPCException,e: + errorString = e.error['message'] + + assert_equal("not an integer" in errorString, True); + + if __name__ == '__main__': WalletTest ().main () |