changeset 29641:c84a21d81435

main: update address index during reorgs
author Braydon Fuller <courier@braydon.com>
date Mon, 28 Mar 2016 16:47:20 -0400
parents 50328b98c542
children 4f69782b14e9
files qa/rpc-tests/addressindex.py src/main.cpp src/txdb.cpp src/txdb.h
diffstat 4 files changed, 71 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/qa/rpc-tests/addressindex.py	Fri Mar 25 14:52:45 2016 -0400
+++ b/qa/rpc-tests/addressindex.py	Mon Mar 28 16:47:20 2016 -0400
@@ -118,10 +118,12 @@
         assert_equal(txidsmany[3], sent_txid)
 
         # Check that balances are correct
+        print "Testing balances..."
         balance0 = self.nodes[1].getaddressbalance("2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br")
         assert_equal(balance0["balance"], 45 * 100000000 + 21)
 
         # Check that balances are correct after spending
+        print "Testing balances after spending..."
         privkey2 = "cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG"
         address2 = "mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW"
         addressHash2 = "0b2f0a0c31bfe0406b0ccc1381fdbe311946dadc".decode("hex")
@@ -158,14 +160,27 @@
 
         # Check that deltas are returned correctly
         deltas = self.nodes[1].getaddressdeltas({"addresses": [address2], "start": 0, "end": 200})
-        balance3 = 0;
+        balance3 = 0
         for delta in deltas:
             balance3 += delta["satoshis"]
         assert_equal(balance3, change_amount)
 
         # 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);
+        assert_equal(len(deltas), 1)
+
+        # 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)
 
         print "Passed\n"
 
--- a/src/main.cpp	Fri Mar 25 14:52:45 2016 -0400
+++ b/src/main.cpp	Mon Mar 28 16:47:20 2016 -0400
@@ -2079,6 +2079,52 @@
         }
     }
 
+    // undo address indexes
+    if (fAddressIndex) {
+        std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex;
+
+        for (unsigned int i = 0; i < block.vtx.size(); i++) {
+            const CTransaction &tx = block.vtx[i];
+            const uint256 txhash = tx.GetHash();
+
+            if (!tx.IsCoinBase()) {
+                for (size_t j = 0; j < tx.vin.size(); j++) {
+                    const CTxOut &prevout = view.GetOutputFor(tx.vin[j]);
+                    if (prevout.scriptPubKey.IsPayToScriptHash()) {
+                        vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+2, prevout.scriptPubKey.begin()+22);
+                        addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
+                    } else if (prevout.scriptPubKey.IsPayToPublicKeyHash()) {
+                        vector<unsigned char> hashBytes(prevout.scriptPubKey.begin()+3, prevout.scriptPubKey.begin()+23);
+                        addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, j, true), prevout.nValue * -1));
+                    } else {
+                        continue;
+                    }
+                }
+            }
+
+            for (unsigned int k = 0; k < tx.vout.size(); k++) {
+                const CTxOut &out = tx.vout[k];
+
+                if (out.scriptPubKey.IsPayToScriptHash()) {
+                    vector<unsigned char> hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22);
+                    addressIndex.push_back(make_pair(CAddressIndexKey(2, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
+                } else if (out.scriptPubKey.IsPayToPublicKeyHash()) {
+                    vector<unsigned char> hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23);
+                    addressIndex.push_back(make_pair(CAddressIndexKey(1, uint160(hashBytes), pindex->nHeight, i, txhash, k, false), out.nValue));
+                } else {
+                    continue;
+                }
+
+            }
+
+        }
+
+        if (!pblocktree->EraseAddressIndex(addressIndex)) {
+            return AbortNode(state, "Failed to delete address index");
+        }
+    }
+
+
     // move best block pointer to prevout block
     view.SetBestBlock(pindex->pprev->GetBlockHash());
 
--- a/src/txdb.cpp	Fri Mar 25 14:52:45 2016 -0400
+++ b/src/txdb.cpp	Mon Mar 28 16:47:20 2016 -0400
@@ -172,6 +172,13 @@
     return WriteBatch(batch);
 }
 
+bool CBlockTreeDB::EraseAddressIndex(const std::vector<std::pair<CAddressIndexKey, CAmount > >&vect) {
+    CDBBatch batch(&GetObfuscateKey());
+    for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=vect.begin(); it!=vect.end(); it++)
+        batch.Erase(make_pair(DB_ADDRESSINDEX, it->first));
+    return WriteBatch(batch);
+}
+
 bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type,
                                     std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
                                     int start, int end) {
--- a/src/txdb.h	Fri Mar 25 14:52:45 2016 -0400
+++ b/src/txdb.h	Mon Mar 28 16:47:20 2016 -0400
@@ -62,6 +62,7 @@
     bool ReadTxIndex(const uint256 &txid, CDiskTxPos &pos);
     bool WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> > &list);
     bool WriteAddressIndex(const std::vector<std::pair<CAddressIndexKey, CAmount> > &vect);
+    bool EraseAddressIndex(const std::vector<std::pair<CAddressIndexKey, CAmount> > &vect);
     bool ReadAddressIndex(uint160 addressHash, int type,
                           std::vector<std::pair<CAddressIndexKey, CAmount> > &addressIndex,
                           int start = 0, int end = 0);