github.com/avahowell/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  }