def run_test(self): self.log.info("Mining blocks...") self.nodes[0].generate(105) self.sync_all() chain_height = self.nodes[1].getblockcount() assert_equal(chain_height, 105) self.log.info("Testing transaction index...") #privkey = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" #address = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" addressHash = bytes([11,47,10,12,49,191,224,64,107,12,204,19,129,253,190,49,25,70,218,220]) scriptPubKey = CScript([OP_DUP, OP_HASH160, addressHash, OP_EQUALVERIFY, OP_CHECKSIG]) unspent = self.nodes[0].listunspent() tx = CTransaction() amount = int(unspent[0]["amount"] * 10000000) tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))] tx.vout = [CTxOut(amount, scriptPubKey)] tx.rehash() signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() # Check verbose raw transaction results verbose = self.nodes[3].getrawtransaction(unspent[0]["txid"], 1) assert_equal(verbose["vout"][0]["valueSat"], 500000000000) assert_equal(verbose["vout"][0]["value"], 5000) self.log.info("All Tests Passed")
def create_tx(self, outpoints, noutput, feerate, locking_script): tx = CTransaction() total_input = 0 for parent_tx, n in outpoints: tx.vin.append( CTxIn(COutPoint(parent_tx.sha256, n), b"", 0xffffffff)) total_input += parent_tx.vout[n].nValue for _ in range(noutput): tx.vout.append(CTxOut(total_input // noutput, locking_script)) tx.rehash() tx_size = len(tx.serialize()) fee_per_output = int(tx_size * feerate // noutput) for output in tx.vout: output.nValue -= fee_per_output if locking_script == self.locking_script: for parent_tx, n in outpoints: self.sign_tx(tx, parent_tx, n) tx.rehash() return tx
def new_transaction(utxokey, utxo, target_tx_size): ndx, tx_to_spend = utxo padding_size = target_tx_size while True: tx = CTransaction() tx.vin.append(CTxIn(COutPoint(tx_to_spend.sha256, ndx), b'')) tx.vin[0].scriptSig = b'' tx.vout.append( CTxOut(tx_to_spend.vout[0].nValue - 2 * target_tx_size, SIMPLE_OUTPUT_SCRIPT)) tx.vout.append( CTxOut(1, CScript([OP_FALSE, OP_RETURN] + [bytes(1) * padding_size]))) sighash = SignatureHashForkId(tx_to_spend.vout[0].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID, tx_to_spend.vout[0].nValue) sig = utxokey.sign(sighash) + bytes( bytearray([SIGHASH_ALL | SIGHASH_FORKID])) tx.vin[0].scriptSig = CScript([sig]) tx.rehash() diff = target_tx_size - len(tx.serialize()) if diff == 0: return tx padding_size += diff
def branch(prevout, initial_value, max_txs, tree_width=5, fee_val=0.0001 * COIN, _total_txs=None): if _total_txs is None: _total_txs = [0] if _total_txs[0] >= max_txs: return txout_value = (initial_value - fee_val) // tree_width if txout_value < fee_val: return vout = [CTxOut(txout_value, CScript([i+1])) for i in range(tree_width)] tx_data = CTransaction() tx_data.vin = [CTxIn(prevout, n_sequence=0)] tx_data.vout = vout tx_hex = tx_to_hex(tx_data) assert(len(tx_data.serialize()) < 100000) txid = self.nodes[0].sendrawtransaction(tx_hex, True) yield tx_data _total_txs[0] += 1 txid = int(txid, 16) for i, _ in enumerate(tx_data.vout): for x in branch(COutPoint(txid, i), txout_value, max_txs, tree_width=tree_width, fee_val=fee_val, _total_txs=_total_txs): yield x
def SignatureHash(script, txTo, inIdx, hashtype): """Consensus-correct SignatureHash Returns (hash, err) to precisely match the consensus-critical behavior of the SIGHASH_SINGLE bug. (inIdx is *not* checked for validity) """ HASH_ONE = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' if inIdx >= len(txTo.vin): return (HASH_ONE, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin))) txtmp = CTransaction(txTo) for txin in txtmp.vin: txin.scriptSig = b'' txtmp.vin[inIdx].scriptSig = FindAndDelete(script, CScript([OP_CODESEPARATOR])) if (hashtype & 0x1f) == SIGHASH_NONE: txtmp.vout = [] for i in range(len(txtmp.vin)): if i != inIdx: txtmp.vin[i].nSequence = 0 elif (hashtype & 0x1f) == SIGHASH_SINGLE: outIdx = inIdx if outIdx >= len(txtmp.vout): return (HASH_ONE, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout))) tmp = txtmp.vout[outIdx] txtmp.vout = [] for i in range(outIdx): txtmp.vout.append(CTxOut()) txtmp.vout.append(tmp) for i in range(len(txtmp.vin)): if i != inIdx: txtmp.vin[i].nSequence = 0 if hashtype & SIGHASH_ANYONECANPAY: tmp = txtmp.vin[inIdx] txtmp.vin = [] txtmp.vin.append(tmp) s = txtmp.serialize() s += struct.pack(b"<I", hashtype) hash = hash256(s) return (hash, None)
def create_transaction(self, node, coinbase, to_address, amount, txModifier=None): from_txid = node.getblock(coinbase)['tx'][0] inputs = [{ "txid" : from_txid, "vout" : 0}] outputs = { to_address : amount } rawtx = node.createrawtransaction(inputs, outputs) tx = CTransaction() if txModifier: f = cStringIO.StringIO(unhexlify(rawtx)) tx.deserialize(f) txModifier(tx) rawtx = hexlify(tx.serialize()) signresult = node.signrawtransaction(rawtx) f = cStringIO.StringIO(unhexlify(signresult['hex'])) tx.deserialize(f) return tx
def create_transaction(node, coinbase, to_address, amount, expiry_height): from_txid = node.getblock(coinbase)['tx'][0] inputs = [{"txid": from_txid, "vout": 0}] outputs = {to_address: amount} rawtx = node.createrawtransaction(inputs, outputs) tx = CTransaction() # Set the expiry height f = cStringIO.StringIO(unhexlify(rawtx)) tx.deserialize(f) tx.nExpiryHeight = expiry_height rawtx = hexlify(tx.serialize()) signresult = node.signrawtransaction(rawtx) f = cStringIO.StringIO(unhexlify(signresult['hex'])) tx.deserialize(f) tx.rehash() return tx
def create_tx(self, outpoints, noutput, feerate, make_long_eval_script=False): """creates p2pk transaction always using the same key (created in constructor), if make_long_eval_script is set we are prepending long evaluating script to the locking script """ pre_script = MemepoolAcceptingTransactionsDuringReorg.long_eval_script if make_long_eval_script else [] tx = CTransaction() total_input = 0 for parent_tx, n in outpoints: tx.vin.append( CTxIn(COutPoint(parent_tx.sha256, n), CScript([b"0" * 72]), 0xffffffff)) total_input += parent_tx.vout[n].nValue for _ in range(noutput): tx.vout.append( CTxOut(total_input // noutput, CScript(pre_script + [self.public_key, OP_CHECKSIG]))) tx.rehash() tx_size = len(tx.serialize()) fee_per_output = int(tx_size * feerate // noutput) for output in tx.vout: output.nValue -= fee_per_output for input, (parent_tx, n) in zip(tx.vin, outpoints): sighash = SignatureHashForkId(parent_tx.vout[n].scriptPubKey, tx, 0, SIGHASH_ALL | SIGHASH_FORKID, parent_tx.vout[n].nValue) input.scriptSig = CScript([ self.private_key.sign(sighash) + bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID])) ]) tx.rehash() return tx
def create_tx(self, outpoints, noutput, feerate): tx = CTransaction() total_input = 0 for parent_tx, n in outpoints: tx.vin.append(CTxIn(COutPoint(parent_tx.sha256, n), b"", 0xffffffff)) total_input += parent_tx.vout[n].nValue for _ in range(noutput): tx.vout.append(CTxOut(total_input//noutput, CScript([b"X"*200, OP_DROP, OP_TRUE]))) tx.rehash() tx_size = len(tx.serialize()) fee_per_output = int(tx_size * feerate // noutput) for output in tx.vout: output.nValue -= fee_per_output tx.rehash() return tx
def decoderawtransaction_asm_sighashtype(self): """Tests decoding scripts via RPC command "decoderawtransaction". This test is in with the "decodescript" tests because they are testing the same "asm" script decodes. """ # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000' rpc_result = self.nodes[0].decoderawtransaction(tx) assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm']) # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs. # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc # verify that we have not altered scriptPubKey decoding. tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000' rpc_result = self.nodes[0].decoderawtransaction(tx) assert_equal('8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid']) assert_equal('0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm']) assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) txSave = CTransaction() txSave.deserialize(StringIO(unhexlify(tx))) # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000' rpc_result = self.nodes[0].decoderawtransaction(tx) assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm']) # verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000' rpc_result = self.nodes[0].decoderawtransaction(tx) assert_equal('OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) assert_equal('OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) # some more full transaction tests of varying specific scriptSigs. used instead of # tests in decodescript_script_sig because the decodescript RPC is specifically # for working on scriptPubKeys (argh!). push_signature = hexlify(txSave.vin[0].scriptSig)[2:(0x48*2+4)] signature = push_signature[2:] der_signature = signature[:-2] signature_sighash_decoded = der_signature + '[ALL]' signature_2 = der_signature + '82' push_signature_2 = '48' + signature_2 signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]' # 1) P2PK scriptSig txSave.vin[0].scriptSig = unhexlify(push_signature) rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) # make sure that the sighash decodes come out correctly for a more complex / lesser used case. txSave.vin[0].scriptSig = unhexlify(push_signature_2) rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) # 2) multisig scriptSig txSave.vin[0].scriptSig = unhexlify('00' + push_signature + push_signature_2) rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) # 3) test a scriptSig that contains more than push operations. # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it. txSave.vin[0].scriptSig = unhexlify('6a143011020701010101010101020601010101010101') rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) print(hexlify('636174')) assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])
def run_test(self): self.nodes[0].generate(161) #block 161 self.log.info("Verify sigops are counted in GBT with pre-BIP141 rules before the fork") txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) tmpl = self.nodes[0].getblocktemplate({}) assert(tmpl['sizelimit'] == 1000000) assert('weightlimit' not in tmpl) assert(tmpl['sigoplimit'] == 20000) assert(tmpl['transactions'][0]['hash'] == txid) assert(tmpl['transactions'][0]['sigops'] == 2) tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']}) assert(tmpl['sizelimit'] == 1000000) assert('weightlimit' not in tmpl) assert(tmpl['sigoplimit'] == 20000) assert(tmpl['transactions'][0]['hash'] == txid) assert(tmpl['transactions'][0]['sigops'] == 2) self.nodes[0].generate(1) #block 162 balance_presetup = self.nodes[0].getbalance() self.pubkey = [] p2sh_ids = [] # p2sh_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE embedded in p2sh wit_ids = [] # wit_ids[NODE][VER] is an array of txids that spend to a witness version VER pkscript to an address for NODE via bare witness for i in range(3): newaddress = self.nodes[i].getnewaddress() self.pubkey.append(self.nodes[i].validateaddress(newaddress)["pubkey"]) multiaddress = self.nodes[i].addmultisigaddress(1, [self.pubkey[-1]]) self.nodes[i].addwitnessaddress(newaddress) self.nodes[i].addwitnessaddress(multiaddress) p2sh_ids.append([]) wit_ids.append([]) for v in range(2): p2sh_ids[i].append([]) wit_ids[i].append([]) for i in range(5): for n in range(3): for v in range(2): wit_ids[n][v].append(send_to_witness(v, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[n], False, Decimal("49.999"))) p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[n], True, Decimal("49.999"))) self.nodes[0].generate(1) #block 163 sync_blocks(self.nodes) # Make sure all nodes recognize the transactions as theirs assert_equal(self.nodes[0].getbalance(), balance_presetup - 60*50 + 20*Decimal("49.999") + 50) assert_equal(self.nodes[1].getbalance(), 20*Decimal("49.999")) assert_equal(self.nodes[2].getbalance(), 20*Decimal("49.999")) self.nodes[0].generate(260) #block 423 sync_blocks(self.nodes) self.log.info("Verify default node can't accept any witness format txs before fork") # unsigned, no scriptsig self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V0][0], False) self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", wit_ids[NODE_0][WIT_V1][0], False) self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False) self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False) # unsigned with redeem script self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V0][0], False, witness_script(False, self.pubkey[0])) self.fail_accept(self.nodes[0], "mandatory-script-verify-flag", p2sh_ids[NODE_0][WIT_V1][0], False, witness_script(True, self.pubkey[0])) # signed self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V0][0], True) self.fail_accept(self.nodes[0], "no-witness-yet", wit_ids[NODE_0][WIT_V1][0], True) self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V0][0], True) self.fail_accept(self.nodes[0], "no-witness-yet", p2sh_ids[NODE_0][WIT_V1][0], True) self.log.info("Verify witness txs are skipped for mining before the fork") self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][0], True) #block 424 self.skip_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][0], True) #block 425 self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][0], True) #block 426 self.skip_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][0], True) #block 427 # TODO: An old node would see these txs without witnesses and be able to mine them self.log.info("Verify unsigned bare witness txs in versionbits-setting blocks are valid before the fork") self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][1], False) #block 428 self.success_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][1], False) #block 429 self.log.info("Verify unsigned p2sh witness txs without a redeem script are invalid") self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V0][1], False) self.fail_accept(self.nodes[2], "mandatory-script-verify-flag", p2sh_ids[NODE_2][WIT_V1][1], False) self.log.info("Verify unsigned p2sh witness txs with a redeem script in versionbits-settings blocks are valid before the fork") self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][1], False, witness_script(False, self.pubkey[2])) #block 430 self.success_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][1], False, witness_script(True, self.pubkey[2])) #block 431 self.log.info("Verify previous witness txs skipped for mining can now be mined") assert_equal(len(self.nodes[2].getrawmempool()), 4) block = self.nodes[2].generate(1) #block 432 (first block with new rules; 432 = 144 * 3) sync_blocks(self.nodes) assert_equal(len(self.nodes[2].getrawmempool()), 0) segwit_tx_list = self.nodes[2].getblock(block[0])["tx"] assert_equal(len(segwit_tx_list), 5) self.log.info("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag") assert(self.nodes[2].getblock(block[0], False) != self.nodes[0].getblock(block[0], False)) assert(self.nodes[1].getblock(block[0], False) == self.nodes[2].getblock(block[0], False)) for i in range(len(segwit_tx_list)): tx = FromHex(CTransaction(), self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) assert(self.nodes[2].getrawtransaction(segwit_tx_list[i]) != self.nodes[0].getrawtransaction(segwit_tx_list[i])) assert(self.nodes[1].getrawtransaction(segwit_tx_list[i], 0) == self.nodes[2].getrawtransaction(segwit_tx_list[i])) assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) != self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) assert(self.nodes[1].getrawtransaction(segwit_tx_list[i]) == self.nodes[2].gettransaction(segwit_tx_list[i])["hex"]) assert(self.nodes[0].getrawtransaction(segwit_tx_list[i]) == bytes_to_hex_str(tx.serialize_without_witness())) self.log.info("Verify witness txs without witness data are invalid after the fork") self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V0][2], False) self.fail_mine(self.nodes[2], wit_ids[NODE_2][WIT_V1][2], False) self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V0][2], False, witness_script(False, self.pubkey[2])) self.fail_mine(self.nodes[2], p2sh_ids[NODE_2][WIT_V1][2], False, witness_script(True, self.pubkey[2])) self.log.info("Verify default node can now use witness txs") self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V0][0], True) #block 432 self.success_mine(self.nodes[0], wit_ids[NODE_0][WIT_V1][0], True) #block 433 self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V0][0], True) #block 434 self.success_mine(self.nodes[0], p2sh_ids[NODE_0][WIT_V1][0], True) #block 435 self.log.info("Verify sigops are counted in GBT with BIP141 rules after the fork") txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) tmpl = self.nodes[0].getblocktemplate({'rules':['segwit']}) assert(tmpl['sizelimit'] >= 3999577) # actual maximum size is lower due to minimum mandatory non-witness data assert(tmpl['weightlimit'] == 4000000) assert(tmpl['sigoplimit'] == 80000) assert(tmpl['transactions'][0]['txid'] == txid) assert(tmpl['transactions'][0]['sigops'] == 8) self.nodes[0].generate(1) # Mine a block to clear the gbt cache self.log.info("Non-segwit miners are able to use GBT response after activation.") # Create a 3-tx chain: tx1 (non-segwit input, paying to a segwit output) -> # tx2 (segwit input, paying to a non-segwit output) -> # tx3 (non-segwit input, paying to a non-segwit output). # tx1 is allowed to appear in the block, but no others. tx_hex = self.nodes[0].gettransaction(txid)['hex'] tx = FromHex(CTransaction(), tx_hex) assert(tx.wit.is_null()) # This should not be a segwit input txid1 = send_to_witness(1, self.nodes[0], find_unspent(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.996")) assert(txid1 in self.nodes[0].getrawmempool()) tx1_hex = self.nodes[0].gettransaction(txid1)['hex'] tx1 = FromHex(CTransaction(), tx1_hex) # Check that wtxid is properly reported in mempool entry (txid1) assert_equal(int(self.nodes[0].getmempoolentry(txid1)["wtxid"], 16), tx1.calc_sha256(True)) # Check that weight and sizei (actually vsize) are properly reported in mempool entry (txid1) assert_equal(self.nodes[0].getmempoolentry(txid1)["size"], (self.nodes[0].getmempoolentry(txid1)["weight"] + 3) // 4) assert_equal(self.nodes[0].getmempoolentry(txid1)["weight"], len(tx1.serialize())*3 + len(tx1.serialize_with_witness())) # Now create tx2, which will spend from txid1. tx2 = CTransaction() tx2.vin.append(CTxIn(COutPoint(int(txid1, 16), 0), b'')) tx2.vout.append(CTxOut(int(49.99*COIN), CScript([OP_TRUE]))) tx2_hex = self.nodes[0].signrawtransaction(ToHex(tx2))['hex'] txid2 = self.nodes[0].sendrawtransaction(tx2_hex) tx2 = FromHex(CTransaction(), tx2_hex) assert(not tx2.wit.is_null()) # Check that wtxid is properly reported in mempool entry (txid2) assert_equal(int(self.nodes[0].getmempoolentry(txid2)["wtxid"], 16), tx2.calc_sha256(True)) # Check that weight and size (actually vsize) are properly reported in mempool entry (txid2) assert_equal(self.nodes[0].getmempoolentry(txid2)["size"], (self.nodes[0].getmempoolentry(txid2)["weight"] + 3) // 4) assert_equal(self.nodes[0].getmempoolentry(txid2)["weight"], len(tx2.serialize())*3 + len(tx2.serialize_with_witness())) # Now create tx3, which will spend from txid2 tx3 = CTransaction() tx3.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b"")) tx3.vout.append(CTxOut(int(49.95*COIN), CScript([OP_TRUE]))) # Huge fee tx3.calc_sha256() txid3 = self.nodes[0].sendrawtransaction(ToHex(tx3)) assert(tx3.wit.is_null()) assert(txid3 in self.nodes[0].getrawmempool()) # Now try calling getblocktemplate() without segwit support. template = self.nodes[0].getblocktemplate() # Check that we got a pre-Segwit template assert(template['sizelimit'] == 1000000) assert('weightlimit' not in template) assert(template['sigoplimit'] == 20000) # TODO: Would be nice to test for non-zero sigops here assert(template['transactions'][0]['sigops'] == 0) # Check that tx1 is the only transaction of the 3 in the template. template_txids = [ t['txid'] for t in template['transactions'] ] assert(txid2 not in template_txids and txid3 not in template_txids) assert(txid1 in template_txids) # Check that running with segwit support results in all 3 being included. template = self.nodes[0].getblocktemplate({"rules": ["segwit"]}) template_txids = [ t['txid'] for t in template['transactions'] ] assert(txid1 in template_txids) assert(txid2 in template_txids) assert(txid3 in template_txids) # Check that hash is properly reported in mempool entry (txid3) assert_equal(int(self.nodes[0].getmempoolentry(txid3)["hash"], 16), tx3.calc_sha256(True)) # Check that wtxid is properly reported in mempool entry (txid3) assert_equal(int(self.nodes[0].getmempoolentry(txid3)["wtxid"], 16), tx3.calc_sha256(True)) # Check that weight and size (actually vsize) are properly reported in mempool entry (txid3) assert_equal(self.nodes[0].getmempoolentry(txid3)["size"], (self.nodes[0].getmempoolentry(txid3)["weight"] + 3) // 4) assert_equal(self.nodes[0].getmempoolentry(txid3)["weight"], len(tx3.serialize())*3 + len(tx3.serialize_with_witness())) # Mine a block to clear the gbt cache again. self.nodes[0].generate(1) self.log.info("Verify behaviour of importaddress, addwitnessaddress and listunspent") # Some public keys to be used later pubkeys = [ "0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242", # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb "02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF", # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97 "04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E", # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV "02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538", # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd "036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228", # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66 "0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC", # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K "0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84", # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ ] # Import a compressed key and an uncompressed key, generate some multisig addresses self.nodes[0].importprivkey("92e6XLo5jVAVwrQKPNTs93oQco8f8sDNBcpv73Dsrs397fQtFQn") uncompressed_spendable_address = ["mvozP4UwyGD2mGZU4D2eMvMLPB9WkMmMQu"] self.nodes[0].importprivkey("cNC8eQ5dg3mFAVePDX4ddmPYpPbw41r9bm2jd1nLJT77e6RrzTRR") compressed_spendable_address = ["mmWQubrDomqpgSYekvsU7HWEVjLFHAakLe"] assert ((self.nodes[0].validateaddress(uncompressed_spendable_address[0])['iscompressed'] == False)) assert ((self.nodes[0].validateaddress(compressed_spendable_address[0])['iscompressed'] == True)) self.nodes[0].importpubkey(pubkeys[0]) compressed_solvable_address = [key_to_p2pkh(pubkeys[0])] self.nodes[0].importpubkey(pubkeys[1]) compressed_solvable_address.append(key_to_p2pkh(pubkeys[1])) self.nodes[0].importpubkey(pubkeys[2]) uncompressed_solvable_address = [key_to_p2pkh(pubkeys[2])] spendable_anytime = [] # These outputs should be seen anytime after importprivkey and addmultisigaddress spendable_after_importaddress = [] # These outputs should be seen after importaddress solvable_after_importaddress = [] # These outputs should be seen after importaddress but not spendable unsolvable_after_importaddress = [] # These outputs should be unsolvable after importaddress solvable_anytime = [] # These outputs should be solvable after importpubkey unseen_anytime = [] # These outputs should never be seen uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], compressed_spendable_address[0]])) uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], uncompressed_spendable_address[0]])) compressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_spendable_address[0]])) uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], uncompressed_solvable_address[0]])) compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]])) compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], compressed_solvable_address[1]])) unknown_address = ["mtKKyoHabkk6e4ppT7NaM7THqPUt7AzPrT", "2NDP3jLWAFT8NDAiUa9qiE6oBt2awmMq7Dx"] # Test multisig_without_privkey # We have 2 public keys without private keys, use addmultisigaddress to add to wallet. # Money sent to P2SH of multisig of this should only be seen after importaddress with the BASE58 P2SH address. multisig_without_privkey_address = self.nodes[0].addmultisigaddress(2, [pubkeys[3], pubkeys[4]]) script = CScript([OP_2, hex_str_to_bytes(pubkeys[3]), hex_str_to_bytes(pubkeys[4]), OP_2, OP_CHECKMULTISIG]) solvable_after_importaddress.append(CScript([OP_HASH160, hash160(script), OP_EQUAL])) for i in compressed_spendable_address: v = self.nodes[0].validateaddress(i) if (v['isscript']): [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v) # bare and p2sh multisig with compressed keys should always be spendable spendable_anytime.extend([bare, p2sh]) # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after direct importaddress spendable_after_importaddress.extend([p2wsh, p2sh_p2wsh]) else: [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v) # normal P2PKH and P2PK with compressed keys should always be spendable spendable_anytime.extend([p2pkh, p2pk]) # P2SH_P2PK, P2SH_P2PKH, and witness with compressed keys are spendable after direct importaddress spendable_after_importaddress.extend([p2wpkh, p2sh_p2wpkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh]) for i in uncompressed_spendable_address: v = self.nodes[0].validateaddress(i) if (v['isscript']): [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v) # bare and p2sh multisig with uncompressed keys should always be spendable spendable_anytime.extend([bare, p2sh]) # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen unseen_anytime.extend([p2wsh, p2sh_p2wsh]) else: [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v) # normal P2PKH and P2PK with uncompressed keys should always be spendable spendable_anytime.extend([p2pkh, p2pk]) # P2SH_P2PK and P2SH_P2PKH are spendable after direct importaddress spendable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh]) # witness with uncompressed keys are never seen unseen_anytime.extend([p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh]) for i in compressed_solvable_address: v = self.nodes[0].validateaddress(i) if (v['isscript']): # Multisig without private is not seen after addmultisigaddress, but seen after importaddress [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v) solvable_after_importaddress.extend([bare, p2sh, p2wsh, p2sh_p2wsh]) else: [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v) # normal P2PKH and P2PK with compressed keys should always be seen solvable_anytime.extend([p2pkh, p2pk]) # P2SH_P2PK, P2SH_P2PKH, and witness with compressed keys are seen after direct importaddress solvable_after_importaddress.extend([p2wpkh, p2sh_p2wpkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh]) for i in uncompressed_solvable_address: v = self.nodes[0].validateaddress(i) if (v['isscript']): [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v) # Base uncompressed multisig without private is not seen after addmultisigaddress, but seen after importaddress solvable_after_importaddress.extend([bare, p2sh]) # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen unseen_anytime.extend([p2wsh, p2sh_p2wsh]) else: [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v) # normal P2PKH and P2PK with uncompressed keys should always be seen solvable_anytime.extend([p2pkh, p2pk]) # P2SH_P2PK, P2SH_P2PKH with uncompressed keys are seen after direct importaddress solvable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh]) # witness with uncompressed keys are never seen unseen_anytime.extend([p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh]) op1 = CScript([OP_1]) op0 = CScript([OP_0]) # 2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe is the P2SH(P2PKH) version of mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V unsolvable_address = ["mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V", "2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe", script_to_p2sh(op1), script_to_p2sh(op0)] unsolvable_address_key = hex_str_to_bytes("02341AEC7587A51CDE5279E0630A531AEA2615A9F80B17E8D9376327BAEAA59E3D") unsolvablep2pkh = CScript([OP_DUP, OP_HASH160, hash160(unsolvable_address_key), OP_EQUALVERIFY, OP_CHECKSIG]) unsolvablep2wshp2pkh = CScript([OP_0, sha256(unsolvablep2pkh)]) p2shop0 = CScript([OP_HASH160, hash160(op0), OP_EQUAL]) p2wshop1 = CScript([OP_0, sha256(op1)]) unsolvable_after_importaddress.append(unsolvablep2pkh) unsolvable_after_importaddress.append(unsolvablep2wshp2pkh) unsolvable_after_importaddress.append(op1) # OP_1 will be imported as script unsolvable_after_importaddress.append(p2wshop1) unseen_anytime.append(op0) # OP_0 will be imported as P2SH address with no script provided unsolvable_after_importaddress.append(p2shop0) spendable_txid = [] solvable_txid = [] spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime, 2)) solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime, 1)) self.mine_and_test_listunspent(spendable_after_importaddress + solvable_after_importaddress + unseen_anytime + unsolvable_after_importaddress, 0) importlist = [] for i in compressed_spendable_address + uncompressed_spendable_address + compressed_solvable_address + uncompressed_solvable_address: v = self.nodes[0].validateaddress(i) if (v['isscript']): bare = hex_str_to_bytes(v['hex']) importlist.append(bytes_to_hex_str(bare)) importlist.append(bytes_to_hex_str(CScript([OP_0, sha256(bare)]))) else: pubkey = hex_str_to_bytes(v['pubkey']) p2pk = CScript([pubkey, OP_CHECKSIG]) p2pkh = CScript([OP_DUP, OP_HASH160, hash160(pubkey), OP_EQUALVERIFY, OP_CHECKSIG]) importlist.append(bytes_to_hex_str(p2pk)) importlist.append(bytes_to_hex_str(p2pkh)) importlist.append(bytes_to_hex_str(CScript([OP_0, hash160(pubkey)]))) importlist.append(bytes_to_hex_str(CScript([OP_0, sha256(p2pk)]))) importlist.append(bytes_to_hex_str(CScript([OP_0, sha256(p2pkh)]))) importlist.append(bytes_to_hex_str(unsolvablep2pkh)) importlist.append(bytes_to_hex_str(unsolvablep2wshp2pkh)) importlist.append(bytes_to_hex_str(op1)) importlist.append(bytes_to_hex_str(p2wshop1)) for i in importlist: # import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC # exceptions and continue. try_rpc(-4, "The wallet already contains the private key for this address or script", self.nodes[0].importaddress, i, "", False, True) self.nodes[0].importaddress(script_to_p2sh(op0)) # import OP_0 as address only self.nodes[0].importaddress(multisig_without_privkey_address) # Test multisig_without_privkey spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2)) solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1)) self.mine_and_test_listunspent(unsolvable_after_importaddress, 1) self.mine_and_test_listunspent(unseen_anytime, 0) # addwitnessaddress should refuse to return a witness address if an uncompressed key is used # note that no witness address should be returned by unsolvable addresses for i in uncompressed_spendable_address + uncompressed_solvable_address + unknown_address + unsolvable_address: assert_raises_rpc_error(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i) # addwitnessaddress should return a witness addresses even if keys are not in the wallet self.nodes[0].addwitnessaddress(multisig_without_privkey_address) for i in compressed_spendable_address + compressed_solvable_address: witaddress = self.nodes[0].addwitnessaddress(i) # addwitnessaddress should return the same address if it is a known P2SH-witness address assert_equal(witaddress, self.nodes[0].addwitnessaddress(witaddress)) spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2)) solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1)) self.mine_and_test_listunspent(unsolvable_after_importaddress, 1) self.mine_and_test_listunspent(unseen_anytime, 0) # Repeat some tests. This time we don't add witness scripts with importaddress # Import a compressed key and an uncompressed key, generate some multisig addresses self.nodes[0].importprivkey("927pw6RW8ZekycnXqBQ2JS5nPyo1yRfGNN8oq74HeddWSpafDJH") uncompressed_spendable_address = ["mguN2vNSCEUh6rJaXoAVwY3YZwZvEmf5xi"] self.nodes[0].importprivkey("cMcrXaaUC48ZKpcyydfFo8PxHAjpsYLhdsp6nmtB3E2ER9UUHWnw") compressed_spendable_address = ["n1UNmpmbVUJ9ytXYXiurmGPQ3TRrXqPWKL"] self.nodes[0].importpubkey(pubkeys[5]) compressed_solvable_address = [key_to_p2pkh(pubkeys[5])] self.nodes[0].importpubkey(pubkeys[6]) uncompressed_solvable_address = [key_to_p2pkh(pubkeys[6])] spendable_after_addwitnessaddress = [] # These outputs should be seen after importaddress solvable_after_addwitnessaddress=[] # These outputs should be seen after importaddress but not spendable unseen_anytime = [] # These outputs should never be seen uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], compressed_spendable_address[0]])) uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], uncompressed_spendable_address[0]])) compressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_spendable_address[0]])) uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], uncompressed_solvable_address[0]])) compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]])) premature_witaddress = [] for i in compressed_spendable_address: v = self.nodes[0].validateaddress(i) if (v['isscript']): [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v) # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after addwitnessaddress spendable_after_addwitnessaddress.extend([p2wsh, p2sh_p2wsh]) premature_witaddress.append(script_to_p2sh(p2wsh)) else: [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v) # P2WPKH, P2SH_P2WPKH are spendable after addwitnessaddress spendable_after_addwitnessaddress.extend([p2wpkh, p2sh_p2wpkh]) premature_witaddress.append(script_to_p2sh(p2wpkh)) for i in uncompressed_spendable_address + uncompressed_solvable_address: v = self.nodes[0].validateaddress(i) if (v['isscript']): [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v) # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen unseen_anytime.extend([p2wsh, p2sh_p2wsh]) else: [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v) # P2WPKH, P2SH_P2WPKH with uncompressed keys are never seen unseen_anytime.extend([p2wpkh, p2sh_p2wpkh]) for i in compressed_solvable_address: v = self.nodes[0].validateaddress(i) if (v['isscript']): # P2WSH multisig without private key are seen after addwitnessaddress [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v) solvable_after_addwitnessaddress.extend([p2wsh, p2sh_p2wsh]) premature_witaddress.append(script_to_p2sh(p2wsh)) else: [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v) # P2SH_P2PK, P2SH_P2PKH with compressed keys are seen after addwitnessaddress solvable_after_addwitnessaddress.extend([p2wpkh, p2sh_p2wpkh]) premature_witaddress.append(script_to_p2sh(p2wpkh)) self.mine_and_test_listunspent(spendable_after_addwitnessaddress + solvable_after_addwitnessaddress + unseen_anytime, 0) # addwitnessaddress should refuse to return a witness address if an uncompressed key is used # note that a multisig address returned by addmultisigaddress is not solvable until it is added with importaddress # premature_witaddress are not accepted until the script is added with addwitnessaddress first for i in uncompressed_spendable_address + uncompressed_solvable_address + premature_witaddress: # This will raise an exception assert_raises_rpc_error(-4, "Public key or redeemscript not known to wallet, or the key is uncompressed", self.nodes[0].addwitnessaddress, i) # after importaddress it should pass addwitnessaddress v = self.nodes[0].validateaddress(compressed_solvable_address[1]) self.nodes[0].importaddress(v['hex'],"",False,True) for i in compressed_spendable_address + compressed_solvable_address + premature_witaddress: witaddress = self.nodes[0].addwitnessaddress(i) assert_equal(witaddress, self.nodes[0].addwitnessaddress(witaddress)) spendable_txid.append(self.mine_and_test_listunspent(spendable_after_addwitnessaddress, 2)) solvable_txid.append(self.mine_and_test_listunspent(solvable_after_addwitnessaddress, 1)) self.mine_and_test_listunspent(unseen_anytime, 0) # Check that spendable outputs are really spendable self.create_and_mine_tx_from_txids(spendable_txid) # import all the private keys so solvable addresses become spendable self.nodes[0].importprivkey("cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb") self.nodes[0].importprivkey("cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97") self.nodes[0].importprivkey("91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV") self.nodes[0].importprivkey("cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd") self.nodes[0].importprivkey("cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66") self.nodes[0].importprivkey("cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K") self.create_and_mine_tx_from_txids(solvable_txid)
def run_test(self): # helper functions def getaddresstxids(node_index, addresses, start, end): return self.nodes[node_index].getaddresstxids({ 'addresses': addresses, 'start': start, 'end': end }) def getaddressdeltas(node_index, addresses, start, end, chainInfo=None): params = { 'addresses': addresses, 'start': start, 'end': end, } if chainInfo is not None: params.update({'chainInfo': chainInfo}) return self.nodes[node_index].getaddressdeltas(params) # default received value is the balance value def check_balance(node_index, address, expected_balance, expected_received=None): if isinstance(address, list): bal = self.nodes[node_index].getaddressbalance( {'addresses': address}) else: bal = self.nodes[node_index].getaddressbalance(address) assert_equal(bal['balance'], expected_balance) if expected_received is None: expected_received = expected_balance assert_equal(bal['received'], expected_received) # begin test self.nodes[0].generate(105) self.sync_all() assert_equal(self.nodes[0].getbalance(), 5 * 10) assert_equal(self.nodes[1].getblockcount(), 105) assert_equal(self.nodes[1].getbalance(), 0) # only the oldest 5; subsequent are not yet mature unspent_txids = [u['txid'] for u in self.nodes[0].listunspent()] # Currently our only unspents are coinbase transactions, choose any one tx = self.nodes[0].getrawtransaction(unspent_txids[0], 1) # It just so happens that the first output is the mining reward, # which has type pay-to-public-key-hash, and the second output # is the founders' reward, which has type pay-to-script-hash. addr_p2pkh = tx['vout'][0]['scriptPubKey']['addresses'][0] addr_p2sh = tx['vout'][1]['scriptPubKey']['addresses'][0] # Check that balances from mining are correct (105 blocks mined); in # regtest, all mining rewards from a single call to generate() are sent # to the same pair of addresses. check_balance(1, addr_p2pkh, 105 * 10 * COIN) check_balance(1, addr_p2sh, 105 * 2.5 * COIN) # Multiple address arguments, results are the sum check_balance(1, [addr_p2sh, addr_p2pkh], 105 * 12.5 * COIN) assert_equal(len(self.nodes[1].getaddresstxids(addr_p2pkh)), 105) assert_equal(len(self.nodes[1].getaddresstxids(addr_p2sh)), 105) # test getaddresstxids for lightwalletd assert_equal(len(self.nodes[3].getaddresstxids(addr_p2pkh)), 105) assert_equal(len(self.nodes[3].getaddresstxids(addr_p2sh)), 105) # only the oldest 5 transactions are in the unspent list, # dup addresses are ignored height_txids = getaddresstxids(1, [addr_p2pkh, addr_p2pkh], 1, 5) assert_equal(sorted(height_txids), sorted(unspent_txids)) height_txids = getaddresstxids(1, [addr_p2sh], 1, 5) assert_equal(sorted(height_txids), sorted(unspent_txids)) # each txid should appear only once height_txids = getaddresstxids(1, [addr_p2pkh, addr_p2sh], 1, 5) assert_equal(sorted(height_txids), sorted(unspent_txids)) # do some transfers, make sure balances are good txids_a1 = [] addr1 = self.nodes[1].getnewaddress() expected = 0 expected_deltas = [] # for checking getaddressdeltas (below) for i in range(5): # first transaction happens at height 105, mined in block 106 txid = self.nodes[0].sendtoaddress(addr1, i + 1) txids_a1.append(txid) self.nodes[0].generate(1) self.sync_all() expected += i + 1 expected_deltas.append({ 'height': 106 + i, 'satoshis': (i + 1) * COIN, 'txid': txid, }) check_balance(1, addr1, expected * COIN) assert_equal(sorted(self.nodes[0].getaddresstxids(addr1)), sorted(txids_a1)) assert_equal(sorted(self.nodes[1].getaddresstxids(addr1)), sorted(txids_a1)) # Restart all nodes to ensure indices are saved to disk and recovered stop_nodes(self.nodes) wait_bitcoinds() self.setup_network() bal = self.nodes[1].getaddressbalance(addr1) assert_equal(bal['balance'], expected * COIN) assert_equal(bal['received'], expected * COIN) assert_equal(sorted(self.nodes[0].getaddresstxids(addr1)), sorted(txids_a1)) assert_equal(sorted(self.nodes[1].getaddresstxids(addr1)), sorted(txids_a1)) # Send 3 from addr1, but -- subtlety alert! -- addr1 at this # time has 4 UTXOs, with values 1, 2, 3, 4. Sending value 3 requires # using up the value 4 UTXO, because of the tx fee # (the 3 UTXO isn't quite large enough). # # The txid from sending *from* addr1 is also added to the list of # txids associated with that address (test will verify below). addr2 = self.nodes[2].getnewaddress() txid = self.nodes[1].sendtoaddress(addr2, 3) self.sync_all() # the one tx in the mempool refers to addresses addr1 and addr2, # check that duplicate addresses are processed correctly mempool = self.nodes[0].getaddressmempool( {'addresses': [addr2, addr1, addr2]}) assert_equal(len(mempool), 3) # test getaddressmempool for lightwalletd node mempool = self.nodes[3].getaddressmempool( {'addresses': [addr2, addr1, addr2]}) assert_equal(len(mempool), 3) # addr2 (first arg) assert_equal(mempool[0]['address'], addr2) assert_equal(mempool[0]['satoshis'], 3 * COIN) assert_equal(mempool[0]['txid'], txid) # addr1 (second arg) assert_equal(mempool[1]['address'], addr1) assert_equal(mempool[1]['satoshis'], (-4) * COIN) assert_equal(mempool[1]['txid'], txid) # addr2 (third arg) assert_equal(mempool[2]['address'], addr2) assert_equal(mempool[2]['satoshis'], 3 * COIN) assert_equal(mempool[2]['txid'], txid) # a single address can be specified as a string (not json object) addr1_mempool = self.nodes[0].getaddressmempool(addr1) assert_equal(len(addr1_mempool), 1) # Don't check the timestamp; it's local to the node, and can mismatch # due to propagation delay. del addr1_mempool[0]['timestamp'] for key in addr1_mempool[0].keys(): assert_equal(mempool[1][key], addr1_mempool[0][key]) tx = self.nodes[0].getrawtransaction(txid, 1) assert_equal(tx['vin'][0]['address'], addr1) assert_equal(tx['vin'][0]['value'], 4) assert_equal(tx['vin'][0]['valueSat'], 4 * COIN) txids_a1.append(txid) expected_deltas.append({ 'height': 111, 'satoshis': (-4) * COIN, 'txid': txid, }) self.sync_all() # ensure transaction is included in the next block self.nodes[0].generate(1) self.sync_all() # the send to addr2 tx is now in a mined block, no longer in the mempool mempool = self.nodes[0].getaddressmempool( {'addresses': [addr2, addr1]}) assert_equal(len(mempool), 0) # Test DisconnectBlock() by invalidating the most recent mined block tip = self.nodes[1].getchaintips()[0] for i in range(self.num_nodes): node = self.nodes[i] # the value 4 UTXO is no longer in our balance check_balance(i, addr1, (expected - 4) * COIN, expected * COIN) check_balance(i, addr2, 3 * COIN) assert_equal(node.getblockcount(), 111) node.invalidateblock(tip['hash']) assert_equal(node.getblockcount(), 110) mempool = node.getaddressmempool({'addresses': [addr2, addr1]}) assert_equal(len(mempool), 2) check_balance(i, addr1, expected * COIN) check_balance(i, addr2, 0) # now re-mine the addr1 to addr2 send self.nodes[0].generate(1) self.sync_all() for node in self.nodes: assert_equal(node.getblockcount(), 111) mempool = self.nodes[0].getaddressmempool( {'addresses': [addr2, addr1]}) assert_equal(len(mempool), 0) # the value 4 UTXO is no longer in our balance check_balance(2, addr1, (expected - 4) * COIN, expected * COIN) # Ensure the change from that transaction appears tx = self.nodes[0].getrawtransaction(txid, 1) change_vout = list( filter(lambda v: v['valueZat'] != 3 * COIN, tx['vout'])) change = change_vout[0]['scriptPubKey']['addresses'][0] # test getaddressbalance for node in (2, 3): bal = self.nodes[node].getaddressbalance(change) assert (bal['received'] > 0) # the inequality is due to randomness in the tx fee assert (bal['received'] < (4 - 3) * COIN) assert_equal(bal['received'], bal['balance']) assert_equal(self.nodes[2].getaddresstxids(change), [txid]) # Further checks that limiting by height works # various ranges for i in range(5): height_txids = getaddresstxids(1, [addr1], 106, 106 + i) assert_equal(height_txids, txids_a1[0:i + 1]) height_txids = getaddresstxids(1, [addr1], 1, 108) assert_equal(height_txids, txids_a1[0:3]) # Further check specifying multiple addresses txids_all = list(txids_a1) txids_all += self.nodes[1].getaddresstxids(addr_p2pkh) txids_all += self.nodes[1].getaddresstxids(addr_p2sh) multitxids = self.nodes[1].getaddresstxids( {'addresses': [addr1, addr_p2sh, addr_p2pkh]}) # No dups in return list from getaddresstxids assert_equal(len(multitxids), len(set(multitxids))) # set(txids_all) removes its (expected) duplicates assert_equal(set(multitxids), set(txids_all)) # test getaddressdeltas for node in (1, 3): deltas = self.nodes[node].getaddressdeltas({'addresses': [addr1]}) assert_equal(len(deltas), len(expected_deltas)) for i in range(len(deltas)): assert_equal(deltas[i]['address'], addr1) assert_equal(deltas[i]['height'], expected_deltas[i]['height']) assert_equal(deltas[i]['satoshis'], expected_deltas[i]['satoshis']) assert_equal(deltas[i]['txid'], expected_deltas[i]['txid']) # 106-111 is the full range (also the default) deltas_limited = getaddressdeltas(1, [addr1], 106, 111) assert_equal(deltas_limited, deltas) # only the first element missing deltas_limited = getaddressdeltas(1, [addr1], 107, 111) assert_equal(deltas_limited, deltas[1:]) deltas_limited = getaddressdeltas(1, [addr1], 109, 109) assert_equal(deltas_limited, deltas[3:4]) # the full range (also the default) deltas_info = getaddressdeltas(1, [addr1], 106, 111, chainInfo=True) assert_equal(deltas_info['deltas'], deltas) # check the additional items returned by chainInfo assert_equal(deltas_info['start']['height'], 106) block_hash = self.nodes[1].getblockhash(106) assert_equal(deltas_info['start']['hash'], block_hash) assert_equal(deltas_info['end']['height'], 111) block_hash = self.nodes[1].getblockhash(111) assert_equal(deltas_info['end']['hash'], block_hash) # Test getaddressutxos by comparing results with deltas utxos = self.nodes[3].getaddressutxos(addr1) # The value 4 note was spent, so won't show up in the utxo list, # so for comparison, remove the 4 (and -4 for output) from the # deltas list deltas = self.nodes[1].getaddressdeltas({'addresses': [addr1]}) deltas = list(filter(lambda d: abs(d['satoshis']) != 4 * COIN, deltas)) assert_equal(len(utxos), len(deltas)) for i in range(len(utxos)): assert_equal(utxos[i]['address'], addr1) assert_equal(utxos[i]['height'], deltas[i]['height']) assert_equal(utxos[i]['satoshis'], deltas[i]['satoshis']) assert_equal(utxos[i]['txid'], deltas[i]['txid']) # Check that outputs with the same address in the same tx return one txid # (can't use createrawtransaction() as it combines duplicate addresses) addr = "t2LMJ6Arw9UWBMWvfUr2QLHM4Xd9w53FftS" addressHash = unhexlify("97643ce74b188f4fb6bbbb285e067a969041caf2") scriptPubKey = CScript([OP_HASH160, addressHash, OP_EQUAL]) # Add an unrecognized script type to vout[], a legal script that pays, # but won't modify the addressindex (since the address can't be extracted). # (This extra output has no effect on the rest of the test.) scriptUnknown = CScript( [OP_HASH160, OP_DUP, OP_DROP, addressHash, OP_EQUAL]) unspent = list( filter(lambda u: u['amount'] >= 4, self.nodes[0].listunspent())) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]['txid'], 16), unspent[0]['vout'])) ] tx.vout = [ CTxOut(1 * COIN, scriptPubKey), CTxOut(2 * COIN, scriptPubKey), CTxOut(7 * COIN, scriptUnknown), ] tx = self.nodes[0].signrawtransaction( hexlify(tx.serialize()).decode('utf-8')) txid = self.nodes[0].sendrawtransaction(tx['hex'], True) self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[1].getaddresstxids(addr), [txid]) check_balance(2, addr, 3 * COIN)
def SignatureHash(script, txTo, inIdx, hashtype, amount, consensusBranchId): """Consensus-correct SignatureHash""" if inIdx >= len(txTo.vin): raise ValueError("inIdx %d out of range (%d)" % (inIdx, len(txTo.vin))) if consensusBranchId != 0: # ZIP 243 hashPrevouts = b'\x00' * 32 hashSequence = b'\x00' * 32 hashOutputs = b'\x00' * 32 hashJoinSplits = b'\x00' * 32 hashShieldedSpends = b'\x00' * 32 hashShieldedOutputs = b'\x00' * 32 if not (hashtype & SIGHASH_ANYONECANPAY): hashPrevouts = getHashPrevouts(txTo) if (not (hashtype & SIGHASH_ANYONECANPAY)) and \ (hashtype & 0x1f) != SIGHASH_SINGLE and \ (hashtype & 0x1f) != SIGHASH_NONE: hashSequence = getHashSequence(txTo) if (hashtype & 0x1f) != SIGHASH_SINGLE and \ (hashtype & 0x1f) != SIGHASH_NONE: hashOutputs = getHashOutputs(txTo) elif (hashtype & 0x1f) == SIGHASH_SINGLE and \ 0 <= inIdx and inIdx < len(txTo.vout): digest = blake2b(digest_size=32, person=b'ZcashOutputsHash') digest.update(txTo.vout[inIdx].serialize()) hashOutputs = digest.digest() if len(txTo.vJoinSplit) > 0: hashJoinSplits = getHashJoinSplits(txTo) if len(txTo.shieldedSpends) > 0: hashShieldedSpends = getHashShieldedSpends(txTo) if len(txTo.shieldedOutputs) > 0: hashShieldedOutputs = getHashShieldedOutputs(txTo) digest = blake2b( digest_size=32, person=b'ZcashSigHash' + struct.pack('<I', consensusBranchId), ) digest.update( struct.pack('<I', (int(txTo.fOverwintered) << 31) | txTo.nVersion)) digest.update(struct.pack('<I', txTo.nVersionGroupId)) digest.update(hashPrevouts) digest.update(hashSequence) digest.update(hashOutputs) digest.update(hashJoinSplits) digest.update(hashShieldedSpends) digest.update(hashShieldedOutputs) digest.update(struct.pack('<I', txTo.nLockTime)) digest.update(struct.pack('<I', txTo.nExpiryHeight)) digest.update(struct.pack('<Q', txTo.valueBalance)) digest.update(struct.pack('<I', hashtype)) if inIdx is not None: digest.update(txTo.vin[inIdx].prevout.serialize()) digest.update(ser_string(script)) digest.update(struct.pack('<Q', amount)) digest.update(struct.pack('<I', txTo.vin[inIdx].nSequence)) return (digest.digest(), None) else: # Pre-Overwinter txtmp = CTransaction(txTo) for txin in txtmp.vin: txin.scriptSig = b'' txtmp.vin[inIdx].scriptSig = script if (hashtype & 0x1f) == SIGHASH_NONE: txtmp.vout = [] for i in range(len(txtmp.vin)): if i != inIdx: txtmp.vin[i].nSequence = 0 elif (hashtype & 0x1f) == SIGHASH_SINGLE: outIdx = inIdx if outIdx >= len(txtmp.vout): raise ValueError("outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout))) tmp = txtmp.vout[outIdx] txtmp.vout = [] for i in range(outIdx): txtmp.vout.append(CTxOut()) txtmp.vout.append(tmp) for i in range(len(txtmp.vin)): if i != inIdx: txtmp.vin[i].nSequence = 0 if hashtype & SIGHASH_ANYONECANPAY: tmp = txtmp.vin[inIdx] txtmp.vin = [] txtmp.vin.append(tmp) s = txtmp.serialize() s += struct.pack(b"<I", hashtype) hash = hash256(s) return (hash, None)
def run_test(self): self.log.info("Mining blocks...") self.nodes[0].generate(105) self.sync_all() chain_height = self.nodes[1].getblockcount() assert_equal(chain_height, 105) assert_equal(self.nodes[1].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 0) # Check that balances are correct balance0 = self.nodes[1].getaddressbalance( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") assert_equal(balance0["balance"], 0) # Check p2pkh and p2sh address indexes self.log.info("Testing p2pkh and p2sh address index...") tx_id0 = self.nodes[0].sendtoaddress( "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 10) self.nodes[0].generate(1) tx_idb0 = self.nodes[0].sendtoaddress( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 10) self.nodes[0].generate(1) tx_id1 = self.nodes[0].sendtoaddress( "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 15) self.nodes[0].generate(1) tx_idb1 = self.nodes[0].sendtoaddress( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 15) self.nodes[0].generate(1) tx_id2 = self.nodes[0].sendtoaddress( "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 20) self.nodes[0].generate(1) tx_idb2 = self.nodes[0].sendtoaddress( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 20) self.nodes[0].generate(1) self.sync_all() txids = self.nodes[1].getaddresstxids( "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs") assert_equal(len(txids), 3) assert_equal(txids[0], tx_id0) assert_equal(txids[1], tx_id1) assert_equal(txids[2], tx_id2) tx_idsb = self.nodes[1].getaddresstxids( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") assert_equal(len(tx_idsb), 3) assert_equal(tx_idsb[0], tx_idb0) assert_equal(tx_idsb[1], tx_idb1) assert_equal(tx_idsb[2], tx_idb2) # Check that limiting by height works self.log.info("Testing querying txids by range of block heights..") height_txids = self.nodes[1].getaddresstxids({ "addresses": ["2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br"], "start": 105, "end": 110 }) assert_equal(len(height_txids), 2) assert_equal(height_txids[0], tx_idb0) assert_equal(height_txids[1], tx_idb1) # Check that multiple addresses works multi_tx_ids = self.nodes[1].getaddresstxids({ "addresses": [ "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs" ] }) assert_equal(len(multi_tx_ids), 6) assert_equal(multi_tx_ids[0], tx_id0) assert_equal(multi_tx_ids[1], tx_idb0) assert_equal(multi_tx_ids[2], tx_id1) assert_equal(multi_tx_ids[3], tx_idb1) assert_equal(multi_tx_ids[4], tx_id2) assert_equal(multi_tx_ids[5], tx_idb2) # Check that balances are correct balance0 = self.nodes[1].getaddressbalance( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") assert_equal(balance0["balance"], 45 * 100000000) # Check that outputs with the same address will only return one txid self.log.info("Testing for txid uniqueness...") address_hash = bytes([ 99, 73, 164, 24, 252, 69, 120, 209, 10, 55, 43, 84, 180, 92, 40, 12, 200, 196, 56, 47 ]) script_pub_key = CScript([OP_HASH160, address_hash, OP_EQUAL]) unspent = self.nodes[0].listunspent() tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] tx.vout = [CTxOut(10, script_pub_key), CTxOut(11, script_pub_key)] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) sent_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() tx_ids_many = self.nodes[1].getaddresstxids( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") assert_equal(len(tx_ids_many), 4) assert_equal(tx_ids_many[3], sent_txid) # Check that balances are correct self.log.info("Testing balances...") balance0 = self.nodes[1].getaddressbalance( "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") assert_equal(balance0["balance"], 45 * 100000000 + 21) # Check that balances are correct after spending self.log.info("Testing balances after spending...") privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" address2 = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" address_hash2 = bytes([ 11, 47, 10, 12, 49, 191, 224, 64, 107, 12, 204, 19, 129, 253, 190, 49, 25, 70, 218, 220 ]) script_pub_key2 = CScript( [OP_DUP, OP_HASH160, address_hash2, OP_EQUALVERIFY, OP_CHECKSIG]) self.nodes[0].importprivkey(privkey2) unspent = self.nodes[0].listunspent() tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] amount = int(unspent[0]["amount"] * 100000000 - 230000) tx.vout = [CTxOut(amount, script_pub_key2)] signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) spending_txid = self.nodes[0].sendrawtransaction( signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() balance1 = self.nodes[1].getaddressbalance(address2) assert_equal(balance1["balance"], amount) tx = CTransaction() tx.vin = [CTxIn(COutPoint(int(spending_txid, 16), 0))] send_amount = 1 * 100000000 + 12840 change_amount = amount - send_amount - 230000 tx.vout = [ CTxOut(change_amount, script_pub_key2), CTxOut(send_amount, script_pub_key) ] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() balance2 = self.nodes[1].getaddressbalance(address2) assert_equal(balance2["balance"], change_amount) # Check that deltas are returned correctly deltas = self.nodes[1].getaddressdeltas({ "addresses": [address2], "start": 1, "end": 200 }) balance3 = 0 for delta in deltas: balance3 += delta["satoshis"] assert_equal(balance3, change_amount) assert_equal(deltas[0]["address"], address2) assert_equal(deltas[0]["blockindex"], 1) # Check that entire range will be queried deltas_all = self.nodes[1].getaddressdeltas({"addresses": [address2]}) assert_equal(len(deltas_all), len(deltas)) # Check that deltas can be returned from range of block heights deltas = self.nodes[1].getaddressdeltas({ "addresses": [address2], "start": 113, "end": 113 }) assert_equal(len(deltas), 1) # Check that unspent outputs can be queried self.log.info("Testing utxos...") utxos = self.nodes[1].getaddressutxos({"addresses": [address2]}) assert_equal(len(utxos), 1) assert_equal(utxos[0]["satoshis"], change_amount) # Check that indexes will be updated with a reorg self.log.info("Testing reorg...") best_hash = self.nodes[0].getbestblockhash() self.nodes[0].invalidateblock(best_hash) self.nodes[1].invalidateblock(best_hash) self.nodes[2].invalidateblock(best_hash) self.nodes[3].invalidateblock(best_hash) self.sync_all() balance4 = self.nodes[1].getaddressbalance(address2) assert_equal(balance4, balance1) utxos2 = self.nodes[1].getaddressutxos({"addresses": [address2]}) assert_equal(len(utxos2), 1) assert_equal(utxos2[0]["satoshis"], amount) # Check sorting of utxos self.nodes[2].generate(150) self.nodes[2].sendtoaddress(address2, 50) self.nodes[2].generate(1) self.nodes[2].sendtoaddress(address2, 50) self.nodes[2].generate(1) self.sync_all() utxos3 = self.nodes[1].getaddressutxos({"addresses": [address2]}) assert_equal(len(utxos3), 3) assert_equal(utxos3[0]["height"], 114) assert_equal(utxos3[1]["height"], 264) assert_equal(utxos3[2]["height"], 265) # Check mempool indexing self.log.info("Testing mempool indexing...") priv_key3 = "cVfUn53hAbRrDEuMexyfgDpZPhF7KqXpS8UZevsyTDaugB7HZ3CD" address3 = "mw4ynwhS7MmrQ27hr82kgqu7zryNDK26JB" address_hash3 = bytes([ 170, 152, 114, 181, 187, 205, 181, 17, 216, 158, 14, 17, 170, 39, 218, 115, 253, 44, 63, 80 ]) script_pub_key3 = CScript( [OP_DUP, OP_HASH160, address_hash3, OP_EQUALVERIFY, OP_CHECKSIG]) #address4 = "2N8oFVB2vThAKury4vnLquW2zVjsYjjAkYQ" script_pub_key4 = CScript([OP_HASH160, address_hash3, OP_EQUAL]) unspent = self.nodes[2].listunspent() tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] amount = int(unspent[0]["amount"] * 100000000 - 230000) tx.vout = [CTxOut(amount, script_pub_key3)] tx.rehash() signed_tx = self.nodes[2].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) mem_txid1 = self.nodes[2].sendrawtransaction(signed_tx["hex"], True) time.sleep(2) tx2 = CTransaction() tx2.vin = [ CTxIn(COutPoint(int(unspent[1]["txid"], 16), unspent[1]["vout"])) ] amount = int(unspent[1]["amount"] * 100000000 - 300000) tx2.vout = [ CTxOut(int(amount / 4), script_pub_key3), CTxOut(int(amount / 4), script_pub_key3), CTxOut(int(amount / 4), script_pub_key4), CTxOut(int(amount / 4), script_pub_key4) ] tx2.rehash() signed_tx2 = self.nodes[2].signrawtransaction( binascii.hexlify(tx2.serialize()).decode("utf-8")) mem_txid2 = self.nodes[2].sendrawtransaction(signed_tx2["hex"], True) time.sleep(2) mempool = self.nodes[2].getaddressmempool({"addresses": [address3]}) assert_equal(len(mempool), 3) assert_equal(mempool[0]["txid"], mem_txid1) assert_equal(mempool[0]["address"], address3) assert_equal(mempool[0]["index"], 0) assert_equal(mempool[1]["txid"], mem_txid2) assert_equal(mempool[1]["index"], 0) assert_equal(mempool[2]["txid"], mem_txid2) assert_equal(mempool[2]["index"], 1) self.nodes[2].generate(1) self.sync_all() mempool2 = self.nodes[2].getaddressmempool({"addresses": [address3]}) assert_equal(len(mempool2), 0) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(mem_txid2, 16), 0)), CTxIn(COutPoint(int(mem_txid2, 16), 1)) ] tx.vout = [CTxOut(int(amount / 2 - 340000), script_pub_key2)] tx.rehash() self.nodes[2].importprivkey(priv_key3) signed_tx3 = self.nodes[2].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) self.nodes[2].sendrawtransaction(signed_tx3["hex"], True) time.sleep(2) mempool3 = self.nodes[2].getaddressmempool({"addresses": [address3]}) assert_equal(len(mempool3), 2) assert_equal(mempool3[0]["prevtxid"], mem_txid2) assert_equal(mempool3[0]["prevout"], 0) assert_equal(mempool3[1]["prevtxid"], mem_txid2) assert_equal(mempool3[1]["prevout"], 1) # sending and receiving to the same address privkey1 = "cQY2s58LhzUCmEXN8jtAp1Etnijx78YRZ466w4ikX1V4UpTpbsf8" address1 = "myAUWSHnwsQrhuMWv4Br6QsCnpB41vFwHn" address1hash = bytes([ 193, 146, 191, 247, 81, 175, 142, 254, 193, 81, 53, 212, 43, 254, 237, 249, 26, 111, 62, 52 ]) address1script = CScript( [OP_DUP, OP_HASH160, address1hash, OP_EQUALVERIFY, OP_CHECKSIG]) self.nodes[0].sendtoaddress(address1, 10) self.nodes[0].generate(1) self.sync_all() utxos = self.nodes[1].getaddressutxos({"addresses": [address1]}) assert_equal(len(utxos), 1) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["outputIndex"])) ] amount = int(utxos[0]["satoshis"] - 200000) tx.vout = [CTxOut(amount, address1script)] tx.rehash() self.nodes[0].importprivkey(privkey1) signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.sync_all() mempool_deltas = self.nodes[2].getaddressmempool( {"addresses": [address1]}) assert_equal(len(mempool_deltas), 2) # Include chaininfo in results self.log.info("Testing results with chain info...") deltas_with_info = self.nodes[1].getaddressdeltas({ "addresses": [address2], "start": 1, "end": 200, "chainInfo": True }) start_block_hash = self.nodes[1].getblockhash(1) end_block_hash = self.nodes[1].getblockhash(200) assert_equal(deltas_with_info["start"]["height"], 1) assert_equal(deltas_with_info["start"]["hash"], start_block_hash) assert_equal(deltas_with_info["end"]["height"], 200) assert_equal(deltas_with_info["end"]["hash"], end_block_hash) utxos_with_info = self.nodes[1].getaddressutxos({ "addresses": [address2], "chainInfo": True }) expected_tip_block_hash = self.nodes[1].getblockhash(267) assert_equal(utxos_with_info["height"], 267) assert_equal(utxos_with_info["hash"], expected_tip_block_hash) self.log.info("All Tests Passed")
def issue_reissue_transfer_test(self): ######################################## # activate assets self.nodes[0].generate(500) self.sync_all() ######################################## # issue to_address = self.nodes[0].getnewaddress() change_address = self.nodes[0].getnewaddress() unspent = self.nodes[0].listunspent()[0] inputs = [{k: unspent[k] for k in ['txid', 'vout']}] outputs = { 'n1issueAssetXXXXXXXXXXXXXXXXWdnemQ': 500, change_address: float(unspent['amount']) - 500.0001, to_address: { 'issue': { 'asset_name': 'TEST_ASSET', 'asset_quantity': 1000, 'units': 0, 'reissuable': 1, 'has_ipfs': 0, } } } tx_issue = self.nodes[0].createrawtransaction(inputs, outputs) tx_issue_signed = self.nodes[0].signrawtransaction(tx_issue) tx_issue_hash = self.nodes[0].sendrawtransaction( tx_issue_signed['hex']) assert_is_hash_string(tx_issue_hash) self.log.info("issue tx: " + tx_issue_hash) self.nodes[0].generate(1) self.sync_all() assert_equal(1000, self.nodes[0].listmyassets('TEST_ASSET')['TEST_ASSET']) assert_equal(1, self.nodes[0].listmyassets('TEST_ASSET!')['TEST_ASSET!']) ######################################## # reissue unspent = self.nodes[0].listunspent()[0] unspent_asset_owner = self.nodes[0].listmyassets( 'TEST_ASSET!', True)['TEST_ASSET!']['outpoints'][0] inputs = [ {k: unspent[k] for k in ['txid', 'vout']}, {k: unspent_asset_owner[k] for k in ['txid', 'vout']}, ] outputs = { 'n1ReissueAssetXXXXXXXXXXXXXXWG9NLd': 100, change_address: float(unspent['amount']) - 100.0001, to_address: { 'reissue': { 'asset_name': 'TEST_ASSET', 'asset_quantity': 1000, } } } tx_reissue = self.nodes[0].createrawtransaction(inputs, outputs) tx_reissue_signed = self.nodes[0].signrawtransaction(tx_reissue) tx_reissue_hash = self.nodes[0].sendrawtransaction( tx_reissue_signed['hex']) assert_is_hash_string(tx_reissue_hash) self.log.info("reissue tx: " + tx_reissue_hash) self.nodes[0].generate(1) self.sync_all() assert_equal(2000, self.nodes[0].listmyassets('TEST_ASSET')['TEST_ASSET']) assert_equal(1, self.nodes[0].listmyassets('TEST_ASSET!')['TEST_ASSET!']) self.sync_all() # ######################################## # # transfer remote_to_address = self.nodes[1].getnewaddress() change_asset_address = self.nodes[0].getnewaddress() unspent = self.nodes[0].listunspent()[0] unspent_asset = self.nodes[0].listmyassets( 'TEST_ASSET', True)['TEST_ASSET']['outpoints'][0] inputs = [ {k: unspent[k] for k in ['txid', 'vout']}, {k: unspent_asset[k] for k in ['txid', 'vout']}, ] outputs = { change_address: float(unspent['amount']) - 0.0001, remote_to_address: { 'transfer': { 'TEST_ASSET': 400 } }, to_address: { 'transfer': { 'TEST_ASSET': float(unspent_asset['amount']) - 400 } } } tx_transfer = self.nodes[0].createrawtransaction(inputs, outputs) tx_transfer_signed = self.nodes[0].signrawtransaction(tx_transfer) tx_hex = tx_transfer_signed['hex'] ######################################## # try tampering with the sig tx = CTransaction() f = BytesIO(hex_str_to_bytes(tx_hex)) tx.deserialize(f) script_sig = bytes_to_hex_str(tx.vin[1].scriptSig) tampered_sig = script_sig[:-8] + "deadbeef" tx.vin[1].scriptSig = hex_str_to_bytes(tampered_sig) tampered_hex = bytes_to_hex_str(tx.serialize()) assert_raises_rpc_error( -26, "mandatory-script-verify-flag-failed (Script failed an OP_EQUALVERIFY operation)", self.nodes[0].sendrawtransaction, tampered_hex) ######################################## # try tampering with the asset script tx = CTransaction() f = BytesIO(hex_str_to_bytes(tx_hex)) tx.deserialize(f) xsrt = '72766e74' #xsrt op_drop = '75' # change asset outputs from 400,600 to 500,500 for i in range(1, 3): script_hex = bytes_to_hex_str(tx.vout[i].scriptPubKey) f = BytesIO( hex_str_to_bytes(script_hex[script_hex.index(xsrt) + len(xsrt):-len(op_drop)])) transfer = CScriptTransfer() transfer.deserialize(f) transfer.amount = 50000000000 tampered_transfer = bytes_to_hex_str(transfer.serialize()) tampered_script = script_hex[:script_hex.index( xsrt)] + xsrt + tampered_transfer + op_drop tx.vout[i].scriptPubKey = hex_str_to_bytes(tampered_script) t2 = CScriptTransfer() t2.deserialize(BytesIO(hex_str_to_bytes(tampered_transfer))) tampered_hex = bytes_to_hex_str(tx.serialize()) assert_raises_rpc_error( -26, "mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation)", self.nodes[0].sendrawtransaction, tampered_hex) ######################################## # send the good transfer tx_transfer_hash = self.nodes[0].sendrawtransaction(tx_hex) assert_is_hash_string(tx_transfer_hash) self.log.info("transfer tx: " + tx_transfer_hash) self.nodes[0].generate(1) self.sync_all() assert_equal(1600, self.nodes[0].listmyassets('TEST_ASSET')['TEST_ASSET']) assert_equal(1, self.nodes[0].listmyassets('TEST_ASSET!')['TEST_ASSET!']) assert_equal(400, self.nodes[1].listmyassets('TEST_ASSET')['TEST_ASSET'])
def decoderawtransaction_asm_sighashtype(self): """Tests decoding scripts via RPC command "decoderawtransaction". This test is in with the "decodescript" tests because they are testing the same "asm" script decodes. """ # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000' rpc_result = self.nodes[0].decoderawtransaction(tx) assert_equal( '304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm']) # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs. # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc # verify that we have not altered scriptPubKey decoding. tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000' rpc_result = self.nodes[0].decoderawtransaction(tx) assert_equal( '8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid']) assert_equal( '0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm']) assert_equal( 'OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) assert_equal( 'OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) txSave = CTransaction() txSave.deserialize(StringIO(unhexlify(tx))) # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000' rpc_result = self.nodes[0].decoderawtransaction(tx) assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm']) # verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000' rpc_result = self.nodes[0].decoderawtransaction(tx) assert_equal( 'OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) assert_equal( 'OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) # some more full transaction tests of varying specific scriptSigs. used instead of # tests in decodescript_script_sig because the decodescript RPC is specifically # for working on scriptPubKeys (argh!). push_signature = hexlify(txSave.vin[0].scriptSig)[2:(0x48 * 2 + 4)] signature = push_signature[2:] der_signature = signature[:-2] signature_sighash_decoded = der_signature + '[ALL]' signature_2 = der_signature + '82' push_signature_2 = '48' + signature_2 signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]' # 1) P2PK scriptSig txSave.vin[0].scriptSig = unhexlify(push_signature) rpc_result = self.nodes[0].decoderawtransaction( hexlify(txSave.serialize())) assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) # make sure that the sighash decodes come out correctly for a more complex / lesser used case. txSave.vin[0].scriptSig = unhexlify(push_signature_2) rpc_result = self.nodes[0].decoderawtransaction( hexlify(txSave.serialize())) assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) # 2) multisig scriptSig txSave.vin[0].scriptSig = unhexlify('00' + push_signature + push_signature_2) rpc_result = self.nodes[0].decoderawtransaction( hexlify(txSave.serialize())) assert_equal( '0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) # 3) test a scriptSig that contains more than push operations. # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it. txSave.vin[0].scriptSig = unhexlify( '6a143011020701010101010101020601010101010101') rpc_result = self.nodes[0].decoderawtransaction( hexlify(txSave.serialize())) print(hexlify('636174')) assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])
def run_test(self): print "Mining blocks..." self.nodes[0].generate(105) self.sync_all() chain_height = self.nodes[1].getblockcount() assert_equal(chain_height, 105) assert_equal(self.nodes[1].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 0) addr1 = "zrCBKy4Uoy1X5jws6cxLqrMuE1ukuctSqfS" addr2 = "ztano5XjpquCJdSipz7VRGFgdLqNjXmV9cD" # Check that balances are correct balance0 = self.nodes[1].getaddressbalance(addr1) assert_equal(balance0["balance"], 0) # Check p2pkh and p2sh address indexes print "Testing p2pkh and p2sh address index..." txid0 = self.nodes[0].sendtoaddress(addr2, 10) self.nodes[0].generate(1) txidb0 = self.nodes[0].sendtoaddress(addr1, 10) self.nodes[0].generate(1) txid1 = self.nodes[0].sendtoaddress(addr2, 15) self.nodes[0].generate(1) txidb1 = self.nodes[0].sendtoaddress(addr1, 15) self.nodes[0].generate(1) txid2 = self.nodes[0].sendtoaddress(addr2, 20) self.nodes[0].generate(1) txidb2 = self.nodes[0].sendtoaddress(addr1, 20) self.nodes[0].generate(1) self.sync_all() txids = self.nodes[1].getaddresstxids(addr2) assert_equal(len(txids), 3) assert_equal(txids[0], txid0) assert_equal(txids[1], txid1) assert_equal(txids[2], txid2) txidsb = self.nodes[1].getaddresstxids(addr1) assert_equal(len(txidsb), 3) assert_equal(txidsb[0], txidb0) assert_equal(txidsb[1], txidb1) assert_equal(txidsb[2], txidb2) # Check that limiting by height works print "Testing querying txids by range of block heights.." height_txids = self.nodes[1].getaddresstxids({ "addresses": [addr1], "start": 105, "end": 110 }) assert_equal(len(height_txids), 2) assert_equal(height_txids[0], txidb0) assert_equal(height_txids[1], txidb1) # Check that multiple addresses works multitxids = self.nodes[1].getaddresstxids( {"addresses": [addr1, addr2]}) assert_equal(len(multitxids), 6) assert_equal(multitxids[0], txid0) assert_equal(multitxids[1], txidb0) assert_equal(multitxids[2], txid1) assert_equal(multitxids[3], txidb1) assert_equal(multitxids[4], txid2) assert_equal(multitxids[5], txidb2) # Check that balances are correct balance0 = self.nodes[1].getaddressbalance(addr1) assert_equal(balance0["balance"], 45 * 100000000) # Check that outputs with the same address will only return one txid print "Testing for txid uniqueness..." op_hash160 = "a9" op_push_20_bytes_onto_the_stack = "14" addressHash = "6349a418fc4578d10a372b54b45c280cc8c4382f" op_equal = "87" genesisCbah = "20bb1acf2c1fc1228967a611c7db30632098f0c641855180b5fe23793b72eea50d00b4" scriptPubKey = binascii.unhexlify(op_hash160 + op_push_20_bytes_onto_the_stack + addressHash + op_equal + genesisCbah) unspent = self.nodes[0].listunspent() unspent.sort(key=lambda x: x["amount"], reverse=True) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] tx.vout = [CTxOut(10, scriptPubKey), CTxOut(11, scriptPubKey)] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) sent_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() txidsmany = self.nodes[1].getaddresstxids(addr1) assert_equal(len(txidsmany), 4) assert_equal(txidsmany[3], sent_txid) # Check that balances are correct print "Testing balances..." balance0 = self.nodes[1].getaddressbalance(addr1) assert_equal(balance0["balance"], 45 * 100000000 + 21) # Check that balances are correct after spending print "Testing balances after spending..." privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" address2 = "ztUB6YWTcj2uUe5Rbucnc7oFevn7wCKyN63" op_dup = "76" addressHash2 = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc" op_equalverify = "88" op_checksig = "ac" scriptPubKey2 = binascii.unhexlify(op_dup + op_hash160 + op_push_20_bytes_onto_the_stack + addressHash2 + op_equalverify + op_checksig + genesisCbah) self.nodes[0].importprivkey(privkey2) unspent = self.nodes[0].listunspent() unspent.sort(key=lambda x: x["amount"], reverse=True) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] amount = unspent[0]["amount"] * 100000000 tx.vout = [CTxOut(amount, scriptPubKey2)] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) spending_txid = self.nodes[0].sendrawtransaction( signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() balance1 = self.nodes[1].getaddressbalance(address2) assert_equal(balance1["balance"], amount) tx = CTransaction() tx.vin = [CTxIn(COutPoint(int(spending_txid, 16), 0))] send_amount = 1 * 100000000 + 12840 change_amount = amount - send_amount - 10000 tx.vout = [ CTxOut(change_amount, scriptPubKey2), CTxOut(send_amount, scriptPubKey) ] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) sent_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() balance2 = self.nodes[1].getaddressbalance(address2) assert_equal(balance2["balance"], change_amount) # Check that deltas are returned correctly deltas = self.nodes[1].getaddressdeltas({ "addresses": [address2], "start": 1, "end": 200 }) balance3 = 0 for delta in deltas: balance3 += delta["satoshis"] assert_equal(balance3, change_amount) assert_equal(deltas[0]["address"], address2) assert_equal(deltas[0]["blockindex"], 1) # Check that entire range will be queried deltasAll = self.nodes[1].getaddressdeltas({"addresses": [address2]}) assert_equal(len(deltasAll), len(deltas)) # Check that deltas can be returned from range of block heights deltas = self.nodes[1].getaddressdeltas({ "addresses": [address2], "start": 113, "end": 113 }) assert_equal(len(deltas), 1) # Check that unspent outputs can be queried print "Testing utxos..." utxos = self.nodes[1].getaddressutxos({"addresses": [address2]}) assert_equal(len(utxos), 1) assert_equal(utxos[0]["satoshis"], change_amount) # Check that indexes will be updated with a reorg print "Testing reorg..." best_hash = self.nodes[0].getbestblockhash() self.nodes[0].invalidateblock(best_hash) self.nodes[1].invalidateblock(best_hash) self.nodes[2].invalidateblock(best_hash) self.nodes[3].invalidateblock(best_hash) self.sync_all() balance4 = self.nodes[1].getaddressbalance(address2) assert_equal(balance4, balance1) utxos2 = self.nodes[1].getaddressutxos({"addresses": [address2]}) assert_equal(len(utxos2), 1) assert_equal(utxos2[0]["satoshis"], amount) # Check sorting of utxos self.nodes[2].generate(150) self.nodes[2].sendtoaddress(address2, 50) self.nodes[2].generate(1) self.nodes[2].sendtoaddress(address2, 50) self.nodes[2].generate(1) self.sync_all() utxos3 = self.nodes[1].getaddressutxos({"addresses": [address2]}) assert_equal(len(utxos3), 3) assert_equal(utxos3[0]["height"], 114) assert_equal(utxos3[1]["height"], 264) assert_equal(utxos3[2]["height"], 265) # Check mempool indexing print "Testing mempool indexing..." privKey3 = "cVfUn53hAbRrDEuMexyfgDpZPhF7KqXpS8UZevsyTDaugB7HZ3CD" address3 = "ztihzFwiPbcoMVWzvMAHf37o8jw9VSHdLtC" addressHash3 = "aa9872b5bbcdb511d89e0e11aa27da73fd2c3f50" scriptPubKey3 = binascii.unhexlify(op_dup + op_hash160 + op_push_20_bytes_onto_the_stack + addressHash3 + op_equalverify + op_checksig + genesisCbah) #address4 = "zrJgNMHvfLY26avAQCeHk8NAQxubq7CExqH" scriptPubKey4 = binascii.unhexlify(op_hash160 + op_push_20_bytes_onto_the_stack + addressHash3 + op_equal + genesisCbah) unspent = self.nodes[2].listunspent() unspent.sort(key=lambda x: x["amount"], reverse=True) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] amount = unspent[0]["amount"] * 100000000 tx.vout = [CTxOut(amount, scriptPubKey3)] tx.rehash() signed_tx = self.nodes[2].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) memtxid1 = self.nodes[2].sendrawtransaction(signed_tx["hex"], True) time.sleep(2) tx2 = CTransaction() tx2.vin = [ CTxIn(COutPoint(int(unspent[1]["txid"], 16), unspent[1]["vout"])) ] amount = unspent[1]["amount"] * 100000000 tx2.vout = [ CTxOut(amount / 4, scriptPubKey3), CTxOut(amount / 4, scriptPubKey3), CTxOut(amount / 4, scriptPubKey4), CTxOut(amount / 4, scriptPubKey4) ] tx2.rehash() signed_tx2 = self.nodes[2].signrawtransaction( binascii.hexlify(tx2.serialize()).decode("utf-8")) memtxid2 = self.nodes[2].sendrawtransaction(signed_tx2["hex"], True) time.sleep(2) mempool = self.nodes[2].getaddressmempool({"addresses": [address3]}) assert_equal(len(mempool), 3) assert_equal(mempool[0]["txid"], memtxid1) assert_equal(mempool[0]["address"], address3) assert_equal(mempool[0]["index"], 0) assert_equal(mempool[1]["txid"], memtxid2) assert_equal(mempool[1]["index"], 0) assert_equal(mempool[2]["txid"], memtxid2) assert_equal(mempool[2]["index"], 1) self.nodes[2].generate(1) self.sync_all() mempool2 = self.nodes[2].getaddressmempool({"addresses": [address3]}) assert_equal(len(mempool2), 0) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(memtxid2, 16), 0)), CTxIn(COutPoint(int(memtxid2, 16), 1)) ] tx.vout = [CTxOut(amount / 2 - 10000, scriptPubKey2)] tx.rehash() self.nodes[2].importprivkey(privKey3) signed_tx3 = self.nodes[2].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) self.nodes[2].sendrawtransaction(signed_tx3["hex"], True) time.sleep(2) mempool3 = self.nodes[2].getaddressmempool({"addresses": [address3]}) assert_equal(len(mempool3), 2) assert_equal(mempool3[0]["prevtxid"], memtxid2) assert_equal(mempool3[0]["prevout"], 0) assert_equal(mempool3[1]["prevtxid"], memtxid2) assert_equal(mempool3[1]["prevout"], 1) # sending and receiving to the same address privkey1 = "cQY2s58LhzUCmEXN8jtAp1Etnijx78YRZ466w4ikX1V4UpTpbsf8" address1 = "ztkoUySJkS8SMoQEjR6SkSgmDXtMB531yiw" address1hash = "c192bff751af8efec15135d42bfeedf91a6f3e34" address1script = binascii.unhexlify(op_dup + op_hash160 + op_push_20_bytes_onto_the_stack + address1hash + op_equalverify + op_checksig + genesisCbah) self.nodes[0].sendtoaddress(address1, 10) self.nodes[0].generate(1) self.sync_all() utxos = self.nodes[1].getaddressutxos({"addresses": [address1]}) assert_equal(len(utxos), 1) tx = CTransaction() tx.vin = [ CTxIn(COutPoint(int(utxos[0]["txid"], 16), utxos[0]["outputIndex"])) ] amount = utxos[0]["satoshis"] - 1000 tx.vout = [CTxOut(amount, address1script)] tx.rehash() self.nodes[0].importprivkey(privkey1) signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.sync_all() mempool_deltas = self.nodes[2].getaddressmempool( {"addresses": [address1]}) assert_equal(len(mempool_deltas), 2) # Include chaininfo in results print "Testing results with chain info..." deltas_with_info = self.nodes[1].getaddressdeltas({ "addresses": [address2], "start": 1, "end": 200, "chainInfo": True }) start_block_hash = self.nodes[1].getblockhash(1) end_block_hash = self.nodes[1].getblockhash(200) assert_equal(deltas_with_info["start"]["height"], 1) assert_equal(deltas_with_info["start"]["hash"], start_block_hash) assert_equal(deltas_with_info["end"]["height"], 200) assert_equal(deltas_with_info["end"]["hash"], end_block_hash) utxos_with_info = self.nodes[1].getaddressutxos({ "addresses": [address2], "chainInfo": True }) expected_tip_block_hash = self.nodes[1].getblockhash(267) assert_equal(utxos_with_info["height"], 267) assert_equal(utxos_with_info["hash"], expected_tip_block_hash) # Check that indexes don't get updated when checking a new block (e.g. when calling getBlockTemplate) # Initial balance is 0 and no index has been stored for addr3 addr3 = self.nodes[1].getnewaddress() addr3_balance = self.nodes[2].getaddressbalance(addr3) addr3_txs = self.nodes[2].getaddresstxids(addr3) addr3_utxos = self.nodes[2].getaddressutxos(addr3) addr3_mempool = self.nodes[2].getaddressmempool(addr3) # The initial balance must be 0 assert_equal(addr3_balance["balance"], 0) # At the beginning no address index must be stored assert_equal(addr3_txs, []) # At the beginning no unspent index must be stored assert_equal(addr3_utxos, []) # At the beginning no address mempool index must be stored assert_equal(addr3_mempool, []) # Add to mempool a transaction that sends money to addr3 addr3_amount = 0.1 addr3_txid = self.nodes[2].sendtoaddress(addr3, addr3_amount) addr3_balance = self.nodes[2].getaddressbalance(addr3) addr3_txs = self.nodes[2].getaddresstxids(addr3) addr3_utxos = self.nodes[2].getaddressutxos(addr3) addr3_mempool = self.nodes[2].getaddressmempool(addr3) # The balance must still be 0 assert_equal(addr3_balance["balance"], 0) # The address index must still be empty assert_equal(addr3_txs, []) # The unspent index must still be empty assert_equal(addr3_utxos, []) # The address mempool index must contain the new transaction assert_equal(len(addr3_mempool), 1) assert_equal(addr3_mempool[0]["txid"], addr3_txid) # Call getBlockTemplate to trigger a call to VerifyBlock() => ConnectBlock() # It should not update any index self.nodes[2].getblocktemplate() addr3_balance = self.nodes[2].getaddressbalance(addr3) addr3_txs = self.nodes[2].getaddresstxids(addr3) addr3_utxos = self.nodes[2].getaddressutxos(addr3) addr3_mempool = self.nodes[2].getaddressmempool(addr3) # The balance must still be 0 assert_equal(addr3_balance["balance"], 0) # The address index must still be empty assert_equal(addr3_txs, []) # The unspent index must still be empty assert_equal(addr3_utxos, []) # The address mempool index must still be empty assert_equal(len(addr3_mempool), 1) assert_equal(addr3_mempool[0]["txid"], addr3_txid) # Connect a new block "validating" the transaction sending money to addr3 self.nodes[2].generate(1) self.sync_all() addr3_balance = self.nodes[2].getaddressbalance(addr3) addr3_txs = self.nodes[2].getaddresstxids(addr3) addr3_utxos = self.nodes[2].getaddressutxos(addr3) addr3_mempool = self.nodes[2].getaddressmempool(addr3) # The balance must be updated assert_equal(addr3_balance["balance"], 0.1 * 1e8) # The address index must contain only the new transaction assert_equal(len(addr3_txs), 1) assert_equal(addr3_txs[0], addr3_txid) # The unspent index must contain only the new transaction assert_equal(len(addr3_utxos), 1) assert_equal(addr3_utxos[0]["txid"], addr3_txid) # The address mempool index must be empty again assert_equal(addr3_mempool, []) print "Passed\n"
def run_test(self): self.log.info("Mining blocks...") self.nodes[0].generate(105) self.sync_all() chain_height = self.nodes[1].getblockcount() assert_equal(chain_height, 105) # Check that self.log.info("Testing spent index...") fee_satoshis = 192000 privkey = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" #address = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" address_hash = bytes([ 11, 47, 10, 12, 49, 191, 224, 64, 107, 12, 204, 19, 129, 253, 190, 49, 25, 70, 218, 220 ]) script_pub_key = CScript( [OP_DUP, OP_HASH160, address_hash, OP_EQUALVERIFY, OP_CHECKSIG]) unspent = self.nodes[0].listunspent() tx = CTransaction() amount = int(unspent[0]["amount"] * 100000000 - fee_satoshis) tx.vin = [ CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"])) ] tx.vout = [CTxOut(amount, script_pub_key)] tx.rehash() signed_tx = self.nodes[0].signrawtransaction( binascii.hexlify(tx.serialize()).decode("utf-8")) txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) self.nodes[0].generate(1) self.sync_all() self.log.info("Testing getspentinfo method...") # Check that the spentinfo works standalone info = self.nodes[1].getspentinfo({ "txid": unspent[0]["txid"], "index": unspent[0]["vout"] }) assert_equal(info["txid"], txid) assert_equal(info["index"], 0) assert_equal(info["height"], 106) self.log.info("Testing getrawtransaction method...") # Check that verbose raw transaction includes spent info tx_verbose = self.nodes[3].getrawtransaction(unspent[0]["txid"], 1) assert_equal(tx_verbose["vout"][unspent[0]["vout"]]["spentTxId"], txid) assert_equal(tx_verbose["vout"][unspent[0]["vout"]]["spentIndex"], 0) assert_equal(tx_verbose["vout"][unspent[0]["vout"]]["spentHeight"], 106) # Check that verbose raw transaction includes input values tx_verbose2 = self.nodes[3].getrawtransaction(txid, 1) assert_equal(float(tx_verbose2["vin"][0]["value"]), (amount + fee_satoshis) / 100000000) assert_equal(tx_verbose2["vin"][0]["valueSat"], amount + fee_satoshis) # Check that verbose raw transaction includes address values and input values #privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" address2 = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" address_hash2 = bytes([ 11, 47, 10, 12, 49, 191, 224, 64, 107, 12, 204, 19, 129, 253, 190, 49, 25, 70, 218, 220 ]) script_pub_key2 = CScript( [OP_DUP, OP_HASH160, address_hash2, OP_EQUALVERIFY, OP_CHECKSIG]) tx2 = CTransaction() tx2.vin = [CTxIn(COutPoint(int(txid, 16), 0))] amount = int(amount - fee_satoshis) tx2.vout = [CTxOut(amount, script_pub_key2)] tx.rehash() self.nodes[0].importprivkey(privkey) signed_tx2 = self.nodes[0].signrawtransaction( binascii.hexlify(tx2.serialize()).decode("utf-8")) txid2 = self.nodes[0].sendrawtransaction(signed_tx2["hex"], True) # Check the mempool index self.sync_all() tx_verbose3 = self.nodes[1].getrawtransaction(txid2, 1) assert_equal(tx_verbose3["vin"][0]["address"], address2) assert_equal(tx_verbose3["vin"][0]["valueSat"], amount + fee_satoshis) assert_equal(float(tx_verbose3["vin"][0]["value"]), (amount + fee_satoshis) / 100000000) # Check the database index block_hash = self.nodes[0].generate(1) self.sync_all() tx_verbose4 = self.nodes[3].getrawtransaction(txid2, 1) assert_equal(tx_verbose4["vin"][0]["address"], address2) assert_equal(tx_verbose4["vin"][0]["valueSat"], amount + fee_satoshis) assert_equal(float(tx_verbose4["vin"][0]["value"]), (amount + fee_satoshis) / 100000000) # Check block deltas self.log.info("Testing getblockdeltas...") block = self.nodes[3].getblockdeltas(block_hash[0]) assert_equal(len(block["deltas"]), 2) assert_equal(block["deltas"][0]["index"], 0) assert_equal(len(block["deltas"][0]["inputs"]), 0) assert_equal(len(block["deltas"][0]["outputs"]), 0) assert_equal(block["deltas"][1]["index"], 1) assert_equal(block["deltas"][1]["txid"], txid2) assert_equal(block["deltas"][1]["inputs"][0]["index"], 0) assert_equal(block["deltas"][1]["inputs"][0]["address"], "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW") assert_equal(block["deltas"][1]["inputs"][0]["satoshis"], (amount + fee_satoshis) * -1) assert_equal(block["deltas"][1]["inputs"][0]["prevtxid"], txid) assert_equal(block["deltas"][1]["inputs"][0]["prevout"], 0) assert_equal(block["deltas"][1]["outputs"][0]["index"], 0) assert_equal(block["deltas"][1]["outputs"][0]["address"], "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW") assert_equal(block["deltas"][1]["outputs"][0]["satoshis"], amount) self.log.info("All Tests Passed")