github.com/johnathanhowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/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 "github.com/NebulousLabs/Sia/crypto" 13 "github.com/NebulousLabs/Sia/modules" 14 "github.com/NebulousLabs/Sia/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 // BlockForWork returns a block that is ready for nonce grinding, along with 24 // the root hash of the block. 25 func (m *Miner) BlockForWork() (b types.Block, t types.Target, err error) { 26 // Check if the wallet is unlocked. If the wallet is unlocked, make sure 27 // that the miner has a recent address. 28 if !m.wallet.Unlocked() { 29 err = modules.ErrLockedWallet 30 return 31 } 32 m.mu.Lock() 33 defer m.mu.Unlock() 34 err = m.checkAddress() 35 if err != nil { 36 return 37 } 38 39 b = m.blockForWork() 40 return b, m.persist.Target, nil 41 } 42 43 // AddBlock adds a block to the consensus set. 44 func (m *Miner) AddBlock() (types.Block, error) { 45 block, err := m.FindBlock() 46 if err != nil { 47 return types.Block{}, err 48 } 49 err = m.cs.AcceptBlock(block) 50 if err != nil { 51 return types.Block{}, err 52 } 53 return block, nil 54 } 55 56 // FindBlock finds at most one block that extends the current blockchain. 57 func (m *Miner) FindBlock() (types.Block, error) { 58 var bfw types.Block 59 var target types.Target 60 err := func() error { 61 m.mu.Lock() 62 defer m.mu.Unlock() 63 64 if !m.wallet.Unlocked() { 65 return modules.ErrLockedWallet 66 } 67 err := m.checkAddress() 68 if err != nil { 69 return err 70 } 71 72 // Get a block for work. 73 bfw = m.blockForWork() 74 target = m.persist.Target 75 return nil 76 }() 77 if err != nil { 78 return types.Block{}, err 79 } 80 81 block, ok := m.SolveBlock(bfw, target) 82 if !ok { 83 return types.Block{}, errors.New("could not solve block using limited hashing power") 84 } 85 return block, nil 86 } 87 88 // SolveBlock takes a block and a target and tries to solve the block for the 89 // target. A bool is returned indicating whether the block was successfully 90 // solved. 91 func (m *Miner) SolveBlock(b types.Block, target types.Target) (types.Block, bool) { 92 // Assemble the header. 93 merkleRoot := b.MerkleRoot() 94 header := make([]byte, 80) 95 copy(header, b.ParentID[:]) 96 binary.LittleEndian.PutUint64(header[40:48], uint64(b.Timestamp)) 97 copy(header[48:], merkleRoot[:]) 98 99 var nonce uint64 100 for i := 0; i < solveAttempts; i++ { 101 id := crypto.HashBytes(header) 102 if bytes.Compare(target[:], id[:]) >= 0 { 103 copy(b.Nonce[:], header[32:40]) 104 return b, true 105 } 106 *(*uint64)(unsafe.Pointer(&header[32])) = nonce 107 nonce++ 108 } 109 return b, false 110 }