File: transactionpool.go

package info (click to toggle)
sia 1.3.0-4
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,340 kB
  • sloc: makefile: 80; sh: 52
file content (169 lines) | stat: -rw-r--r-- 6,929 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package modules

import (
	"errors"

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
	"github.com/NebulousLabs/Sia/types"
)

const (
	// TransactionSizeLimit defines the size of the largest transaction that
	// will be accepted by the transaction pool according to the IsStandard
	// rules.
	TransactionSizeLimit = 32e3

	// TransactionSetSizeLimit defines the largest set of dependent unconfirmed
	// transactions that will be accepted by the transaction pool.
	TransactionSetSizeLimit = 250e3
)

var (
	// ErrDuplicateTransactionSet is the error that gets returned if a
	// duplicate transaction set is given to the transaction pool.
	ErrDuplicateTransactionSet = errors.New("transaction set contains only duplicate transactions")

	// ErrLargeTransaction is the error that gets returned if a transaction
	// provided to the transaction pool is larger than what is allowed by the
	// IsStandard rules.
	ErrLargeTransaction = errors.New("transaction is too large for this transaction pool")

	// ErrLargeTransactionSet is the error that gets returned if a transaction
	// set given to the transaction pool is larger than the limit placed by the
	// IsStandard rules of the transaction pool.
	ErrLargeTransactionSet = errors.New("transaction set is too large for this transaction pool")

	// ErrInvalidArbPrefix is the error that gets returned if a transaction is
	// submitted to the transaction pool which contains a prefix that is not
	// recognized. This helps prevent miners on old versions from mining
	// potentially illegal transactions in the event of a soft-fork.
	ErrInvalidArbPrefix = errors.New("transaction contains non-standard arbitrary data")

	// PrefixNonSia defines the prefix that should be appended to any
	// transactions that use the arbitrary data for reasons outside of the
	// standard Sia protocol. This will prevent these transactions from being
	// rejected by the IsStandard set of rules, but also means that the data
	// will never be used within the formal Sia protocol.
	PrefixNonSia = types.Specifier{'N', 'o', 'n', 'S', 'i', 'a'}

	// TransactionPoolDir is the name of the directory that is used to store
	// the transaction pool's persistent data.
	TransactionPoolDir = "transactionpool"
)

type (
	// ConsensusConflict implements the error interface, and indicates that a
	// transaction was rejected due to being incompatible with the current
	// consensus set, meaning either a double spend or a consensus rule violation -
	// it is unlikely that the transaction will ever be valid.
	ConsensusConflict string

	// TransactionSetID is a type-safe wrapper for a crypto.Hash that represents
	// the ID of an entire transaction set.
	TransactionSetID crypto.Hash

	// A TransactionPoolDiff indicates the adding or removal of a transaction set to
	// the transaction pool. The transactions in the pool are not persisted, so at
	// startup modules should assume an empty transaction pool.
	TransactionPoolDiff struct {
		AppliedTransactions  []*UnconfirmedTransactionSet
		RevertedTransactions []TransactionSetID
	}

	// UnconfirmedTransactionSet defines a new unconfirmed transaction that has
	// been added to the transaction pool. ID is the ID of the set, IDs contians
	// an ID for each transaction, eliminating the need to recompute it (because
	// that's an expensive operation).
	UnconfirmedTransactionSet struct {
		Change *ConsensusChange
		ID     TransactionSetID

		IDs          []types.TransactionID
		Sizes        []uint64
		Transactions []types.Transaction
	}
)

type (
	// A TransactionPoolSubscriber receives updates about the confirmed and
	// unconfirmed set from the transaction pool. Generally, there is no need to
	// subscribe to both the consensus set and the transaction pool.
	TransactionPoolSubscriber interface {
		// ReceiveTransactionPoolUpdate notifies subscribers of a change to the
		// consensus set and/or unconfirmed set, and includes the consensus change
		// that would result if all of the transactions made it into a block.
		ReceiveUpdatedUnconfirmedTransactions(*TransactionPoolDiff)
	}

	// A TransactionPool manages unconfirmed transactions.
	TransactionPool interface {
		// AcceptTransactionSet accepts a set of potentially interdependent
		// transactions.
		AcceptTransactionSet([]types.Transaction) error

		// Broadcast broadcasts a transaction set to all of the transaction pool's
		// peers.
		Broadcast(ts []types.Transaction)

		// Close is necessary for clean shutdown (e.g. during testing).
		Close() error

		// FeeEstimation returns an estimation for how high the transaction fee
		// needs to be per byte. The minimum recommended targets getting accepted
		// in ~3 blocks, and the maximum recommended targets getting accepted
		// immediately. Taking the average has a moderate chance of being accepted
		// within one block. The minimum has a strong chance of getting accepted
		// within 10 blocks.
		FeeEstimation() (minimumRecommended, maximumRecommended types.Currency)

		// PurgeTransactionPool is a temporary function available to the miner. In
		// the event that a miner mines an unacceptable block, the transaction pool
		// will be purged to clear out the transaction pool and get rid of the
		// illegal transaction. This should never happen, however there are bugs
		// that make this condition necessary.
		PurgeTransactionPool()

		// TransactionList returns a list of all transactions in the transaction
		// pool. The transactions are provided in an order that can acceptably be
		// put into a block.
		TransactionList() []types.Transaction

		// TransactionPoolSubscribe adds a subscriber to the transaction pool.
		// Subscribers will receive all consensus set changes as well as
		// transaction pool changes, and should not subscribe to both.
		TransactionPoolSubscribe(TransactionPoolSubscriber)

		// Transaction returns the transaction and unconfirmed parents
		// corresponding to the provided transaction id.
		Transaction(id types.TransactionID) (txn types.Transaction, unconfirmedParents []types.Transaction, exists bool)

		// Unsubscribe removes a subscriber from the transaction pool.
		// This is necessary for clean shutdown of the miner.
		Unsubscribe(TransactionPoolSubscriber)
	}
)

// NewConsensusConflict returns a consensus conflict, which implements the
// error interface.
func NewConsensusConflict(s string) ConsensusConflict {
	return ConsensusConflict("consensus conflict: " + s)
}

// Error implements the error interface, turning the consensus conflict into an
// acceptable error type.
func (cc ConsensusConflict) Error() string {
	return string(cc)
}

// CalculateFee returns the fee-per-byte of a transaction set.
func CalculateFee(ts []types.Transaction) types.Currency {
	var sum types.Currency
	for _, t := range ts {
		for _, fee := range t.MinerFees {
			sum = sum.Add(fee)
		}
	}
	size := len(encoding.Marshal(ts))
	return sum.Div64(uint64(size))
}