github.com/fozzysec/SiaPrime@v0.0.0-20190612043147-66c8e8d11fe3/modules/miner/testminer.go (about) 1 package miner 2 3 // testminer.go implements the TestMiner interface, whose primary purpose is 4 // integration testing. 5 6 import ( 7 "bytes" 8 "encoding/binary" 9 "errors" 10 "unsafe" 11 12 "SiaPrime/crypto" 13 "SiaPrime/modules" 14 "SiaPrime/types" 15 ) 16 17 const ( 18 // solveAttempts is the number of times that SolveBlock will try to solve a 19 // block before giving up. 20 solveAttempts = 16e3 21 ) 22 23 // solveBlock takes a block and a target and tries to solve the block for the 24 // target. A bool is returned indicating whether the block was successfully 25 // solved. 26 func solveBlock(b types.Block, target types.Target) (types.Block, bool) { 27 // Assemble the header. 28 merkleRoot := b.MerkleRoot() 29 header := make([]byte, 80) 30 copy(header, b.ParentID[:]) 31 binary.LittleEndian.PutUint64(header[40:48], uint64(b.Timestamp)) 32 copy(header[48:], merkleRoot[:]) 33 34 var nonce uint64 35 for i := 0; i < solveAttempts; i++ { 36 id := crypto.HashBytes(header) 37 if bytes.Compare(target[:], id[:]) >= 0 { 38 copy(b.Nonce[:], header[32:40]) 39 return b, true 40 } 41 *(*uint64)(unsafe.Pointer(&header[32])) = nonce 42 nonce += types.ASICHardforkFactor 43 } 44 return b, false 45 } 46 47 // BlockForWork returns a block that is ready for nonce grinding, along with 48 // the root hash of the block. 49 func (m *Miner) BlockForWork() (b types.Block, t types.Target, err error) { 50 // Check if the wallet is unlocked. If the wallet is unlocked, make sure 51 // that the miner has a recent address. 52 unlocked, err := m.wallet.Unlocked() 53 if err != nil { 54 return types.Block{}, types.Target{}, err 55 } 56 if !unlocked { 57 err = modules.ErrLockedWallet 58 return 59 } 60 m.mu.Lock() 61 defer m.mu.Unlock() 62 err = m.checkAddress() 63 if err != nil { 64 return 65 } 66 67 b = m.blockForWork() 68 return b, m.persist.Target, nil 69 } 70 71 // AddBlock adds a block to the consensus set. 72 func (m *Miner) AddBlock() (types.Block, error) { 73 block, err := m.FindBlock() 74 if err != nil { 75 return types.Block{}, err 76 } 77 err = m.cs.AcceptBlock(block) 78 if err != nil { 79 return types.Block{}, err 80 } 81 return block, nil 82 } 83 84 // FindBlock finds at most one block that extends the current blockchain. 85 func (m *Miner) FindBlock() (types.Block, error) { 86 var bfw types.Block 87 var target types.Target 88 err := func() error { 89 m.mu.Lock() 90 defer m.mu.Unlock() 91 92 unlocked, err := m.wallet.Unlocked() 93 if err != nil { 94 return err 95 } 96 if !unlocked { 97 return modules.ErrLockedWallet 98 } 99 err = m.checkAddress() 100 if err != nil { 101 return err 102 } 103 104 // Get a block for work. 105 bfw = m.blockForWork() 106 target = m.persist.Target 107 return nil 108 }() 109 if err != nil { 110 return types.Block{}, err 111 } 112 113 block, ok := m.SolveBlock(bfw, target) 114 if !ok { 115 return types.Block{}, errors.New("could not solve block using limited hashing power") 116 } 117 return block, nil 118 } 119 120 // SolveBlock takes a block and a target and tries to solve the block for the 121 // target. A bool is returned indicating whether the block was successfully 122 // solved. 123 func (m *Miner) SolveBlock(b types.Block, target types.Target) (types.Block, bool) { 124 return solveBlock(b, target) 125 }