github.com/deso-protocol/core@v1.2.9/lib/block_view_flush.go (about)

     1  package lib
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/btcsuite/btcd/btcec"
     6  	"github.com/dgraph-io/badger/v3"
     7  	"github.com/golang/glog"
     8  	"github.com/pkg/errors"
     9  	"reflect"
    10  )
    11  
    12  func (bav *UtxoView) FlushToDb() error {
    13  	// Make sure everything happens inside a single transaction.
    14  	var err error
    15  	if bav.Postgres != nil {
    16  		err = bav.Postgres.FlushView(bav)
    17  		if err != nil {
    18  			return err
    19  		}
    20  	}
    21  
    22  	err = bav.Handle.Update(func(txn *badger.Txn) error {
    23  		return bav.FlushToDbWithTxn(txn)
    24  	})
    25  	if err != nil {
    26  		return err
    27  	}
    28  
    29  	// After a successful flush, reset the in-memory mappings for the view
    30  	// so that it can be re-used if desired.
    31  	//
    32  	// Note that the TipHash does not get reset as part of _ResetViewMappingsAfterFlush because
    33  	// it is not something that is affected by a flush operation. Moreover, its value
    34  	// is consistent with the view regardless of whether or not the view is flushed or
    35  	// not.
    36  	bav._ResetViewMappingsAfterFlush()
    37  
    38  	return nil
    39  }
    40  
    41  func (bav *UtxoView) FlushToDbWithTxn(txn *badger.Txn) error {
    42  	// Only flush to BadgerDB if Postgres is disabled
    43  	if bav.Postgres == nil {
    44  		if err := bav._flushUtxosToDbWithTxn(txn); err != nil {
    45  			return err
    46  		}
    47  		if err := bav._flushProfileEntriesToDbWithTxn(txn); err != nil {
    48  			return err
    49  		}
    50  		if err := bav._flushPKIDEntriesToDbWithTxn(txn); err != nil {
    51  			return err
    52  		}
    53  		if err := bav._flushPostEntriesToDbWithTxn(txn); err != nil {
    54  			return err
    55  		}
    56  		if err := bav._flushLikeEntriesToDbWithTxn(txn); err != nil {
    57  			return err
    58  		}
    59  		if err := bav._flushFollowEntriesToDbWithTxn(txn); err != nil {
    60  			return err
    61  		}
    62  		if err := bav._flushDiamondEntriesToDbWithTxn(txn); err != nil {
    63  			return err
    64  		}
    65  		if err := bav._flushMessageEntriesToDbWithTxn(txn); err != nil {
    66  			return err
    67  		}
    68  		if err := bav._flushBalanceEntriesToDbWithTxn(txn); err != nil {
    69  			return err
    70  		}
    71  		if err := bav._flushDeSoBalancesToDbWithTxn(txn); err != nil {
    72  			return err
    73  		}
    74  		if err := bav._flushForbiddenPubKeyEntriesToDbWithTxn(txn); err != nil {
    75  			return err
    76  		}
    77  		if err := bav._flushNFTEntriesToDbWithTxn(txn); err != nil {
    78  			return err
    79  		}
    80  		if err := bav._flushNFTBidEntriesToDbWithTxn(txn); err != nil {
    81  			return err
    82  		}
    83  		if err := bav._flushDerivedKeyEntryToDbWithTxn(txn); err != nil {
    84  			return err
    85  		}
    86  	}
    87  
    88  	// Always flush to BadgerDB.
    89  	if err := bav._flushBitcoinExchangeDataWithTxn(txn); err != nil {
    90  		return err
    91  	}
    92  	if err := bav._flushGlobalParamsEntryToDbWithTxn(txn); err != nil {
    93  		return err
    94  	}
    95  	if err := bav._flushAcceptedBidEntriesToDbWithTxn(txn); err != nil {
    96  		return err
    97  	}
    98  	if err := bav._flushRepostEntriesToDbWithTxn(txn); err != nil {
    99  		return err
   100  	}
   101  
   102  	return nil
   103  }
   104  
   105  func (bav *UtxoView) _flushUtxosToDbWithTxn(txn *badger.Txn) error {
   106  	glog.V(1).Infof("_flushUtxosToDbWithTxn: flushing %d mappings", len(bav.UtxoKeyToUtxoEntry))
   107  
   108  	for utxoKeyIter, utxoEntry := range bav.UtxoKeyToUtxoEntry {
   109  		// Make a copy of the iterator since it might change from under us.
   110  		utxoKey := utxoKeyIter
   111  
   112  		// As a sanity-check, make sure the back-reference for each entry
   113  		// points to its key.
   114  		if utxoEntry.UtxoKey == nil || *utxoEntry.UtxoKey != utxoKey {
   115  			return fmt.Errorf("_flushUtxosToDbWithTxn: Found utxoEntry %+v for "+
   116  				"utxoKey %v has invalid back-refernce utxoKey %v",
   117  				utxoEntry, utxoKey, utxoEntry.UtxoKey)
   118  		}
   119  
   120  		// Start by deleting the pre-existing mappings in the db for this key if they
   121  		// have not yet been modified.
   122  		if err := DeleteUnmodifiedMappingsForUtxoWithTxn(txn, &utxoKey); err != nil {
   123  			return err
   124  		}
   125  	}
   126  	numDeleted := 0
   127  	numPut := 0
   128  	for utxoKeyIter, utxoEntry := range bav.UtxoKeyToUtxoEntry {
   129  		// Make a copy of the iterator since it might change from under us.
   130  		utxoKey := utxoKeyIter
   131  
   132  		if utxoEntry.isSpent {
   133  			numDeleted++
   134  			// If an entry is spent then there's nothing to do, since the mappings in
   135  			// the db have already been deleted.
   136  		} else {
   137  			numPut++
   138  			// If the entry is unspent, then we need to re-set its mappings in the db
   139  			// appropriately.
   140  			if err := PutMappingsForUtxoWithTxn(txn, &utxoKey, utxoEntry); err != nil {
   141  				return err
   142  			}
   143  		}
   144  	}
   145  
   146  	glog.V(1).Infof("_flushUtxosToDbWithTxn: deleted %d mappings, put %d mappings", numDeleted, numPut)
   147  
   148  	// Now update the number of entries in the db with confidence.
   149  	if err := PutUtxoNumEntriesWithTxn(txn, bav.NumUtxoEntries); err != nil {
   150  		return err
   151  	}
   152  
   153  	// At this point, the db's position index should be updated and the (key -> entry)
   154  	// index should be updated to remove all spent utxos. The number of entries field
   155  	// in the db should also be accurate.
   156  
   157  	return nil
   158  }
   159  
   160  func (bav *UtxoView) _flushDeSoBalancesToDbWithTxn(txn *badger.Txn) error {
   161  	glog.V(1).Infof("_flushDeSoBalancesToDbWithTxn: flushing %d mappings",
   162  		len(bav.PublicKeyToDeSoBalanceNanos))
   163  
   164  	for pubKeyIter := range bav.PublicKeyToDeSoBalanceNanos {
   165  		// Make a copy of the iterator since it might change from under us.
   166  		pubKey := pubKeyIter[:]
   167  
   168  		// Start by deleting the pre-existing mappings in the db for this key if they
   169  		// have not yet been modified.
   170  		if err := DbDeletePublicKeyToDeSoBalanceWithTxn(txn, pubKey); err != nil {
   171  			return err
   172  		}
   173  	}
   174  	for pubKeyIter, balanceNanos := range bav.PublicKeyToDeSoBalanceNanos {
   175  		// Make a copy of the iterator since it might change from under us.
   176  		pubKey := pubKeyIter[:]
   177  
   178  		if balanceNanos > 0 {
   179  			if err := DbPutDeSoBalanceForPublicKeyWithTxn(txn, pubKey, balanceNanos); err != nil {
   180  				return err
   181  			}
   182  		}
   183  	}
   184  
   185  	return nil
   186  }
   187  
   188  func (bav *UtxoView) _flushGlobalParamsEntryToDbWithTxn(txn *badger.Txn) error {
   189  	globalParamsEntry := bav.GlobalParamsEntry
   190  	if err := DbPutGlobalParamsEntryWithTxn(txn, *globalParamsEntry); err != nil {
   191  		return errors.Wrapf(err, "_flushGlobalParamsEntryToDbWithTxn: Problem putting global params entry in DB")
   192  	}
   193  	return nil
   194  }
   195  
   196  func (bav *UtxoView) _flushForbiddenPubKeyEntriesToDbWithTxn(txn *badger.Txn) error {
   197  
   198  	// Go through all the entries in the KeyTorepostEntry map.
   199  	for _, forbiddenPubKeyEntry := range bav.ForbiddenPubKeyToForbiddenPubKeyEntry {
   200  		// Delete the existing mappings in the db for this ForbiddenPubKeyEntry. They will be re-added
   201  		// if the corresponding entry in memory has isDeleted=false.
   202  		if err := DbDeleteForbiddenBlockSignaturePubKeyWithTxn(
   203  			txn, forbiddenPubKeyEntry.PubKey[:]); err != nil {
   204  
   205  			return errors.Wrapf(
   206  				err, "_flushForbiddenPubKeyEntriesToDbWithTxn: Problem deleting "+
   207  					"forbidden public key: %v: ", &forbiddenPubKeyEntry.PubKey)
   208  		}
   209  	}
   210  	for _, forbiddenPubKeyEntry := range bav.ForbiddenPubKeyToForbiddenPubKeyEntry {
   211  		if forbiddenPubKeyEntry.isDeleted {
   212  			// If the ForbiddenPubKeyEntry has isDeleted=true then there's nothing to do because
   213  			// we already deleted the entry above.
   214  		} else {
   215  			// If the ForbiddenPubKeyEntry has (isDeleted = false) then we put the corresponding
   216  			// mappings for it into the db.
   217  			if err := DbPutForbiddenBlockSignaturePubKeyWithTxn(txn, forbiddenPubKeyEntry.PubKey); err != nil {
   218  				return err
   219  			}
   220  		}
   221  	}
   222  
   223  	return nil
   224  }
   225  
   226  func (bav *UtxoView) _flushBitcoinExchangeDataWithTxn(txn *badger.Txn) error {
   227  	// Iterate through our in-memory map. If anything has a value of false it means
   228  	// that particular mapping should be expunged from the db. If anything has a value
   229  	// of true it means that mapping should be added to the db.
   230  	for bitcoinBurnTxIDIter, mappingExists := range bav.BitcoinBurnTxIDs {
   231  		// Be paranoid and copy the iterator in case anything takes a reference below.
   232  		bitcoinBurnTxID := bitcoinBurnTxIDIter
   233  
   234  		if mappingExists {
   235  			// In this case we should add the mapping to the db.
   236  			if err := DbPutBitcoinBurnTxIDWithTxn(txn, &bitcoinBurnTxID); err != nil {
   237  				return errors.Wrapf(err, "UtxoView._flushBitcoinExchangeDataWithTxn: "+
   238  					"Problem putting BitcoinBurnTxID %v to db", &bitcoinBurnTxID)
   239  			}
   240  		} else {
   241  			// In this case we should delete the mapping from the db.
   242  			if err := DbDeleteBitcoinBurnTxIDWithTxn(txn, &bitcoinBurnTxID); err != nil {
   243  				return errors.Wrapf(err, "UtxoView._flushBitcoinExchangeDataWithTxn: "+
   244  					"Problem deleting BitcoinBurnTxID %v to db", &bitcoinBurnTxID)
   245  			}
   246  		}
   247  	}
   248  
   249  	// Update NanosPurchased
   250  	if err := DbPutNanosPurchasedWithTxn(txn, bav.NanosPurchased); err != nil {
   251  		errors.Wrapf(err, "UtxoView._flushBitcoinExchangeDataWithTxn: "+
   252  			"Problem putting NanosPurchased %d to db", bav.NanosPurchased)
   253  	}
   254  
   255  	// Update the BitcoinUSDExchangeRate in the db
   256  	if err := DbPutUSDCentsPerBitcoinExchangeRateWithTxn(txn, bav.USDCentsPerBitcoin); err != nil {
   257  		errors.Wrapf(err, "UtxoView.FlushToDBWithTxn: "+
   258  			"Problem putting USDCentsPerBitcoin %d to db", bav.USDCentsPerBitcoin)
   259  	}
   260  
   261  	// DB should be fully up to date as far as BitcoinBurnTxIDs and NanosPurchased go.
   262  	return nil
   263  }
   264  
   265  func (bav *UtxoView) _flushMessageEntriesToDbWithTxn(txn *badger.Txn) error {
   266  	// Go through all the entries in the MessageKeyToMessageEntry map.
   267  	for messageKeyIter, messageEntry := range bav.MessageKeyToMessageEntry {
   268  		// Make a copy of the iterator since we take references to it below.
   269  		messageKey := messageKeyIter
   270  
   271  		// Sanity-check that one of the MessageKey computed from the MEssageEntry is
   272  		// equal to the MessageKey that maps to that entry.
   273  		senderMessageKeyInEntry := MakeMessageKey(
   274  			messageEntry.SenderPublicKey, messageEntry.TstampNanos)
   275  		recipientMessageKeyInEntry := MakeMessageKey(
   276  			messageEntry.RecipientPublicKey, messageEntry.TstampNanos)
   277  		if senderMessageKeyInEntry != messageKey && recipientMessageKeyInEntry != messageKey {
   278  			return fmt.Errorf("_flushMessageEntriesToDbWithTxn: MessageEntry has "+
   279  				"SenderMessageKey: %v and RecipientMessageKey %v, neither of which match "+
   280  				"the MessageKeyToMessageEntry map key %v",
   281  				&senderMessageKeyInEntry, &recipientMessageKeyInEntry, &messageKey)
   282  		}
   283  
   284  		// Delete the existing mappings in the db for this MessageKey. They will be re-added
   285  		// if the corresponding entry in memory has isDeleted=false.
   286  		if err := DbDeleteMessageEntryMappingsWithTxn(
   287  			txn, messageKey.PublicKey[:], messageKey.TstampNanos); err != nil {
   288  
   289  			return errors.Wrapf(
   290  				err, "_flushMessageEntriesToDbWithTxn: Problem deleting mappings "+
   291  					"for MessageKey: %v: ", &messageKey)
   292  		}
   293  	}
   294  	// Go through all the entries in the MessageKeyToMessageEntry map.
   295  	for _, messageEntry := range bav.MessageKeyToMessageEntry {
   296  		if messageEntry.isDeleted {
   297  			// If the MessageEntry has isDeleted=true then there's nothing to do because
   298  			// we already deleted the entry above.
   299  		} else {
   300  			// If the MessageEntry has (isDeleted = false) then we put the corresponding
   301  			// mappings for it into the db.
   302  			if err := DbPutMessageEntryWithTxn(txn, messageEntry); err != nil {
   303  
   304  				return err
   305  			}
   306  		}
   307  	}
   308  
   309  	// At this point all of the MessageEntry mappings in the db should be up-to-date.
   310  
   311  	return nil
   312  }
   313  
   314  func (bav *UtxoView) _flushRepostEntriesToDbWithTxn(txn *badger.Txn) error {
   315  
   316  	// Go through all the entries in the repostKeyTorepostEntry map.
   317  	for repostKeyIter, repostEntry := range bav.RepostKeyToRepostEntry {
   318  		// Make a copy of the iterator since we make references to it below.
   319  		repostKey := repostKeyIter
   320  
   321  		// Sanity-check that the RepostKey computed from the RepostEntry is
   322  		// equal to the RepostKey that maps to that entry.
   323  		repostKeyInEntry := MakeRepostKey(repostEntry.ReposterPubKey, *repostEntry.RepostedPostHash)
   324  		if repostKeyInEntry != repostKey {
   325  			return fmt.Errorf("_flushRepostEntriesToDbWithTxn: RepostEntry has "+
   326  				"RepostKey: %v, which doesn't match the RepostKeyToRepostEntry map key %v",
   327  				&repostKeyInEntry, &repostKey)
   328  		}
   329  
   330  		// Delete the existing mappings in the db for this RepostKey. They will be re-added
   331  		// if the corresponding entry in memory has isDeleted=false.
   332  		if err := DbDeleteRepostMappingsWithTxn(
   333  			txn, repostKey.ReposterPubKey[:], repostKey.RepostedPostHash); err != nil {
   334  
   335  			return errors.Wrapf(
   336  				err, "_flushRepostEntriesToDbWithTxn: Problem deleting mappings "+
   337  					"for RepostKey: %v: ", &repostKey)
   338  		}
   339  	}
   340  	for _, repostEntry := range bav.RepostKeyToRepostEntry {
   341  		if repostEntry.isDeleted {
   342  			// If the RepostedEntry has isDeleted=true then there's nothing to do because
   343  			// we already deleted the entry above.
   344  		} else {
   345  			// If the RepostEntry has (isDeleted = false) then we put the corresponding
   346  			// mappings for it into the db.
   347  			if err := DbPutRepostMappingsWithTxn(
   348  				txn, repostEntry.ReposterPubKey, *repostEntry.RepostedPostHash, *repostEntry); err != nil {
   349  				return err
   350  			}
   351  		}
   352  	}
   353  
   354  	// At this point all of the RepostEntry mappings in the db should be up-to-date.
   355  
   356  	return nil
   357  }
   358  
   359  func (bav *UtxoView) _flushLikeEntriesToDbWithTxn(txn *badger.Txn) error {
   360  
   361  	// Go through all the entries in the LikeKeyToLikeEntry map.
   362  	for likeKeyIter, likeEntry := range bav.LikeKeyToLikeEntry {
   363  		// Make a copy of the iterator since we make references to it below.
   364  		likeKey := likeKeyIter
   365  
   366  		// Sanity-check that the LikeKey computed from the LikeEntry is
   367  		// equal to the LikeKey that maps to that entry.
   368  		likeKeyInEntry := MakeLikeKey(likeEntry.LikerPubKey, *likeEntry.LikedPostHash)
   369  		if likeKeyInEntry != likeKey {
   370  			return fmt.Errorf("_flushLikeEntriesToDbWithTxn: LikeEntry has "+
   371  				"LikeKey: %v, which doesn't match the LikeKeyToLikeEntry map key %v",
   372  				&likeKeyInEntry, &likeKey)
   373  		}
   374  
   375  		// Delete the existing mappings in the db for this LikeKey. They will be re-added
   376  		// if the corresponding entry in memory has isDeleted=false.
   377  		if err := DbDeleteLikeMappingsWithTxn(
   378  			txn, likeKey.LikerPubKey[:], likeKey.LikedPostHash); err != nil {
   379  
   380  			return errors.Wrapf(
   381  				err, "_flushLikeEntriesToDbWithTxn: Problem deleting mappings "+
   382  					"for LikeKey: %v: ", &likeKey)
   383  		}
   384  	}
   385  
   386  	// Go through all the entries in the LikeKeyToLikeEntry map.
   387  	for _, likeEntry := range bav.LikeKeyToLikeEntry {
   388  
   389  		if likeEntry.isDeleted {
   390  			// If the LikeEntry has isDeleted=true then there's nothing to do because
   391  			// we already deleted the entry above.
   392  		} else {
   393  			// If the LikeEntry has (isDeleted = false) then we put the corresponding
   394  			// mappings for it into the db.
   395  			if err := DbPutLikeMappingsWithTxn(
   396  				txn, likeEntry.LikerPubKey, *likeEntry.LikedPostHash); err != nil {
   397  
   398  				return err
   399  			}
   400  		}
   401  	}
   402  
   403  	return nil
   404  }
   405  
   406  func (bav *UtxoView) _flushFollowEntriesToDbWithTxn(txn *badger.Txn) error {
   407  
   408  	// Go through all the entries in the FollowKeyToFollowEntry map.
   409  	for followKeyIter, followEntry := range bav.FollowKeyToFollowEntry {
   410  		// Make a copy of the iterator since we make references to it below.
   411  		followKey := followKeyIter
   412  
   413  		// Sanity-check that the FollowKey computed from the FollowEntry is
   414  		// equal to the FollowKey that maps to that entry.
   415  		followKeyInEntry := MakeFollowKey(
   416  			followEntry.FollowerPKID, followEntry.FollowedPKID)
   417  		if followKeyInEntry != followKey {
   418  			return fmt.Errorf("_flushFollowEntriesToDbWithTxn: FollowEntry has "+
   419  				"FollowKey: %v, which doesn't match the FollowKeyToFollowEntry map key %v",
   420  				&followKeyInEntry, &followKey)
   421  		}
   422  
   423  		// Delete the existing mappings in the db for this FollowKey. They will be re-added
   424  		// if the corresponding entry in memory has isDeleted=false.
   425  		if err := DbDeleteFollowMappingsWithTxn(
   426  			txn, followEntry.FollowerPKID, followEntry.FollowedPKID); err != nil {
   427  
   428  			return errors.Wrapf(
   429  				err, "_flushFollowEntriesToDbWithTxn: Problem deleting mappings "+
   430  					"for FollowKey: %v: ", &followKey)
   431  		}
   432  	}
   433  
   434  	// Go through all the entries in the FollowKeyToFollowEntry map.
   435  	for _, followEntry := range bav.FollowKeyToFollowEntry {
   436  		if followEntry.isDeleted {
   437  			// If the FollowEntry has isDeleted=true then there's nothing to do because
   438  			// we already deleted the entry above.
   439  		} else {
   440  			// If the FollowEntry has (isDeleted = false) then we put the corresponding
   441  			// mappings for it into the db.
   442  			if err := DbPutFollowMappingsWithTxn(
   443  				txn, followEntry.FollowerPKID, followEntry.FollowedPKID); err != nil {
   444  
   445  				return err
   446  			}
   447  		}
   448  	}
   449  
   450  	return nil
   451  }
   452  
   453  func (bav *UtxoView) _flushNFTEntriesToDbWithTxn(txn *badger.Txn) error {
   454  
   455  	// Go through and delete all the entries so they can be added back fresh.
   456  	for nftKeyIter, nftEntry := range bav.NFTKeyToNFTEntry {
   457  		// Make a copy of the iterator since we make references to it below.
   458  		nftKey := nftKeyIter
   459  
   460  		// Sanity-check that the NFTKey computed from the NFTEntry is
   461  		// equal to the NFTKey that maps to that entry.
   462  		nftKeyInEntry := MakeNFTKey(nftEntry.NFTPostHash, nftEntry.SerialNumber)
   463  		if nftKeyInEntry != nftKey {
   464  			return fmt.Errorf("_flushNFTEntriesToDbWithTxn: NFTEntry has "+
   465  				"NFTKey: %v, which doesn't match the NFTKeyToNFTEntry map key %v",
   466  				&nftKeyInEntry, &nftKey)
   467  		}
   468  
   469  		// Delete the existing mappings in the db for this NFTKey. They will be re-added
   470  		// if the corresponding entry in memory has isDeleted=false.
   471  		if err := DBDeleteNFTMappingsWithTxn(txn, nftEntry.NFTPostHash, nftEntry.SerialNumber); err != nil {
   472  
   473  			return errors.Wrapf(
   474  				err, "_flushNFTEntriesToDbWithTxn: Problem deleting mappings "+
   475  					"for NFTKey: %v: ", &nftKey)
   476  		}
   477  	}
   478  
   479  	// Add back all of the entries that aren't deleted.
   480  	for _, nftEntry := range bav.NFTKeyToNFTEntry {
   481  		if nftEntry.isDeleted {
   482  			// If the NFTEntry has isDeleted=true then there's nothing to do because
   483  			// we already deleted the entry above.
   484  		} else {
   485  			// If the NFTEntry has (isDeleted = false) then we put the corresponding
   486  			// mappings for it into the db.
   487  			if err := DBPutNFTEntryMappingsWithTxn(txn, nftEntry); err != nil {
   488  				return err
   489  			}
   490  		}
   491  	}
   492  
   493  	return nil
   494  }
   495  
   496  func (bav *UtxoView) _flushAcceptedBidEntriesToDbWithTxn(txn *badger.Txn) error {
   497  
   498  	// Go through and delete all the entries so they can be added back fresh.
   499  	for nftKeyIter, _ := range bav.NFTKeyToAcceptedNFTBidHistory {
   500  		// Make a copy of the iterator since we make references to it below.
   501  		nftKey := nftKeyIter
   502  
   503  		// We skip the standard sanity check.  Since it is possible to accept a bid on serial number 0, it is possible
   504  		// that none of the accepted bids have the same serial number as the key.
   505  
   506  		// Delete the existing mappings in the db for this NFTKey. They will be re-added
   507  		// if the corresponding entry in memory has isDeleted=false.
   508  		if err := DBDeleteAcceptedNFTBidEntriesMappingsWithTxn(txn, &nftKey.NFTPostHash, nftKey.SerialNumber); err != nil {
   509  
   510  			return errors.Wrapf(
   511  				err, "_flushAcceptedBidEntriesToDbWithTxn: Problem deleting mappings "+
   512  					"for NFTKey: %v: ", &nftKey)
   513  		}
   514  	}
   515  
   516  	// Add back all of the entries that aren't nil or of length 0
   517  	for nftKey, acceptedNFTBidEntries := range bav.NFTKeyToAcceptedNFTBidHistory {
   518  		if acceptedNFTBidEntries == nil || len(*acceptedNFTBidEntries) == 0 {
   519  			// If the acceptedNFTBidEntries is nil or has length 0 then there's nothing to do because
   520  			// we already deleted the entry above. length 0 means that there are no accepted bids yet.
   521  		} else {
   522  			// If the NFTEntry has (isDeleted = false) then we put the corresponding
   523  			// mappings for it into the db.
   524  			if err := DBPutAcceptedNFTBidEntriesMappingWithTxn(txn, nftKey, acceptedNFTBidEntries); err != nil {
   525  				return err
   526  			}
   527  		}
   528  	}
   529  
   530  	return nil
   531  }
   532  
   533  func (bav *UtxoView) _flushNFTBidEntriesToDbWithTxn(txn *badger.Txn) error {
   534  
   535  	// Go through and delete all the entries so they can be added back fresh.
   536  	for nftBidKeyIter, nftBidEntry := range bav.NFTBidKeyToNFTBidEntry {
   537  		// Make a copy of the iterator since we make references to it below.
   538  		nftBidKey := nftBidKeyIter
   539  
   540  		// Sanity-check that the NFTBidKey computed from the NFTBidEntry is
   541  		// equal to the NFTBidKey that maps to that entry.
   542  		nftBidKeyInEntry := MakeNFTBidKey(
   543  			nftBidEntry.BidderPKID, nftBidEntry.NFTPostHash, nftBidEntry.SerialNumber)
   544  		if nftBidKeyInEntry != nftBidKey {
   545  			return fmt.Errorf("_flushNFTBidEntriesToDbWithTxn: NFTBidEntry has "+
   546  				"NFTBidKey: %v, which doesn't match the NFTBidKeyToNFTEntry map key %v",
   547  				&nftBidKeyInEntry, &nftBidKey)
   548  		}
   549  
   550  		// Delete the existing mappings in the db for this NFTBidKey. They will be re-added
   551  		// if the corresponding entry in memory has isDeleted=false.
   552  		if err := DBDeleteNFTBidMappingsWithTxn(txn, &nftBidKey); err != nil {
   553  
   554  			return errors.Wrapf(
   555  				err, "_flushNFTBidEntriesToDbWithTxn: Problem deleting mappings "+
   556  					"for NFTBidKey: %v: ", &nftBidKey)
   557  		}
   558  	}
   559  
   560  	// Add back all of the entries that aren't deleted.
   561  	for _, nftBidEntry := range bav.NFTBidKeyToNFTBidEntry {
   562  		if nftBidEntry.isDeleted {
   563  			// If the NFTEntry has isDeleted=true then there's nothing to do because
   564  			// we already deleted the entry above.
   565  		} else {
   566  			// If the NFTEntry has (isDeleted = false) then we put the corresponding
   567  			// mappings for it into the db.
   568  			if err := DBPutNFTBidEntryMappingsWithTxn(txn, nftBidEntry); err != nil {
   569  				return err
   570  			}
   571  		}
   572  	}
   573  
   574  	return nil
   575  }
   576  
   577  func (bav *UtxoView) _flushDiamondEntriesToDbWithTxn(txn *badger.Txn) error {
   578  
   579  	// Go through and delete all the entries so they can be added back fresh.
   580  	for diamondKeyIter, diamondEntry := range bav.DiamondKeyToDiamondEntry {
   581  		// Make a copy of the iterator since we make references to it below.
   582  		diamondKey := diamondKeyIter
   583  
   584  		// Sanity-check that the DiamondKey computed from the DiamondEntry is
   585  		// equal to the DiamondKey that maps to that entry.
   586  		diamondKeyInEntry := MakeDiamondKey(
   587  			diamondEntry.SenderPKID, diamondEntry.ReceiverPKID, diamondEntry.DiamondPostHash)
   588  		if diamondKeyInEntry != diamondKey {
   589  			return fmt.Errorf("_flushDiamondEntriesToDbWithTxn: DiamondEntry has "+
   590  				"DiamondKey: %v, which doesn't match the DiamondKeyToDiamondEntry map key %v",
   591  				&diamondKeyInEntry, &diamondKey)
   592  		}
   593  
   594  		// Delete the existing mappings in the db for this DiamondKey. They will be re-added
   595  		// if the corresponding entry in memory has isDeleted=false.
   596  		if err := DbDeleteDiamondMappingsWithTxn(txn, diamondEntry); err != nil {
   597  
   598  			return errors.Wrapf(
   599  				err, "_flushDiamondEntriesToDbWithTxn: Problem deleting mappings "+
   600  					"for DiamondKey: %v: ", &diamondKey)
   601  		}
   602  	}
   603  
   604  	// Add back all of the entries that aren't deleted.
   605  	for _, diamondEntry := range bav.DiamondKeyToDiamondEntry {
   606  		if diamondEntry.isDeleted {
   607  			// If the DiamondEntry has isDeleted=true then there's nothing to do because
   608  			// we already deleted the entry above.
   609  		} else {
   610  			// If the DiamondEntry has (isDeleted = false) then we put the corresponding
   611  			// mappings for it into the db.
   612  			if err := DbPutDiamondMappingsWithTxn(
   613  				txn,
   614  				diamondEntry); err != nil {
   615  				return err
   616  			}
   617  		}
   618  	}
   619  
   620  	// At this point all of the MessageEntry mappings in the db should be up-to-date.
   621  
   622  	return nil
   623  }
   624  
   625  func (bav *UtxoView) _flushPostEntriesToDbWithTxn(txn *badger.Txn) error {
   626  	// TODO(DELETEME): Remove flush logging after debugging MarkBlockInvalid bug.
   627  	glog.V(1).Infof("_flushPostEntriesToDbWithTxn: flushing %d mappings", len(bav.PostHashToPostEntry))
   628  
   629  	// Go through all the entries in the PostHashToPostEntry map.
   630  	for postHashIter, postEntry := range bav.PostHashToPostEntry {
   631  		// Make a copy of the iterator since we take references to it below.
   632  		postHash := postHashIter
   633  
   634  		// Sanity-check that the hash in the post is the same as the hash in the
   635  		// entry
   636  		if postHash != *postEntry.PostHash {
   637  			return fmt.Errorf("_flushPostEntriesToDbWithTxn: PostEntry has "+
   638  				"PostHash: %v, neither of which match "+
   639  				"the PostHashToPostEntry map key %v",
   640  				postHash, postEntry.PostHash)
   641  		}
   642  
   643  		// Delete the existing mappings in the db for this PostHash. They will be re-added
   644  		// if the corresponding entry in memory has isDeleted=false.
   645  		if err := DBDeletePostEntryMappingsWithTxn(txn, &postHash, bav.Params); err != nil {
   646  			return errors.Wrapf(
   647  				err, "_flushPostEntriesToDbWithTxn: Problem deleting mappings "+
   648  					"for PostHash: %v: ", postHash)
   649  		}
   650  	}
   651  	numDeleted := 0
   652  	numPut := 0
   653  	for _, postEntry := range bav.PostHashToPostEntry {
   654  		if postEntry.isDeleted {
   655  			numDeleted++
   656  			// If the PostEntry has isDeleted=true then there's nothing to do because
   657  			// we already deleted the entry above.
   658  		} else {
   659  			numPut++
   660  			// If the PostEntry has (isDeleted = false) then we put the corresponding
   661  			// mappings for it into the db.
   662  			if err := DBPutPostEntryMappingsWithTxn(txn, postEntry, bav.Params); err != nil {
   663  
   664  				return err
   665  			}
   666  		}
   667  	}
   668  
   669  	// TODO(DELETEME): Remove flush logging after debugging MarkBlockInvalid bug.
   670  	glog.V(1).Infof("_flushPostEntriesToDbWithTxn: deleted %d mappings, put %d mappings", numDeleted, numPut)
   671  
   672  	// At this point all of the PostEntry mappings in the db should be up-to-date.
   673  
   674  	return nil
   675  }
   676  func (bav *UtxoView) _flushPKIDEntriesToDbWithTxn(txn *badger.Txn) error {
   677  	for pubKeyIter, pkidEntry := range bav.PublicKeyToPKIDEntry {
   678  		pubKeyCopy := make([]byte, btcec.PubKeyBytesLenCompressed)
   679  		copy(pubKeyCopy, pubKeyIter[:])
   680  
   681  		// Delete the existing mappings in the db for this PKID. They will be re-added
   682  		// if the corresponding entry in memory has isDeleted=false.
   683  		if err := DBDeletePKIDMappingsWithTxn(txn, pubKeyCopy, bav.Params); err != nil {
   684  			return errors.Wrapf(
   685  				err, "_flushPKIDEntriesToDbWithTxn: Problem deleting mappings "+
   686  					"for pkid: %v, public key: %v: ", PkToString(pkidEntry.PKID[:], bav.Params),
   687  				PkToString(pubKeyCopy, bav.Params))
   688  		}
   689  	}
   690  
   691  	// Go through all the entries in the ProfilePublicKeyToProfileEntry map.
   692  	for pubKeyIter, pkidEntry := range bav.PublicKeyToPKIDEntry {
   693  		pubKeyCopy := make([]byte, btcec.PubKeyBytesLenCompressed)
   694  		copy(pubKeyCopy, pubKeyIter[:])
   695  
   696  		if pkidEntry.isDeleted {
   697  			// If the ProfileEntry has isDeleted=true then there's nothing to do because
   698  			// we already deleted the entry above.
   699  		} else {
   700  			// Sanity-check that the public key in the entry matches the public key in
   701  			// the mapping.
   702  			if !reflect.DeepEqual(pubKeyCopy, pkidEntry.PublicKey) {
   703  				return fmt.Errorf("_flushPKIDEntriesToDbWithTxn: Sanity-check failed. "+
   704  					"Public key in entry %v does not match public key in mapping %v ",
   705  					PkToString(pkidEntry.PublicKey[:], bav.Params),
   706  					PkToString(pubKeyCopy, bav.Params))
   707  			}
   708  			// Sanity-check that the mapping in the public key map lines up with the mapping
   709  			// in the PKID map.
   710  			if _, pkidEntryExists := bav.PKIDToPublicKey[*pkidEntry.PKID]; !pkidEntryExists {
   711  				return fmt.Errorf("_flushPKIDEntriesToDbWithTxn: Sanity-check failed. "+
   712  					"PKID %v for public key %v does not exist in PKIDToPublicKey map.",
   713  					PkToString(pkidEntry.PKID[:], bav.Params),
   714  					PkToString(pubKeyCopy, bav.Params))
   715  			}
   716  
   717  			// If the ProfileEntry has (isDeleted = false) then we put the corresponding
   718  			// mappings for it into the db.
   719  			if err := DBPutPKIDMappingsWithTxn(txn, pubKeyCopy, pkidEntry, bav.Params); err != nil {
   720  				return err
   721  			}
   722  		}
   723  	}
   724  
   725  	// At this point all of the PKIDEntry mappings in the db should be up-to-date.
   726  	return nil
   727  }
   728  
   729  func (bav *UtxoView) _flushProfileEntriesToDbWithTxn(txn *badger.Txn) error {
   730  	glog.V(1).Infof("_flushProfilesToDbWithTxn: flushing %d mappings", len(bav.ProfilePKIDToProfileEntry))
   731  
   732  	// Go through all the entries in the ProfilePublicKeyToProfileEntry map.
   733  	for profilePKIDIter, profileEntry := range bav.ProfilePKIDToProfileEntry {
   734  		// Make a copy of the iterator since we take references to it below.
   735  		profilePKID := profilePKIDIter
   736  
   737  		// Delete the existing mappings in the db for this PKID. They will be re-added
   738  		// if the corresponding entry in memory has isDeleted=false.
   739  		if err := DBDeleteProfileEntryMappingsWithTxn(txn, &profilePKID, bav.Params); err != nil {
   740  			return errors.Wrapf(
   741  				err, "_flushProfileEntriesToDbWithTxn: Problem deleting mappings "+
   742  					"for pkid: %v, public key: %v: ", PkToString(profilePKID[:], bav.Params),
   743  				PkToString(profileEntry.PublicKey, bav.Params))
   744  		}
   745  	}
   746  	numDeleted := 0
   747  	numPut := 0
   748  	for profilePKIDIter, profileEntry := range bav.ProfilePKIDToProfileEntry {
   749  		// Make a copy of the iterator since we take references to it below.
   750  		profilePKID := profilePKIDIter
   751  
   752  		if profileEntry.isDeleted {
   753  			numDeleted++
   754  			// If the ProfileEntry has isDeleted=true then there's nothing to do because
   755  			// we already deleted the entry above.
   756  		} else {
   757  			numPut++
   758  			// Get the PKID according to another map in the view and
   759  			// sanity-check that it lines up.
   760  			viewPKIDEntry := bav.GetPKIDForPublicKey(profileEntry.PublicKey)
   761  			if viewPKIDEntry == nil || viewPKIDEntry.isDeleted || *viewPKIDEntry.PKID != profilePKID {
   762  				return fmt.Errorf("_flushProfileEntriesToDbWithTxn: Sanity-check failed: PKID %v does "+
   763  					"not exist in view mapping for profile with public key %v",
   764  					PkToString(profilePKID[:], bav.Params),
   765  					PkToString(profileEntry.PublicKey, bav.Params))
   766  			}
   767  
   768  			// If the ProfileEntry has (isDeleted = false) then we put the corresponding
   769  			// mappings for it into the db.
   770  			if err := DBPutProfileEntryMappingsWithTxn(
   771  				txn, profileEntry, &profilePKID, bav.Params); err != nil {
   772  
   773  				return err
   774  			}
   775  		}
   776  	}
   777  
   778  	glog.V(1).Infof("_flushProfilesToDbWithTxn: deleted %d mappings, put %d mappings", numDeleted, numPut)
   779  
   780  	// At this point all of the PostEntry mappings in the db should be up-to-date.
   781  
   782  	return nil
   783  }
   784  
   785  func (bav *UtxoView) _flushBalanceEntriesToDbWithTxn(txn *badger.Txn) error {
   786  	glog.V(1).Infof("_flushBalanceEntriesToDbWithTxn: flushing %d mappings", len(bav.HODLerPKIDCreatorPKIDToBalanceEntry))
   787  
   788  	// Go through all the entries in the HODLerPubKeyCreatorPubKeyToBalanceEntry map.
   789  	for balanceKeyIter, balanceEntry := range bav.HODLerPKIDCreatorPKIDToBalanceEntry {
   790  		// Make a copy of the iterator since we take references to it below.
   791  		balanceKey := balanceKeyIter
   792  
   793  		// Sanity-check that the balance key in the map is the same
   794  		// as the public key in the entry.
   795  		computedBalanceKey := MakeCreatorCoinBalanceKey(
   796  			balanceEntry.HODLerPKID, balanceEntry.CreatorPKID)
   797  		if !reflect.DeepEqual(balanceKey, computedBalanceKey) {
   798  			return fmt.Errorf("_flushBalanceEntriesToDbWithTxn: BalanceEntry has "+
   799  				"map key: %v which does not match match "+
   800  				"the HODLerPubKeyCreatorPubKeyToBalanceEntry map key %v",
   801  				balanceKey, computedBalanceKey)
   802  		}
   803  
   804  		// Delete the existing mappings in the db for this balance key. They will be re-added
   805  		// if the corresponding entry in memory has isDeleted=false.
   806  		if err := DBDeleteCreatorCoinBalanceEntryMappingsWithTxn(
   807  			txn, &(balanceKey.HODLerPKID), &(balanceKey.CreatorPKID), bav.Params); err != nil {
   808  
   809  			return errors.Wrapf(
   810  				err, "_flushBalanceEntriesToDbWithTxn: Problem deleting mappings "+
   811  					"for public key: %v: ", balanceKey)
   812  		}
   813  	}
   814  	numDeleted := 0
   815  	numPut := 0
   816  	// Go through all the entries in the HODLerPubKeyCreatorPubKeyToBalanceEntry map.
   817  	for _, balanceEntry := range bav.HODLerPKIDCreatorPKIDToBalanceEntry {
   818  		// Make a copy of the iterator since we take references to it below.
   819  		if balanceEntry.isDeleted {
   820  			numDeleted++
   821  			// If the ProfileEntry has isDeleted=true then there's nothing to do because
   822  			// we already deleted the entry above.
   823  		} else {
   824  			numPut++
   825  			// If the ProfileEntry has (isDeleted = false) then we put the corresponding
   826  			// mappings for it into the db.
   827  			if err := DBPutCreatorCoinBalanceEntryMappingsWithTxn(
   828  				txn, balanceEntry, bav.Params); err != nil {
   829  
   830  				return err
   831  			}
   832  		}
   833  	}
   834  
   835  	glog.V(1).Infof("_flushBalanceEntriesToDbWithTxn: deleted %d mappings, put %d mappings", numDeleted, numPut)
   836  
   837  	// At this point all of the PostEntry mappings in the db should be up-to-date.
   838  
   839  	return nil
   840  }
   841  
   842  func (bav *UtxoView) _flushDerivedKeyEntryToDbWithTxn(txn *badger.Txn) error {
   843  	glog.V(1).Infof("_flushDerivedKeyEntryToDbWithTxn: flushing %d mappings", len(bav.DerivedKeyToDerivedEntry))
   844  
   845  	// Go through all entries in the DerivedKeyToDerivedEntry map and add them to the DB.
   846  	for derivedKeyMapKey, derivedKeyEntry := range bav.DerivedKeyToDerivedEntry {
   847  		// Delete the existing mapping in the DB for this map key, this will be re-added
   848  		// later if isDeleted=false.
   849  		if err := DBDeleteDerivedKeyMappingWithTxn(txn, derivedKeyMapKey.OwnerPublicKey,
   850  			derivedKeyMapKey.DerivedPublicKey); err != nil {
   851  			return errors.Wrapf(err, "UtxoView._flushDerivedKeyEntryToDbWithTxn: "+
   852  				"Problem deleting DerivedKeyEntry %v from db", *derivedKeyEntry)
   853  		}
   854  
   855  		numDeleted := 0
   856  		numPut := 0
   857  		if derivedKeyEntry.isDeleted {
   858  			// Since entry is deleted, there's nothing to do.
   859  			numDeleted++
   860  		} else {
   861  			// In this case we add the mapping to the DB.
   862  			if err := DBPutDerivedKeyMappingWithTxn(txn, derivedKeyMapKey.OwnerPublicKey,
   863  				derivedKeyMapKey.DerivedPublicKey, derivedKeyEntry); err != nil {
   864  				return errors.Wrapf(err, "UtxoView._flushDerivedKeyEntryToDbWithTxn: "+
   865  					"Problem putting DerivedKeyEntry %v to db", *derivedKeyEntry)
   866  			}
   867  			numPut++
   868  		}
   869  		glog.V(1).Infof("_flushDerivedKeyEntryToDbWithTxn: deleted %d mappings, put %d mappings", numDeleted, numPut)
   870  	}
   871  
   872  	return nil
   873  }