|
| 1 | +#!/usr/bin/env python2 |
| 2 | +# Copyright (c) 2014-2015 The Bitcoin Core developers |
| 3 | +# Distributed under the MIT software license, see the accompanying |
| 4 | +# file COPYING or http://www.opensource.org/licenses/mit-license.php. |
| 5 | + |
| 6 | +# |
| 7 | +# Test addressindex generation and fetching |
| 8 | +# |
| 9 | + |
| 10 | +import time |
| 11 | +from test_framework.test_framework import BitcoinTestFramework |
| 12 | +from test_framework.util import * |
| 13 | +from test_framework.script import * |
| 14 | +from test_framework.mininode import * |
| 15 | +import binascii |
| 16 | + |
| 17 | +class AddressIndexTest(BitcoinTestFramework): |
| 18 | + |
| 19 | + def setup_chain(self): |
| 20 | + print("Initializing test directory "+self.options.tmpdir) |
| 21 | + initialize_chain_clean(self.options.tmpdir, 4) |
| 22 | + |
| 23 | + def setup_network(self): |
| 24 | + self.nodes = [] |
| 25 | + # Nodes 0/1 are "wallet" nodes |
| 26 | + self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"])) |
| 27 | + self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-addressindex"])) |
| 28 | + # Nodes 2/3 are used for testing |
| 29 | + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug", "-addressindex"])) |
| 30 | + self.nodes.append(start_node(3, self.options.tmpdir, ["-debug", "-addressindex"])) |
| 31 | + connect_nodes(self.nodes[0], 1) |
| 32 | + connect_nodes(self.nodes[0], 2) |
| 33 | + connect_nodes(self.nodes[0], 3) |
| 34 | + |
| 35 | + self.is_network_split = False |
| 36 | + self.sync_all() |
| 37 | + |
| 38 | + def run_test(self): |
| 39 | + print "Mining blocks..." |
| 40 | + self.nodes[0].generate(105) |
| 41 | + self.sync_all() |
| 42 | + |
| 43 | + chain_height = self.nodes[1].getblockcount() |
| 44 | + assert_equal(chain_height, 105) |
| 45 | + assert_equal(self.nodes[1].getbalance(), 0) |
| 46 | + assert_equal(self.nodes[2].getbalance(), 0) |
| 47 | + |
| 48 | + # Check that balances are correct |
| 49 | + balance0 = self.nodes[1].getaddressbalance("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") |
| 50 | + assert_equal(balance0["balance"], 0) |
| 51 | + |
| 52 | + # Check p2pkh and p2sh address indexes |
| 53 | + print "Testing p2pkh and p2sh address index..." |
| 54 | + |
| 55 | + txid0 = self.nodes[0].sendtoaddress("mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 10) |
| 56 | + self.nodes[0].generate(1) |
| 57 | + |
| 58 | + txidb0 = self.nodes[0].sendtoaddress("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 10) |
| 59 | + self.nodes[0].generate(1) |
| 60 | + |
| 61 | + txid1 = self.nodes[0].sendtoaddress("mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 15) |
| 62 | + self.nodes[0].generate(1) |
| 63 | + |
| 64 | + txidb1 = self.nodes[0].sendtoaddress("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 15) |
| 65 | + self.nodes[0].generate(1) |
| 66 | + |
| 67 | + txid2 = self.nodes[0].sendtoaddress("mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs", 20) |
| 68 | + self.nodes[0].generate(1) |
| 69 | + |
| 70 | + txidb2 = self.nodes[0].sendtoaddress("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", 20) |
| 71 | + self.nodes[0].generate(1) |
| 72 | + |
| 73 | + self.sync_all() |
| 74 | + |
| 75 | + txids = self.nodes[1].getaddresstxids("mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs") |
| 76 | + assert_equal(len(txids), 3) |
| 77 | + assert_equal(txids[0], txid0) |
| 78 | + assert_equal(txids[1], txid1) |
| 79 | + assert_equal(txids[2], txid2) |
| 80 | + |
| 81 | + txidsb = self.nodes[1].getaddresstxids("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") |
| 82 | + assert_equal(len(txidsb), 3) |
| 83 | + assert_equal(txidsb[0], txidb0) |
| 84 | + assert_equal(txidsb[1], txidb1) |
| 85 | + assert_equal(txidsb[2], txidb2) |
| 86 | + |
| 87 | + # Check that limiting by height works |
| 88 | + print "Testing querying txids by range of block heights.." |
| 89 | + height_txids = self.nodes[1].getaddresstxids({ |
| 90 | + "addresses": ["2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br"], |
| 91 | + "start": 105, |
| 92 | + "end": 110 |
| 93 | + }) |
| 94 | + assert_equal(len(height_txids), 2) |
| 95 | + assert_equal(height_txids[0], txidb0) |
| 96 | + assert_equal(height_txids[1], txidb1) |
| 97 | + |
| 98 | + # Check that multiple addresses works |
| 99 | + multitxids = self.nodes[1].getaddresstxids({"addresses": ["2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br", "mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs"]}) |
| 100 | + assert_equal(len(multitxids), 6) |
| 101 | + assert_equal(multitxids[0], txid0) |
| 102 | + assert_equal(multitxids[1], txidb0) |
| 103 | + assert_equal(multitxids[2], txid1) |
| 104 | + assert_equal(multitxids[3], txidb1) |
| 105 | + assert_equal(multitxids[4], txid2) |
| 106 | + assert_equal(multitxids[5], txidb2) |
| 107 | + |
| 108 | + # Check that balances are correct |
| 109 | + balance0 = self.nodes[1].getaddressbalance("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") |
| 110 | + assert_equal(balance0["balance"], 45 * 100000000) |
| 111 | + |
| 112 | + # Check that outputs with the same address will only return one txid |
| 113 | + print "Testing for txid uniqueness..." |
| 114 | + addressHash = "6349a418fc4578d10a372b54b45c280cc8c4382f".decode("hex") |
| 115 | + scriptPubKey = CScript([OP_HASH160, addressHash, OP_EQUAL]) |
| 116 | + unspent = self.nodes[0].listunspent() |
| 117 | + tx = CTransaction() |
| 118 | + tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))] |
| 119 | + tx.vout = [CTxOut(10, scriptPubKey), CTxOut(11, scriptPubKey)] |
| 120 | + tx.rehash() |
| 121 | + |
| 122 | + signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) |
| 123 | + sent_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) |
| 124 | + |
| 125 | + self.nodes[0].generate(1) |
| 126 | + self.sync_all() |
| 127 | + |
| 128 | + txidsmany = self.nodes[1].getaddresstxids("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") |
| 129 | + assert_equal(len(txidsmany), 4) |
| 130 | + assert_equal(txidsmany[3], sent_txid) |
| 131 | + |
| 132 | + # Check that balances are correct |
| 133 | + print "Testing balances..." |
| 134 | + balance0 = self.nodes[1].getaddressbalance("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br") |
| 135 | + assert_equal(balance0["balance"], 45 * 100000000 + 21) |
| 136 | + |
| 137 | + # Check that balances are correct after spending |
| 138 | + print "Testing balances after spending..." |
| 139 | + privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG" |
| 140 | + address2 = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW" |
| 141 | + addressHash2 = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc".decode("hex") |
| 142 | + scriptPubKey2 = CScript([OP_DUP, OP_HASH160, addressHash2, OP_EQUALVERIFY, OP_CHECKSIG]) |
| 143 | + self.nodes[0].importprivkey(privkey2) |
| 144 | + |
| 145 | + unspent = self.nodes[0].listunspent() |
| 146 | + tx = CTransaction() |
| 147 | + tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))] |
| 148 | + amount = unspent[0]["amount"] * 100000000 |
| 149 | + tx.vout = [CTxOut(amount, scriptPubKey2)] |
| 150 | + tx.rehash() |
| 151 | + signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) |
| 152 | + spending_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) |
| 153 | + self.nodes[0].generate(1) |
| 154 | + self.sync_all() |
| 155 | + balance1 = self.nodes[1].getaddressbalance(address2) |
| 156 | + assert_equal(balance1["balance"], amount) |
| 157 | + |
| 158 | + tx = CTransaction() |
| 159 | + tx.vin = [CTxIn(COutPoint(int(spending_txid, 16), 0))] |
| 160 | + send_amount = 1 * 100000000 + 12840 |
| 161 | + change_amount = amount - send_amount - 10000 |
| 162 | + tx.vout = [CTxOut(change_amount, scriptPubKey2), CTxOut(send_amount, scriptPubKey)] |
| 163 | + tx.rehash() |
| 164 | + |
| 165 | + signed_tx = self.nodes[0].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) |
| 166 | + sent_txid = self.nodes[0].sendrawtransaction(signed_tx["hex"], True) |
| 167 | + self.nodes[0].generate(1) |
| 168 | + self.sync_all() |
| 169 | + |
| 170 | + balance2 = self.nodes[1].getaddressbalance(address2) |
| 171 | + assert_equal(balance2["balance"], change_amount) |
| 172 | + |
| 173 | + # Check that deltas are returned correctly |
| 174 | + deltas = self.nodes[1].getaddressdeltas({"addresses": [address2], "start": 0, "end": 200}) |
| 175 | + balance3 = 0 |
| 176 | + for delta in deltas: |
| 177 | + balance3 += delta["satoshis"] |
| 178 | + assert_equal(balance3, change_amount) |
| 179 | + assert_equal(deltas[0]["address"], address2) |
| 180 | + assert_equal(deltas[0]["blockindex"], 1) |
| 181 | + |
| 182 | + # Check that entire range will be queried |
| 183 | + deltasAll = self.nodes[1].getaddressdeltas({"addresses": [address2]}) |
| 184 | + assert_equal(len(deltasAll), len(deltas)) |
| 185 | + |
| 186 | + # Check that deltas can be returned from range of block heights |
| 187 | + deltas = self.nodes[1].getaddressdeltas({"addresses": [address2], "start": 113, "end": 113}) |
| 188 | + assert_equal(len(deltas), 1) |
| 189 | + |
| 190 | + # Check that unspent outputs can be queried |
| 191 | + print "Testing utxos..." |
| 192 | + utxos = self.nodes[1].getaddressutxos({"addresses": [address2]}) |
| 193 | + assert_equal(len(utxos), 1) |
| 194 | + assert_equal(utxos[0]["satoshis"], change_amount) |
| 195 | + |
| 196 | + # Check that indexes will be updated with a reorg |
| 197 | + print "Testing reorg..." |
| 198 | + |
| 199 | + best_hash = self.nodes[0].getbestblockhash() |
| 200 | + self.nodes[0].invalidateblock(best_hash) |
| 201 | + self.nodes[1].invalidateblock(best_hash) |
| 202 | + self.nodes[2].invalidateblock(best_hash) |
| 203 | + self.nodes[3].invalidateblock(best_hash) |
| 204 | + self.sync_all() |
| 205 | + |
| 206 | + balance4 = self.nodes[1].getaddressbalance(address2) |
| 207 | + assert_equal(balance4, balance1) |
| 208 | + |
| 209 | + utxos2 = self.nodes[1].getaddressutxos({"addresses": [address2]}) |
| 210 | + assert_equal(len(utxos2), 1) |
| 211 | + assert_equal(utxos2[0]["satoshis"], 5000000000) |
| 212 | + |
| 213 | + # Check sorting of utxos |
| 214 | + self.nodes[2].generate(150) |
| 215 | + |
| 216 | + txidsort1 = self.nodes[2].sendtoaddress(address2, 50) |
| 217 | + self.nodes[2].generate(1) |
| 218 | + txidsort2 = self.nodes[2].sendtoaddress(address2, 50) |
| 219 | + self.nodes[2].generate(1) |
| 220 | + self.sync_all() |
| 221 | + |
| 222 | + utxos3 = self.nodes[1].getaddressutxos({"addresses": [address2]}) |
| 223 | + assert_equal(len(utxos3), 3) |
| 224 | + assert_equal(utxos3[0]["height"], 114) |
| 225 | + assert_equal(utxos3[1]["height"], 264) |
| 226 | + assert_equal(utxos3[2]["height"], 265) |
| 227 | + |
| 228 | + # Check mempool indexing |
| 229 | + print "Testing mempool indexing..." |
| 230 | + |
| 231 | + privKey3 = "cVfUn53hAbRrDEuMexyfgDpZPhF7KqXpS8UZevsyTDaugB7HZ3CD" |
| 232 | + address3 = "mw4ynwhS7MmrQ27hr82kgqu7zryNDK26JB" |
| 233 | + addressHash3 = "aa9872b5bbcdb511d89e0e11aa27da73fd2c3f50".decode("hex") |
| 234 | + scriptPubKey3 = CScript([OP_DUP, OP_HASH160, addressHash3, OP_EQUALVERIFY, OP_CHECKSIG]) |
| 235 | + unspent = self.nodes[2].listunspent() |
| 236 | + |
| 237 | + tx = CTransaction() |
| 238 | + tx.vin = [CTxIn(COutPoint(int(unspent[0]["txid"], 16), unspent[0]["vout"]))] |
| 239 | + amount = unspent[0]["amount"] * 100000000 |
| 240 | + tx.vout = [CTxOut(amount, scriptPubKey3)] |
| 241 | + tx.rehash() |
| 242 | + signed_tx = self.nodes[2].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) |
| 243 | + memtxid1 = self.nodes[2].sendrawtransaction(signed_tx["hex"], True) |
| 244 | + time.sleep(2) |
| 245 | + |
| 246 | + tx2 = CTransaction() |
| 247 | + tx2.vin = [CTxIn(COutPoint(int(unspent[1]["txid"], 16), unspent[1]["vout"]))] |
| 248 | + amount = unspent[1]["amount"] * 100000000 |
| 249 | + tx2.vout = [CTxOut(amount, scriptPubKey3)] |
| 250 | + tx2.rehash() |
| 251 | + signed_tx2 = self.nodes[2].signrawtransaction(binascii.hexlify(tx2.serialize()).decode("utf-8")) |
| 252 | + memtxid2 = self.nodes[2].sendrawtransaction(signed_tx2["hex"], True) |
| 253 | + time.sleep(2) |
| 254 | + |
| 255 | + mempool = self.nodes[2].getaddressmempool({"addresses": [address3]}) |
| 256 | + assert_equal(len(mempool), 2) |
| 257 | + assert_equal(mempool[0]["txid"], memtxid1) |
| 258 | + assert_equal(mempool[1]["txid"], memtxid2) |
| 259 | + assert_equal(mempool[0]["address"], address3) |
| 260 | + |
| 261 | + self.nodes[2].generate(1); |
| 262 | + self.sync_all(); |
| 263 | + mempool2 = self.nodes[2].getaddressmempool({"addresses": [address3]}) |
| 264 | + assert_equal(len(mempool2), 0) |
| 265 | + |
| 266 | + tx = CTransaction() |
| 267 | + tx.vin = [CTxIn(COutPoint(int(memtxid2, 16), 0))] |
| 268 | + tx.vout = [CTxOut(amount - 10000, scriptPubKey2)] |
| 269 | + tx.rehash() |
| 270 | + self.nodes[2].importprivkey(privKey3) |
| 271 | + signed_tx3 = self.nodes[2].signrawtransaction(binascii.hexlify(tx.serialize()).decode("utf-8")) |
| 272 | + memtxid3 = self.nodes[2].sendrawtransaction(signed_tx3["hex"], True) |
| 273 | + time.sleep(2) |
| 274 | + |
| 275 | + mempool3 = self.nodes[2].getaddressmempool({"addresses": [address3]}) |
| 276 | + assert_equal(len(mempool3), 1) |
| 277 | + assert_equal(mempool3[0]["prevtxid"], memtxid2) |
| 278 | + assert_equal(mempool3[0]["prevout"], 0) |
| 279 | + |
| 280 | + print "Passed\n" |
| 281 | + |
| 282 | + |
| 283 | +if __name__ == '__main__': |
| 284 | + AddressIndexTest().main() |
0 commit comments