github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/transactionpool/transactionpool.go (about)

     1  package transactionpool
     2  
     3  import (
     4  	"errors"
     5  
     6  	"github.com/NebulousLabs/demotemutex"
     7  
     8  	"github.com/NebulousLabs/Sia/crypto"
     9  	"github.com/NebulousLabs/Sia/modules"
    10  	"github.com/NebulousLabs/Sia/persist"
    11  	"github.com/NebulousLabs/Sia/types"
    12  )
    13  
    14  const (
    15  	dbFilename = "transactionpool.db"
    16  )
    17  
    18  var (
    19  	dbMetadata = persist.Metadata{
    20  		Header:  "Sia Transaction Pool DB",
    21  		Version: "0.6.0",
    22  	}
    23  
    24  	errNilCS      = errors.New("transaction pool cannot initialize with a nil consensus set")
    25  	errNilGateway = errors.New("transaction pool cannot initialize with a nil gateway")
    26  )
    27  
    28  type (
    29  	// ObjectIDs are the IDs of objects such as siacoin outputs and file
    30  	// contracts, and are used to see if there are conflicts or overlaps within
    31  	// the transaction pool. A TransactionSetID is the hash of a transaction
    32  	// set.
    33  	ObjectID         crypto.Hash
    34  	TransactionSetID crypto.Hash
    35  
    36  	// The TransactionPool tracks incoming transactions, accepting them or
    37  	// rejecting them based on internal criteria such as fees and unconfirmed
    38  	// double spends.
    39  	TransactionPool struct {
    40  		// Dependencies of the transaction pool.
    41  		consensusSet modules.ConsensusSet
    42  		gateway      modules.Gateway
    43  
    44  		// To prevent double spends in the unconfirmed transaction set, the
    45  		// transaction pool keeps a list of all objects that have either been
    46  		// created or consumed by the current unconfirmed transaction pool. All
    47  		// transactions with overlaps are rejected. This model is
    48  		// over-aggressive - one transaction set may create an object that
    49  		// another transaction set spends. This is done to minimize the
    50  		// computation and memory load on the transaction pool. Dependent
    51  		// transactions should be lumped into a single transaction set.
    52  		//
    53  		// transactionSetDiffs map form a transaction set id to the set of
    54  		// diffs that resulted from the transaction set.
    55  		knownObjects        map[ObjectID]TransactionSetID
    56  		transactionSets     map[TransactionSetID][]types.Transaction
    57  		transactionSetDiffs map[TransactionSetID]modules.ConsensusChange
    58  		transactionListSize int
    59  		// TODO: Write a consistency check comparing transactionSets,
    60  		// transactionSetDiffs.
    61  		//
    62  		// TODO: Write a consistency check making sure that all unconfirmedIDs
    63  		// point to the right place, and that all UnconfirmedIDs are accounted for.
    64  
    65  		// The consensus change index tracks how many consensus changes have
    66  		// been sent to the transaction pool. When a new subscriber joins the
    67  		// transaction pool, all prior consensus changes are sent to the new
    68  		// subscriber.
    69  		subscribers []modules.TransactionPoolSubscriber
    70  
    71  		// Utilities.
    72  		db         *persist.BoltDatabase
    73  		mu         demotemutex.DemoteMutex
    74  		persistDir string
    75  	}
    76  )
    77  
    78  // New creates a transaction pool that is ready to receive transactions.
    79  func New(cs modules.ConsensusSet, g modules.Gateway, persistDir string) (*TransactionPool, error) {
    80  	// Check that the input modules are non-nil.
    81  	if cs == nil {
    82  		return nil, errNilCS
    83  	}
    84  	if g == nil {
    85  		return nil, errNilGateway
    86  	}
    87  
    88  	// Initialize a transaction pool.
    89  	tp := &TransactionPool{
    90  		consensusSet: cs,
    91  		gateway:      g,
    92  
    93  		knownObjects:        make(map[ObjectID]TransactionSetID),
    94  		transactionSets:     make(map[TransactionSetID][]types.Transaction),
    95  		transactionSetDiffs: make(map[TransactionSetID]modules.ConsensusChange),
    96  
    97  		persistDir: persistDir,
    98  	}
    99  
   100  	// Open the tpool database.
   101  	err := tp.initPersist()
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  
   106  	// Register RPCs
   107  	g.RegisterRPC("RelayTransactionSet", tp.relayTransactionSet)
   108  
   109  	return tp, nil
   110  }
   111  
   112  func (tp *TransactionPool) Close() error {
   113  	tp.consensusSet.Unsubscribe(tp)
   114  	return tp.db.Close()
   115  }
   116  
   117  // FeeEstimation returns an estimation for what fee should be applied to
   118  // transactions.
   119  func (tp *TransactionPool) FeeEstimation() (min, max types.Currency) {
   120  	// TODO: The fee estimation tool should look at the recent blocks and use
   121  	// them to guage what sort of fee should be required, as opposed to just
   122  	// guessing blindly.
   123  	return types.SiacoinPrecision.Mul64(10).Div64(1e3), types.SiacoinPrecision.Mul64(25).Div64(1e3)
   124  }
   125  
   126  // TransactionList returns a list of all transactions in the transaction pool.
   127  // The transactions are provided in an order that can acceptably be put into a
   128  // block.
   129  func (tp *TransactionPool) TransactionList() []types.Transaction {
   130  	var txns []types.Transaction
   131  	for _, tSet := range tp.transactionSets {
   132  		txns = append(txns, tSet...)
   133  	}
   134  	return txns
   135  }