diff options
Diffstat (limited to 'qa')
-rwxr-xr-x | qa/pull-tester/rpc-tests.sh | 5 | ||||
-rw-r--r-- | qa/rpc-tests/README.md | 2 | ||||
-rwxr-xr-x | qa/rpc-tests/decodescript.py | 116 | ||||
-rwxr-xr-x | qa/rpc-tests/fundrawtransaction.py | 556 | ||||
-rwxr-xr-x | qa/rpc-tests/httpbasics.py | 34 | ||||
-rwxr-xr-x | qa/rpc-tests/nodehandling.py | 69 | ||||
-rwxr-xr-x | qa/rpc-tests/proxy_test.py | 62 |
7 files changed, 811 insertions, 33 deletions
diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 9b318650e9..c032f8a038 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -30,8 +30,12 @@ testScripts=( 'zapwallettxes.py' 'proxy_test.py' 'merkle_blocks.py' + 'fundrawtransaction.py' 'signrawtransactions.py' 'walletbackup.py' + 'nodehandling.py' + 'reindex.py' + 'decodescript.py' ); testScriptsExt=( 'bipdersig-p2p.py' @@ -43,7 +47,6 @@ testScriptsExt=( 'invalidateblock.py' 'keypool.py' 'receivedby.py' - 'reindex.py' 'rpcbind_test.py' # 'script_test.py' 'smartfees.py' diff --git a/qa/rpc-tests/README.md b/qa/rpc-tests/README.md index 6221c93d8b..efc81e7a97 100644 --- a/qa/rpc-tests/README.md +++ b/qa/rpc-tests/README.md @@ -25,7 +25,7 @@ Run all possible tests with `qa/pull-tester/rpc-tests.sh -extended`. Possible options: -```` +``` -h, --help show this help message and exit --nocleanup Leave bitcoinds and test.* datadir on exit or error --noshutdown Don't stop bitcoinds after the test execution diff --git a/qa/rpc-tests/decodescript.py b/qa/rpc-tests/decodescript.py new file mode 100755 index 0000000000..ce3bc94ef7 --- /dev/null +++ b/qa/rpc-tests/decodescript.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python2 +# Copyright (c) 2015 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * + +class DecodeScriptTest(BitcoinTestFramework): + """Tests decoding scripts via RPC command "decodescript".""" + + def setup_chain(self): + print('Initializing test directory ' + self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 1) + + def setup_network(self, split=False): + self.nodes = start_nodes(1, self.options.tmpdir) + self.is_network_split = False + + def decodescript_script_sig(self): + signature = '304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001' + push_signature = '48' + signature + public_key = '03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2' + push_public_key = '21' + public_key + + # below are test cases for all of the standard transaction types + + # 1) P2PK scriptSig + # the scriptSig of a public key scriptPubKey simply pushes a signature onto the stack + rpc_result = self.nodes[0].decodescript(push_signature) + assert_equal(signature, rpc_result['asm']) + + # 2) P2PKH scriptSig + rpc_result = self.nodes[0].decodescript(push_signature + push_public_key) + assert_equal(signature + ' ' + public_key, rpc_result['asm']) + + # 3) multisig scriptSig + # this also tests the leading portion of a P2SH multisig scriptSig + # OP_0 <A sig> <B sig> + rpc_result = self.nodes[0].decodescript('00' + push_signature + push_signature) + assert_equal('0 ' + signature + ' ' + signature, rpc_result['asm']) + + # 4) P2SH scriptSig + # an empty P2SH redeemScript is valid and makes for a very simple test case. + # thus, such a spending scriptSig would just need to pass the outer redeemScript + # hash test and leave true on the top of the stack. + rpc_result = self.nodes[0].decodescript('5100') + assert_equal('1 0', rpc_result['asm']) + + # 5) null data scriptSig - no such thing because null data scripts can not be spent. + # thus, no test case for that standard transaction type is here. + + def decodescript_script_pub_key(self): + public_key = '03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2' + push_public_key = '21' + public_key + public_key_hash = '11695b6cd891484c2d49ec5aa738ec2b2f897777' + push_public_key_hash = '14' + public_key_hash + + # below are test cases for all of the standard transaction types + + # 1) P2PK scriptPubKey + # <pubkey> OP_CHECKSIG + rpc_result = self.nodes[0].decodescript(push_public_key + 'ac') + assert_equal(public_key + ' OP_CHECKSIG', rpc_result['asm']) + + # 2) P2PKH scriptPubKey + # OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG + rpc_result = self.nodes[0].decodescript('76a9' + push_public_key_hash + '88ac') + assert_equal('OP_DUP OP_HASH160 ' + public_key_hash + ' OP_EQUALVERIFY OP_CHECKSIG', rpc_result['asm']) + + # 3) multisig scriptPubKey + # <m> <A pubkey> <B pubkey> <C pubkey> <n> OP_CHECKMULTISIG + # just imagine that the pub keys used below are different. + # for our purposes here it does not matter that they are the same even though it is unrealistic. + rpc_result = self.nodes[0].decodescript('52' + push_public_key + push_public_key + push_public_key + '53ae') + assert_equal('2 ' + public_key + ' ' + public_key + ' ' + public_key + ' 3 OP_CHECKMULTISIG', rpc_result['asm']) + + # 4) P2SH scriptPubKey + # OP_HASH160 <Hash160(redeemScript)> OP_EQUAL. + # push_public_key_hash here should actually be the hash of a redeem script. + # but this works the same for purposes of this test. + rpc_result = self.nodes[0].decodescript('a9' + push_public_key_hash + '87') + assert_equal('OP_HASH160 ' + public_key_hash + ' OP_EQUAL', rpc_result['asm']) + + # 5) null data scriptPubKey + # use a signature look-alike here to make sure that we do not decode random data as a signature. + # this matters if/when signature sighash decoding comes along. + # would want to make sure that no such decoding takes place in this case. + signature_imposter = '48304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001' + # OP_RETURN <data> + rpc_result = self.nodes[0].decodescript('6a' + signature_imposter) + assert_equal('OP_RETURN ' + signature_imposter[2:], rpc_result['asm']) + + # 6) a CLTV redeem script. redeem scripts are in-effect scriptPubKey scripts, so adding a test here. + # OP_NOP2 is also known as OP_CHECKLOCKTIMEVERIFY. + # just imagine that the pub keys used below are different. + # for our purposes here it does not matter that they are the same even though it is unrealistic. + # + # OP_IF + # <receiver-pubkey> OP_CHECKSIGVERIFY + # OP_ELSE + # <lock-until> OP_NOP2 OP_DROP + # OP_ENDIF + # <sender-pubkey> OP_CHECKSIG + # + # lock until block 500,000 + rpc_result = self.nodes[0].decodescript('63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac') + assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_NOP2 OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm']) + + def run_test(self): + self.decodescript_script_sig() + self.decodescript_script_pub_key() + +if __name__ == '__main__': + DecodeScriptTest().main() + diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py new file mode 100755 index 0000000000..e859b26433 --- /dev/null +++ b/qa/rpc-tests/fundrawtransaction.py @@ -0,0 +1,556 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +from pprint import pprint +from time import sleep + +# Create one-input, one-output, no-fee transaction: +class RawTransactionsTest(BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 3) + + def setup_network(self, split=False): + self.nodes = start_nodes(3, self.options.tmpdir) + + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + + self.is_network_split=False + self.sync_all() + + def run_test(self): + print "Mining blocks..." + feeTolerance = Decimal(0.00000002) #if the fee's positive delta is higher than this value tests will fail, neg. delta always fail the tests + + self.nodes[2].generate(1) + self.nodes[0].generate(101) + self.sync_all() + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5); + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0); + self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),5.0); + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + ############### + # simple test # + ############### + inputs = [ ] + outputs = { self.nodes[0].getnewaddress() : 1.0 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + + assert_equal(len(dec_tx['vin']), 1) #one vin coin + assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') + assert_equal(fee + totalOut, 1.5) #the 1.5BTC coin must be taken + + ############################## + # simple test with two coins # + ############################## + inputs = [ ] + outputs = { self.nodes[0].getnewaddress() : 2.2 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + + assert_equal(len(dec_tx['vin']), 2) #one vin coin + assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') + assert_equal(dec_tx['vin'][1]['scriptSig']['hex'], '') + assert_equal(fee + totalOut, 2.5) #the 1.5BTC+1.0BTC coins must have be taken + + ############################## + # simple test with two coins # + ############################## + inputs = [ ] + outputs = { self.nodes[0].getnewaddress() : 2.6 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + + assert_equal(len(dec_tx['vin']), 1) #one vin coin + assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') + assert_equal(fee + totalOut, 5.0) #the 5.0BTC coin must have be taken + + + ################################ + # simple test with two outputs # + ################################ + inputs = [ ] + outputs = { self.nodes[0].getnewaddress() : 2.6, self.nodes[1].getnewaddress() : 2.5 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + + assert_equal(len(dec_tx['vin']), 2) #one vin coin + assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '') + assert_equal(dec_tx['vin'][1]['scriptSig']['hex'], '') + assert_equal(fee + totalOut, 6.0) #the 5.0BTC + 1.0BTC coins must have be taken + + + + ######################################################################### + # test a fundrawtransaction with a VIN greater than the required amount # + ######################################################################### + utx = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 5.0: + utx = aUtx + break; + + assert_equal(utx!=False, True) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] + outputs = { self.nodes[0].getnewaddress() : 1.0 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + + assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee + + + + ##################################################################### + # test a fundrawtransaction with which will not get a change output # + ##################################################################### + utx = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 5.0: + utx = aUtx + break; + + assert_equal(utx!=False, True) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] + outputs = { self.nodes[0].getnewaddress() : Decimal(5.0) - fee - feeTolerance } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + + assert_equal(rawtxfund['changepos'], -1) + assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee + + + + ######################################################################### + # test a fundrawtransaction with a VIN smaller than the required amount # + ######################################################################### + utx = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 1.0: + utx = aUtx + break; + + assert_equal(utx!=False, True) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}] + outputs = { self.nodes[0].getnewaddress() : 1.0 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + + # 4-byte version + 1-byte vin count + 36-byte prevout then script_len + rawtx = rawtx[:82] + "0100" + rawtx[84:] + + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex']) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + matchingOuts = 0 + for i, out in enumerate(dec_tx['vout']): + totalOut += out['value'] + if outputs.has_key(out['scriptPubKey']['addresses'][0]): + matchingOuts+=1 + else: + assert_equal(i, rawtxfund['changepos']) + + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex']) + + assert_equal(matchingOuts, 1) + assert_equal(len(dec_tx['vout']), 2) + + assert_equal(fee + totalOut, 2.5) #this tx must use the 1.0BTC and the 1.5BTC coin + + + ########################################### + # test a fundrawtransaction with two VINs # + ########################################### + utx = False + utx2 = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 1.0: + utx = aUtx + if aUtx['amount'] == 5.0: + utx2 = aUtx + + + assert_equal(utx!=False, True) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ] + outputs = { self.nodes[0].getnewaddress() : 6.0 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + matchingOuts = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + if outputs.has_key(out['scriptPubKey']['addresses'][0]): + matchingOuts+=1 + + assert_equal(matchingOuts, 1) + assert_equal(len(dec_tx['vout']), 2) + + matchingIns = 0 + for vinOut in dec_tx['vin']: + for vinIn in inputs: + if vinIn['txid'] == vinOut['txid']: + matchingIns+=1 + + assert_equal(matchingIns, 2) #we now must see two vins identical to vins given as params + assert_equal(fee + totalOut, 7.5) #this tx must use the 1.0BTC and the 1.5BTC coin + + + ######################################################### + # test a fundrawtransaction with two VINs and two vOUTs # + ######################################################### + utx = False + utx2 = False + listunspent = self.nodes[2].listunspent() + for aUtx in listunspent: + if aUtx['amount'] == 1.0: + utx = aUtx + if aUtx['amount'] == 5.0: + utx2 = aUtx + + + assert_equal(utx!=False, True) + + inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ] + outputs = { self.nodes[0].getnewaddress() : 6.0, self.nodes[0].getnewaddress() : 1.0 } + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) + + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + fee = rawtxfund['fee'] + dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) + totalOut = 0 + matchingOuts = 0 + for out in dec_tx['vout']: + totalOut += out['value'] + if outputs.has_key(out['scriptPubKey']['addresses'][0]): + matchingOuts+=1 + + assert_equal(matchingOuts, 2) + assert_equal(len(dec_tx['vout']), 3) + assert_equal(fee + totalOut, 7.5) #this tx must use the 1.0BTC and the 1.5BTC coin + + + ############################################## + # test a fundrawtransaction with invalid vin # + ############################################## + listunspent = self.nodes[2].listunspent() + inputs = [ {'txid' : "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1", 'vout' : 0} ] #invalid vin! + outputs = { self.nodes[0].getnewaddress() : 1.0} + rawtx = self.nodes[2].createrawtransaction(inputs, outputs) + dec_tx = self.nodes[2].decoderawtransaction(rawtx) + + errorString = "" + try: + rawtxfund = self.nodes[2].fundrawtransaction(rawtx) + except JSONRPCException,e: + errorString = e.error['message'] + + assert_equal("Insufficient" in errorString, True); + + + + ############################################################ + #compare fee of a standard pubkeyhash transaction + inputs = [] + outputs = {self.nodes[1].getnewaddress():1.1} + rawTx = self.nodes[0].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[0].fundrawtransaction(rawTx) + + #create same transaction over sendtoaddress + txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1); + signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] + + #compare fee + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee); + assert(feeDelta >= 0 and feeDelta <= feeTolerance) + ############################################################ + + ############################################################ + #compare fee of a standard pubkeyhash transaction with multiple outputs + inputs = [] + outputs = {self.nodes[1].getnewaddress():1.1,self.nodes[1].getnewaddress():1.2,self.nodes[1].getnewaddress():0.1,self.nodes[1].getnewaddress():1.3,self.nodes[1].getnewaddress():0.2,self.nodes[1].getnewaddress():0.3} + rawTx = self.nodes[0].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[0].fundrawtransaction(rawTx) + #create same transaction over sendtoaddress + txId = self.nodes[0].sendmany("", outputs); + signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] + + #compare fee + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee); + assert(feeDelta >= 0 and feeDelta <= feeTolerance) + ############################################################ + + + ############################################################ + #compare fee of a 2of2 multisig p2sh transaction + + # create 2of2 addr + addr1 = self.nodes[1].getnewaddress() + addr2 = self.nodes[1].getnewaddress() + + addr1Obj = self.nodes[1].validateaddress(addr1) + addr2Obj = self.nodes[1].validateaddress(addr2) + + mSigObj = self.nodes[1].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) + + inputs = [] + outputs = {mSigObj:1.1} + rawTx = self.nodes[0].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[0].fundrawtransaction(rawTx) + + #create same transaction over sendtoaddress + txId = self.nodes[0].sendtoaddress(mSigObj, 1.1); + signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] + + #compare fee + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee); + assert(feeDelta >= 0 and feeDelta <= feeTolerance) + ############################################################ + + + ############################################################ + #compare fee of a standard pubkeyhash transaction + + # create 4of5 addr + addr1 = self.nodes[1].getnewaddress() + addr2 = self.nodes[1].getnewaddress() + addr3 = self.nodes[1].getnewaddress() + addr4 = self.nodes[1].getnewaddress() + addr5 = self.nodes[1].getnewaddress() + + addr1Obj = self.nodes[1].validateaddress(addr1) + addr2Obj = self.nodes[1].validateaddress(addr2) + addr3Obj = self.nodes[1].validateaddress(addr3) + addr4Obj = self.nodes[1].validateaddress(addr4) + addr5Obj = self.nodes[1].validateaddress(addr5) + + mSigObj = self.nodes[1].addmultisigaddress(4, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey'], addr4Obj['pubkey'], addr5Obj['pubkey']]) + + inputs = [] + outputs = {mSigObj:1.1} + rawTx = self.nodes[0].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[0].fundrawtransaction(rawTx) + + #create same transaction over sendtoaddress + txId = self.nodes[0].sendtoaddress(mSigObj, 1.1); + signedFee = self.nodes[0].getrawmempool(True)[txId]['fee'] + + #compare fee + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee); + assert(feeDelta >= 0 and feeDelta <= feeTolerance) + ############################################################ + + + ############################################################ + # spend a 2of2 multisig transaction over fundraw + + # create 2of2 addr + addr1 = self.nodes[2].getnewaddress() + addr2 = self.nodes[2].getnewaddress() + + addr1Obj = self.nodes[2].validateaddress(addr1) + addr2Obj = self.nodes[2].validateaddress(addr2) + + mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) + + + # send 1.2 BTC to msig addr + txId = self.nodes[0].sendtoaddress(mSigObj, 1.2); + self.sync_all() + self.nodes[1].generate(1) + self.sync_all() + + oldBalance = self.nodes[1].getbalance() + inputs = [] + outputs = {self.nodes[1].getnewaddress():1.1} + rawTx = self.nodes[2].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[2].fundrawtransaction(rawTx) + + signedTx = self.nodes[2].signrawtransaction(fundedTx['hex']) + txId = self.nodes[2].sendrawtransaction(signedTx['hex']) + self.sync_all() + self.nodes[1].generate(1) + self.sync_all() + + # make sure funds are received at node1 + assert_equal(oldBalance+Decimal('1.10000000'), self.nodes[1].getbalance()) + + ############################################################ + # locked wallet test + self.nodes[1].encryptwallet("test") + self.nodes.pop(1) + stop_nodes(self.nodes) + wait_bitcoinds() + + self.nodes = start_nodes(3, self.options.tmpdir) + + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + self.is_network_split=False + self.sync_all() + + error = False + try: + self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2); + except: + error = True + assert(error) + + oldBalance = self.nodes[0].getbalance() + + inputs = [] + outputs = {self.nodes[0].getnewaddress():1.1} + rawTx = self.nodes[1].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[1].fundrawtransaction(rawTx) + + #now we need to unlock + self.nodes[1].walletpassphrase("test", 100) + signedTx = self.nodes[1].signrawtransaction(fundedTx['hex']) + txId = self.nodes[1].sendrawtransaction(signedTx['hex']) + self.sync_all() + self.nodes[1].generate(1) + self.sync_all() + + # make sure funds are received at node1 + assert_equal(oldBalance+Decimal('51.10000000'), self.nodes[0].getbalance()) + + + + ############################################### + # multiple (~19) inputs tx test | Compare fee # + ############################################### + + #empty node1, send some small coins from node0 to node1 + self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True); + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + for i in range(0,20): + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01); + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + #fund a tx with ~20 small inputs + inputs = [] + outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04} + rawTx = self.nodes[1].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[1].fundrawtransaction(rawTx) + + #create same transaction over sendtoaddress + txId = self.nodes[1].sendmany("", outputs); + signedFee = self.nodes[1].getrawmempool(True)[txId]['fee'] + + #compare fee + feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee); + assert(feeDelta >= 0 and feeDelta <= feeTolerance*19) #~19 inputs + + + ############################################# + # multiple (~19) inputs tx test | sign/send # + ############################################# + + #again, empty node1, send some small coins from node0 to node1 + self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True); + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + for i in range(0,20): + self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01); + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + #fund a tx with ~20 small inputs + oldBalance = self.nodes[0].getbalance() + + inputs = [] + outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04} + rawTx = self.nodes[1].createrawtransaction(inputs, outputs) + fundedTx = self.nodes[1].fundrawtransaction(rawTx) + fundedAndSignedTx = self.nodes[1].signrawtransaction(fundedTx['hex']) + txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex']) + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + assert_equal(oldBalance+Decimal('50.19000000'), self.nodes[0].getbalance()) #0.19+block reward + + +if __name__ == '__main__': + RawTransactionsTest().main() diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py index 64ba49df64..8ccb821286 100755 --- a/qa/rpc-tests/httpbasics.py +++ b/qa/rpc-tests/httpbasics.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. # -# Test REST interface +# Test rpc http basics # from test_framework.test_framework import BitcoinTestFramework @@ -20,83 +20,83 @@ try: except ImportError: import urlparse -class HTTPBasicsTest (BitcoinTestFramework): +class HTTPBasicsTest (BitcoinTestFramework): def setup_nodes(self): return start_nodes(4, self.options.tmpdir, extra_args=[['-rpckeepalive=1'], ['-rpckeepalive=0'], [], []]) - def run_test(self): - + def run_test(self): + ################################################# # lowlevel check for http persistent connection # ################################################# url = urlparse.urlparse(self.nodes[0].url) authpair = url.username + ':' + url.password headers = {"Authorization": "Basic " + base64.b64encode(authpair)} - + conn = httplib.HTTPConnection(url.hostname, url.port) conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read(); assert_equal('"error":null' in out1, True) assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! - + #send 2nd request without closing connection conn.request('POST', '/', '{"method": "getchaintips"}', headers) out2 = conn.getresponse().read(); assert_equal('"error":null' in out1, True) #must also response with a correct json-rpc message assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! conn.close() - + #same should be if we add keep-alive because this should be the std. behaviour headers = {"Authorization": "Basic " + base64.b64encode(authpair), "Connection": "keep-alive"} - + conn = httplib.HTTPConnection(url.hostname, url.port) conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read(); assert_equal('"error":null' in out1, True) assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! - + #send 2nd request without closing connection conn.request('POST', '/', '{"method": "getchaintips"}', headers) out2 = conn.getresponse().read(); assert_equal('"error":null' in out1, True) #must also response with a correct json-rpc message assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! conn.close() - + #now do the same with "Connection: close" headers = {"Authorization": "Basic " + base64.b64encode(authpair), "Connection":"close"} - + conn = httplib.HTTPConnection(url.hostname, url.port) conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read(); assert_equal('"error":null' in out1, True) - assert_equal(conn.sock!=None, False) #now the connection must be closed after the response - + assert_equal(conn.sock!=None, False) #now the connection must be closed after the response + #node1 (2nd node) is running with disabled keep-alive option urlNode1 = urlparse.urlparse(self.nodes[1].url) authpair = urlNode1.username + ':' + urlNode1.password headers = {"Authorization": "Basic " + base64.b64encode(authpair)} - + conn = httplib.HTTPConnection(urlNode1.hostname, urlNode1.port) conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read(); assert_equal('"error":null' in out1, True) assert_equal(conn.sock!=None, False) #connection must be closed because keep-alive was set to false - + #node2 (third node) is running with standard keep-alive parameters which means keep-alive is off urlNode2 = urlparse.urlparse(self.nodes[2].url) authpair = urlNode2.username + ':' + urlNode2.password headers = {"Authorization": "Basic " + base64.b64encode(authpair)} - + conn = httplib.HTTPConnection(urlNode2.hostname, urlNode2.port) conn.connect() conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) out1 = conn.getresponse().read(); assert_equal('"error":null' in out1, True) assert_equal(conn.sock!=None, True) #connection must be closed because bitcoind should use keep-alive by default - + if __name__ == '__main__': HTTPBasicsTest ().main () diff --git a/qa/rpc-tests/nodehandling.py b/qa/rpc-tests/nodehandling.py new file mode 100755 index 0000000000..9a77bd97e8 --- /dev/null +++ b/qa/rpc-tests/nodehandling.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test node handling +# + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import base64 + +try: + import http.client as httplib +except ImportError: + import httplib +try: + import urllib.parse as urlparse +except ImportError: + import urlparse + +class NodeHandlingTest (BitcoinTestFramework): + def run_test(self): + ########################### + # setban/listbanned tests # + ########################### + assert_equal(len(self.nodes[2].getpeerinfo()), 4) #we should have 4 nodes at this point + self.nodes[2].setban("127.0.0.1", "add") + time.sleep(3) #wait till the nodes are disconected + assert_equal(len(self.nodes[2].getpeerinfo()), 0) #all nodes must be disconnected at this point + assert_equal(len(self.nodes[2].listbanned()), 1) + self.nodes[2].clearbanned() + assert_equal(len(self.nodes[2].listbanned()), 0) + self.nodes[2].setban("127.0.0.0/24", "add") + assert_equal(len(self.nodes[2].listbanned()), 1) + try: + self.nodes[2].setban("127.0.0.1", "add") #throws exception because 127.0.0.1 is within range 127.0.0.0/24 + except: + pass + assert_equal(len(self.nodes[2].listbanned()), 1) #still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24 + try: + self.nodes[2].setban("127.0.0.1", "remove") + except: + pass + assert_equal(len(self.nodes[2].listbanned()), 1) + self.nodes[2].setban("127.0.0.0/24", "remove") + assert_equal(len(self.nodes[2].listbanned()), 0) + self.nodes[2].clearbanned() + assert_equal(len(self.nodes[2].listbanned()), 0) + + ########################### + # RPC disconnectnode test # + ########################### + url = urlparse.urlparse(self.nodes[1].url) + self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1))) + time.sleep(2) #disconnecting a node needs a little bit of time + for node in self.nodes[0].getpeerinfo(): + assert(node['addr'] != url.hostname+":"+str(p2p_port(1))) + + connect_nodes_bi(self.nodes,0,1) #reconnect the node + found = False + for node in self.nodes[0].getpeerinfo(): + if node['addr'] == url.hostname+":"+str(p2p_port(1)): + found = True + assert(found) + +if __name__ == '__main__': + NodeHandlingTest ().main () diff --git a/qa/rpc-tests/proxy_test.py b/qa/rpc-tests/proxy_test.py index 9a9b2f5300..3623c16162 100755 --- a/qa/rpc-tests/proxy_test.py +++ b/qa/rpc-tests/proxy_test.py @@ -68,10 +68,10 @@ class ProxyTest(BitcoinTestFramework): ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-proxyrandomize=1'], ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf1.addr),'-onion=%s:%i' % (self.conf2.addr),'-proxyrandomize=0'], ['-listen', '-debug=net', '-debug=proxy', '-proxy=%s:%i' % (self.conf2.addr),'-proxyrandomize=1'], - ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0'] + ['-listen', '-debug=net', '-debug=proxy', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion'] ]) - def node_test(self, node, proxies, auth): + def node_test(self, node, proxies, auth, test_onion=True): rv = [] # Test: outgoing IPv4 connection through node node.addnode("15.61.23.23:1234", "onetry") @@ -99,17 +99,18 @@ class ProxyTest(BitcoinTestFramework): assert_equal(cmd.password, None) rv.append(cmd) - # Test: outgoing onion connection through node - node.addnode("bitcoinostk4e4re.onion:8333", "onetry") - cmd = proxies[2].queue.get() - assert(isinstance(cmd, Socks5Command)) - assert_equal(cmd.atyp, AddressType.DOMAINNAME) - assert_equal(cmd.addr, "bitcoinostk4e4re.onion") - assert_equal(cmd.port, 8333) - if not auth: - assert_equal(cmd.username, None) - assert_equal(cmd.password, None) - rv.append(cmd) + if test_onion: + # Test: outgoing onion connection through node + node.addnode("bitcoinostk4e4re.onion:8333", "onetry") + cmd = proxies[2].queue.get() + assert(isinstance(cmd, Socks5Command)) + assert_equal(cmd.atyp, AddressType.DOMAINNAME) + assert_equal(cmd.addr, "bitcoinostk4e4re.onion") + assert_equal(cmd.port, 8333) + if not auth: + assert_equal(cmd.username, None) + assert_equal(cmd.password, None) + rv.append(cmd) # Test: outgoing DNS name connection through node node.addnode("node.noumenon:8333", "onetry") @@ -139,8 +140,41 @@ class ProxyTest(BitcoinTestFramework): assert_equal(len(credentials), 4) # proxy on IPv6 localhost - self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3], False) + self.node_test(self.nodes[3], [self.serv3, self.serv3, self.serv3, self.serv3], False, False) + + def networks_dict(d): + r = {} + for x in d['networks']: + r[x['name']] = x + return r + + # test RPC getnetworkinfo + n0 = networks_dict(self.nodes[0].getnetworkinfo()) + for net in ['ipv4','ipv6','onion']: + assert_equal(n0[net]['proxy'], '%s:%i' % (self.conf1.addr)) + assert_equal(n0[net]['proxy_randomize_credentials'], True) + assert_equal(n0['onion']['reachable'], True) + + n1 = networks_dict(self.nodes[1].getnetworkinfo()) + for net in ['ipv4','ipv6']: + assert_equal(n1[net]['proxy'], '%s:%i' % (self.conf1.addr)) + assert_equal(n1[net]['proxy_randomize_credentials'], False) + assert_equal(n1['onion']['proxy'], '%s:%i' % (self.conf2.addr)) + assert_equal(n1['onion']['proxy_randomize_credentials'], False) + assert_equal(n1['onion']['reachable'], True) + n2 = networks_dict(self.nodes[2].getnetworkinfo()) + for net in ['ipv4','ipv6','onion']: + assert_equal(n2[net]['proxy'], '%s:%i' % (self.conf2.addr)) + assert_equal(n2[net]['proxy_randomize_credentials'], True) + assert_equal(n2['onion']['reachable'], True) + + n3 = networks_dict(self.nodes[3].getnetworkinfo()) + for net in ['ipv4','ipv6']: + assert_equal(n3[net]['proxy'], '[%s]:%i' % (self.conf3.addr)) + assert_equal(n3[net]['proxy_randomize_credentials'], False) + assert_equal(n3['onion']['reachable'], False) + if __name__ == '__main__': ProxyTest().main() |