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

     1  package lib
     2  
     3  import (
     4  	"container/heap"
     5  	"container/list"
     6  	"encoding/hex"
     7  	"encoding/json"
     8  	"fmt"
     9  	"github.com/btcsuite/btcutil"
    10  	"github.com/gernest/mention"
    11  	"log"
    12  	"math"
    13  	"os"
    14  	"path/filepath"
    15  	"regexp"
    16  	"sort"
    17  	"strings"
    18  	"sync/atomic"
    19  	"time"
    20  
    21  	"github.com/dgraph-io/badger/v3"
    22  
    23  	"github.com/btcsuite/btcd/btcec"
    24  	"github.com/deso-protocol/go-deadlock"
    25  	"github.com/golang/glog"
    26  	"github.com/pkg/errors"
    27  )
    28  
    29  // mempool.go contains all of the mempool logic for the DeSo node.
    30  
    31  const (
    32  	// MaxTotalTransactionSizeBytes is the maximum number of bytes the pool can store
    33  	// across all of its transactions. Once this limit is reached, transactions must
    34  	// be evicted from the pool based on their feerate before new transactions can be
    35  	// added.
    36  	MaxTotalTransactionSizeBytes = 250000000 // 250MB
    37  
    38  	// UnconnectedTxnExpirationInterval is how long we wait before automatically removing an
    39  	// unconnected transaction.
    40  	UnconnectedTxnExpirationInterval = time.Minute * 5
    41  
    42  	// The maximum number of unconnected transactions the pool will store.
    43  	MaxUnconnectedTransactions = 10000
    44  
    45  	// The maximum number of bytes a single unconnected transaction can take up
    46  	MaxUnconnectedTxSizeBytes = 100000
    47  )
    48  
    49  var (
    50  	// The readOnlyUtxoView will update after the number of seconds specified here OR
    51  	// the number of transactions specified here, whichever comes first. An update
    52  	// resets both counters.
    53  	//
    54  	// We make these vars rather than const for testing
    55  	ReadOnlyUtxoViewRegenerationIntervalSeconds = float64(1.0)
    56  	ReadOnlyUtxoViewRegenerationIntervalTxns    = int64(1000)
    57  
    58  	// LowFeeTxLimitBytesPerTenMinutes defines the number of bytes per 10 minutes of "low fee"
    59  	// transactions the mempool will tolerate before it starts rejecting transactions
    60  	// that fail to meet the MinTxFeePerKBNanos threshold.
    61  	LowFeeTxLimitBytesPerTenMinutes = 150000 // Allow 150KB per minute in low-fee txns.
    62  )
    63  
    64  // MempoolTx contains a transaction along with additional metadata like the
    65  // fee and time added.
    66  type MempoolTx struct {
    67  	Tx *MsgDeSoTxn
    68  
    69  	// TxMeta is the transaction metadata
    70  	TxMeta *TransactionMetadata
    71  
    72  	// Hash is a hash of the transaction so we don't have to recompute
    73  	// it all the time.
    74  	Hash *BlockHash
    75  
    76  	// TxSizeBytes is the cached size of the transaction.
    77  	TxSizeBytes uint64
    78  
    79  	// The time when the txn was added to the pool
    80  	Added time.Time
    81  
    82  	// The block height when the txn was added to the pool. It's generally set
    83  	// to tip+1.
    84  	Height uint32
    85  
    86  	// The total fee the txn pays. Cached for efficiency reasons.
    87  	Fee uint64
    88  
    89  	// The fee rate of the transaction in nanos per KB.
    90  	FeePerKB uint64
    91  
    92  	// index is used by the heap logic to allow for modification in-place.
    93  	index int
    94  }
    95  
    96  // Summary stats for a set of transactions of a specific type in the mempool.
    97  type SummaryStats struct {
    98  	// Number of transactions of this type in the mempool.
    99  	Count uint32
   100  
   101  	// Number of bytes for transactions of this type in the mempool.
   102  	TotalBytes uint64
   103  }
   104  
   105  func (mempoolTx *MempoolTx) String() string {
   106  	return fmt.Sprintf("< Added: %v, index: %d, Fee: %d, Type: %v, Hash: %v", mempoolTx.Added, mempoolTx.index, mempoolTx.Fee, mempoolTx.Tx.TxnMeta.GetTxnType(), mempoolTx.Hash)
   107  }
   108  
   109  // MempoolTxFeeMinHeap is a priority queue based on transaction fee rate
   110  type MempoolTxFeeMinHeap []*MempoolTx
   111  
   112  func (pq MempoolTxFeeMinHeap) Len() int { return len(pq) }
   113  
   114  func (pq MempoolTxFeeMinHeap) Less(i, j int) bool {
   115  	// We want Pop to give us the lowest-fee transactions so we use < here.
   116  	return pq[i].FeePerKB < pq[j].FeePerKB
   117  }
   118  
   119  func (pq MempoolTxFeeMinHeap) Swap(i, j int) {
   120  	pq[i], pq[j] = pq[j], pq[i]
   121  	pq[i].index = i
   122  	pq[j].index = j
   123  }
   124  
   125  func (pq *MempoolTxFeeMinHeap) Push(x interface{}) {
   126  	n := len(*pq)
   127  	item := x.(*MempoolTx)
   128  	item.index = n
   129  	*pq = append(*pq, item)
   130  }
   131  
   132  func (pq *MempoolTxFeeMinHeap) Pop() interface{} {
   133  	old := *pq
   134  	n := len(old)
   135  	item := old[n-1]
   136  	old[n-1] = nil  // avoid memory leak
   137  	item.index = -1 // for safety
   138  	*pq = old[0 : n-1]
   139  	return item
   140  }
   141  
   142  // UnconnectedTx is a transaction that has dependencies that we haven't added yet.
   143  type UnconnectedTx struct {
   144  	tx *MsgDeSoTxn
   145  	// The ID of the Peer who initially sent the unconnected txn. Useful for
   146  	// removing unconnected transactions when a Peer disconnects.
   147  	peerID     uint64
   148  	expiration time.Time
   149  }
   150  
   151  // DeSoMempool is the core mempool object. It's what any outside service should use
   152  // to aggregate transactions and mine them into blocks.
   153  type DeSoMempool struct {
   154  	// Stops the mempool's services.
   155  	quit chan struct{}
   156  
   157  	// A reference to a blockchain object that can be used to validate transactions before
   158  	// adding them to the pool.
   159  	bc *Blockchain
   160  
   161  	// Transactions with a feerate below this threshold are outright rejected.
   162  	minFeeRateNanosPerKB uint64
   163  
   164  	// rateLimitFeeRateNanosPerKB defines the minimum transaction feerate in "nanos per KB"
   165  	// before a transaction is considered for rate-limiting. Note that even if a
   166  	// transaction with a feerate below this threshold is not rate-limited, it must
   167  	// still have a high enough feerate to be considered as part of the mempool.
   168  	rateLimitFeeRateNanosPerKB uint64
   169  
   170  	mtx deadlock.RWMutex
   171  
   172  	// poolMap contains all of the transactions that have been validated by the pool.
   173  	// Transactions in poolMap should be directly consumable by a miner and formed into
   174  	// a block by taking them in order of when they were Added.
   175  	poolMap map[BlockHash]*MempoolTx
   176  	// txFeeMinHeap organizes transactions stored in poolMap by their FeePerKB. It is used
   177  	// in order to prevent the pool from exhausing memory due to having to store too
   178  	// many low-fee transactions.
   179  	txFeeMinheap MempoolTxFeeMinHeap
   180  	// totalTxSizeBytes is the total size of all of the transactions stored in poolMap. We
   181  	// use it to determine when the pool is nearing memory-exhaustion so we can start
   182  	// evicting transactions.
   183  	totalTxSizeBytes uint64
   184  	// Stores the inputs for every transaction stored in poolMap. Used to quickly check
   185  	// if a transaction is double-spending.
   186  	outpoints map[UtxoKey]*MsgDeSoTxn
   187  	// Unconnected contains transactions whose inputs reference UTXOs that are not yet
   188  	// present in either our UTXO database or the transactions stored in pool.
   189  	unconnectedTxns map[BlockHash]*UnconnectedTx
   190  	// Organizes unconnectedTxns by their UTXOs. Used when adding a transaction to determine
   191  	// which unconnectedTxns are no longer missing parents.
   192  	unconnectedTxnsByPrev map[UtxoKey]map[BlockHash]*MsgDeSoTxn
   193  	// An exponentially-decayed accumulator of "low-fee" transactions we've relayed.
   194  	// This is used to prevent someone from flooding the network with low-fee
   195  	// transactions.
   196  	lowFeeTxSizeAccumulator float64
   197  	// The UNIX time (in seconds) when the last "low-fee" transaction was relayed.
   198  	lastLowFeeTxUnixTime int64
   199  
   200  	// pubKeyToTxnMap stores a mapping from the public key of outputs added
   201  	// to the mempool to the corresponding transaction that resulted in their
   202  	// addition. It is useful for figuring out how much DeSo a particular public
   203  	// key has available to spend.
   204  	pubKeyToTxnMap map[PkMapKey]map[BlockHash]*MempoolTx
   205  
   206  	// The next time the unconnectTxn pool will be scanned for expired unconnectedTxns.
   207  	nextExpireScan time.Time
   208  
   209  	// Optional. When set, we use the BlockCypher API to detect double-spends.
   210  	blockCypherAPIKey string
   211  
   212  	// These two views are used to check whether a transaction is valid before
   213  	// adding it to the mempool. This is done by applying the transaction to the
   214  	// backup view, and then restoring the backup view if there's an error. In
   215  	// the future, if we can figure out an easy way to rollback bad transactions
   216  	// on a single view, then we won't need the second view anymore.
   217  	backupUniversalUtxoView  *UtxoView
   218  	universalUtxoView        *UtxoView
   219  	universalTransactionList []*MempoolTx
   220  
   221  	// When set, transactions are initially read from this dir and dumped
   222  	// to this dir.
   223  	mempoolDir string
   224  
   225  	// Whether or not we should be computing readOnlyUtxoViews.
   226  	generateReadOnlyUtxoView bool
   227  	// A view that contains a *near* up-to-date snapshot of the mempool. It is
   228  	// updated periodically after N transactions OR after M  seconds, whichever
   229  	// comes first. It's useful because it can be obtained without acquiring a
   230  	// lock on the mempool.
   231  	//
   232  	// This field isn't reset with ResetPool. It requires an explicit call to
   233  	// UpdateReadOnlyView.
   234  	readOnlyUtxoView *UtxoView
   235  	// Keep a list of all transactions in the mempool. This is useful for dumping
   236  	// to the database periodically.
   237  	readOnlyUniversalTransactionList []*MempoolTx
   238  	readOnlyUniversalTransactionMap  map[BlockHash]*MempoolTx
   239  	readOnlyOutpoints                map[UtxoKey]*MsgDeSoTxn
   240  	// Every time the readOnlyUtxoView is updated, this is incremented. It can
   241  	// be used by obtainers of the readOnlyUtxoView to wait until a particular
   242  	// transaction has been run.
   243  	//
   244  	// This field isn't reset with ResetPool. It requires an explicit call to
   245  	// UpdateReadOnlyView.
   246  	readOnlyUtxoViewSequenceNumber int64
   247  	// The total number of times we've called processTransaction. Used to
   248  	// determine whether we should update the readOnlyUtxoView.
   249  	//
   250  	// This field isn't reset with ResetPool. It requires an explicit call to
   251  	// UpdateReadOnlyView.
   252  	totalProcessTransactionCalls int64
   253  
   254  	// We pass a copy of the data dir flag to the tx pool so that we can instantiate
   255  	// temp badger db instances and dump mempool txns to them.
   256  	dataDir string
   257  }
   258  
   259  // See comment on RemoveUnconnectedTxn. The mempool lock must be called for writing
   260  // when calling this function.
   261  func (mp *DeSoMempool) removeUnconnectedTxn(tx *MsgDeSoTxn, removeRedeemers bool) {
   262  	txHash := tx.Hash()
   263  	if txHash == nil {
   264  		// If an error occurs hashing the transaction then there's nothing to do. Just
   265  		// log and reteurn.
   266  		glog.Error("removeUnconnectedTxn: Problem hashing txn: ")
   267  		return
   268  	}
   269  	unconnectedTxn, exists := mp.unconnectedTxns[*txHash]
   270  	if !exists {
   271  		return
   272  	}
   273  
   274  	// Remove the unconnected txn from the unconnectedTxnsByPrev index
   275  	for _, txIn := range unconnectedTxn.tx.TxInputs {
   276  		unconnectedTxns, exists := mp.unconnectedTxnsByPrev[UtxoKey(*txIn)]
   277  		if exists {
   278  			delete(unconnectedTxns, *txHash)
   279  
   280  			// Remove the map entry altogether if there are no
   281  			// longer any unconnectedTxns which depend on it.
   282  			if len(unconnectedTxns) == 0 {
   283  				delete(mp.unconnectedTxnsByPrev, UtxoKey(*txIn))
   284  			}
   285  		}
   286  	}
   287  
   288  	// Remove any unconnectedTxns that spend this txn
   289  	if removeRedeemers {
   290  		prevOut := DeSoInput{TxID: *txHash}
   291  		for txOutIdx := range tx.TxOutputs {
   292  			prevOut.Index = uint32(txOutIdx)
   293  			for _, unconnectedTx := range mp.unconnectedTxnsByPrev[UtxoKey(prevOut)] {
   294  				mp.removeUnconnectedTxn(unconnectedTx, true)
   295  			}
   296  		}
   297  	}
   298  
   299  	// Delete the txn from the unconnectedTxn map
   300  	delete(mp.unconnectedTxns, *txHash)
   301  }
   302  
   303  // ResetPool replaces all of the internal data associated with a pool object with the
   304  // data of the pool object passed in. It's useful when we want to do a "scorch the earth"
   305  // update of the pool by re-processing all of its transactions into a new pool object
   306  // first.
   307  //
   308  // Note the write lock must be held before calling this function.
   309  func (mp *DeSoMempool) resetPool(newPool *DeSoMempool) {
   310  	// Replace the internal mappings of the original pool with the mappings of the new
   311  	// pool.
   312  	mp.poolMap = newPool.poolMap
   313  	mp.txFeeMinheap = newPool.txFeeMinheap
   314  	mp.totalTxSizeBytes = newPool.totalTxSizeBytes
   315  	mp.outpoints = newPool.outpoints
   316  	mp.pubKeyToTxnMap = newPool.pubKeyToTxnMap
   317  	mp.unconnectedTxns = newPool.unconnectedTxns
   318  	mp.unconnectedTxnsByPrev = newPool.unconnectedTxnsByPrev
   319  	mp.nextExpireScan = newPool.nextExpireScan
   320  	mp.backupUniversalUtxoView = newPool.backupUniversalUtxoView
   321  	mp.universalUtxoView = newPool.universalUtxoView
   322  	mp.universalTransactionList = newPool.universalTransactionList
   323  
   324  	// We don't adjust blockCypherAPIKey or blockCypherCheckDoubleSpendChan
   325  	// since those should be unaffected
   326  
   327  	// We don't adjust the following fields without an explicit call to
   328  	// UpdateReadOnlyView.
   329  	// - runReadOnlyUtxoView bool
   330  	// - readOnlyUtxoView *UtxoView
   331  	// - readOnlyUtxoViewSequenceNumber int64
   332  	// - totalProcessTransactionCalls int64
   333  	// - readOnlyUniversalTransactionList    []*MempoolTx
   334  	// - readOnlyUniversalTransactionMap map[BlockHash]*MempoolTx
   335  	// - readOnlyOutpoints map[UtxoKey]*MsgDeSoTxn
   336  	//
   337  	// Regenerate the view if needed.
   338  	if mp.generateReadOnlyUtxoView {
   339  		mp.regenerateReadOnlyView()
   340  	}
   341  
   342  	// Don't adjust the lowFeeTxSizeAccumulator or the lastLowFeeTxUnixTime since
   343  	// the old values should be unaffected.
   344  }
   345  
   346  // UpdateAfterConnectBlock updates the mempool after a block has been added to the
   347  // blockchain. It does this by basically removing all known transactions in the block
   348  // from the mempool as follows:
   349  // - Build a map of all of the transactions in the block indexed by their hash.
   350  // - Create a new mempool object.
   351  // - Iterate through all the transactions in the mempool and add the transactions
   352  //   to the new pool object *only if* they don't appear in the block. Do this for
   353  //   transactions in the pool and in the unconnectedTx pool.
   354  // - Compute which transactions were newly-accepted into the pool by effectively diffing
   355  //   the new pool's transactions with the old pool's transactions.
   356  // - Once the new pool object is up-to-date, the fields of the new pool object
   357  //   replace the fields of the original pool object.
   358  // - Return the newly added transactions computed earlier.
   359  //
   360  // TODO: This is fairly inefficient but the story is the same as for
   361  // UpdateAfterDisconnectBlock.
   362  func (mp *DeSoMempool) UpdateAfterConnectBlock(blk *MsgDeSoBlock) (_txnsAddedToMempool []*MempoolTx) {
   363  	// Protect concurrent access.
   364  	mp.mtx.Lock()
   365  	defer mp.mtx.Unlock()
   366  
   367  	// Make a map of all the txns in the block except the block reward.
   368  	txnsInBlock := make(map[BlockHash]bool)
   369  	for _, txn := range blk.Txns[1:] {
   370  		txHash := txn.Hash()
   371  		txnsInBlock[*txHash] = true
   372  	}
   373  
   374  	// Create a new pool object. No need to set the min fees as we're just using this
   375  	// as a temporary data structure for validation.
   376  	//
   377  	// Don't make the new pool object deal with the BlockCypher API.
   378  	newPool := NewDeSoMempool(
   379  		mp.bc, 0, /* rateLimitFeeRateNanosPerKB */
   380  		0,     /* minFeeRateNanosPerKB */
   381  		"",    /*blockCypherAPIKey*/
   382  		false, /*runReadOnlyViewUpdater*/
   383  		"" /*dataDir*/, "")
   384  
   385  	// Get all the transactions from the old pool object.
   386  	oldMempoolTxns, oldUnconnectedTxns, err := mp._getTransactionsOrderedByTimeAdded()
   387  	if err != nil {
   388  		glog.Warning(errors.Wrapf(err, "UpdateAfterConnectBlock: "))
   389  	}
   390  
   391  	// Add all the txns from the old pool into the new pool unless they are already
   392  	// present in the block.
   393  
   394  	for _, mempoolTx := range oldMempoolTxns {
   395  		if _, exists := txnsInBlock[*mempoolTx.Hash]; exists {
   396  			continue
   397  		}
   398  
   399  		// Attempt to add the txn to the mempool as we go. If it fails that's fine.
   400  		txnsAccepted, err := newPool.processTransaction(
   401  			mempoolTx.Tx, true /*allowUnconnected*/, false, /*rateLimit*/
   402  			0 /*peerID*/, false /*verifySignatures*/)
   403  		if err != nil {
   404  			glog.Warning(errors.Wrapf(err, "UpdateAfterConnectBlock: "))
   405  		}
   406  		if len(txnsAccepted) == 0 {
   407  			glog.Warningf("UpdateAfterConnectBlock: Dropping txn %v", mempoolTx.Tx)
   408  		}
   409  	}
   410  
   411  	// Add all the unconnectedTxns from the old pool into the new pool unless they are already
   412  	// present in the block.
   413  	for _, unconnectedTx := range oldUnconnectedTxns {
   414  		// Only add transactions to the pool if they haven't already been added by the
   415  		// block.
   416  		unconnectedTxHash := unconnectedTx.tx.Hash()
   417  		if _, exists := txnsInBlock[*unconnectedTxHash]; exists {
   418  			continue
   419  		}
   420  
   421  		// Fully process unconnectedTxns
   422  		rateLimit := false
   423  		unconnectedTxns := true
   424  		verifySignatures := false
   425  		_, err := newPool.processTransaction(unconnectedTx.tx, unconnectedTxns, rateLimit, unconnectedTx.peerID, verifySignatures)
   426  		if err != nil {
   427  			glog.Warning(errors.Wrapf(err, "UpdateAfterConnectBlock: "))
   428  		}
   429  	}
   430  
   431  	// At this point, the new pool should contain an up-to-date view of the transactions
   432  	// that should be in the mempool after connecting this block.
   433  
   434  	// Figure out what transactions are in the new pool but not in the old pool. These
   435  	// are transactions that were newly-added as a result of this block clearing up some
   436  	// dependencies and so we will likely want to relay these transactions.
   437  	newlyAcceptedTxns := []*MempoolTx{}
   438  	for poolHash, newMempoolTx := range newPool.poolMap {
   439  		// No need to copy poolHash since nothing saves a reference to it.
   440  		if _, txExistsInOldPool := mp.poolMap[poolHash]; !txExistsInOldPool {
   441  			newlyAcceptedTxns = append(newlyAcceptedTxns, newMempoolTx)
   442  		}
   443  	}
   444  
   445  	// Now set the fields on the old pool to match the new pool.
   446  	mp.resetPool(newPool)
   447  
   448  	// Return the newly accepted transactions now that we've fully updated our mempool.
   449  	return newlyAcceptedTxns
   450  }
   451  
   452  // UpdateAfterDisconnectBlock updates the mempool to reflect that a block has been
   453  // disconnected from the blockchain. It does this by basically adding all the
   454  // transactions in the block back to the mempool as follows:
   455  // - A new pool object is created containing no transactions.
   456  // - The block's transactions are added to this new pool object. This is done in order
   457  //   to minimize dependency-related conflicts with transactions already in the mempool.
   458  // - Then the transactions in the original pool are layered on top of the block's
   459  //   transactions in the new pool object. Again this is done to avoid dependency
   460  //   issues since the ordering of <block txns> followed by <original mempool txns>
   461  //   is much less likely to have issues.
   462  // - Then, once the new pool object is up-to-date, the fields of the new pool object
   463  //   replace the fields of the original pool object.
   464  //
   465  // This function is safe for concurrent access. It is assumed the ChainLock is
   466  // held before this function is a accessed.
   467  //
   468  // TODO: This is fairly inefficient and basically only necessary because computing a
   469  // transaction's dependencies is a little shaky. If we end up making the dependency
   470  // detection logic more robust then we could come back here and change this so that
   471  // we're not effectively reprocessing the entire mempool every time we have a new block.
   472  // But until then doing it this way significantly reduces complexity and should hold up
   473  // for a while.
   474  func (mp *DeSoMempool) UpdateAfterDisconnectBlock(blk *MsgDeSoBlock) {
   475  	// Protect concurrent access.
   476  	mp.mtx.Lock()
   477  	defer mp.mtx.Unlock()
   478  
   479  	// Create a new DeSoMempool. No need to set the min fees since we're just using
   480  	// this as a temporary data structure for validation.
   481  	//
   482  	// Don't make the new pool object deal with the BlockCypher API.
   483  	newPool := NewDeSoMempool(mp.bc, 0, /* rateLimitFeeRateNanosPerKB */
   484  		0, /* minFeeRateNanosPerKB */
   485  		"" /*blockCypherAPIKey*/, false,
   486  		"" /*dataDir*/, "")
   487  
   488  	// Add the transactions from the block to the new pool (except for the block reward,
   489  	// which should always be the first transaction). Break out if we encounter
   490  	// an error.
   491  	for _, txn := range blk.Txns[1:] {
   492  		// For transactions being added from the block just set the peerID to zero. It
   493  		// shouldn't matter since these transactions won't be unconnectedTxns.
   494  		rateLimit := false
   495  		allowUnconnectedTxns := false
   496  		peerID := uint64(0)
   497  		verifySignatures := false
   498  		_, err := newPool.processTransaction(txn, allowUnconnectedTxns, rateLimit, peerID, verifySignatures)
   499  		if err != nil {
   500  			// Log errors but don't stop adding transactions. We do this because we'd prefer
   501  			// to drop a transaction here or there rather than lose the whole block because
   502  			// of one bad apple.
   503  			glog.Warning(errors.Wrapf(err, "UpdateAfterDisconnectBlock: "))
   504  		}
   505  	}
   506  
   507  	// At this point the block txns have been added to the new pool. Now we need to
   508  	// add the txns from the original pool. Start by fetching them in slice form.
   509  	oldMempoolTxns, oldUnconnectedTxns, err := mp._getTransactionsOrderedByTimeAdded()
   510  	if err != nil {
   511  		glog.Warning(errors.Wrapf(err, "UpdateAfterDisconnectBlock: "))
   512  	}
   513  	// Iterate through the pool transactions and add them to our new pool.
   514  
   515  	for _, mempoolTx := range oldMempoolTxns {
   516  		// Attempt to add the txn to the mempool as we go. If it fails that's fine.
   517  		txnsAccepted, err := newPool.processTransaction(
   518  			mempoolTx.Tx, true /*allowUnconnectedTxns*/, false, /*rateLimit*/
   519  			0 /*peerID*/, false /*verifySignatures*/)
   520  		if err != nil {
   521  			glog.Warning(errors.Wrapf(err, "UpdateAfterDisconnectBlock: "))
   522  		}
   523  		if len(txnsAccepted) == 0 {
   524  			glog.Warningf("UpdateAfterDisconnectBlock: Dropping txn %v", mempoolTx.Tx)
   525  		}
   526  	}
   527  
   528  	// Iterate through the unconnectedTxns and add them to our new pool as well.
   529  	for _, oTx := range oldUnconnectedTxns {
   530  		rateLimit := false
   531  		allowUnconnectedTxns := true
   532  		verifySignatures := false
   533  		_, err := newPool.processTransaction(oTx.tx, allowUnconnectedTxns, rateLimit, oTx.peerID, verifySignatures)
   534  		if err != nil {
   535  			glog.Warning(errors.Wrapf(err, "UpdateAfterDisconnectBlock: "))
   536  		}
   537  	}
   538  
   539  	// At this point the new mempool should be a duplicate of the original mempool but with
   540  	// the block's transactions added (with timestamps set before the transactions that
   541  	// were in the original pool.
   542  
   543  	// Replace the internal mappings of the original pool with the mappings of the new
   544  	// pool.
   545  	mp.resetPool(newPool)
   546  }
   547  
   548  // Acquires a read lock before returning the transactions.
   549  func (mp *DeSoMempool) GetTransactionsOrderedByTimeAdded() (_poolTxns []*MempoolTx, _unconnectedTxns []*UnconnectedTx, _err error) {
   550  	poolTxns := []*MempoolTx{}
   551  	poolTxns = append(poolTxns, mp.readOnlyUniversalTransactionList...)
   552  
   553  	// Sort and return the txns.
   554  	sort.Slice(poolTxns, func(ii, jj int) bool {
   555  		return poolTxns[ii].Added.Before(poolTxns[jj].Added)
   556  	})
   557  
   558  	/*
   559  		// TODO: We need to support unconnectedTxns as part of the readOnly infrastructure.
   560  		unconnectedTxns := []*UnconnectedTx{}
   561  		for _, oTx := range mp.readOnly {
   562  			unconnectedTxns = append(unconnectedTxns, oTx)
   563  		}
   564  	*/
   565  
   566  	return poolTxns, nil, nil
   567  }
   568  
   569  func (mp *DeSoMempool) GetTransaction(txId *BlockHash) (txn *MempoolTx) {
   570  	return mp.readOnlyUniversalTransactionMap[*txId]
   571  }
   572  
   573  // GetTransactionsOrderedByTimeAdded returns all transactions in the mempool ordered
   574  // by when they were added to the mempool.
   575  func (mp *DeSoMempool) _getTransactionsOrderedByTimeAdded() (_poolTxns []*MempoolTx, _unconnectedTxns []*UnconnectedTx, _err error) {
   576  	poolTxns := []*MempoolTx{}
   577  	for _, mempoolTx := range mp.poolMap {
   578  		poolTxns = append(poolTxns, mempoolTx)
   579  	}
   580  	// Sort the list based on when the transactions were added.
   581  	sort.Slice(poolTxns, func(ii, jj int) bool {
   582  		return poolTxns[ii].Added.Before(poolTxns[jj].Added)
   583  	})
   584  
   585  	unconnectedTxns := []*UnconnectedTx{}
   586  	for _, oTx := range mp.unconnectedTxns {
   587  		unconnectedTxns = append(unconnectedTxns, oTx)
   588  	}
   589  
   590  	return poolTxns, unconnectedTxns, nil
   591  }
   592  
   593  // Evicts unconnectedTxns if we're over the maximum number of unconnectedTxns allowed, or if
   594  // unconnectedTxns have exired. Must be called with the write lock held.
   595  func (mp *DeSoMempool) limitNumUnconnectedTxns() error {
   596  	if now := time.Now(); now.After(mp.nextExpireScan) {
   597  		prevNumUnconnectedTxns := len(mp.unconnectedTxns)
   598  		for _, unconnectedTxn := range mp.unconnectedTxns {
   599  			if now.After(unconnectedTxn.expiration) {
   600  				mp.removeUnconnectedTxn(unconnectedTxn.tx, true)
   601  			}
   602  		}
   603  
   604  		numUnconnectedTxns := len(mp.unconnectedTxns)
   605  		if numExpired := prevNumUnconnectedTxns - numUnconnectedTxns; numExpired > 0 {
   606  			glog.V(1).Infof("Expired %d unconnectedTxns (remaining: %d)", numExpired, numUnconnectedTxns)
   607  		}
   608  	}
   609  
   610  	if len(mp.unconnectedTxns)+1 <= MaxUnconnectedTransactions {
   611  		return nil
   612  	}
   613  
   614  	for _, otx := range mp.unconnectedTxns {
   615  		mp.removeUnconnectedTxn(otx.tx, false)
   616  		break
   617  	}
   618  
   619  	return nil
   620  }
   621  
   622  // Adds an unconnected txn to the pool. Must be called with the write lock held.
   623  func (mp *DeSoMempool) addUnconnectedTxn(tx *MsgDeSoTxn, peerID uint64) {
   624  	if MaxUnconnectedTransactions <= 0 {
   625  		return
   626  	}
   627  
   628  	mp.limitNumUnconnectedTxns()
   629  
   630  	txHash := tx.Hash()
   631  	if txHash == nil {
   632  		glog.Error(fmt.Errorf("addUnconnectedTxn: Problem hashing txn: "))
   633  		return
   634  	}
   635  	mp.unconnectedTxns[*txHash] = &UnconnectedTx{
   636  		tx:         tx,
   637  		peerID:     peerID,
   638  		expiration: time.Now().Add(UnconnectedTxnExpirationInterval),
   639  	}
   640  	for _, txIn := range tx.TxInputs {
   641  		if _, exists := mp.unconnectedTxnsByPrev[UtxoKey(*txIn)]; !exists {
   642  			mp.unconnectedTxnsByPrev[UtxoKey(*txIn)] =
   643  				make(map[BlockHash]*MsgDeSoTxn)
   644  		}
   645  		mp.unconnectedTxnsByPrev[UtxoKey(*txIn)][*txHash] = tx
   646  	}
   647  
   648  	glog.V(1).Infof("Added unconnected transaction %v with total txns: %d)", txHash, len(mp.unconnectedTxns))
   649  }
   650  
   651  // Consider adding an unconnected txn to the pool. Must be called with the write lock held.
   652  func (mp *DeSoMempool) tryAddUnconnectedTxn(tx *MsgDeSoTxn, peerID uint64) error {
   653  	txBytes, err := tx.ToBytes(false)
   654  	if err != nil {
   655  		return errors.Wrapf(err, "tryAddUnconnectedTxn: Problem serializing txn: ")
   656  	}
   657  	serializedLen := len(txBytes)
   658  	if serializedLen > MaxUnconnectedTxSizeBytes {
   659  		return TxErrorTooLarge
   660  	}
   661  
   662  	mp.addUnconnectedTxn(tx, peerID)
   663  
   664  	return nil
   665  }
   666  
   667  // Remove unconnectedTxns that are no longer valid after applying the passed-in txn.
   668  func (mp *DeSoMempool) removeUnconnectedTxnDoubleSpends(tx *MsgDeSoTxn) {
   669  	for _, txIn := range tx.TxInputs {
   670  		for _, unconnectedTx := range mp.unconnectedTxnsByPrev[UtxoKey(*txIn)] {
   671  			mp.removeUnconnectedTxn(unconnectedTx, true)
   672  		}
   673  	}
   674  }
   675  
   676  // Must be called with the write lock held.
   677  func (mp *DeSoMempool) isTransactionInPool(hash *BlockHash) bool {
   678  	if _, exists := mp.poolMap[*hash]; exists {
   679  		return true
   680  	}
   681  
   682  	return false
   683  }
   684  
   685  // Whether or not a txn is in the pool. Safe for concurrent access.
   686  func (mp *DeSoMempool) IsTransactionInPool(hash *BlockHash) bool {
   687  	_, exists := mp.readOnlyUniversalTransactionMap[*hash]
   688  	return exists
   689  }
   690  
   691  // Whether or not an unconnected txn is in the unconnected pool. Must be called with the write
   692  // lock held.
   693  func (mp *DeSoMempool) isUnconnectedTxnInPool(hash *BlockHash) bool {
   694  	if _, exists := mp.unconnectedTxns[*hash]; exists {
   695  		return true
   696  	}
   697  
   698  	return false
   699  }
   700  
   701  func (mp *DeSoMempool) DumpTxnsToDB() {
   702  	// Dump all mempool txns into data_dir_path/temp_mempool_dump.
   703  	err := mp.OpenTempDBAndDumpTxns()
   704  	if err != nil {
   705  		glog.Infof("DumpTxnsToDB: Problem opening temp db / dumping mempool txns: %v", err)
   706  		return
   707  	}
   708  
   709  	// Now we shuffle the directories we created. The temp that we just created will become
   710  	// the latest dump and the latest dump will become the previous dump.  By doing this
   711  	// shuffle, we ensure that we always have a complete view of the mempool to load from.
   712  	tempDir := filepath.Join(mp.mempoolDir, "temp_mempool_dump")
   713  	previousDir := filepath.Join(mp.mempoolDir, "previous_mempool_dump")
   714  	latestDir := filepath.Join(mp.mempoolDir, "latest_mempool_dump")
   715  
   716  	// If latestDir exists, move latestDir --> previousDir.
   717  	// Check that latestDir exists before trying to move it.
   718  	_, err = os.Stat(latestDir)
   719  	if err == nil {
   720  		err = os.RemoveAll(previousDir)
   721  		if err != nil {
   722  			glog.Infof("DumpTxnsToDB: Problem deleting previous dir: %v", err)
   723  			return
   724  		}
   725  		err = os.Rename(latestDir, previousDir)
   726  		if err != nil {
   727  			glog.Infof("DumpTxnsToDB: Problem moving latest mempool dir to previous: %v", err)
   728  			return
   729  		}
   730  	}
   731  
   732  	// Move tempDir --> latestDir. No need to delete latestDir, it was renamed above.
   733  	err = os.Rename(tempDir, latestDir)
   734  	if err != nil {
   735  		glog.Infof("DumpTxnsToDB: Problem moving temp mempool dir to previous: %v", err)
   736  		return
   737  	}
   738  }
   739  
   740  // This function attempts to make the file path provided. Returns an =errors if a parent
   741  // directory in the path does not exist or another error is encountered.
   742  // User permissions are set to "rwx" so that it can be manipulated.
   743  // See: https://stackoverflow.com/questions/14249467/os-mkdir-and-os-mkdirall-permission-value/31151508
   744  func MakeDirIfNonExistent(filePath string) error {
   745  	_, err := os.Stat(filePath)
   746  	if os.IsNotExist(err) {
   747  		err = os.Mkdir(filePath, 0700)
   748  		if err != nil {
   749  			return fmt.Errorf("OpenTempDBAndDumpTxns: Error making dir: %v", err)
   750  		}
   751  	} else if err != nil {
   752  		return fmt.Errorf("OpenTempDBAndDumpTxns: os.Stat() error: %v", err)
   753  	}
   754  	return nil
   755  }
   756  
   757  func (mp *DeSoMempool) OpenTempDBAndDumpTxns() error {
   758  	allTxns := mp.readOnlyUniversalTransactionList
   759  
   760  	tempMempoolDBDir := filepath.Join(mp.mempoolDir, "temp_mempool_dump")
   761  	glog.Infof("OpenTempDBAndDumpTxns: Opening new temp db %v", tempMempoolDBDir)
   762  	// Make the top-level folder if it doesn't exist.
   763  	err := MakeDirIfNonExistent(mp.mempoolDir)
   764  	if err != nil {
   765  		return fmt.Errorf("OpenTempDBAndDumpTxns: Error making top-level dir: %v", err)
   766  	}
   767  	tempMempoolDBOpts := badger.DefaultOptions(tempMempoolDBDir)
   768  	tempMempoolDBOpts.ValueDir = tempMempoolDBDir
   769  	tempMempoolDBOpts.MemTableSize = 1024 << 20
   770  	tempMempoolDB, err := badger.Open(tempMempoolDBOpts)
   771  	if err != nil {
   772  		return fmt.Errorf("OpenTempDBAndDumpTxns: Could not open temp db to dump mempool: %v", err)
   773  	}
   774  	defer tempMempoolDB.Close()
   775  
   776  	// Dump txns into the temp mempool db.
   777  	startTime := time.Now()
   778  	// Flush the new mempool state to the DB.
   779  	//
   780  	// Dump 1k txns at a time to avoid overwhelming badger
   781  	txnsToDump := []*MempoolTx{}
   782  	for ii, mempoolTx := range allTxns {
   783  		txnsToDump = append(txnsToDump, mempoolTx)
   784  		// If we're at a multiple of 1k or we're at the end of the list
   785  		// then dump the txns to disk
   786  		if len(txnsToDump)%1000 == 0 || ii == len(allTxns)-1 {
   787  			glog.Infof("OpenTempDBAndDumpTxns: Dumping txns %v to %v", ii-len(txnsToDump)+1, ii)
   788  			err := tempMempoolDB.Update(func(txn *badger.Txn) error {
   789  				return FlushMempoolToDbWithTxn(txn, txnsToDump)
   790  			})
   791  			if err != nil {
   792  				return fmt.Errorf("OpenTempDBAndDumpTxns: Error flushing mempool txns to DB: %v", err)
   793  			}
   794  			txnsToDump = []*MempoolTx{}
   795  		}
   796  	}
   797  	endTime := time.Now()
   798  	glog.Infof("OpenTempDBAndDumpTxns: Full txn dump of %v txns completed "+
   799  		"in %v seconds. Safe to reboot node", len(allTxns), endTime.Sub(startTime).Seconds())
   800  	return nil
   801  }
   802  
   803  // Adds a txn to the pool. This function does not do any validation, and so it should
   804  // only be called when one is sure that a transaction is valid. Otherwise, it could
   805  // mess up the UtxoViews that we store internally.
   806  func (mp *DeSoMempool) addTransaction(
   807  	tx *MsgDeSoTxn, height uint32, fee uint64, updateBackupView bool) (*MempoolTx, error) {
   808  
   809  	// Add the transaction to the pool and mark the referenced outpoints
   810  	// as spent by the pool.
   811  	txBytes, err := tx.ToBytes(false)
   812  	if err != nil {
   813  		return nil, errors.Wrapf(err, "addTransaction: Problem serializing txn: ")
   814  	}
   815  	serializedLen := uint64(len(txBytes))
   816  
   817  	txHash := tx.Hash()
   818  	if txHash == nil {
   819  		return nil, errors.Wrapf(err, "addTransaction: Problem hashing tx: ")
   820  	}
   821  
   822  	// If this txn would put us over our threshold then don't accept it.
   823  	//
   824  	// TODO: We don't replace txns in the mempool right now. Instead, a node can be
   825  	// rebooted with a higher fee if the transactions start to get rejected due to
   826  	// the mempool being full.
   827  	if serializedLen+mp.totalTxSizeBytes > MaxTotalTransactionSizeBytes {
   828  		return nil, errors.Wrapf(TxErrorInsufficientFeePriorityQueue, "addTransaction: ")
   829  	}
   830  
   831  	// At this point we are certain that the mempool has enough room to accomodate
   832  	// this transaction.
   833  
   834  	mempoolTx := &MempoolTx{
   835  		Tx:          tx,
   836  		Hash:        txHash,
   837  		TxSizeBytes: uint64(serializedLen),
   838  		Added:       time.Now(),
   839  		Height:      height,
   840  		Fee:         fee,
   841  		FeePerKB:    fee * 1000 / serializedLen,
   842  		// index will be set by the heap code.
   843  	}
   844  
   845  	// Add the transaction to the main pool map.
   846  	mp.poolMap[*txHash] = mempoolTx
   847  	// Add the transaction to the outpoints map.
   848  	for _, txIn := range tx.TxInputs {
   849  		mp.outpoints[UtxoKey(*txIn)] = tx
   850  	}
   851  	// Add the transaction to the min heap.
   852  	heap.Push(&mp.txFeeMinheap, mempoolTx)
   853  	// Update the size of the mempool to reflect the added transaction.
   854  	mp.totalTxSizeBytes += mempoolTx.TxSizeBytes
   855  
   856  	// Whenever transactions are accepted into the mempool, add a mapping
   857  	// for each public key that they send an output to. This is useful so
   858  	// we can find all of these outputs if, for example, the user wants
   859  	// to know her balance while factoring in mempool transactions.
   860  	mp._addMempoolTxToPubKeyOutputMap(mempoolTx)
   861  
   862  	// Add it to the universal view. We assume the txn was already added to the
   863  	// backup view.
   864  	_, _, _, _, err = mp.universalUtxoView._connectTransaction(mempoolTx.Tx, mempoolTx.Hash, int64(mempoolTx.TxSizeBytes), height,
   865  		false /*verifySignatures*/, false /*ignoreUtxos*/)
   866  	if err != nil {
   867  		return nil, fmt.Errorf("ERROR addTransaction: _connectTransaction " +
   868  			"failed on universalUtxoView; this is a HUGE problem and should never happen")
   869  	}
   870  	// Add it to the universalTransactionList if it made it through the view
   871  	mp.universalTransactionList = append(mp.universalTransactionList, mempoolTx)
   872  	if updateBackupView {
   873  		_, _, _, _, err = mp.backupUniversalUtxoView._connectTransaction(mempoolTx.Tx, mempoolTx.Hash, int64(mempoolTx.TxSizeBytes), height,
   874  			false /*verifySignatures*/, false /*ignoreUtxos*/)
   875  		if err != nil {
   876  			return nil, fmt.Errorf("ERROR addTransaction: _connectTransaction " +
   877  				"failed on backupUniversalUtxoView; this is a HUGE problem and should never happen")
   878  		}
   879  	}
   880  
   881  	return mempoolTx, nil
   882  }
   883  
   884  func (mp *DeSoMempool) CheckSpend(op UtxoKey) *MsgDeSoTxn {
   885  	txR := mp.readOnlyOutpoints[op]
   886  
   887  	return txR
   888  }
   889  
   890  // GetAugmentedUtxoViewForPublicKey creates a UtxoView that has connected all of
   891  // the transactions that could result in utxos for the passed-in public key
   892  // plus all of the dependencies of those transactions. This is useful for
   893  // when we want to validate a transaction that builds on a transaction that has
   894  // not yet been mined into a block. It is also useful for when we want to fetch all
   895  // the unspent UtxoEntrys factoring in what's been spent by transactions in
   896  // the mempool.
   897  func (mp *DeSoMempool) GetAugmentedUtxoViewForPublicKey(pkBytes []byte, optionalTxn *MsgDeSoTxn) (*UtxoView, error) {
   898  	return mp.GetAugmentedUniversalView()
   899  }
   900  
   901  // GetAugmentedUniversalView creates a view that just connects everything
   902  // in the mempool...
   903  // TODO(performance): We should make a read-only version of the universal view that
   904  // you can get from the mempool.
   905  func (mp *DeSoMempool) GetAugmentedUniversalView() (*UtxoView, error) {
   906  	newView, err := mp.readOnlyUtxoView.CopyUtxoView()
   907  	if err != nil {
   908  		return nil, err
   909  	}
   910  	return newView, nil
   911  }
   912  
   913  func (mp *DeSoMempool) FetchTransaction(txHash *BlockHash) *MempoolTx {
   914  	if mempoolTx, exists := mp.readOnlyUniversalTransactionMap[*txHash]; exists {
   915  		return mempoolTx
   916  	}
   917  	return nil
   918  }
   919  
   920  // TODO(performance): This function is slow, and the only reason we have it is because
   921  // we need to validate BitcoinExchange transactions both before they have valid merkle
   922  // proofs and *after* they have valid merkle proofs. In the latter case we can't use
   923  // the universal view because the transaction is in the "middle" of the sorted list of
   924  // transactions ordered by time added.
   925  func (mp *DeSoMempool) _quickCheckBitcoinExchangeTxn(
   926  	tx *MsgDeSoTxn, txHash *BlockHash, checkMerkleProof bool) (
   927  	_fees uint64, _err error) {
   928  
   929  	// Create a view that we'll use to validate this txn.
   930  	//
   931  	// Note that it is safe to use this because we expect that the blockchain
   932  	// lock is held for the duration of this function call so there shouldn't
   933  	// be any shifting of the db happening beneath our fee.
   934  	utxoView, err := NewUtxoView(mp.bc.db, mp.bc.params, mp.bc.postgres)
   935  	if err != nil {
   936  		return 0, errors.Wrapf(err,
   937  			"_helpConnectDepsAndFinalTxn: Problem initializing UtxoView")
   938  	}
   939  
   940  	// Connnect all of this transaction's dependencies to the UtxoView in order. Note
   941  	// that we can do this because _findMempoolDependencies returns the transactions in
   942  	// sorted order based on when transactions were added.
   943  	bestHeight := uint32(mp.bc.blockTip().Height + 1)
   944  	// Don't verify signatures since this transaction is already in the mempool.
   945  	//
   946  	// Additionally mempool verification does not require that BitcoinExchange
   947  	// transactions meet the MinBurnWork requirement. Note that a BitcoinExchange
   948  	// transaction will only get this far once we are positive the BitcoinManager
   949  	// has the block corresponding to the transaction.
   950  	// We skip verifying txn size for bitcoin exchange transactions.
   951  	_, _, _, txFee, err := utxoView._connectTransaction(
   952  		tx, txHash, 0, bestHeight, false, false)
   953  	if err != nil {
   954  		// Note this can happen in odd cases where a transaction's dependency was removed
   955  		// but the transaction depending on it was not. See the comment on
   956  		// _findMempoolDependencies for more info on this case.
   957  		return 0, errors.Wrapf(
   958  			err, "_helpConnectDepsAndFinalTxn: Problem connecting "+
   959  				"transaction dependency: ")
   960  	}
   961  
   962  	return txFee, nil
   963  }
   964  
   965  func (mp *DeSoMempool) rebuildBackupView() {
   966  	// We need to rebuild the backup view since the _connectTransaction broke it.
   967  	var copyErr error
   968  	mp.backupUniversalUtxoView, copyErr = mp.universalUtxoView.CopyUtxoView()
   969  	if copyErr != nil {
   970  		glog.Errorf("ERROR tryAcceptTransaction: Problem copying "+
   971  			"view. This should NEVER happen: %v", copyErr)
   972  	}
   973  }
   974  
   975  // See TryAcceptTransaction. The write lock must be held when calling this function.
   976  //
   977  // TODO: Allow replacing a transaction with a higher fee.
   978  func (mp *DeSoMempool) tryAcceptTransaction(
   979  	tx *MsgDeSoTxn, rateLimit bool, rejectDupUnconnected bool, verifySignatures bool) (
   980  	_missingParents []*BlockHash, _mempoolTx *MempoolTx, _err error) {
   981  
   982  	// Block reward transactions shouldn't appear individually
   983  	if tx.TxnMeta != nil && tx.TxnMeta.GetTxnType() == TxnTypeBlockReward {
   984  		return nil, nil, TxErrorIndividualBlockReward
   985  	}
   986  
   987  	// Compute the hash of the transaction.
   988  	txHash := tx.Hash()
   989  	if txHash == nil {
   990  		return nil, nil, fmt.Errorf("tryAcceptTransaction: Problem computing tx hash: ")
   991  	}
   992  
   993  	// Reject the txn if it already exists.
   994  	if mp.isTransactionInPool(txHash) || (rejectDupUnconnected &&
   995  		mp.isUnconnectedTxnInPool(txHash)) {
   996  
   997  		return nil, nil, TxErrorDuplicate
   998  	}
   999  
  1000  	// Iterate over the transaction's inputs. If any of them don't have utxos in the
  1001  	// UtxoView that are unspent at this point then the transaction is an unconnected
  1002  	// txn. Use a map to ensure there are no duplicates.
  1003  	missingParentsMap := make(map[BlockHash]bool)
  1004  	for _, txIn := range tx.TxInputs {
  1005  		utxoKey := UtxoKey(*txIn)
  1006  		utxoEntry := mp.universalUtxoView.GetUtxoEntryForUtxoKey(&utxoKey)
  1007  		if utxoEntry == nil {
  1008  			missingParentsMap[utxoKey.TxID] = true
  1009  		}
  1010  	}
  1011  	if len(missingParentsMap) > 0 {
  1012  		var missingParents []*BlockHash
  1013  		for txID := range missingParentsMap {
  1014  			// Must make a copy of the hash here since the iterator
  1015  			// is replaced and taking its address directly would
  1016  			// result in all of the entries pointing to the same
  1017  			// memory location and thus all be the final hash.
  1018  			hashCopy := txID
  1019  			missingParents = append(missingParents, &hashCopy)
  1020  		}
  1021  		return missingParents, nil, nil
  1022  	}
  1023  
  1024  	// Attempt to add the transaction to the backup view. If it fails, reconstruct the backup
  1025  	// view and return an error.
  1026  	totalNanosPurchasedBefore := mp.backupUniversalUtxoView.NanosPurchased
  1027  	usdCentsPerBitcoinBefore := mp.backupUniversalUtxoView.GetCurrentUSDCentsPerBitcoin()
  1028  	bestHeight := uint32(mp.bc.blockTip().Height + 1)
  1029  	// We can skip verifying the transaction size as related to the minimum fee here.
  1030  	utxoOps, totalInput, totalOutput, txFee, err := mp.backupUniversalUtxoView._connectTransaction(
  1031  		tx, txHash, 0, bestHeight, verifySignatures, false)
  1032  	if err != nil {
  1033  		mp.rebuildBackupView()
  1034  		return nil, nil, errors.Wrapf(err, "tryAcceptTransaction: Problem "+
  1035  			"connecting transaction after connecting dependencies: ")
  1036  	}
  1037  
  1038  	// Compute the feerate for this transaction for use below.
  1039  	txBytes, err := tx.ToBytes(false)
  1040  	if err != nil {
  1041  		mp.rebuildBackupView()
  1042  		return nil, nil, errors.Wrapf(err, "tryAcceptTransaction: Problem serializing txn: ")
  1043  	}
  1044  	serializedLen := uint64(len(txBytes))
  1045  	txFeePerKB := txFee * 1000 / serializedLen
  1046  
  1047  	// Transactions with a feerate below the minimum threshold will be outright
  1048  	// rejected. This is the first line of defense against attacks against the
  1049  	// mempool.
  1050  	if rateLimit && txFeePerKB < mp.minFeeRateNanosPerKB {
  1051  		errRet := fmt.Errorf("tryAcceptTransaction: Fee rate per KB found was %d, which is below the "+
  1052  			"minimum required which is %d (= %d * %d / 1000). Total input: %d, total output: %d, "+
  1053  			"txn hash: %v, txn hex: %v",
  1054  			txFeePerKB, mp.minFeeRateNanosPerKB, mp.minFeeRateNanosPerKB, serializedLen,
  1055  			totalInput, totalOutput, txHash, hex.EncodeToString(txBytes))
  1056  		glog.Error(errRet)
  1057  		mp.rebuildBackupView()
  1058  		return nil, nil, errors.Wrapf(TxErrorInsufficientFeeMinFee, errRet.Error())
  1059  	}
  1060  
  1061  	// If the transaction is bigger than half the maximum allowable size,
  1062  	// then reject it.
  1063  	maxTxnSize := mp.bc.params.MinerMaxBlockSizeBytes / 2
  1064  	if serializedLen > maxTxnSize {
  1065  		mp.rebuildBackupView()
  1066  		return nil, nil, errors.Wrapf(err, "tryAcceptTransaction: "+
  1067  			"Txn size %v exceeds maximum allowable txn size %v", serializedLen, maxTxnSize)
  1068  	}
  1069  
  1070  	// If the feerate is below the minimum we've configured for the node, then apply
  1071  	// some rate-limiting logic to avoid stalling in situations in which someone is trying
  1072  	// to flood the network with low-value transacitons. This avoids a form of amplification
  1073  	// DDOS attack brought on by the fact that a single broadcast results in all nodes
  1074  	// communicating with each other.
  1075  	if rateLimit && txFeePerKB < mp.rateLimitFeeRateNanosPerKB {
  1076  		nowUnix := time.Now().Unix()
  1077  
  1078  		// Exponentially decay the accumulator by a factor of 2 every 10m.
  1079  		mp.lowFeeTxSizeAccumulator /= math.Pow(2.0,
  1080  			float64(nowUnix-mp.lastLowFeeTxUnixTime)/(10*60))
  1081  		mp.lastLowFeeTxUnixTime = nowUnix
  1082  
  1083  		// Check to see if the accumulator is over the limit.
  1084  		if mp.lowFeeTxSizeAccumulator >= float64(LowFeeTxLimitBytesPerTenMinutes) {
  1085  			mp.rebuildBackupView()
  1086  			return nil, nil, TxErrorInsufficientFeeRateLimit
  1087  		}
  1088  
  1089  		// Update the accumulator and potentially log the state.
  1090  		oldTotal := mp.lowFeeTxSizeAccumulator
  1091  		mp.lowFeeTxSizeAccumulator += float64(serializedLen)
  1092  		glog.V(2).Infof("tryAcceptTransaction: Rate limit current total ~(%v) bytes/10m, nextTotal: ~(%v) bytes/10m, "+
  1093  			"limit ~(%v) bytes/10m", oldTotal, mp.lowFeeTxSizeAccumulator, LowFeeTxLimitBytesPerTenMinutes)
  1094  	}
  1095  
  1096  	// Add to transaction pool. Don't update the backup view since the call above
  1097  	// will have already done this.
  1098  	mempoolTx, err := mp.addTransaction(tx, bestHeight, txFee, false /*updateBackupUniversalView*/)
  1099  	if err != nil {
  1100  		mp.rebuildBackupView()
  1101  		return nil, nil, errors.Wrapf(err, "tryAcceptTransaction: ")
  1102  	}
  1103  
  1104  	// Calculate metadata
  1105  	txnMeta, err := ComputeTransactionMetadata(tx, mp.backupUniversalUtxoView, nil, totalNanosPurchasedBefore,
  1106  		usdCentsPerBitcoinBefore, totalInput, totalOutput, txFee, uint64(0), utxoOps)
  1107  	if err == nil {
  1108  		mempoolTx.TxMeta = txnMeta
  1109  	}
  1110  
  1111  	glog.V(2).Infof("tryAcceptTransaction: Accepted transaction %v (pool size: %v)", txHash,
  1112  		len(mp.poolMap))
  1113  
  1114  	return nil, mempoolTx, nil
  1115  }
  1116  
  1117  func ComputeTransactionMetadata(txn *MsgDeSoTxn, utxoView *UtxoView, blockHash *BlockHash,
  1118  	totalNanosPurchasedBefore uint64, usdCentsPerBitcoinBefore uint64, totalInput uint64, totalOutput uint64,
  1119  	fees uint64, txnIndexInBlock uint64, utxoOps []*UtxoOperation) (*TransactionMetadata, error) {
  1120  
  1121  	var err error
  1122  	txnMeta := &TransactionMetadata{
  1123  		TxnIndexInBlock: txnIndexInBlock,
  1124  		TxnType:         txn.TxnMeta.GetTxnType().String(),
  1125  
  1126  		// This may be overwritten later on, for example if we're dealing with a
  1127  		// BitcoinExchange txn which doesn't set the txn.PublicKey
  1128  		TransactorPublicKeyBase58Check: PkToString(txn.PublicKey, utxoView.Params),
  1129  
  1130  		// General transaction metadata
  1131  		BasicTransferTxindexMetadata: &BasicTransferTxindexMetadata{
  1132  			TotalInputNanos:  totalInput,
  1133  			TotalOutputNanos: totalOutput,
  1134  			FeeNanos:         fees,
  1135  			// TODO: This doesn't add much value, and it makes output hard to read because
  1136  			// it's so long so I'm commenting it out for now.
  1137  			//UtxoOpsDump:      spew.Sdump(utxoOps),
  1138  
  1139  			// We need to include the utxoOps because it allows us to compute implicit
  1140  			// outputs.
  1141  			UtxoOps: utxoOps,
  1142  		},
  1143  
  1144  		TxnOutputs: txn.TxOutputs,
  1145  	}
  1146  
  1147  	if blockHash != nil {
  1148  		txnMeta.BlockHashHex = hex.EncodeToString(blockHash[:])
  1149  	}
  1150  
  1151  	extraData := txn.ExtraData
  1152  
  1153  	// Set the affected public keys for the basic transfer.
  1154  	for _, output := range txn.TxOutputs {
  1155  		txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1156  			PublicKeyBase58Check: PkToString(output.PublicKey, utxoView.Params),
  1157  			Metadata:             "BasicTransferOutput",
  1158  		})
  1159  	}
  1160  
  1161  	if txn.TxnMeta.GetTxnType() == TxnTypeBitcoinExchange {
  1162  		txnMeta.BitcoinExchangeTxindexMetadata, txnMeta.TransactorPublicKeyBase58Check, err =
  1163  			_computeBitcoinExchangeFields(utxoView.Params, txn.TxnMeta.(*BitcoinExchangeMetadata),
  1164  				totalNanosPurchasedBefore, usdCentsPerBitcoinBefore)
  1165  		if err != nil {
  1166  			return nil, fmt.Errorf(
  1167  				"UpdateTxindex: Error computing BitcoinExchange txn metadata: %v", err)
  1168  		}
  1169  
  1170  		// Set the nanos purchased before/after.
  1171  		txnMeta.BitcoinExchangeTxindexMetadata.TotalNanosPurchasedBefore = totalNanosPurchasedBefore
  1172  		txnMeta.BitcoinExchangeTxindexMetadata.TotalNanosPurchasedAfter = utxoView.NanosPurchased
  1173  
  1174  		// Always associate BitcoinExchange txns with the burn public key. This makes it
  1175  		//		// easy to enumerate all burn txns in the block explorer.
  1176  		txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1177  			PublicKeyBase58Check: BurnPubKeyBase58Check,
  1178  			Metadata:             "BurnPublicKey",
  1179  		})
  1180  	}
  1181  	if txn.TxnMeta.GetTxnType() == TxnTypeCreatorCoin {
  1182  		// Get the txn metadata
  1183  		realTxMeta := txn.TxnMeta.(*CreatorCoinMetadataa)
  1184  
  1185  		// Rosetta needs to know the change in DESOLockedNanos so it can model the change in
  1186  		// total deso locked in the creator coin. Calculate this by comparing the current CoinEntry
  1187  		// to the previous CoinEntry
  1188  		profileEntry := utxoView.GetProfileEntryForPublicKey(realTxMeta.ProfilePublicKey)
  1189  		var prevCoinEntry *CoinEntry
  1190  		for _, op := range utxoOps {
  1191  			if op.Type == OperationTypeCreatorCoin {
  1192  				prevCoinEntry = op.PrevCoinEntry
  1193  				break
  1194  			}
  1195  		}
  1196  
  1197  		desoLockedNanosDiff := int64(0)
  1198  		if profileEntry == nil || prevCoinEntry == nil {
  1199  			glog.Errorf("Update TxIndex: missing DESOLockedNanosDiff error: %v", txn.Hash().String())
  1200  		} else {
  1201  			desoLockedNanosDiff = int64(profileEntry.DeSoLockedNanos - prevCoinEntry.DeSoLockedNanos)
  1202  		}
  1203  
  1204  		// Set the amount of the buy/sell/add
  1205  		txnMeta.CreatorCoinTxindexMetadata = &CreatorCoinTxindexMetadata{
  1206  			DeSoToSellNanos:        realTxMeta.DeSoToSellNanos,
  1207  			CreatorCoinToSellNanos: realTxMeta.CreatorCoinToSellNanos,
  1208  			DeSoToAddNanos:         realTxMeta.DeSoToAddNanos,
  1209  			DESOLockedNanosDiff:    desoLockedNanosDiff,
  1210  		}
  1211  
  1212  		// Set the type of the operation.
  1213  		if realTxMeta.OperationType == CreatorCoinOperationTypeBuy {
  1214  			txnMeta.CreatorCoinTxindexMetadata.OperationType = "buy"
  1215  		} else if realTxMeta.OperationType == CreatorCoinOperationTypeSell {
  1216  			txnMeta.CreatorCoinTxindexMetadata.OperationType = "sell"
  1217  		} else {
  1218  			txnMeta.CreatorCoinTxindexMetadata.OperationType = "add"
  1219  		}
  1220  
  1221  		// Set the affected public key to the owner of the creator coin so that they
  1222  		// get notified.
  1223  		txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1224  			PublicKeyBase58Check: PkToString(realTxMeta.ProfilePublicKey, utxoView.Params),
  1225  			Metadata:             "CreatorPublicKey",
  1226  		})
  1227  	}
  1228  	if txn.TxnMeta.GetTxnType() == TxnTypeCreatorCoinTransfer {
  1229  		realTxMeta := txn.TxnMeta.(*CreatorCoinTransferMetadataa)
  1230  		creatorProfileEntry := utxoView.GetProfileEntryForPublicKey(realTxMeta.ProfilePublicKey)
  1231  		txnMeta.CreatorCoinTransferTxindexMetadata = &CreatorCoinTransferTxindexMetadata{
  1232  			CreatorUsername:            string(creatorProfileEntry.Username),
  1233  			CreatorCoinToTransferNanos: realTxMeta.CreatorCoinToTransferNanos,
  1234  		}
  1235  
  1236  		diamondLevelBytes, hasDiamondLevel := txn.ExtraData[DiamondLevelKey]
  1237  		diamondPostHash, hasDiamondPostHash := txn.ExtraData[DiamondPostHashKey]
  1238  		if hasDiamondLevel && hasDiamondPostHash {
  1239  			diamondLevel, bytesRead := Varint(diamondLevelBytes)
  1240  			if bytesRead <= 0 {
  1241  				glog.Errorf("Update TxIndex: Error reading diamond level for txn: %v", txn.Hash().String())
  1242  			} else {
  1243  				txnMeta.CreatorCoinTransferTxindexMetadata.DiamondLevel = diamondLevel
  1244  				txnMeta.CreatorCoinTransferTxindexMetadata.PostHashHex = hex.EncodeToString(diamondPostHash)
  1245  			}
  1246  		}
  1247  
  1248  		txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1249  			PublicKeyBase58Check: PkToString(realTxMeta.ReceiverPublicKey, utxoView.Params),
  1250  			Metadata:             "ReceiverPublicKey",
  1251  		})
  1252  	}
  1253  	if txn.TxnMeta.GetTxnType() == TxnTypeUpdateProfile {
  1254  		realTxMeta := txn.TxnMeta.(*UpdateProfileMetadata)
  1255  
  1256  		txnMeta.UpdateProfileTxindexMetadata = &UpdateProfileTxindexMetadata{}
  1257  		if len(realTxMeta.ProfilePublicKey) == btcec.PubKeyBytesLenCompressed {
  1258  			txnMeta.UpdateProfileTxindexMetadata.ProfilePublicKeyBase58Check =
  1259  				PkToString(realTxMeta.ProfilePublicKey, utxoView.Params)
  1260  		}
  1261  		txnMeta.UpdateProfileTxindexMetadata.NewUsername = string(realTxMeta.NewUsername)
  1262  		txnMeta.UpdateProfileTxindexMetadata.NewDescription = string(realTxMeta.NewDescription)
  1263  		txnMeta.UpdateProfileTxindexMetadata.NewProfilePic = string(realTxMeta.NewProfilePic)
  1264  		txnMeta.UpdateProfileTxindexMetadata.NewCreatorBasisPoints = realTxMeta.NewCreatorBasisPoints
  1265  		txnMeta.UpdateProfileTxindexMetadata.NewStakeMultipleBasisPoints = realTxMeta.NewStakeMultipleBasisPoints
  1266  		txnMeta.UpdateProfileTxindexMetadata.IsHidden = realTxMeta.IsHidden
  1267  
  1268  		// Add the ProfilePublicKey to the AffectedPublicKeys
  1269  		txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1270  			PublicKeyBase58Check: PkToString(realTxMeta.ProfilePublicKey, utxoView.Params),
  1271  			Metadata:             "ProfilePublicKeyBase58Check",
  1272  		})
  1273  	}
  1274  	if txn.TxnMeta.GetTxnType() == TxnTypeSubmitPost {
  1275  		realTxMeta := txn.TxnMeta.(*SubmitPostMetadata)
  1276  		_ = realTxMeta
  1277  
  1278  		txnMeta.SubmitPostTxindexMetadata = &SubmitPostTxindexMetadata{}
  1279  		if len(realTxMeta.PostHashToModify) == HashSizeBytes {
  1280  			txnMeta.SubmitPostTxindexMetadata.PostHashBeingModifiedHex = hex.EncodeToString(
  1281  				realTxMeta.PostHashToModify)
  1282  		}
  1283  		if len(realTxMeta.ParentStakeID) == HashSizeBytes {
  1284  			txnMeta.SubmitPostTxindexMetadata.ParentPostHashHex = hex.EncodeToString(
  1285  				realTxMeta.ParentStakeID)
  1286  		}
  1287  		// If a post hash didn't get set then the hash of the transaction itself will
  1288  		// end up being used as the post hash so set that here.
  1289  		if txnMeta.SubmitPostTxindexMetadata.PostHashBeingModifiedHex == "" {
  1290  			txnMeta.SubmitPostTxindexMetadata.PostHashBeingModifiedHex =
  1291  				hex.EncodeToString(txn.Hash()[:])
  1292  		}
  1293  
  1294  		// PosterPublicKeyBase58Check = TransactorPublicKeyBase58Check
  1295  
  1296  		// If ParentPostHashHex is set then get the parent posts public key and
  1297  		// mark it as affected.
  1298  		// ParentPosterPublicKeyBase58Check is in AffectedPublicKeys
  1299  		if len(realTxMeta.ParentStakeID) == HashSizeBytes {
  1300  			postHash := &BlockHash{}
  1301  			copy(postHash[:], realTxMeta.ParentStakeID)
  1302  			postEntry := utxoView.GetPostEntryForPostHash(postHash)
  1303  			if postEntry == nil {
  1304  				return nil, fmt.Errorf(
  1305  					"UpdateTxindex: Error creating SubmitPostTxindexMetadata; "+
  1306  						"missing parent post for hash %v: %v", postHash, err)
  1307  			}
  1308  
  1309  			txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1310  				PublicKeyBase58Check: PkToString(postEntry.PosterPublicKey, utxoView.Params),
  1311  				Metadata:             "ParentPosterPublicKeyBase58Check",
  1312  			})
  1313  		}
  1314  
  1315  		// The profiles that are mentioned are in the AffectedPublicKeys
  1316  		// MentionedPublicKeyBase58Check in AffectedPublicKeys. We need to
  1317  		// parse them out of the post and then look up their public keys.
  1318  		//
  1319  		// Start by trying to parse the body JSON
  1320  		bodyObj := &DeSoBodySchema{}
  1321  		if err := json.Unmarshal(realTxMeta.Body, &bodyObj); err != nil {
  1322  			// Don't worry about bad posts unless we're debugging with high verbosity.
  1323  			glog.V(2).Infof("UpdateTxindex: Error parsing post body for @ mentions: "+
  1324  				"%v %v", string(realTxMeta.Body), err)
  1325  		} else {
  1326  			terminators := []rune(" ,.\n&*()-+~'\"[]{}")
  1327  			dollarTagsFound := mention.GetTagsAsUniqueStrings('$', bodyObj.Body, terminators...)
  1328  			atTagsFound := mention.GetTagsAsUniqueStrings('@', bodyObj.Body, terminators...)
  1329  			tagsFound := atTagsFound
  1330  			// We check that cashtag usernames have at least 1 non-numeric character
  1331  			dollarTagRegex := regexp.MustCompile("\\w*[a-zA-Z_]\\w*")
  1332  			for _, dollarTagFound := range dollarTagsFound {
  1333  				if dollarTagRegex.MatchString(dollarTagFound) {
  1334  					tagsFound = append(tagsFound, dollarTagFound)
  1335  				}
  1336  			}
  1337  			for _, tag := range tagsFound {
  1338  				profileFound := utxoView.GetProfileEntryForUsername([]byte(strings.ToLower(tag)))
  1339  				// Don't worry about tags that don't line up to a profile.
  1340  				if profileFound == nil {
  1341  					continue
  1342  				}
  1343  				// If we found a profile then set it as an affected public key.
  1344  				txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1345  					PublicKeyBase58Check: PkToString(profileFound.PublicKey, utxoView.Params),
  1346  					Metadata:             "MentionedPublicKeyBase58Check",
  1347  				})
  1348  			}
  1349  			// Additionally, we need to check if this post is a repost and
  1350  			// fetch the original poster
  1351  			if repostedPostHash, isRepost := extraData[RepostedPostHash]; isRepost {
  1352  				repostedBlockHash := &BlockHash{}
  1353  				copy(repostedBlockHash[:], repostedPostHash)
  1354  				repostPost := utxoView.GetPostEntryForPostHash(repostedBlockHash)
  1355  				if repostPost != nil {
  1356  					txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1357  						PublicKeyBase58Check: PkToString(repostPost.PosterPublicKey, utxoView.Params),
  1358  						Metadata:             "RepostedPublicKeyBase58Check",
  1359  					})
  1360  				}
  1361  			}
  1362  		}
  1363  	}
  1364  	if txn.TxnMeta.GetTxnType() == TxnTypeLike {
  1365  		realTxMeta := txn.TxnMeta.(*LikeMetadata)
  1366  		_ = realTxMeta
  1367  
  1368  		// LikerPublicKeyBase58Check = TransactorPublicKeyBase58Check
  1369  
  1370  		txnMeta.LikeTxindexMetadata = &LikeTxindexMetadata{
  1371  			IsUnlike:    realTxMeta.IsUnlike,
  1372  			PostHashHex: hex.EncodeToString(realTxMeta.LikedPostHash[:]),
  1373  		}
  1374  
  1375  		// Get the public key of the poster and set it as having been affected
  1376  		// by this like.
  1377  		//
  1378  		// PosterPublicKeyBase58Check in AffectedPublicKeys
  1379  		postHash := &BlockHash{}
  1380  		copy(postHash[:], realTxMeta.LikedPostHash[:])
  1381  		postEntry := utxoView.GetPostEntryForPostHash(postHash)
  1382  		if postEntry == nil {
  1383  			return nil, fmt.Errorf(
  1384  				"UpdateTxindex: Error creating LikeTxindexMetadata; "+
  1385  					"missing post for hash %v: %v", postHash, err)
  1386  		}
  1387  
  1388  		txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1389  			PublicKeyBase58Check: PkToString(postEntry.PosterPublicKey, utxoView.Params),
  1390  			Metadata:             "PosterPublicKeyBase58Check",
  1391  		})
  1392  	}
  1393  	if txn.TxnMeta.GetTxnType() == TxnTypeFollow {
  1394  		realTxMeta := txn.TxnMeta.(*FollowMetadata)
  1395  		_ = realTxMeta
  1396  
  1397  		txnMeta.FollowTxindexMetadata = &FollowTxindexMetadata{
  1398  			IsUnfollow: realTxMeta.IsUnfollow,
  1399  		}
  1400  
  1401  		// FollowerPublicKeyBase58Check = TransactorPublicKeyBase58Check
  1402  
  1403  		// FollowedPublicKeyBase58Check in AffectedPublicKeys
  1404  		txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1405  			PublicKeyBase58Check: PkToString(realTxMeta.FollowedPublicKey, utxoView.Params),
  1406  			Metadata:             "FollowedPublicKeyBase58Check",
  1407  		})
  1408  	}
  1409  	if txn.TxnMeta.GetTxnType() == TxnTypePrivateMessage {
  1410  		realTxMeta := txn.TxnMeta.(*PrivateMessageMetadata)
  1411  		_ = realTxMeta
  1412  
  1413  		txnMeta.PrivateMessageTxindexMetadata = &PrivateMessageTxindexMetadata{
  1414  			TimestampNanos: realTxMeta.TimestampNanos,
  1415  		}
  1416  
  1417  		// SenderPublicKeyBase58Check = TransactorPublicKeyBase58Check
  1418  
  1419  		// RecipientPublicKeyBase58Check in AffectedPublicKeys
  1420  		txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1421  			PublicKeyBase58Check: PkToString(realTxMeta.RecipientPublicKey, utxoView.Params),
  1422  			Metadata:             "RecipientPublicKeyBase58Check",
  1423  		})
  1424  	}
  1425  	if txn.TxnMeta.GetTxnType() == TxnTypeSwapIdentity {
  1426  		realTxMeta := txn.TxnMeta.(*SwapIdentityMetadataa)
  1427  		_ = realTxMeta
  1428  
  1429  		// Rosetta needs to know the current locked deso in each profile so it can model the swap of
  1430  		// the creator coins. Rosetta models a swap identity as two INPUTs and two OUTPUTs effectively
  1431  		// swapping the balances of total deso locked. If no profile exists, from/to is zero.
  1432  		fromNanos := uint64(0)
  1433  		fromProfile := utxoView.GetProfileEntryForPublicKey(realTxMeta.FromPublicKey)
  1434  		if fromProfile != nil {
  1435  			fromNanos = fromProfile.CoinEntry.DeSoLockedNanos
  1436  		}
  1437  
  1438  		toNanos := uint64(0)
  1439  		toProfile := utxoView.GetProfileEntryForPublicKey(realTxMeta.ToPublicKey)
  1440  		if toProfile != nil {
  1441  			toNanos = toProfile.CoinEntry.DeSoLockedNanos
  1442  		}
  1443  
  1444  		txnMeta.SwapIdentityTxindexMetadata = &SwapIdentityTxindexMetadata{
  1445  			FromPublicKeyBase58Check: PkToString(realTxMeta.FromPublicKey, utxoView.Params),
  1446  			ToPublicKeyBase58Check:   PkToString(realTxMeta.ToPublicKey, utxoView.Params),
  1447  			FromDeSoLockedNanos:      fromNanos,
  1448  			ToDeSoLockedNanos:        toNanos,
  1449  		}
  1450  
  1451  		// The to and from public keys are affected by this.
  1452  
  1453  		txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1454  			PublicKeyBase58Check: PkToString(realTxMeta.FromPublicKey, utxoView.Params),
  1455  			Metadata:             "FromPublicKeyBase58Check",
  1456  		})
  1457  		txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1458  			PublicKeyBase58Check: PkToString(realTxMeta.ToPublicKey, utxoView.Params),
  1459  			Metadata:             "ToPublicKeyBase58Check",
  1460  		})
  1461  	}
  1462  	if txn.TxnMeta.GetTxnType() == TxnTypeNFTBid {
  1463  		realTxMeta := txn.TxnMeta.(*NFTBidMetadata)
  1464  		_ = realTxMeta
  1465  
  1466  		txnMeta.NFTBidTxindexMetadata = &NFTBidTxindexMetadata{
  1467  			NFTPostHashHex: hex.EncodeToString(realTxMeta.NFTPostHash[:]),
  1468  			SerialNumber:   realTxMeta.SerialNumber,
  1469  			BidAmountNanos: realTxMeta.BidAmountNanos,
  1470  		}
  1471  
  1472  		// We don't send notifications for standing offers.
  1473  		if realTxMeta.SerialNumber != 0 {
  1474  			nftKey := MakeNFTKey(realTxMeta.NFTPostHash, realTxMeta.SerialNumber)
  1475  			nftEntry := utxoView.GetNFTEntryForNFTKey(&nftKey)
  1476  			txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1477  				PublicKeyBase58Check: PkToString(utxoView.GetPublicKeyForPKID(nftEntry.OwnerPKID), utxoView.Params),
  1478  				Metadata:             "NFTOwnerPublicKeyBase58Check",
  1479  			})
  1480  		}
  1481  	}
  1482  	if txn.TxnMeta.GetTxnType() == TxnTypeAcceptNFTBid {
  1483  		realTxMeta := txn.TxnMeta.(*AcceptNFTBidMetadata)
  1484  		_ = realTxMeta
  1485  
  1486  		// Rosetta needs to know the royalty paid to the creator coin so it can model the change in
  1487  		// total deso locked in the creator coin correctly.
  1488  		var prevCoinEntry *CoinEntry
  1489  		var creatorPublicKey []byte
  1490  		for _, utxoOp := range utxoOps {
  1491  			if utxoOp.Type == OperationTypeAcceptNFTBid {
  1492  				prevCoinEntry = utxoOp.PrevCoinEntry
  1493  				if utxoOp.PrevPostEntry != nil {
  1494  					creatorPublicKey = utxoOp.PrevPostEntry.PosterPublicKey
  1495  				}
  1496  				break
  1497  			}
  1498  		}
  1499  
  1500  		creatorCoinRoyaltyNanos := uint64(0)
  1501  		profileEntry := utxoView.GetProfileEntryForPublicKey(creatorPublicKey)
  1502  		if profileEntry == nil {
  1503  			glog.Errorf("Update TxIndex: Missing profile entry: %v", txn.Hash().String())
  1504  		} else if prevCoinEntry == nil {
  1505  			glog.Errorf("Update TxIndex: Missing previous coin entry: %v", txn.Hash().String())
  1506  		} else if profileEntry.CoinEntry.DeSoLockedNanos < prevCoinEntry.DeSoLockedNanos {
  1507  			glog.Errorf("Update TxIndex: CreatorCoinRoyaltyNanos overflow error: %v", txn.Hash().String())
  1508  		} else {
  1509  			creatorCoinRoyaltyNanos = profileEntry.CoinEntry.DeSoLockedNanos - prevCoinEntry.DeSoLockedNanos
  1510  		}
  1511  
  1512  		txnMeta.AcceptNFTBidTxindexMetadata = &AcceptNFTBidTxindexMetadata{
  1513  			NFTPostHashHex:              hex.EncodeToString(realTxMeta.NFTPostHash[:]),
  1514  			SerialNumber:                realTxMeta.SerialNumber,
  1515  			BidAmountNanos:              realTxMeta.BidAmountNanos,
  1516  			CreatorCoinRoyaltyNanos:     creatorCoinRoyaltyNanos,
  1517  			CreatorPublicKeyBase58Check: PkToString(creatorPublicKey, utxoView.Params),
  1518  		}
  1519  
  1520  		txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1521  			PublicKeyBase58Check: PkToString(utxoView.GetPublicKeyForPKID(realTxMeta.BidderPKID), utxoView.Params),
  1522  			Metadata:             "NFTBidderPublicKeyBase58Check",
  1523  		})
  1524  	}
  1525  	if txn.TxnMeta.GetTxnType() == TxnTypeNFTTransfer {
  1526  		realTxMeta := txn.TxnMeta.(*NFTTransferMetadata)
  1527  		_ = realTxMeta
  1528  
  1529  		txnMeta.NFTTransferTxindexMetadata = &NFTTransferTxindexMetadata{
  1530  			NFTPostHashHex: hex.EncodeToString(realTxMeta.NFTPostHash[:]),
  1531  			SerialNumber: realTxMeta.SerialNumber,
  1532  		}
  1533  
  1534  		txnMeta.AffectedPublicKeys = append(txnMeta.AffectedPublicKeys, &AffectedPublicKey{
  1535  			PublicKeyBase58Check: PkToString(realTxMeta.ReceiverPublicKey, utxoView.Params),
  1536  			Metadata:             "NFTTransferRecipientPublicKeyBase58Check",
  1537  		})
  1538  
  1539  	}
  1540  	if txn.TxnMeta.GetTxnType() == TxnTypeBasicTransfer {
  1541  		diamondLevelBytes, hasDiamondLevel := txn.ExtraData[DiamondLevelKey]
  1542  		diamondPostHash, hasDiamondPostHash := txn.ExtraData[DiamondPostHashKey]
  1543  		if hasDiamondLevel && hasDiamondPostHash {
  1544  			diamondLevel, bytesRead := Varint(diamondLevelBytes)
  1545  			if bytesRead <= 0 {
  1546  				glog.Errorf("Update TxIndex: Error reading diamond level for txn: %v", txn.Hash().String())
  1547  			} else {
  1548  				txnMeta.BasicTransferTxindexMetadata.DiamondLevel = diamondLevel
  1549  				txnMeta.BasicTransferTxindexMetadata.PostHashHex = hex.EncodeToString(diamondPostHash)
  1550  			}
  1551  		}
  1552  	}
  1553  
  1554  	return txnMeta, nil
  1555  }
  1556  
  1557  func _computeBitcoinExchangeFields(params *DeSoParams,
  1558  	txMetaa *BitcoinExchangeMetadata, totalNanosPurchasedBefore uint64, usdCentsPerBitcoin uint64) (
  1559  	_btcMeta *BitcoinExchangeTxindexMetadata, _spendPkBase58Check string, _err error) {
  1560  
  1561  	// Extract a public key from the BitcoinTransaction's inputs. Note that we only
  1562  	// consider P2PKH inputs to be valid. If no P2PKH inputs are found then we consider
  1563  	// the transaction as a whole to be invalid since we don't know who to credit the
  1564  	// new DeSo to. If we find more than one P2PKH input, we consider the public key
  1565  	// corresponding to the first of these inputs to be the one that will receive the
  1566  	// DeSo that will be created.
  1567  	publicKey, err := ExtractBitcoinPublicKeyFromBitcoinTransactionInputs(
  1568  		txMetaa.BitcoinTransaction, params.BitcoinBtcdParams)
  1569  	if err != nil {
  1570  		return nil, "", RuleErrorBitcoinExchangeValidPublicKeyNotFoundInInputs
  1571  	}
  1572  	// At this point, we should have extracted a public key from the Bitcoin transaction
  1573  	// that we expect to credit the newly-created DeSo to.
  1574  
  1575  	// The burn address cannot create this type of transaction.
  1576  	addrFromPubKey, err := btcutil.NewAddressPubKey(
  1577  		publicKey.SerializeCompressed(), params.BitcoinBtcdParams)
  1578  	if err != nil {
  1579  		return nil, "", fmt.Errorf("_connectBitcoinExchange: Error "+
  1580  			"converting public key to Bitcoin address: %v", err)
  1581  	}
  1582  	addrString := addrFromPubKey.AddressPubKeyHash().EncodeAddress()
  1583  	if addrString == params.BitcoinBurnAddress {
  1584  		return nil, "", RuleErrorBurnAddressCannotBurnBitcoin
  1585  	}
  1586  
  1587  	// Go through the transaction's outputs and count up the satoshis that are being
  1588  	// allocated to the burn address. If no Bitcoin is being sent to the burn address
  1589  	// then we consider the transaction to be invalid. Watch out for overflow as we do
  1590  	// this.
  1591  	totalBurnOutput, err := _computeBitcoinBurnOutput(
  1592  		txMetaa.BitcoinTransaction, params.BitcoinBurnAddress,
  1593  		params.BitcoinBtcdParams)
  1594  	if err != nil {
  1595  		return nil, "", RuleErrorBitcoinExchangeProblemComputingBurnOutput
  1596  	}
  1597  	if totalBurnOutput <= 0 {
  1598  		return nil, "", RuleErrorBitcoinExchangeTotalOutputLessThanOrEqualZero
  1599  	}
  1600  
  1601  	// At this point we know how many satoshis were burned and we know the public key
  1602  	// that should receive the DeSo we are going to create.
  1603  
  1604  	// Compute the amount of DeSo that we should create as a result of this transaction.
  1605  	nanosToCreate := CalcNanosToCreate(
  1606  		totalNanosPurchasedBefore, uint64(totalBurnOutput), usdCentsPerBitcoin)
  1607  
  1608  	bitcoinTxHash := txMetaa.BitcoinTransaction.TxHash()
  1609  	return &BitcoinExchangeTxindexMetadata{
  1610  		BitcoinSpendAddress: addrString,
  1611  		SatoshisBurned:      uint64(totalBurnOutput),
  1612  		NanosCreated:        nanosToCreate,
  1613  		BitcoinTxnHash:      bitcoinTxHash.String(),
  1614  	}, PkToString(publicKey.SerializeCompressed(), params), nil
  1615  }
  1616  
  1617  func ConnectTxnAndComputeTransactionMetadata(
  1618  	txn *MsgDeSoTxn, utxoView *UtxoView, blockHash *BlockHash,
  1619  	blockHeight uint32, txnIndexInBlock uint64) (*TransactionMetadata, error) {
  1620  
  1621  	totalNanosPurchasedBefore := utxoView.NanosPurchased
  1622  	usdCentsPerBitcoinBefore := utxoView.GetCurrentUSDCentsPerBitcoin()
  1623  	utxoOps, totalInput, totalOutput, fees, err := utxoView._connectTransaction(
  1624  		txn, txn.Hash(), 0, blockHeight, false, false)
  1625  	if err != nil {
  1626  		return nil, fmt.Errorf(
  1627  			"UpdateTxindex: Error connecting txn to UtxoView: %v", err)
  1628  	}
  1629  
  1630  	return ComputeTransactionMetadata(txn, utxoView, blockHash, totalNanosPurchasedBefore,
  1631  		usdCentsPerBitcoinBefore, totalInput, totalOutput, fees, txnIndexInBlock, utxoOps)
  1632  }
  1633  
  1634  // This is the main function used for adding a new txn to the pool. It will
  1635  // run all needed validation on the txn before adding it, and it will only
  1636  // accept the txn if these validations pass.
  1637  //
  1638  // The ChainLock must be held for reading calling this function.
  1639  func (mp *DeSoMempool) TryAcceptTransaction(tx *MsgDeSoTxn, rateLimit bool, verifySignatures bool) ([]*BlockHash, *MempoolTx, error) {
  1640  	// Protect concurrent access.
  1641  	mp.mtx.Lock()
  1642  	defer mp.mtx.Unlock()
  1643  
  1644  	hashes, mempoolTx, err := mp.tryAcceptTransaction(tx, rateLimit, true, verifySignatures)
  1645  
  1646  	return hashes, mempoolTx, err
  1647  }
  1648  
  1649  // See comment on ProcessUnconnectedTransactions
  1650  func (mp *DeSoMempool) processUnconnectedTransactions(acceptedTx *MsgDeSoTxn, rateLimit bool, verifySignatures bool) []*MempoolTx {
  1651  	var acceptedTxns []*MempoolTx
  1652  
  1653  	processList := list.New()
  1654  	processList.PushBack(acceptedTx)
  1655  	for processList.Len() > 0 {
  1656  		firstElement := processList.Remove(processList.Front())
  1657  		processItem := firstElement.(*MsgDeSoTxn)
  1658  
  1659  		processHash := processItem.Hash()
  1660  		if processHash == nil {
  1661  			glog.Error(fmt.Errorf("processUnconnectedTransactions: Problem hashing tx: "))
  1662  			return nil
  1663  		}
  1664  		prevOut := DeSoInput{TxID: *processHash}
  1665  		for txOutIdx := range processItem.TxOutputs {
  1666  			prevOut.Index = uint32(txOutIdx)
  1667  			unconnectedTxns, exists := mp.unconnectedTxnsByPrev[UtxoKey(prevOut)]
  1668  			if !exists {
  1669  				continue
  1670  			}
  1671  
  1672  			for _, tx := range unconnectedTxns {
  1673  				missing, mempoolTx, err := mp.tryAcceptTransaction(
  1674  					tx, rateLimit, false, verifySignatures)
  1675  				if err != nil {
  1676  					mp.removeUnconnectedTxn(tx, true)
  1677  					break
  1678  				}
  1679  
  1680  				if len(missing) > 0 {
  1681  					continue
  1682  				}
  1683  
  1684  				acceptedTxns = append(acceptedTxns, mempoolTx)
  1685  				mp.removeUnconnectedTxn(tx, false)
  1686  				processList.PushBack(tx)
  1687  
  1688  				break
  1689  			}
  1690  		}
  1691  	}
  1692  
  1693  	mp.removeUnconnectedTxnDoubleSpends(acceptedTx)
  1694  	for _, mempoolTx := range acceptedTxns {
  1695  		mp.removeUnconnectedTxnDoubleSpends(mempoolTx.Tx)
  1696  	}
  1697  
  1698  	return acceptedTxns
  1699  }
  1700  
  1701  // ProcessUnconnectedTransactions tries to see if any unconnectedTxns can now be added to the pool.
  1702  func (mp *DeSoMempool) ProcessUnconnectedTransactions(acceptedTx *MsgDeSoTxn, rateLimit bool, verifySignatures bool) []*MempoolTx {
  1703  	mp.mtx.Lock()
  1704  	acceptedTxns := mp.processUnconnectedTransactions(acceptedTx, rateLimit, verifySignatures)
  1705  	mp.mtx.Unlock()
  1706  
  1707  	return acceptedTxns
  1708  }
  1709  
  1710  func (mp *DeSoMempool) _addTxnToPublicKeyMap(mempoolTx *MempoolTx, publicKey []byte) {
  1711  	pkMapKey := MakePkMapKey(publicKey)
  1712  	mapForPk, exists := mp.pubKeyToTxnMap[pkMapKey]
  1713  	if !exists {
  1714  		mapForPk = make(map[BlockHash]*MempoolTx)
  1715  		mp.pubKeyToTxnMap[pkMapKey] = mapForPk
  1716  	}
  1717  	mapForPk[*mempoolTx.Hash] = mempoolTx
  1718  }
  1719  
  1720  func (mp *DeSoMempool) PublicKeyTxnMap(publicKey []byte) (txnMap map[BlockHash]*MempoolTx) {
  1721  	pkMapKey := MakePkMapKey(publicKey)
  1722  	return mp.pubKeyToTxnMap[pkMapKey]
  1723  }
  1724  
  1725  // TODO: This needs to consolidate with ConnectTxnAndComputeTransactionMetadata which
  1726  // does a similar thing.
  1727  func _getPublicKeysToIndexForTxn(txn *MsgDeSoTxn, params *DeSoParams) [][]byte {
  1728  	pubKeysToIndex := [][]byte{}
  1729  
  1730  	// For each output in the transaction, add the public key.
  1731  	for _, txOut := range txn.TxOutputs {
  1732  		pubKeysToIndex = append(pubKeysToIndex, txOut.PublicKey)
  1733  	}
  1734  
  1735  	// In addition to adding a mapping for each output public key, add a mapping
  1736  	// for the transaction's overall public key. This helps us find transactions
  1737  	// where this key is referenced as an input.
  1738  	if len(txn.PublicKey) == btcec.PubKeyBytesLenCompressed {
  1739  		pubKeysToIndex = append(pubKeysToIndex, txn.PublicKey)
  1740  	}
  1741  
  1742  	// If the transaction is a PrivateMessage then add a mapping from the
  1743  	// recipient to this message so that it comes up when the recipient
  1744  	// creates an augmented view. Note the sender is already covered since
  1745  	// their public key is the one at the top-level transaction, which we
  1746  	// index just above.
  1747  	if txn.TxnMeta.GetTxnType() == TxnTypePrivateMessage {
  1748  		txnMeta := txn.TxnMeta.(*PrivateMessageMetadata)
  1749  
  1750  		pubKeysToIndex = append(pubKeysToIndex, txnMeta.RecipientPublicKey)
  1751  	}
  1752  
  1753  	if txn.TxnMeta.GetTxnType() == TxnTypeFollow {
  1754  		txnMeta := txn.TxnMeta.(*FollowMetadata)
  1755  
  1756  		pubKeysToIndex = append(pubKeysToIndex, txnMeta.FollowedPublicKey)
  1757  	}
  1758  
  1759  	// Index SwapIdentity txns by the pub keys embedded within the metadata
  1760  	if txn.TxnMeta.GetTxnType() == TxnTypeSwapIdentity {
  1761  		txnMeta := txn.TxnMeta.(*SwapIdentityMetadataa)
  1762  
  1763  		// The ToPublicKey and the FromPublicKey can differ from the txn.PublicKey,
  1764  		// and so we need to index them separately.
  1765  		pubKeysToIndex = append(pubKeysToIndex, txnMeta.ToPublicKey)
  1766  		pubKeysToIndex = append(pubKeysToIndex, txnMeta.FromPublicKey)
  1767  	}
  1768  
  1769  	if txn.TxnMeta.GetTxnType() == TxnTypeCreatorCoin {
  1770  		txnMeta := txn.TxnMeta.(*CreatorCoinMetadataa)
  1771  
  1772  		// The HODLer public key is indexed when we return the txn.PublicKey
  1773  		// so we just need to additionally consider the creator.
  1774  		pubKeysToIndex = append(pubKeysToIndex, txnMeta.ProfilePublicKey)
  1775  	}
  1776  
  1777  	// If the transaction is a BitcoinExchange transaction, add a mapping
  1778  	// for the implicit output created by it. Also add a mapping for the
  1779  	// burn public key so that we can easily find all burns in the block
  1780  	// explorer.
  1781  	if txn.TxnMeta.GetTxnType() == TxnTypeBitcoinExchange {
  1782  		// Add the mapping for the implicit output
  1783  		{
  1784  			txnMeta := txn.TxnMeta.(*BitcoinExchangeMetadata)
  1785  			publicKey, err := ExtractBitcoinPublicKeyFromBitcoinTransactionInputs(
  1786  				txnMeta.BitcoinTransaction, params.BitcoinBtcdParams)
  1787  			if err != nil {
  1788  				glog.Errorf("_addMempoolTxToPubKeyOutputMap: Problem extracting public key "+
  1789  					"from Bitcoin transaction for txnMeta %v", txnMeta)
  1790  			} else {
  1791  				pubKeysToIndex = append(pubKeysToIndex, publicKey.SerializeCompressed())
  1792  			}
  1793  		}
  1794  
  1795  		// Add the mapping for the burn public key.
  1796  		pubKeysToIndex = append(pubKeysToIndex, MustBase58CheckDecode(BurnPubKeyBase58Check))
  1797  	}
  1798  
  1799  	return pubKeysToIndex
  1800  }
  1801  
  1802  func (mp *DeSoMempool) _addMempoolTxToPubKeyOutputMap(mempoolTx *MempoolTx) {
  1803  	// Index the transaction by any associated public keys.
  1804  	publicKeysToIndex := _getPublicKeysToIndexForTxn(mempoolTx.Tx, mp.bc.params)
  1805  	for _, pkToIndex := range publicKeysToIndex {
  1806  		mp._addTxnToPublicKeyMap(mempoolTx, pkToIndex)
  1807  	}
  1808  }
  1809  
  1810  func (mp *DeSoMempool) processTransaction(
  1811  	tx *MsgDeSoTxn, allowUnconnectedTxn, rateLimit bool,
  1812  	peerID uint64, verifySignatures bool) ([]*MempoolTx, error) {
  1813  
  1814  	txHash := tx.Hash()
  1815  	if txHash == nil {
  1816  		return nil, fmt.Errorf("ProcessTransaction: Problem hashing tx")
  1817  	}
  1818  	glog.V(2).Infof("Processing transaction %v", txHash)
  1819  
  1820  	// Run validation and try to add this txn to the pool.
  1821  	missingParents, mempoolTx, err := mp.tryAcceptTransaction(
  1822  		tx, rateLimit, true, verifySignatures)
  1823  	if err != nil {
  1824  		return nil, err
  1825  	}
  1826  
  1827  	// Update the readOnlyUtxoView if we've accumulated enough calls
  1828  	// to this function. This needs to be done after the tryAcceptTransaction
  1829  	// call
  1830  	if mp.generateReadOnlyUtxoView &&
  1831  		mp.totalProcessTransactionCalls%ReadOnlyUtxoViewRegenerationIntervalTxns == 0 {
  1832  		// We call the version that doesn't lock.
  1833  		mp.regenerateReadOnlyView()
  1834  	}
  1835  	// Update the total number of transactions we've processed.
  1836  	mp.totalProcessTransactionCalls += 1
  1837  
  1838  	if len(missingParents) == 0 {
  1839  		newTxs := mp.processUnconnectedTransactions(tx, rateLimit, verifySignatures)
  1840  		acceptedTxs := make([]*MempoolTx, len(newTxs)+1)
  1841  
  1842  		acceptedTxs[0] = mempoolTx
  1843  		copy(acceptedTxs[1:], newTxs)
  1844  
  1845  		return acceptedTxs, nil
  1846  	}
  1847  
  1848  	// Reject the txn if it's an unconnected txn and we're set up to reject unconnectedTxns.
  1849  	if !allowUnconnectedTxn {
  1850  		glog.V(2).Infof("DeSoMempool.processTransaction: TxErrorUnconnectedTxnNotAllowed: %v %v",
  1851  			tx.Hash(), tx.TxnMeta.GetTxnType())
  1852  		return nil, TxErrorUnconnectedTxnNotAllowed
  1853  	}
  1854  
  1855  	// Try to add the the transaction to the pool as an unconnected txn.
  1856  	err = mp.tryAddUnconnectedTxn(tx, peerID)
  1857  	if err != nil {
  1858  		glog.V(2).Infof("DeSoMempool.processTransaction: Error adding transaction as unconnected txn: %v", err)
  1859  	}
  1860  	return nil, err
  1861  }
  1862  
  1863  // ProcessTransaction is the main function called by outside services to potentially
  1864  // add a transaction to the mempool. It will try to add the txn to the main pool, and
  1865  // then try to add it as an unconnected txn if that fails.
  1866  func (mp *DeSoMempool) ProcessTransaction(tx *MsgDeSoTxn, allowUnconnectedTxn bool, rateLimit bool, peerID uint64, verifySignatures bool) ([]*MempoolTx, error) {
  1867  	// Protect concurrent access.
  1868  	mp.mtx.Lock()
  1869  	defer mp.mtx.Unlock()
  1870  
  1871  	return mp.processTransaction(tx, allowUnconnectedTxn, rateLimit, peerID, verifySignatures)
  1872  }
  1873  
  1874  // Returns an estimate of the number of txns in the mempool. This is an estimate because
  1875  // it looks up the number from a readOnly view, which updates at regular intervals and
  1876  // *not* every time a txn is added to the pool.
  1877  func (mp *DeSoMempool) Count() int {
  1878  	return len(mp.readOnlyUniversalTransactionList)
  1879  }
  1880  
  1881  // Returns the hashes of all the txns in the pool using the readOnly view, which could be
  1882  // slightly out of date.
  1883  func (mp *DeSoMempool) TxHashes() []*BlockHash {
  1884  	poolMap := mp.readOnlyUniversalTransactionMap
  1885  	hashes := make([]*BlockHash, len(poolMap))
  1886  	ii := 0
  1887  	for hash := range poolMap {
  1888  		hashCopy := hash
  1889  		hashes[ii] = &hashCopy
  1890  		ii++
  1891  	}
  1892  
  1893  	return hashes
  1894  }
  1895  
  1896  // Returns all MempoolTxs from the readOnly view.
  1897  func (mp *DeSoMempool) MempoolTxs() []*MempoolTx {
  1898  	poolMap := mp.readOnlyUniversalTransactionMap
  1899  	descs := make([]*MempoolTx, len(poolMap))
  1900  	i := 0
  1901  	for _, desc := range poolMap {
  1902  		descs[i] = desc
  1903  		i++
  1904  	}
  1905  
  1906  	return descs
  1907  }
  1908  
  1909  func (mp *DeSoMempool) GetMempoolSummaryStats() (_summaryStatsMap map[string]*SummaryStats) {
  1910  	allTxns := mp.readOnlyUniversalTransactionList
  1911  
  1912  	transactionSummaryStats := make(map[string]*SummaryStats)
  1913  	for _, mempoolTx := range allTxns {
  1914  		// Update the mempool summary stats.
  1915  		updatedSummaryStats := &SummaryStats{}
  1916  		txnType := mempoolTx.Tx.TxnMeta.GetTxnType().String()
  1917  		summaryStats := transactionSummaryStats[txnType]
  1918  		if summaryStats == nil {
  1919  			updatedSummaryStats.Count = 1
  1920  			updatedSummaryStats.TotalBytes = mempoolTx.TxSizeBytes
  1921  		} else {
  1922  			updatedSummaryStats = summaryStats
  1923  			updatedSummaryStats.Count += 1
  1924  			updatedSummaryStats.TotalBytes += mempoolTx.TxSizeBytes
  1925  		}
  1926  		transactionSummaryStats[txnType] = updatedSummaryStats
  1927  
  1928  	}
  1929  
  1930  	// Return the map
  1931  	return transactionSummaryStats
  1932  }
  1933  
  1934  func (mp *DeSoMempool) inefficientRemoveTransaction(tx *MsgDeSoTxn) {
  1935  	// In this case we remove the transaction by re-adding all the txns we can
  1936  	// to the mempool except this one.
  1937  	// TODO(performance): This could be a bit slow.
  1938  	//
  1939  	// Create a new DeSoMempool. No need to set the min fees since we're just using
  1940  	// this as a temporary data structure for validation.
  1941  	//
  1942  	// Don't make the new pool object deal with the BlockCypher API.
  1943  	newPool := NewDeSoMempool(mp.bc, 0, /* rateLimitFeeRateNanosPerKB */
  1944  		0, /* minFeeRateNanosPerKB */
  1945  		"" /*blockCypherAPIKey*/, false,
  1946  		"" /*dataDir*/, "")
  1947  	// At this point the block txns have been added to the new pool. Now we need to
  1948  	// add the txns from the original pool. Start by fetching them in slice form.
  1949  	oldMempoolTxns, oldUnconnectedTxns, err := mp._getTransactionsOrderedByTimeAdded()
  1950  	if err != nil {
  1951  		glog.Warning(errors.Wrapf(err, "inefficientRemoveTransaction: "))
  1952  	}
  1953  	// Iterate through the pool transactions and add them to our new pool.
  1954  
  1955  	for _, mempoolTx := range oldMempoolTxns {
  1956  		if *(mempoolTx.Tx.Hash()) == *(tx.Hash()) {
  1957  			continue
  1958  		}
  1959  
  1960  		// Attempt to add the txn to the mempool as we go. If it fails that's fine.
  1961  		txnsAccepted, err := newPool.processTransaction(
  1962  			mempoolTx.Tx, false /*allowUnconnectedTxn*/, false, /*rateLimit*/
  1963  			0 /*peerID*/, false /*verifySignatures*/)
  1964  		if err != nil {
  1965  			glog.Warning(errors.Wrapf(err, "inefficientRemoveTransaction: "))
  1966  		}
  1967  		if len(txnsAccepted) == 0 {
  1968  			glog.Warningf("inefficientRemoveTransaction: Dropping txn %v", mempoolTx.Tx)
  1969  		}
  1970  	}
  1971  	// Iterate through the unconnectedTxns and add them to our new pool as well.
  1972  	for _, oTx := range oldUnconnectedTxns {
  1973  		rateLimit := false
  1974  		allowUnconnectedTxn := true
  1975  		verifySignatures := false
  1976  		_, err := newPool.processTransaction(oTx.tx, allowUnconnectedTxn, rateLimit, oTx.peerID, verifySignatures)
  1977  		if err != nil {
  1978  			glog.Warning(errors.Wrapf(err, "inefficientRemoveTransaction: "))
  1979  		}
  1980  	}
  1981  
  1982  	// At this point the new mempool should be a duplicate of the original mempool but with
  1983  	// the non-double-spend transactions added (with timestamps set before the transactions that
  1984  	// were in the original pool.
  1985  
  1986  	// Replace the internal mappings of the original pool with the mappings of the new
  1987  	// pool.
  1988  	mp.resetPool(newPool)
  1989  }
  1990  
  1991  func (mp *DeSoMempool) InefficientRemoveTransaction(tx *MsgDeSoTxn) {
  1992  	mp.mtx.Lock()
  1993  	defer mp.mtx.Unlock()
  1994  
  1995  	mp.inefficientRemoveTransaction(tx)
  1996  }
  1997  
  1998  func (mp *DeSoMempool) StartReadOnlyUtxoViewRegenerator() {
  1999  	glog.Info("Calling StartReadOnlyUtxoViewRegenerator...")
  2000  
  2001  	go func() {
  2002  		var oldSeqNum int64
  2003  	out:
  2004  		for {
  2005  			select {
  2006  			case <-time.After(time.Duration(ReadOnlyUtxoViewRegenerationIntervalSeconds) * time.Second):
  2007  				glog.V(2).Infof("StartReadOnlyUtxoViewRegenerator: Woke up!")
  2008  
  2009  				// When we wake up, only do an update if one didn't occur since before
  2010  				// we slept. Note that the number of transactions being processed can
  2011  				// also trigger an update, which is why this check is necessary.
  2012  				newSeqNum := atomic.LoadInt64(&mp.readOnlyUtxoViewSequenceNumber)
  2013  				if oldSeqNum == newSeqNum {
  2014  					glog.V(2).Infof("StartReadOnlyUtxoViewRegenerator: Updating view at prescribed interval")
  2015  					// Acquire a read lock when we do this.
  2016  					mp.RegenerateReadOnlyView()
  2017  					glog.V(2).Infof("StartReadOnlyUtxoViewRegenerator: Finished view update at prescribed interval")
  2018  				} else {
  2019  					glog.V(2).Infof("StartReadOnlyUtxoViewRegenerator: View updated while sleeping; nothing to do")
  2020  				}
  2021  
  2022  				// Get the sequence number before our timer hits.
  2023  				oldSeqNum = atomic.LoadInt64(&mp.readOnlyUtxoViewSequenceNumber)
  2024  
  2025  			case <-mp.quit:
  2026  				break out
  2027  			}
  2028  		}
  2029  	}()
  2030  }
  2031  
  2032  func (mp *DeSoMempool) regenerateReadOnlyView() error {
  2033  	newView, err := mp.universalUtxoView.CopyUtxoView()
  2034  	if err != nil {
  2035  		return fmt.Errorf("Error generating readOnlyUtxoView: %v", err)
  2036  	}
  2037  
  2038  	// Update the view and bump the sequence number. This is how callers will
  2039  	// know that the view was updated.
  2040  	mp.readOnlyUtxoView = newView
  2041  
  2042  	newTxnList := []*MempoolTx{}
  2043  	txMap := make(map[BlockHash]*MempoolTx)
  2044  	for _, mempoolTx := range mp.universalTransactionList {
  2045  		newTxnList = append(newTxnList, mempoolTx)
  2046  		txMap[*mempoolTx.Hash] = mempoolTx
  2047  	}
  2048  
  2049  	mp.readOnlyUniversalTransactionList = newTxnList
  2050  	mp.readOnlyUniversalTransactionMap = txMap
  2051  
  2052  	atomic.AddInt64(&mp.readOnlyUtxoViewSequenceNumber, 1)
  2053  	return nil
  2054  }
  2055  
  2056  func (mp *DeSoMempool) RegenerateReadOnlyView() error {
  2057  	mp.mtx.RLock()
  2058  	defer mp.mtx.RUnlock()
  2059  
  2060  	return mp.regenerateReadOnlyView()
  2061  }
  2062  
  2063  func (mp *DeSoMempool) BlockUntilReadOnlyViewRegenerated() {
  2064  	oldSeqNum := atomic.LoadInt64(&mp.readOnlyUtxoViewSequenceNumber)
  2065  	newSeqNum := oldSeqNum
  2066  	for newSeqNum == oldSeqNum {
  2067  		// Check fairly often. Not too often.
  2068  		time.Sleep(100 * time.Millisecond)
  2069  
  2070  		newSeqNum = atomic.LoadInt64(&mp.readOnlyUtxoViewSequenceNumber)
  2071  	}
  2072  }
  2073  
  2074  func (mp *DeSoMempool) StartMempoolDBDumper() {
  2075  	// If we were instructed to dump txns to the db, then do so periodically
  2076  	// Note this acquired a very minimal lock on the universalTransactionList
  2077  	go func() {
  2078  	out:
  2079  		for {
  2080  			select {
  2081  			case <-time.After(30 * time.Second):
  2082  				glog.Info("StartMempoolDBDumper: Waking up! Dumping txns now...")
  2083  
  2084  				// Dump the txns and time it.
  2085  				mp.DumpTxnsToDB()
  2086  
  2087  			case <-mp.quit:
  2088  				break out
  2089  			}
  2090  		}
  2091  	}()
  2092  }
  2093  
  2094  func (mp *DeSoMempool) LoadTxnsFromDB() {
  2095  	glog.Infof("LoadTxnsFromDB: Loading mempool txns from db because --load_mempool_txns_from_db was set")
  2096  	startTime := time.Now()
  2097  
  2098  	// The mempool shuffles dumped txns between temp, previous, and latest dirs. By dumping txns
  2099  	// to temp first, we ensure that we always have a full set of txns in latest and previous dir.
  2100  	// Note that it is possible for previousDir to exist even if latestDir does not because
  2101  	// the machine could crash after moving latest to previous. Thus, we check both.
  2102  	savedTxnsDir := filepath.Join(mp.mempoolDir, "latest_mempool_dump")
  2103  	_, err := os.Stat(savedTxnsDir)
  2104  	if os.IsNotExist(err) {
  2105  		savedTxnsDir = filepath.Join(mp.mempoolDir, "previous_mempool_dump")
  2106  		_, err = os.Stat(savedTxnsDir)
  2107  		if err != nil {
  2108  			glog.Infof("LoadTxnsFromDB: os.Stat(previousDir) error: %v", err)
  2109  			return
  2110  		}
  2111  	} else if err != nil {
  2112  		glog.Infof("LoadTxnsFromDB: os.Stat(latestDir) error: %v", err)
  2113  		return
  2114  	}
  2115  
  2116  	// If we make it this far, we found a mempool dump to load.  Woohoo!
  2117  	tempMempoolDBOpts := badger.DefaultOptions(savedTxnsDir)
  2118  	tempMempoolDBOpts.ValueDir = savedTxnsDir
  2119  	tempMempoolDBOpts.MemTableSize = 1024 << 20
  2120  	glog.Infof("LoadTxnsFrom: Opening new temp db %v", savedTxnsDir)
  2121  	tempMempoolDB, err := badger.Open(tempMempoolDBOpts)
  2122  	if err != nil {
  2123  		glog.Infof("LoadTxnsFrom: Could not open temp db to dump mempool: %v", err)
  2124  		return
  2125  	}
  2126  	defer tempMempoolDB.Close()
  2127  
  2128  	// Get all saved mempool transactions from the DB.
  2129  	dbMempoolTxnsOrderedByTime, err := DbGetAllMempoolTxnsSortedByTimeAdded(tempMempoolDB)
  2130  	if err != nil {
  2131  		log.Fatalf("NewDeSoMempool: Failed to get mempoolTxs from the DB: %v", err)
  2132  	}
  2133  
  2134  	for _, mempoolTxn := range dbMempoolTxnsOrderedByTime {
  2135  		_, err := mp.processTransaction(mempoolTxn, false, false, 0, false)
  2136  		if err != nil {
  2137  			// Log errors but don't stop adding transactions. We do this because we'd prefer
  2138  			// to drop a transaction here or there rather than lose the whole block because
  2139  			// of one bad apple.
  2140  			glog.Warning(errors.Wrapf(err, "NewDeSoMempool: Not adding txn from DB "+
  2141  				"because it had an error: "))
  2142  		}
  2143  	}
  2144  	endTime := time.Now()
  2145  	glog.Infof("LoadTxnsFromDB: Loaded %v txns in %v seconds", len(dbMempoolTxnsOrderedByTime), endTime.Sub(startTime).Seconds())
  2146  }
  2147  
  2148  func (mp *DeSoMempool) Stop() {
  2149  	close(mp.quit)
  2150  }
  2151  
  2152  // Create a new pool with no transactions in it.
  2153  func NewDeSoMempool(_bc *Blockchain, _rateLimitFeerateNanosPerKB uint64,
  2154  	_minFeerateNanosPerKB uint64, _blockCypherAPIKey string,
  2155  	_runReadOnlyViewUpdater bool, _dataDir string, _mempoolDumpDir string) *DeSoMempool {
  2156  
  2157  	utxoView, _ := NewUtxoView(_bc.db, _bc.params, _bc.postgres)
  2158  	backupUtxoView, _ := NewUtxoView(_bc.db, _bc.params, _bc.postgres)
  2159  	readOnlyUtxoView, _ := NewUtxoView(_bc.db, _bc.params, _bc.postgres)
  2160  	newPool := &DeSoMempool{
  2161  		quit:                            make(chan struct{}),
  2162  		bc:                              _bc,
  2163  		rateLimitFeeRateNanosPerKB:      _rateLimitFeerateNanosPerKB,
  2164  		minFeeRateNanosPerKB:            _minFeerateNanosPerKB,
  2165  		poolMap:                         make(map[BlockHash]*MempoolTx),
  2166  		unconnectedTxns:                 make(map[BlockHash]*UnconnectedTx),
  2167  		unconnectedTxnsByPrev:           make(map[UtxoKey]map[BlockHash]*MsgDeSoTxn),
  2168  		outpoints:                       make(map[UtxoKey]*MsgDeSoTxn),
  2169  		pubKeyToTxnMap:                  make(map[PkMapKey]map[BlockHash]*MempoolTx),
  2170  		blockCypherAPIKey:               _blockCypherAPIKey,
  2171  		backupUniversalUtxoView:         backupUtxoView,
  2172  		universalUtxoView:               utxoView,
  2173  		mempoolDir:                      _mempoolDumpDir,
  2174  		generateReadOnlyUtxoView:        _runReadOnlyViewUpdater,
  2175  		readOnlyUtxoView:                readOnlyUtxoView,
  2176  		readOnlyUniversalTransactionMap: make(map[BlockHash]*MempoolTx),
  2177  		readOnlyOutpoints:               make(map[UtxoKey]*MsgDeSoTxn),
  2178  		dataDir:                         _dataDir,
  2179  	}
  2180  
  2181  	if newPool.mempoolDir != "" {
  2182  		newPool.LoadTxnsFromDB()
  2183  	}
  2184  
  2185  	// If the caller wants the readOnlyUtxoView to update periodically then kick
  2186  	// that off here.
  2187  	if newPool.generateReadOnlyUtxoView {
  2188  		newPool.StartReadOnlyUtxoViewRegenerator()
  2189  	}
  2190  
  2191  	if newPool.mempoolDir != "" {
  2192  		newPool.StartMempoolDBDumper()
  2193  	}
  2194  
  2195  	return newPool
  2196  }