gitlab.com/jokerrs1/Sia@v1.3.2/modules/miner/blockmanager.go (about) 1 package miner 2 3 import ( 4 "errors" 5 "time" 6 7 "github.com/NebulousLabs/Sia/crypto" 8 "github.com/NebulousLabs/Sia/modules" 9 "github.com/NebulousLabs/Sia/types" 10 "github.com/NebulousLabs/fastrand" 11 ) 12 13 var ( 14 errLateHeader = errors.New("header is old, block could not be recovered") 15 ) 16 17 // blockForWork returns a block that is ready for nonce grinding, including 18 // correct miner payouts and a random transaction to prevent collisions and 19 // overlapping work with other blocks being mined in parallel or for different 20 // forks (during testing). 21 func (m *Miner) blockForWork() types.Block { 22 b := m.persist.UnsolvedBlock 23 24 // Update the timestamp. 25 if b.Timestamp < types.CurrentTimestamp() { 26 b.Timestamp = types.CurrentTimestamp() 27 } 28 29 // Update the address + payouts. 30 err := m.checkAddress() 31 if err != nil { 32 m.log.Println(err) 33 } 34 b.MinerPayouts = []types.SiacoinOutput{{ 35 Value: b.CalculateSubsidy(m.persist.Height + 1), 36 UnlockHash: m.persist.Address, 37 }} 38 39 // Add an arb-data txn to the block to create a unique merkle root. 40 randBytes := fastrand.Bytes(types.SpecifierLen) 41 randTxn := types.Transaction{ 42 ArbitraryData: [][]byte{append(modules.PrefixNonSia[:], randBytes...)}, 43 } 44 b.Transactions = append([]types.Transaction{randTxn}, b.Transactions...) 45 46 return b 47 } 48 49 // newSourceBlock creates a new source block for the block manager so that new 50 // headers will use the updated source block. 51 func (m *Miner) newSourceBlock() { 52 // To guarantee garbage collection of old blocks, delete all header entries 53 // that have not been reached for the current block. 54 for m.memProgress%(HeaderMemory/BlockMemory) != 0 { 55 delete(m.blockMem, m.headerMem[m.memProgress]) 56 delete(m.arbDataMem, m.headerMem[m.memProgress]) 57 m.memProgress++ 58 if m.memProgress == HeaderMemory { 59 m.memProgress = 0 60 } 61 } 62 63 // Update the source block. 64 block := m.blockForWork() 65 m.sourceBlock = &block 66 m.sourceBlockTime = time.Now() 67 } 68 69 // HeaderForWork returns a header that is ready for nonce grinding. The miner 70 // will store the header in memory for a while, depending on the constants 71 // 'HeaderMemory', 'BlockMemory', and 'MaxSourceBlockAge'. On the full network, 72 // it is typically safe to assume that headers will be remembered for 73 // min(10 minutes, 10e3 requests). 74 func (m *Miner) HeaderForWork() (types.BlockHeader, types.Target, error) { 75 if err := m.tg.Add(); err != nil { 76 return types.BlockHeader{}, types.Target{}, err 77 } 78 defer m.tg.Done() 79 80 m.mu.Lock() 81 defer m.mu.Unlock() 82 83 // Return a blank header with an error if the wallet is locked. 84 if !m.wallet.Unlocked() { 85 return types.BlockHeader{}, types.Target{}, modules.ErrLockedWallet 86 } 87 88 // Check that the wallet has been initialized, and that the miner has 89 // successfully fetched an address. 90 err := m.checkAddress() 91 if err != nil { 92 return types.BlockHeader{}, types.Target{}, err 93 } 94 95 // If too much time has elapsed since the last source block, get a new one. 96 // This typically only happens if the miner has just turned on after being 97 // off for a while. If the current block has been used for too many 98 // requests, fetch a new source block. 99 if time.Since(m.sourceBlockTime) > MaxSourceBlockAge || m.memProgress%(HeaderMemory/BlockMemory) == 0 { 100 m.newSourceBlock() 101 } 102 103 // Create a header from the source block - this may be a race condition, 104 // but I don't think so (underlying slice may be shared with other blocks 105 // accessible outside the miner). 106 var arbData [crypto.EntropySize]byte 107 fastrand.Read(arbData[:]) 108 copy(m.sourceBlock.Transactions[0].ArbitraryData[0], arbData[:]) 109 header := m.sourceBlock.Header() 110 111 // Save the mapping from the header to its block and from the header to its 112 // arbitrary data, replacing whatever header already exists. 113 delete(m.blockMem, m.headerMem[m.memProgress]) 114 delete(m.arbDataMem, m.headerMem[m.memProgress]) 115 m.blockMem[header] = m.sourceBlock 116 m.arbDataMem[header] = arbData 117 m.headerMem[m.memProgress] = header 118 m.memProgress++ 119 if m.memProgress == HeaderMemory { 120 m.memProgress = 0 121 } 122 123 // Return the header and target. 124 return header, m.persist.Target, nil 125 } 126 127 // managedSubmitBlock takes a solved block and submits it to the blockchain. 128 func (m *Miner) managedSubmitBlock(b types.Block) error { 129 // Give the block to the consensus set. 130 err := m.cs.AcceptBlock(b) 131 // Add the miner to the blocks list if the only problem is that it's stale. 132 if err == modules.ErrNonExtendingBlock { 133 m.mu.Lock() 134 m.persist.BlocksFound = append(m.persist.BlocksFound, b.ID()) 135 m.mu.Unlock() 136 m.log.Println("Mined a stale block - block appears valid but does not extend the blockchain") 137 return err 138 } 139 if err == modules.ErrBlockUnsolved { 140 m.log.Println("Mined an unsolved block - header submission appears to be incorrect") 141 return err 142 } 143 if err != nil { 144 m.tpool.PurgeTransactionPool() 145 m.log.Critical("ERROR: an invalid block was submitted:", err) 146 return err 147 } 148 m.mu.Lock() 149 defer m.mu.Unlock() 150 151 // Grab a new address for the miner. Call may fail if the wallet is locked 152 // or if the wallet addresses have been exhausted. 153 m.persist.BlocksFound = append(m.persist.BlocksFound, b.ID()) 154 var uc types.UnlockConditions 155 uc, err = m.wallet.NextAddress() 156 if err != nil { 157 return err 158 } 159 m.persist.Address = uc.UnlockHash() 160 return m.saveSync() 161 } 162 163 // SubmitHeader accepts a block header. 164 func (m *Miner) SubmitHeader(bh types.BlockHeader) error { 165 if err := m.tg.Add(); err != nil { 166 return err 167 } 168 defer m.tg.Done() 169 170 // Because a call to managedSubmitBlock is required at the end of this 171 // function, the first part needs to be wrapped in an anonymous function 172 // for lock safety. 173 var b types.Block 174 err := func() error { 175 m.mu.Lock() 176 defer m.mu.Unlock() 177 178 // Lookup the block that corresponds to the provided header. 179 nonce := bh.Nonce 180 bh.Nonce = [8]byte{} 181 bPointer, bExists := m.blockMem[bh] 182 arbData, arbExists := m.arbDataMem[bh] 183 if !bExists || !arbExists { 184 return errLateHeader 185 } 186 187 // Block is going to be passed to external memory, but the memory pointed 188 // to by the transactions slice is still being modified - needs to be 189 // copied. Same with the memory being pointed to by the arb data slice. 190 b = *bPointer 191 txns := make([]types.Transaction, len(b.Transactions)) 192 copy(txns, b.Transactions) 193 b.Transactions = txns 194 b.Transactions[0].ArbitraryData = [][]byte{arbData[:]} 195 b.Nonce = nonce 196 197 // Sanity check - block should have same id as header. 198 bh.Nonce = nonce 199 if types.BlockID(crypto.HashObject(bh)) != b.ID() { 200 m.log.Critical("block reconstruction failed") 201 } 202 return nil 203 }() 204 if err != nil { 205 m.log.Println("ERROR during call to SubmitHeader, pre SubmitBlock:", err) 206 return err 207 } 208 err = m.managedSubmitBlock(b) 209 if err != nil { 210 m.log.Println("ERROR returned by managedSubmitBlock:", err) 211 return err 212 } 213 return nil 214 }