forked from NebulousLabs/Sia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
miner.go
135 lines (112 loc) · 3.09 KB
/
miner.go
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
package miner
import (
"errors"
"sync"
"time"
"github.com/NebulousLabs/Sia/build"
"github.com/NebulousLabs/Sia/modules"
"github.com/NebulousLabs/Sia/types"
)
const (
iterationsPerAttempt = 32 * 1024
)
type Miner struct {
cs modules.ConsensusSet
tpool modules.TransactionPool
wallet modules.Wallet
// Block variables - helps the miner construct the next block.
parent types.BlockID
height types.BlockHeight
transactions []types.Transaction
target types.Target
earliestTimestamp types.Timestamp
address types.UnlockHash
startTime time.Time
attempts uint64
hashRate int64
blocksFound []types.BlockID
threads int // how many threads the miner uses, shouldn't ever be 0.
desiredThreads int // 0 if not mining.
runningThreads int
subscribers []chan struct{}
mu sync.Mutex
}
// New returns a ready-to-go miner that is not mining.
func New(cs modules.ConsensusSet, tpool modules.TransactionPool, w modules.Wallet) (m *Miner, err error) {
// Create the miner and its dependencies.
if cs == nil {
err = errors.New("miner cannot use a nil state")
return
}
if tpool == nil {
err = errors.New("miner cannot use a nil transaction pool")
return
}
if w == nil {
err = errors.New("miner cannot use a nil wallet")
return
}
currentBlock := cs.CurrentBlock().ID()
currentTarget, exists1 := cs.ChildTarget(currentBlock)
earliestTimestamp, exists2 := cs.EarliestChildTimestamp(currentBlock)
if build.DEBUG {
if !exists1 {
panic("could not get child target")
}
if !exists2 {
panic("could not get child earliest timestamp")
}
}
m = &Miner{
cs: cs,
tpool: tpool,
wallet: w,
parent: currentBlock,
target: currentTarget,
earliestTimestamp: earliestTimestamp,
threads: 1,
}
// Get an address for the miner payout.
addr, _, err := m.wallet.CoinAddress(false) // false indicates that the address should not be visible to the user.
if err != nil {
return
}
m.address = addr
// Subscribe to the transaction pool to get transactions to put in blocks.
m.tpool.TransactionPoolSubscribe(m)
return
}
// SetThreads establishes how many threads the miner will use when mining.
func (m *Miner) SetThreads(threads int) error {
m.mu.Lock()
defer m.mu.Unlock()
if threads == 0 {
return errors.New("cannot have a miner with 0 threads.")
}
m.threads = threads
m.attempts = 0
m.startTime = time.Now()
return nil
}
// StartMining spawns a bunch of mining threads which will mine until stop is
// called.
func (m *Miner) StartMining() error {
m.mu.Lock()
defer m.mu.Unlock()
// Increase the number of threads to m.desiredThreads.
m.desiredThreads = m.threads
for i := m.runningThreads; i < m.desiredThreads; i++ {
go m.threadedMine()
}
return nil
}
// StopMining sets desiredThreads to 0, a value which is polled by mining
// threads. When set to 0, the mining threads will all cease mining.
func (m *Miner) StopMining() error {
m.mu.Lock()
defer m.mu.Unlock()
// Set desiredThreads to 0. The miners will shut down automatically.
m.desiredThreads = 0
m.hashRate = 0
return nil
}