gitlab.com/jokerrs1/Sia@v1.3.2/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  // 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++
    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  	if !m.wallet.Unlocked() {
    53  		err = modules.ErrLockedWallet
    54  		return
    55  	}
    56  	m.mu.Lock()
    57  	defer m.mu.Unlock()
    58  	err = m.checkAddress()
    59  	if err != nil {
    60  		return
    61  	}
    62  
    63  	b = m.blockForWork()
    64  	return b, m.persist.Target, nil
    65  }
    66  
    67  // AddBlock adds a block to the consensus set.
    68  func (m *Miner) AddBlock() (types.Block, error) {
    69  	block, err := m.FindBlock()
    70  	if err != nil {
    71  		return types.Block{}, err
    72  	}
    73  	err = m.cs.AcceptBlock(block)
    74  	if err != nil {
    75  		return types.Block{}, err
    76  	}
    77  	return block, nil
    78  }
    79  
    80  // FindBlock finds at most one block that extends the current blockchain.
    81  func (m *Miner) FindBlock() (types.Block, error) {
    82  	var bfw types.Block
    83  	var target types.Target
    84  	err := func() error {
    85  		m.mu.Lock()
    86  		defer m.mu.Unlock()
    87  
    88  		if !m.wallet.Unlocked() {
    89  			return modules.ErrLockedWallet
    90  		}
    91  		err := m.checkAddress()
    92  		if err != nil {
    93  			return err
    94  		}
    95  
    96  		// Get a block for work.
    97  		bfw = m.blockForWork()
    98  		target = m.persist.Target
    99  		return nil
   100  	}()
   101  	if err != nil {
   102  		return types.Block{}, err
   103  	}
   104  
   105  	block, ok := m.SolveBlock(bfw, target)
   106  	if !ok {
   107  		return types.Block{}, errors.New("could not solve block using limited hashing power")
   108  	}
   109  	return block, nil
   110  }
   111  
   112  // SolveBlock takes a block and a target and tries to solve the block for the
   113  // target. A bool is returned indicating whether the block was successfully
   114  // solved.
   115  func (m *Miner) SolveBlock(b types.Block, target types.Target) (types.Block, bool) {
   116  	return solveBlock(b, target)
   117  }