github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/cmd/derod/miner.go (about)

     1  // Copyright 2017-2018 DERO Project. All rights reserved.
     2  // Use of this source code in any form is governed by RESEARCH license.
     3  // license can be found in the LICENSE file.
     4  // GPG: 0F39 E425 8C65 3947 702A  8234 08B2 0360 A03A 9DE8
     5  //
     6  //
     7  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
     8  // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     9  // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
    10  // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    11  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    12  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    13  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    14  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
    15  // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    16  
    17  package main
    18  
    19  /*
    20  import "io"
    21  import "os"
    22  
    23  import "fmt"
    24  import "bytes"
    25  import "bufio"
    26  import "strings"
    27  import "strconv"
    28  import "runtime"
    29  import "crypto/sha1"
    30  import "encoding/hex"
    31  import "encoding/json"
    32  import "path/filepath"
    33  
    34  import "github.com/romana/rlog"
    35  import "github.com/chzyer/readline"
    36  import "github.com/docopt/docopt-go"
    37  import log "github.com/sirupsen/logrus"
    38  
    39  import "github.com/deroproject/derosuite/address"
    40  import "github.com/deroproject/derosuite/p2pv2"
    41  
    42  
    43  import "github.com/deroproject/derosuite/config"
    44  
    45  import "github.com/deroproject/derosuite/transaction"
    46  
    47  //import "github.com/deroproject/derosuite/checkpoints"
    48  import "github.com/deroproject/derosuite/crypto"
    49  import "github.com/deroproject/derosuite/crypto/ringct"
    50  import "github.com/deroproject/derosuite/blockchain/rpcserver"
    51  */
    52  
    53  import "time"
    54  import "sync"
    55  import "math/big"
    56  import "crypto/rand"
    57  import "sync/atomic"
    58  
    59  //import "encoding/hex"
    60  import "encoding/binary"
    61  
    62  import "github.com/deroproject/derosuite/block"
    63  import "github.com/deroproject/derosuite/crypto"
    64  import "github.com/deroproject/derosuite/globals"
    65  import "github.com/deroproject/derosuite/address"
    66  import "github.com/deroproject/derosuite/blockchain"
    67  import "github.com/deroproject/derosuite/cryptonight"
    68  
    69  // p2p needs to export a varible declaring whether the chain is in syncronising mode
    70  
    71  var counter uint64 = 0 // used to track speeds of current miner
    72  
    73  var mining bool // whether system is mining
    74  
    75  // request block chain template, see if the tip changes, then continously mine
    76  func start_miner(chain *blockchain.Blockchain, addr *address.Address, threads int) {
    77  
    78  	mining = true
    79  	counter = 0
    80  	//tip_counter := 0
    81  
    82  	for {
    83  		//time.Sleep(50 * time.Millisecond)
    84  
    85  		if !mining {
    86  			break
    87  		}
    88  
    89  		if chain.MINING_BLOCK == true {
    90  			time.Sleep(10 * time.Millisecond)
    91  			continue
    92  		}
    93  
    94  		cbl, bl := chain.Create_new_miner_block(*addr)
    95  
    96  		difficulty := chain.Get_Difficulty_At_Tips(nil, bl.Tips)
    97  
    98  		//globals.Logger.Infof("Difficulty of new block is %s", difficulty.String())
    99  		// calculate difficulty once
   100  		// update job from chain
   101  		wg := sync.WaitGroup{}
   102  		wg.Add(threads) // add total number of tx as work
   103  
   104  		for i := 0; i < threads; i++ {
   105  			go generate_valid_PoW(chain, 0, cbl, cbl.Bl, difficulty, &wg) // work should be complete in approx 100 ms, on a 12 cpu system, this would add cost of launching 12 g routine per second
   106  		}
   107  		wg.Wait()
   108  	}
   109  
   110  	// g
   111  }
   112  
   113  // each invoke will be take atleast 250 milliseconds
   114  func generate_valid_PoW(chain *blockchain.Blockchain, hf_version uint64, cbl *block.Complete_Block, bl *block.Block, current_difficulty *big.Int, wg *sync.WaitGroup) {
   115  	var powhash crypto.Hash
   116  	block_work := bl.GetBlockWork()
   117  
   118  	// extra nonce is always at offset 36 and is of length 32
   119  	var extra_nonce [16]byte
   120  	rand.Read(extra_nonce[:]) // fill extra nonce with random buffer
   121  
   122  	bl.SetExtraNonce(extra_nonce[:])
   123  
   124  	// TODO  this time must be replaced  by detecting TIP change
   125  	start := time.Now()
   126  	//deadline := time.Now().Add(250*time.Millisecond)
   127  	i := uint32(0)
   128  
   129  	nonce_buf := block_work[39 : 39+4] // take last 8 bytes as nonce counter and bruteforce it, since slices are linked, it modifies parent
   130  	for {
   131  		//time.Sleep(1000 * time.Millisecond)
   132  
   133  		atomic.AddUint64(&counter, 1)
   134  
   135  		binary.BigEndian.PutUint32(nonce_buf, i)
   136  
   137  		//PoW := crypto.Scrypt_1024_1_1_256(block_work)
   138  		//PoW := crypto.Keccak256(block_work)
   139  		PoW := cryptonight.SlowHash(block_work)
   140  		copy(powhash[:], PoW[:])
   141  
   142  		if blockchain.CheckPowHashBig(powhash, current_difficulty) == true {
   143  
   144  			bl.CopyNonceFromBlockWork(block_work)
   145  			//globals.Logger.Infof("Pow Successfully solved, Submitting block")
   146  
   147  			if _, ok := chain.Add_Complete_Block(cbl); ok {
   148  				globals.Logger.Infof("Block %s successfully accepted diff %s", bl.GetHash(), current_difficulty.String())
   149  				chain.P2P_Block_Relayer(cbl, 0) // broadcast block to network ASAP
   150  
   151  				break
   152  			}
   153  
   154  		}
   155  
   156  		if time.Now().Sub(start) > 250*time.Millisecond {
   157  			break
   158  		}
   159  		i++
   160  
   161  	}
   162  
   163  	wg.Done()
   164  
   165  }