claimtrie.cpp 107 KB
Newer Older
1
#include "claimtrie.h"
2
3
#include "coins.h"
#include "hash.h"
4
5

#include <boost/scoped_ptr.hpp>
6
7
#include <iostream>
#include <algorithm>
8

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
std::vector<unsigned char> heightToVch(int n)
{
    std::vector<unsigned char> vchHeight;
    vchHeight.resize(8);
    vchHeight[0] = 0;
    vchHeight[1] = 0;
    vchHeight[2] = 0;
    vchHeight[3] = 0;
    vchHeight[4] = n >> 24;
    vchHeight[5] = n >> 16;
    vchHeight[6] = n >> 8;
    vchHeight[7] = n;
    return vchHeight;
}

24
uint256 getValueHash(COutPoint outPoint, int nHeightOfLastTakeover)
25
{
26
    CHash256 txHasher;
27
    txHasher.Write(outPoint.hash.begin(), outPoint.hash.size());
28
29
    std::vector<unsigned char> vchtxHash(txHasher.OUTPUT_SIZE);
    txHasher.Finalize(&(vchtxHash[0]));
30

31
    CHash256 nOutHasher;
32
    std::stringstream ss;
33
    ss << outPoint.n;
34
    std::string snOut = ss.str();
35
36
37
38
    nOutHasher.Write((unsigned char*) snOut.data(), snOut.size());
    std::vector<unsigned char> vchnOutHash(nOutHasher.OUTPUT_SIZE);
    nOutHasher.Finalize(&(vchnOutHash[0]));

39
40
41
42
43
44
    CHash256 takeoverHasher;
    std::vector<unsigned char> vchTakeoverHeightToHash = heightToVch(nHeightOfLastTakeover);
    takeoverHasher.Write(vchTakeoverHeightToHash.data(), vchTakeoverHeightToHash.size());
    std::vector<unsigned char> vchTakeoverHash(takeoverHasher.OUTPUT_SIZE);
    takeoverHasher.Finalize(&(vchTakeoverHash[0]));

45
46
47
    CHash256 hasher;
    hasher.Write(vchtxHash.data(), vchtxHash.size());
    hasher.Write(vchnOutHash.data(), vchnOutHash.size());
48
    hasher.Write(vchTakeoverHash.data(), vchTakeoverHash.size());
49
50
    std::vector<unsigned char> vchHash(hasher.OUTPUT_SIZE);
    hasher.Finalize(&(vchHash[0]));
51

52
53
    uint256 valueHash(vchHash);
    return valueHash;
54
55
}

56
bool CClaimTrieNode::insertClaim(CClaimValue claim)
57
{
58
    LogPrintf("%s: Inserting %s:%d (amount: %d)  into the claim trie\n", __func__, claim.outPoint.hash.ToString(), claim.outPoint.n, claim.nAmount);
59
    claims.push_back(claim);
60
61
62
    return true;
}

63
bool CClaimTrieNode::removeClaim(const COutPoint& outPoint, CClaimValue& claim)
64
{
65
    LogPrintf("%s: Removing txid: %s, nOut: %d from the claim trie\n", __func__, outPoint.hash.ToString(), outPoint.n);
66

67
68
    std::vector<CClaimValue>::iterator itClaims;
    for (itClaims = claims.begin(); itClaims != claims.end(); ++itClaims)
69
    {
70
        if (itClaims->outPoint == outPoint)
71
        {
72
            std::swap(claim, *itClaims);
73
74
75
            break;
        }
    }
76
77
78
79
    if (itClaims != claims.end())
    {
        claims.erase(itClaims);
    }
80
81
    else
    {
82
83
84
        LogPrintf("CClaimTrieNode::%s() : asked to remove a claim that doesn't exist\n", __func__);
        LogPrintf("CClaimTrieNode::%s() : claims that do exist:\n", __func__);
        for (unsigned int i = 0; i < claims.size(); i++)
85
        {
86
            LogPrintf("\ttxhash: %s, nOut: %d:\n", claims[i].outPoint.hash.ToString(), claims[i].outPoint.n);
87
        }
88
89
90
91
92
        return false;
    }
    return true;
}

93
bool CClaimTrieNode::getBestClaim(CClaimValue& claim) const
94
{
95
    if (claims.empty())
96
    {
97
        return false;
98
    }
99
100
    else
    {
101
        claim = claims.front();
102
103
104
105
        return true;
    }
}

106
bool CClaimTrieNode::haveClaim(const COutPoint& outPoint) const
107
{
108
    for (std::vector<CClaimValue>::const_iterator itclaim = claims.begin(); itclaim != claims.end(); ++itclaim)
109
110
    {
        if (itclaim->outPoint == outPoint)
111
            return true;
112
    }
113
114
115
    return false;
}

116
void CClaimTrieNode::reorderClaims(supportMapEntryType& supports)
117
{
118
    std::vector<CClaimValue>::iterator itclaim;
119

120
    for (itclaim = claims.begin(); itclaim != claims.end(); ++itclaim)
121
    {
122
        itclaim->nEffectiveAmount = itclaim->nAmount;
123
124
    }

125
    for (supportMapEntryType::iterator itsupport = supports.begin(); itsupport != supports.end(); ++itsupport)
126
    {
127
        for (itclaim = claims.begin(); itclaim != claims.end(); ++itclaim)
128
        {
129
            if (itsupport->supportedClaimId == itclaim->claimId)
130
            {
131
                itclaim->nEffectiveAmount += itsupport->nAmount;
132
133
134
135
                break;
            }
        }
    }
136

137
    std::make_heap(claims.begin(), claims.end());
138
139
}

140
uint256 CClaimTrie::getMerkleHash()
141
142
143
144
{
    return root.hash;
}

145
bool CClaimTrie::empty() const
146
147
148
149
{
    return root.empty();
}

150
template<typename K> bool CClaimTrie::keyTypeEmpty(char keyType, K& dummy) const
151
{
152
    boost::scoped_ptr<CDBIterator> pcursor(const_cast<CDBWrapper*>(&db)->NewIterator());
153
    pcursor->SeekToFirst();
154

155
156
    while (pcursor->Valid())
    {
157
158
        std::pair<char, K> key;
        if (pcursor->GetKey(key))
159
        {
160
            if (key.first == keyType)
161
162
163
164
            {
                return false;
            }
        }
165
        else
166
        {
167
            break;
168
169
170
171
        }
        pcursor->Next();
    }
    return true;
172
173
}

174
175
bool CClaimTrie::queueEmpty() const
{
176
    for (claimQueueType::const_iterator itRow = dirtyQueueRows.begin(); itRow != dirtyQueueRows.end(); ++itRow)
177
178
179
180
    {
        if (!itRow->second.empty())
            return false;
    }
181
    int dummy;
182
    return keyTypeEmpty(CLAIM_QUEUE_ROW, dummy);
183
184
}

185
bool CClaimTrie::expirationQueueEmpty() const
186
{
187
    for (expirationQueueType::const_iterator itRow = dirtyExpirationQueueRows.begin(); itRow != dirtyExpirationQueueRows.end(); ++itRow)
188
189
190
191
    {
        if (!itRow->second.empty())
            return false;
    }
192
193
    int dummy;
    return keyTypeEmpty(EXP_QUEUE_ROW, dummy);
194
}
195

196
197
198
bool CClaimTrie::supportEmpty() const
{
    for (supportMapType::const_iterator itNode = dirtySupportNodes.begin(); itNode != dirtySupportNodes.end(); ++itNode)
199
    {
200
201
        if (!itNode->second.empty())
            return false;
202
    }
203
204
    std::string dummy;
    return keyTypeEmpty(SUPPORT, dummy);
205
206
207
208
}

bool CClaimTrie::supportQueueEmpty() const
{
209
    for (supportQueueType::const_iterator itRow = dirtySupportQueueRows.begin(); itRow != dirtySupportQueueRows.end(); ++itRow)
210
211
212
213
    {
        if (!itRow->second.empty())
            return false;
    }
214
    int dummy;
215
    return keyTypeEmpty(SUPPORT_QUEUE_ROW, dummy);
216
217
}

218
void CClaimTrie::setExpirationTime(int t)
219
220
{
    nExpirationTime = t;
221
    LogPrintf("%s: Expiration time is now %d\n", __func__, nExpirationTime);
222
223
}

224
void CClaimTrie::clear()
Jimmy Kiselak's avatar
Jimmy Kiselak committed
225
226
227
228
{
    clear(&root);
}

229
void CClaimTrie::clear(CClaimTrieNode* current)
Jimmy Kiselak's avatar
Jimmy Kiselak committed
230
231
232
233
234
235
236
237
{
    for (nodeMapType::const_iterator itchildren = current->children.begin(); itchildren != current->children.end(); ++itchildren)
    {
        clear(itchildren->second);
        delete itchildren->second;
    }
}

238
bool CClaimTrie::haveClaim(const std::string& name, const COutPoint& outPoint) const
239
{
240
    const CClaimTrieNode* current = &root;
241
242
243
244
245
246
247
    for (std::string::const_iterator itname = name.begin(); itname != name.end(); ++itname)
    {
        nodeMapType::const_iterator itchildren = current->children.find(*itname);
        if (itchildren == current->children.end())
            return false;
        current = itchildren->second;
    }
248
    return current->haveClaim(outPoint);
249
250
}

251
bool CClaimTrie::haveSupport(const std::string& name, const COutPoint& outPoint) const
252
{
253
    supportMapEntryType node;
254
255
256
257
    if (!getSupportNode(name, node))
    {
        return false;
    }
258
    for (supportMapEntryType::const_iterator itnode = node.begin(); itnode != node.end(); ++itnode)
259
    {
260
        if (itnode->outPoint == outPoint)
261
262
263
264
265
            return true;
    }
    return false;
}

266
bool CClaimTrie::haveClaimInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const
267
{
268
    queueNameRowType nameRow;
269
    if (!getQueueNameRow(name, nameRow))
270
    {
271
        return false;
272
    }
273
    queueNameRowType::const_iterator itNameRow;
274
    for (itNameRow = nameRow.begin(); itNameRow != nameRow.end(); ++itNameRow)
275
    {
276
        if (itNameRow->outPoint == outPoint)
277
        {
278
            nValidAtHeight = itNameRow->nHeight;
279
            break;
280
281
        }
    }
282
283
284
285
286
287
    if (itNameRow == nameRow.end())
    {
        return false;
    }
    claimQueueRowType row;
    if (getQueueRow(nValidAtHeight, row))
288
    {
289
        for (claimQueueRowType::const_iterator itRow = row.begin(); itRow != row.end(); ++itRow)
290
        {
291
            if (itRow->first == name && itRow->second.outPoint == outPoint)
292
293
294
            {
                if (itRow->second.nValidAtHeight != nValidAtHeight)
                {
295
                    LogPrintf("%s: An inconsistency was found in the claim queue. Please report this to the developers:\nDifferent nValidAtHeight between named queue and height queue\n: name: %s, txid: %s, nOut: %d, nValidAtHeight in named queue: %d, nValidAtHeight in height queue: %d current height: %d\n", __func__, name, outPoint.hash.GetHex(), outPoint.n, nValidAtHeight, itRow->second.nValidAtHeight, nCurrentHeight);
296
297
298
                }
                return true;
            }
299
300
        }
    }
301
    LogPrintf("%s: An inconsistency was found in the claim queue. Please report this to the developers:\nFound in named queue but not in height queue: name: %s, txid: %s, nOut: %d, nValidAtHeight: %d, current height: %d\n", __func__, name, outPoint.hash.GetHex(), outPoint.n, nValidAtHeight, nCurrentHeight);
Jimmy Kiselak's avatar
Jimmy Kiselak committed
302
    return false;
303
304
}

305
bool CClaimTrie::haveSupportInQueue(const std::string& name, const COutPoint& outPoint, int& nValidAtHeight) const
306
{
307
    queueNameRowType nameRow;
308
309
310
311
    if (!getSupportQueueNameRow(name, nameRow))
    {
        return false;
    }
312
    queueNameRowType::const_iterator itNameRow;
313
    for (itNameRow = nameRow.begin(); itNameRow != nameRow.end(); ++itNameRow)
314
    {
315
        if (itNameRow->outPoint == outPoint)
316
        {
317
            nValidAtHeight = itNameRow->nHeight;
318
            break;
319
320
        }
    }
321
    if (itNameRow == nameRow.end())
322
    {
323
        return false;
324
    }
325
    supportQueueRowType row;
326
    if (getSupportQueueRow(nValidAtHeight, row))
327
    {
328
        for (supportQueueRowType::const_iterator itRow = row.begin(); itRow != row.end(); ++itRow)
329
        {
330
            if (itRow->first == name && itRow->second.outPoint == outPoint)
331
332
333
            {
                if (itRow->second.nValidAtHeight != nValidAtHeight)
                {
334
                    LogPrintf("%s: An inconsistency was found in the support queue. Please report this to the developers:\nDifferent nValidAtHeight between named queue and height queue\n: name: %s, txid: %s, nOut: %d, nValidAtHeight in named queue: %d, nValidAtHeight in height queue: %d current height: %d\n", __func__, name, outPoint.hash.GetHex(), outPoint.n, nValidAtHeight, itRow->second.nValidAtHeight, nCurrentHeight);
335
336
337
                }
                return true;
            }
338
339
        }
    }
340
    LogPrintf("%s: An inconsistency was found in the claim queue. Please report this to the developers:\nFound in named queue but not in height queue: name: %s, txid: %s, nOut: %d, nValidAtHeight: %d, current height: %d\n", __func__, name, outPoint.hash.GetHex(), outPoint.n, nValidAtHeight, nCurrentHeight);
341
342
343
    return false;
}

344
unsigned int CClaimTrie::getTotalNamesInTrie() const
345
346
347
{
    if (empty())
        return 0;
348
    const CClaimTrieNode* current = &root;
349
350
351
    return getTotalNamesRecursive(current);
}

352
unsigned int CClaimTrie::getTotalNamesRecursive(const CClaimTrieNode* current) const
353
354
{
    unsigned int names_in_subtrie = 0;
355
    if (!(current->claims.empty()))
356
357
358
359
360
361
362
363
        names_in_subtrie += 1;
    for (nodeMapType::const_iterator it = current->children.begin(); it != current->children.end(); ++it)
    {
        names_in_subtrie += getTotalNamesRecursive(it->second);
    }
    return names_in_subtrie;
}

364
unsigned int CClaimTrie::getTotalClaimsInTrie() const
365
366
367
{
    if (empty())
        return 0;
368
    const CClaimTrieNode* current = &root;
369
370
371
    return getTotalClaimsRecursive(current);
}

372
unsigned int CClaimTrie::getTotalClaimsRecursive(const CClaimTrieNode* current) const
373
{
374
    unsigned int claims_in_subtrie = current->claims.size();
375
376
377
378
379
380
381
    for (nodeMapType::const_iterator it = current->children.begin(); it != current->children.end(); ++it)
    {
        claims_in_subtrie += getTotalClaimsRecursive(it->second);
    }
    return claims_in_subtrie;
}

382
CAmount CClaimTrie::getTotalValueOfClaimsInTrie(bool fControllingOnly) const
383
384
385
{
    if (empty())
        return 0;
386
    const CClaimTrieNode* current = &root;
387
388
389
    return getTotalValueOfClaimsRecursive(current, fControllingOnly);
}

390
CAmount CClaimTrie::getTotalValueOfClaimsRecursive(const CClaimTrieNode* current, bool fControllingOnly) const
391
392
{
    CAmount value_in_subtrie = 0;
393
    for (std::vector<CClaimValue>::const_iterator itclaim = current->claims.begin(); itclaim != current->claims.end(); ++itclaim)
394
    {
395
        value_in_subtrie += itclaim->nAmount;
396
397
398
399
400
401
402
403
404
405
        if (fControllingOnly)
            break;
    }
    for (nodeMapType::const_iterator itchild = current->children.begin(); itchild != current->children.end(); ++itchild)
     {
         value_in_subtrie += getTotalValueOfClaimsRecursive(itchild->second, fControllingOnly);
     }
     return value_in_subtrie;
}

406
bool CClaimTrie::recursiveFlattenTrie(const std::string& name, const CClaimTrieNode* current, std::vector<namedNodeType>& nodes) const
407
{
408
409
    namedNodeType node(name, *current);
    nodes.push_back(node);
410
411
412
413
    for (nodeMapType::const_iterator it = current->children.begin(); it != current->children.end(); ++it)
    {
        std::stringstream ss;
        ss << name << it->first;
414
        if (!recursiveFlattenTrie(ss.str(), it->second, nodes))
415
416
417
418
419
            return false;
    }
    return true;
}

420
std::vector<namedNodeType> CClaimTrie::flattenTrie() const
421
{
422
423
424
425
    std::vector<namedNodeType> nodes;
    if (!recursiveFlattenTrie("", &root, nodes))
        LogPrintf("%s: Something went wrong flattening the trie", __func__);
    return nodes;
426
427
}

428
const CClaimTrieNode* CClaimTrie::getNodeForName(const std::string& name) const
429
{
430
    const CClaimTrieNode* current = &root;
431
432
433
434
    for (std::string::const_iterator itname = name.begin(); itname != name.end(); ++itname)
    {
        nodeMapType::const_iterator itchildren = current->children.find(*itname);
        if (itchildren == current->children.end())
435
            return NULL;
436
437
        current = itchildren->second;
    }
438
439
440
441
442
443
444
    return current;
}

bool CClaimTrie::getInfoForName(const std::string& name, CClaimValue& claim) const
{
    const CClaimTrieNode* current = getNodeForName(name);
    if (current)
445
    {
446
        return current->getBestClaim(claim);
447
    }
448
449
450
451
452
453
    return false;
}

bool CClaimTrie::getLastTakeoverForName(const std::string& name, int& lastTakeoverHeight) const
{
    const CClaimTrieNode* current = getNodeForName(name);
454
    if (current && !current->claims.empty())
455
456
457
458
459
    {
        lastTakeoverHeight = current->nHeightOfLastTakeover;
        return true;
    }
    return false;
460
461
}

462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
claimsForNameType CClaimTrie::getClaimsForName(const std::string& name) const
{
    std::vector<CClaimValue> claims;
    std::vector<CSupportValue> supports;
    int nLastTakeoverHeight = 0;
    const CClaimTrieNode* current = getNodeForName(name);
    if (current)
    {
        if (!current->claims.empty())
        {
            nLastTakeoverHeight = current->nHeightOfLastTakeover;
        }
        for (std::vector<CClaimValue>::const_iterator itClaims = current->claims.begin(); itClaims != current->claims.end(); ++itClaims)
        {
            claims.push_back(*itClaims);
        }
    }
    supportMapEntryType supportNode;
    if (getSupportNode(name, supportNode))
    {
        for (std::vector<CSupportValue>::const_iterator itSupports = supportNode.begin(); itSupports != supportNode.end(); ++itSupports)
        {
            supports.push_back(*itSupports);
        }
    }
    queueNameRowType namedClaimRow;
    if (getQueueNameRow(name, namedClaimRow))
    {
        for (queueNameRowType::const_iterator itClaimsForName = namedClaimRow.begin(); itClaimsForName != namedClaimRow.end(); ++itClaimsForName)
        {
            claimQueueRowType claimRow;
            if (getQueueRow(itClaimsForName->nHeight, claimRow))
            {
                for (claimQueueRowType::const_iterator itClaimRow = claimRow.begin(); itClaimRow != claimRow.end(); ++itClaimRow)
                 {
                     if (itClaimRow->first == name && itClaimRow->second.outPoint == itClaimsForName->outPoint)
                     {
                         claims.push_back(itClaimRow->second);
                         break;
                     }
                 }
            }
        }
    }
    queueNameRowType namedSupportRow;
    if (getSupportQueueNameRow(name, namedSupportRow))
    {
        for (queueNameRowType::const_iterator itSupportsForName = namedSupportRow.begin(); itSupportsForName != namedSupportRow.end(); ++itSupportsForName)
        {
            supportQueueRowType supportRow;
            if (getSupportQueueRow(itSupportsForName->nHeight, supportRow))
            {
                for (supportQueueRowType::const_iterator itSupportRow = supportRow.begin(); itSupportRow != supportRow.end(); ++itSupportRow)
                {
                    if (itSupportRow->first == name && itSupportRow->second.outPoint == itSupportsForName->outPoint)
                    {
                        supports.push_back(itSupportRow->second);
                        break;
                    }
                }
            }
        }
    }
    claimsForNameType allClaims(claims, supports, nLastTakeoverHeight);
    return allClaims;
}

529
//return effective amount from claim, retuns 0 if claim is not found
530
CAmount CClaimTrie::getEffectiveAmountForClaim(const std::string& name, const uint160& claimId, std::vector<CSupportValue>* supports) const
531
{
532
    return getEffectiveAmountForClaim(getClaimsForName(name), claimId, supports);
533
}
534

535
CAmount CClaimTrie::getEffectiveAmountForClaim(const claimsForNameType& claims, const uint160& claimId, std::vector<CSupportValue>* supports) const
536
537
{
    CAmount effectiveAmount = 0;
538
539
    for (std::vector<CClaimValue>::const_iterator it = claims.claims.begin(); it != claims.claims.end(); ++it) {
        if (it->claimId == claimId && it->nValidAtHeight < nCurrentHeight) {
540
            effectiveAmount += it->nAmount;
541
542
543
544
545
546
            for (std::vector<CSupportValue>::const_iterator it = claims.supports.begin(); it != claims.supports.end(); ++it) {
                if (it->supportedClaimId == claimId && it->nValidAtHeight < nCurrentHeight) {
                    effectiveAmount += it->nAmount;
                    if (supports) supports->push_back(*it);
                }
            }
547
548
549
550
            break;
        }
    }
    return effectiveAmount;
551
552
}

553
bool CClaimTrie::checkConsistency() const
554
{
555
556
    if (empty())
        return true;
557
558
559
    return recursiveCheckConsistency(&root);
}

560
bool CClaimTrie::recursiveCheckConsistency(const CClaimTrieNode* node) const
561
{
562
    std::vector<unsigned char> vchToHash;
563

564
    for (nodeMapType::const_iterator it = node->children.begin(); it != node->children.end(); ++it)
565
566
567
    {
        if (recursiveCheckConsistency(it->second))
        {
568
569
            vchToHash.push_back(it->first);
            vchToHash.insert(vchToHash.end(), it->second->hash.begin(), it->second->hash.end());
570
571
572
573
        }
        else
            return false;
    }
574

575
576
    CClaimValue claim;
    bool hasClaim = node->getBestClaim(claim);
577

578
    if (hasClaim)
579
    {
580
581
        uint256 valueHash = getValueHash(claim.outPoint, node->nHeightOfLastTakeover);
        vchToHash.insert(vchToHash.end(), valueHash.begin(), valueHash.end());
582
583
    }

584
585
    CHash256 hasher;
    std::vector<unsigned char> vchHash(hasher.OUTPUT_SIZE);
586
    hasher.Write(vchToHash.data(), vchToHash.size());
587
588
589
590
591
    hasher.Finalize(&(vchHash[0]));
    uint256 calculatedHash(vchHash);
    return calculatedHash == node->hash;
}

592
593
594
595
void CClaimTrie::addToClaimIndex(const std::string& name, const CClaimValue& claim)
{
    CClaimIndexElement element = { name, claim };
    LogPrintf("%s: ClaimIndex[%s] updated %s\n", __func__, claim.claimId.GetHex(), name);
596
    db.Write(std::make_pair(CLAIM_BY_ID, claim.claimId), element);
597
598
599
600
}

void CClaimTrie::removeFromClaimIndex(const CClaimValue& claim)
{
601
    LogPrintf("%s: ClaimIndex[%s] removed\n", __func__, claim.claimId.GetHex());
602
    db.Erase(std::make_pair(CLAIM_BY_ID, claim.claimId));
603
604
605
606
607
608
609
}

bool CClaimTrie::getClaimById(const uint160 claimId, std::string& name, CClaimValue& claim) const
{
    CClaimIndexElement element;
    if (db.Read(std::make_pair(CLAIM_BY_ID, claimId), element))
    {
610
611
612
613
614
615
616
617
        if (element.claim.claimId == claimId) {
            name = element.name;
            claim = element.claim;
            return true;
        } else {
            LogPrintf("%s: ClaimIndex[%s] returned unmatched claimId %s when looking for %s\n",
                __func__, claimId.GetHex(), element.claim.claimId.GetHex(), name);
        }
618
619
620
621
    }
    return false;
}

622
bool CClaimTrie::getQueueRow(int nHeight, claimQueueRowType& row) const
623
{
624
    claimQueueType::const_iterator itQueueRow = dirtyQueueRows.find(nHeight);
625
    if (itQueueRow != dirtyQueueRows.end())
626
    {
627
628
        row = itQueueRow->second;
        return true;
629
    }
630
    return db.Read(std::make_pair(CLAIM_QUEUE_ROW, nHeight), row);
631
632
}

633
bool CClaimTrie::getQueueNameRow(const std::string& name, queueNameRowType& row) const
634
{
635
    queueNameType::const_iterator itQueueNameRow = dirtyQueueNameRows.find(name);
636
637
638
639
640
641
642
643
    if (itQueueNameRow != dirtyQueueNameRows.end())
    {
        row = itQueueNameRow->second;
        return true;
    }
    return db.Read(std::make_pair(CLAIM_QUEUE_NAME_ROW, name), row);
}

644
bool CClaimTrie::getExpirationQueueRow(int nHeight, expirationQueueRowType& row) const
645
{
646
    expirationQueueType::const_iterator itQueueRow = dirtyExpirationQueueRows.find(nHeight);
647
648
649
650
651
    if (itQueueRow != dirtyExpirationQueueRows.end())
    {
        row = itQueueRow->second;
        return true;
    }
652
    return db.Read(std::make_pair(EXP_QUEUE_ROW, nHeight), row);
653
654
}

655
void CClaimTrie::updateQueueRow(int nHeight, claimQueueRowType& row)
656
{
657
    claimQueueType::iterator itQueueRow = dirtyQueueRows.find(nHeight);
658
    if (itQueueRow == dirtyQueueRows.end())
659
    {
660
661
662
663
664
665
666
667
668
        claimQueueRowType newRow;
        std::pair<claimQueueType::iterator, bool> ret;
        ret = dirtyQueueRows.insert(std::pair<int, claimQueueRowType >(nHeight, newRow));
        assert(ret.second);
        itQueueRow = ret.first;
    }
    itQueueRow->second.swap(row);
}

669
void CClaimTrie::updateQueueNameRow(const std::string& name, queueNameRowType& row)
670
{
671
    queueNameType::iterator itQueueRow = dirtyQueueNameRows.find(name);
672
673
    if (itQueueRow == dirtyQueueNameRows.end())
    {
674
675
676
        queueNameRowType newRow;
        std::pair<queueNameType::iterator, bool> ret;
        ret = dirtyQueueNameRows.insert(std::pair<std::string, queueNameRowType>(name, newRow));
677
678
        assert(ret.second);
        itQueueRow = ret.first;
679
    }
680
    itQueueRow->second.swap(row);
681
682
}

683
void CClaimTrie::updateExpirationRow(int nHeight, expirationQueueRowType& row)
684
{
685
    expirationQueueType::iterator itQueueRow = dirtyExpirationQueueRows.find(nHeight);
686
687
    if (itQueueRow == dirtyExpirationQueueRows.end())
    {
688
689
690
        expirationQueueRowType newRow;
        std::pair<expirationQueueType::iterator, bool> ret;
        ret = dirtyExpirationQueueRows.insert(std::pair<int, expirationQueueRowType >(nHeight, newRow));
691
692
693
694
695
696
        assert(ret.second);
        itQueueRow = ret.first;
    }
    itQueueRow->second.swap(row);
}

697
void CClaimTrie::updateSupportMap(const std::string& name, supportMapEntryType& node)
698
699
700
701
{
    supportMapType::iterator itNode = dirtySupportNodes.find(name);
    if (itNode == dirtySupportNodes.end())
    {
702
        supportMapEntryType newNode;
703
        std::pair<supportMapType::iterator, bool> ret;
704
        ret = dirtySupportNodes.insert(std::pair<std::string, supportMapEntryType>(name, newNode));
705
706
707
708
709
710
        assert(ret.second);
        itNode = ret.first;
    }
    itNode->second.swap(node);
}

711
void CClaimTrie::updateSupportQueue(int nHeight, supportQueueRowType& row)
712
{
713
    supportQueueType::iterator itQueueRow = dirtySupportQueueRows.find(nHeight);
714
715
    if (itQueueRow == dirtySupportQueueRows.end())
    {
716
717
718
719
720
721
722
723
724
        supportQueueRowType newRow;
        std::pair<supportQueueType::iterator, bool> ret;
        ret = dirtySupportQueueRows.insert(std::pair<int, supportQueueRowType >(nHeight, newRow));
        assert(ret.second);
        itQueueRow = ret.first;
    }
    itQueueRow->second.swap(row);
}

725
void CClaimTrie::updateSupportNameQueue(const std::string& name, queueNameRowType& row)
726
{
727
    queueNameType::iterator itQueueRow = dirtySupportQueueNameRows.find(name);
728
729
    if (itQueueRow == dirtySupportQueueNameRows.end())
    {
730
731
732
        queueNameRowType newRow;
        std::pair<queueNameType::iterator, bool> ret;
        ret = dirtySupportQueueNameRows.insert(std::pair<std::string, queueNameRowType>(name, newRow));
733
734
735
736
737
738
        assert(ret.second);
        itQueueRow = ret.first;
    }
    itQueueRow->second.swap(row);
}

739
void CClaimTrie::updateSupportExpirationQueue(int nHeight, expirationQueueRowType& row)
Jimmy Kiselak's avatar
Jimmy Kiselak committed
740
{
741
    expirationQueueType::iterator itQueueRow = dirtySupportExpirationQueueRows.find(nHeight);
Jimmy Kiselak's avatar
Jimmy Kiselak committed
742
743
    if (itQueueRow == dirtySupportExpirationQueueRows.end())
    {
744
745
746
        expirationQueueRowType newRow;
        std::pair<expirationQueueType::iterator, bool> ret;
        ret = dirtySupportExpirationQueueRows.insert(std::pair<int, expirationQueueRowType >(nHeight, newRow));
Jimmy Kiselak's avatar
Jimmy Kiselak committed
747
748
749
750
751
752
        assert(ret.second);
        itQueueRow = ret.first;
    }
    itQueueRow->second.swap(row);
}

753
bool CClaimTrie::getSupportNode(std::string name, supportMapEntryType& node) const
754
755
756
757
758
759
760
761
762
763
{
    supportMapType::const_iterator itNode = dirtySupportNodes.find(name);
    if (itNode != dirtySupportNodes.end())
    {
        node = itNode->second;
        return true;
    }
    return db.Read(std::make_pair(SUPPORT, name), node);
}

764
bool CClaimTrie::getSupportQueueRow(int nHeight, supportQueueRowType& row) const
765
{
766
    supportQueueType::const_iterator itQueueRow = dirtySupportQueueRows.find(nHeight);
767
768
769
770
771
    if (itQueueRow != dirtySupportQueueRows.end())
    {
        row = itQueueRow->second;
        return true;
    }
772
773
774
    return db.Read(std::make_pair(SUPPORT_QUEUE_ROW, nHeight), row);
}

775
bool CClaimTrie::getSupportQueueNameRow(const std::string& name, queueNameRowType& row) const
776
{
777
    queueNameType::const_iterator itQueueNameRow = dirtySupportQueueNameRows.find(name);
778
779
780
781
782
783
    if (itQueueNameRow != dirtySupportQueueNameRows.end())
    {
        row = itQueueNameRow->second;
        return true;
    }
    return db.Read(std::make_pair(SUPPORT_QUEUE_NAME_ROW, name), row);
784
785
}

786
bool CClaimTrie::getSupportExpirationQueueRow(int nHeight, expirationQueueRowType& row) const
Jimmy Kiselak's avatar
Jimmy Kiselak committed
787
{
788
    expirationQueueType::const_iterator itQueueRow = dirtySupportExpirationQueueRows.find(nHeight);
Jimmy Kiselak's avatar
Jimmy Kiselak committed
789
790
791
792
793
794
795
796
    if (itQueueRow != dirtySupportExpirationQueueRows.end())
    {
        row = itQueueRow->second;
        return true;
    }
    return db.Read(std::make_pair(SUPPORT_EXP_QUEUE_ROW, nHeight), row);
}

797
bool CClaimTrie::update(nodeCacheType& cache, hashMapType& hashes, std::map<std::string, int>& takeoverHeights, const uint256& hashBlockIn, claimQueueType& queueCache, queueNameType& queueNameCache, expirationQueueType& expirationQueueCache, int nNewHeight, supportMapType& supportCache, supportQueueType& supportQueueCache, queueNameType& supportQueueNameCache, expirationQueueType& supportExpirationQueueCache)
798
799
800
{
    for (nodeCacheType::iterator itcache = cache.begin(); itcache != cache.end(); ++itcache)
    {
801
        if (!updateName(itcache->first, itcache->second))
802
803
        {
            LogPrintf("%s: Failed to update name for:%s\n", __func__, itcache->first);
804
            return false;
805
        }
806
807
808
    }
    for (hashMapType::iterator ithash = hashes.begin(); ithash != hashes.end(); ++ithash)
    {
809
        if (!updateHash(ithash->first, ithash->second))
810
811
        {
            LogPrintf("%s: Failed to update hash for:%s\n", __func__, ithash->first);
812
            return false;
813
        }
814
815
816
817
    }
    for (std::map<std::string, int>::iterator itheight = takeoverHeights.begin(); itheight != takeoverHeights.end(); ++itheight)
    {
        if (!updateTakeoverHeight(itheight->first, itheight->second))
818
819
        {
            LogPrintf("%s: Failed to update takeover height for:%s\n", __func__, itheight->first);
820
            return false;
821
        }
822
    }
823
    for (claimQueueType::iterator itQueueCacheRow = queueCache.begin(); itQueueCacheRow != queueCache.end(); ++itQueueCacheRow)
824
    {
825
        updateQueueRow(itQueueCacheRow->first, itQueueCacheRow->second);
826
    }
827
    for (queueNameType::iterator itQueueNameCacheRow = queueNameCache.begin(); itQueueNameCacheRow != queueNameCache.end(); ++itQueueNameCacheRow)
828
829
830
    {
        updateQueueNameRow(itQueueNameCacheRow->first, itQueueNameCacheRow->second);
    }
831
    for (expirationQueueType::iterator itExpirationRow = expirationQueueCache.begin(); itExpirationRow != expirationQueueCache.end(); ++itExpirationRow)
832
833
834
    {
        updateExpirationRow(itExpirationRow->first, itExpirationRow->second);
    }
835
836
837
838
    for (supportMapType::iterator itSupportCache = supportCache.begin(); itSupportCache != supportCache.end(); ++itSupportCache)
    {
        updateSupportMap(itSupportCache->first, itSupportCache->second);
    }
839
    for (supportQueueType::iterator itSupportQueue = supportQueueCache.begin(); itSupportQueue != supportQueueCache.end(); ++itSupportQueue)
840
841
842
    {
        updateSupportQueue(itSupportQueue->first, itSupportQueue->second);
    }
843
    for (queueNameType::iterator itSupportNameQueue = supportQueueNameCache.begin(); itSupportNameQueue != supportQueueNameCache.end(); ++itSupportNameQueue)
844
845
846
    {
        updateSupportNameQueue(itSupportNameQueue->first, itSupportNameQueue->second);
    }
847
    for (expirationQueueType::iterator itSupportExpirationQueue = supportExpirationQueueCache.begin(); itSupportExpirationQueue != supportExpirationQueueCache.end(); ++itSupportExpirationQueue)
Jimmy Kiselak's avatar
Jimmy Kiselak committed
848
849
850
    {
        updateSupportExpirationQueue(itSupportExpirationQueue->first, itSupportExpirationQueue->second);
    }
851
    hashBlock = hashBlockIn;
852
    nCurrentHeight = nNewHeight;
853
854
855
    return true;
}

856
void CClaimTrie::markNodeDirty(const std::string &name, CClaimTrieNode* node)
857
858
{
    std::pair<nodeCacheType::iterator, bool> ret;
859
    ret = dirtyNodes.insert(std::pair<std::string, CClaimTrieNode*>(name, node));
860
861
862
863
    if (ret.second == false)
        ret.first->second = node;
}

864
bool CClaimTrie::updateName(const std::string &name, CClaimTrieNode* updatedNode)
865
{
866
    CClaimTrieNode* current = &root;
867
868
869
870
871
872
873
    for (std::string::const_iterator itname = name.begin(); itname != name.end(); ++itname)
    {
        nodeMapType::iterator itchild = current->children.find(*itname);
        if (itchild == current->children.end())
        {
            if (itname + 1 == name.end())
            {
874
                CClaimTrieNode* newNode = new CClaimTrieNode();
875
876
877
878
879
880
881
882
883
884
885
886
                current->children[*itname] = newNode;
                current = newNode;
            }
            else
                return false;
        }
        else
        {
            current = itchild->second;
        }
    }
    assert(current != NULL);
887
    current->claims.swap(updatedNode->claims);
888
    markNodeDirty(name, current);
889
890
891
892
893
894
895
896
897
898
    for (nodeMapType::iterator itchild = current->children.begin(); itchild != current->children.end();)
    {
        nodeMapType::iterator itupdatechild = updatedNode->children.find(itchild->first);
        if (itupdatechild == updatedNode->children.end())
        {
            // This character has apparently been deleted, so delete
            // all descendents from this child.
            std::stringstream ss;
            ss << name << itchild->first;
            std::string newName = ss.str();
899
            if (!recursiveNullify(itchild->second, newName))