aboutsummaryrefslogtreecommitdiff
path: root/qa/rpc-tests
diff options
context:
space:
mode:
Diffstat (limited to 'qa/rpc-tests')
-rwxr-xr-xqa/rpc-tests/fundrawtransaction.py16
-rwxr-xr-xqa/rpc-tests/p2p-acceptblock.py87
-rwxr-xr-xqa/rpc-tests/rest.py3
-rwxr-xr-xqa/rpc-tests/test_framework/comptool.py4
-rwxr-xr-xqa/rpc-tests/wallet.py66
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 ()