github.com/johnathanhowell/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 }