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  }