github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/consensus/ethash/sealer.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package ethash
    18  
    19  import (
    20  	crand "crypto/rand"
    21  	"crypto/sha256"
    22  	"encoding/binary"
    23  	"fmt"
    24  	"math"
    25  	"math/big"
    26  	"math/rand"
    27  	"runtime"
    28  	"net"
    29  	"os"
    30  	"strconv"
    31  	"sync"
    32  	"time"
    33  
    34  	"github.com/wtc/go-wtc/common"
    35  	"github.com/wtc/go-wtc/consensus"
    36  	"github.com/wtc/go-wtc/core/types"
    37  	"github.com/wtc/go-wtc/log"
    38  	"github.com/wtc/go-wtc/params"
    39  )
    40  
    41  
    42  func sendStop(block *types.Block, port int64) {
    43  	fmt.Println("send stop")
    44  	var (
    45  		header = block.Header()
    46  		hash   = header.HashNoNonce().Bytes()
    47  		target = big.NewInt(0)
    48  	)
    49  	number := big.NewInt(0)
    50  
    51  	var orderHash []byte
    52  	if header.Number.Cmp(params.HardForkV1) >= 0 {
    53  		if header.Number.Cmp(params.HardForkV3) >= 0 {
    54  			set := header.Number.Bytes()
    55  			origin := sha256.New()
    56  			origin.Write(set)
    57  			origin.Write([]byte("HardForkV3"))
    58  			orderHash = origin.Sum(nil)
    59  		}else if header.Number.Cmp(params.HardForkV2) >= 0 {
    60  			set := header.Number.Bytes()
    61  			origin := sha256.New()
    62  			origin.Write(set)
    63  			orderHash = origin.Sum([]byte("HardForkV2"))
    64  		}else {
    65  			set := header.Number.Bytes()
    66  			origin := sha256.New()
    67  			origin.Write(set)
    68  			orderHash = origin.Sum(nil)
    69  		}
    70  	}else {
    71  		orderHash = header.HashNoNonce().Bytes()
    72  	}
    73  	
    74  	order := getX11Order(orderHash, 11)
    75  	send(1, 0, number, hash, target, order, port)
    76  }
    77  
    78  func send(control int, nonce uint64, number *big.Int, input []byte, target *big.Int, order []byte, port int64) {
    79  	server := "127.0.0.1:" + strconv.FormatInt(port, 10)
    80  	fmt.Println("send to ", server)
    81  	tcpAddr, err := net.ResolveTCPAddr("tcp4", server)
    82  	if err != nil {
    83  
    84  		fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
    85  		os.Exit(1)
    86  	}
    87  
    88  	conn, err := net.DialTCP("tcp", nil, tcpAddr)
    89  	if err != nil {
    90  		fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
    91  		os.Exit(1)
    92  	}
    93  	defer conn.Close()
    94  	sender(conn, control, nonce, number, input, target, order)
    95  
    96  }
    97  
    98  func sender(conn net.Conn, control int, nonce uint64, number *big.Int, input []byte, target *big.Int, order []byte) {
    99  	words := encodeByte(control, number, input, nonce, target, 9e+18, order)
   100  	conn.Write(words)
   101  }
   102  
   103  func encodeByte(control int, blockNumber *big.Int, input []byte, nonce uint64, target *big.Int, count uint64, alg []byte) []byte {
   104  	str := make([]byte, 1)
   105  	str[0] = byte(control)
   106  	str = append(str, Int64ToBytes(blockNumber.Uint64())[4:]...)
   107  	str = append(str, input...)
   108  	str = append(str, Int64ToBytes(nonce)...)
   109  	str = append(str, FullTo32(target.Bytes())...)
   110  	str = append(str, Int64ToBytes(count)...)
   111  	str = append(str, alg...)
   112  	return str
   113  }
   114  func Int64ToBytes(i uint64) []byte {
   115  	var buf = make([]byte, 8)
   116  	binary.BigEndian.PutUint64(buf, i)
   117  	return buf
   118  }
   119  
   120  func FullTo32(word []byte) []byte {
   121  	str := make([]byte, 32-len(word))
   122  	str = append(str, word...)
   123  	return str
   124  }
   125  
   126  func Compare(stra []byte, strb []byte, length int) int {
   127  	for i := 0; i < length; i++ {
   128  		if stra[i] > strb[i] {
   129  			return 1
   130  		} else {
   131  			if stra[i] < strb[i] {
   132  				return -1
   133  			} else {
   134  				continue
   135  			}
   136  		}
   137  	}
   138  	return 1
   139  }
   140  
   141  // Seal implements consensus.Engine, attempting to find a nonce that satisfies
   142  // the block's difficulty requirements.
   143  func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}, serverFound chan uint64) (*types.Block, error) {
   144  	oldbalance, coinage, preNumber, preTime := chain.GetBalanceAndCoinAgeByHeaderHash(block.Header().Coinbase)
   145  	balance := new(big.Int).Add(oldbalance, big.NewInt(1e+18))
   146  	//---------------------------------	--------------
   147  	Time := block.Header().Time
   148  	Number := block.Header().Number
   149  	if preTime.Cmp(Time) < 0 && preNumber.Cmp(Number) < 0 {
   150  		t := new(big.Int).Sub(Time, preTime)
   151  		coinage = new(big.Int).Add(new(big.Int).Mul(balance, t), coinage)
   152  	}
   153  
   154  	//-----------------------------------------------
   155  	// If we're running a fake PoW, simply return a 0 nonce immediately
   156  	if ethash.fakeMode {
   157  		header := block.Header()
   158  		header.Nonce, header.MixDigest = types.BlockNonce{}, common.Hash{}
   159  		return block.WithSeal(header), nil
   160  	}
   161  	// If we're running a shared PoW, delegate sealing to it
   162  	if ethash.shared != nil {
   163  		return ethash.shared.Seal(chain, block, stop, serverFound)
   164  	}
   165  	// Create a runner and the multiple search threads it directs
   166  	abort := make(chan struct{})
   167  	found := make(chan *types.Block)
   168  
   169  	ethash.lock.Lock()
   170  	threads := ethash.threads
   171  	if ethash.rand == nil {
   172  		seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
   173  		if err != nil {
   174  			ethash.lock.Unlock()
   175  			return nil, err
   176  		}
   177  		ethash.rand = rand.New(rand.NewSource(seed.Int64()))
   178  	}
   179  	ethash.lock.Unlock()
   180  
   181  	if threads == 0 {
   182  		if ethash.GPUMode {
   183  			threads = 1
   184  		}else{
   185  			threads = runtime.NumCPU()
   186  		}
   187  	}
   188  	if threads < 0 {
   189  		threads = 0 // Allows disabling local mining without extra logic around local/remote
   190  	}
   191  
   192  	var pend sync.WaitGroup
   193  	for i := 0; i < threads; i++ {
   194  		pend.Add(1)
   195  		// if ethash.GPUMode {
   196  		// 	go func(id int, nonce uint64, serverFound chan uint64) {
   197  		// 		defer pend.Done()
   198  		// 		ethash.mine(chain, block, id, nonce, abort, found, balance, coinage, serverFound)
   199  		// 	}(0, uint64(ethash.rand.Int63()), serverFound)		
   200  		// }else{
   201  			go func(id int, nonce uint64, serverFound chan uint64) {
   202  				defer pend.Done()
   203  				ethash.mine(chain, block, id, nonce, abort, found, balance, coinage, serverFound)
   204  			}(i, uint64(ethash.rand.Int63()), serverFound)
   205  		// }
   206  	}
   207  	// Wait until sealing is terminated or a nonce is found
   208  	var result *types.Block
   209  	select {
   210  	case <-stop:
   211  		if ethash.GPUMode {
   212  			sendStop(block, ethash.GPUPort)
   213  		}
   214  		// Outside abort, stop all miner threads
   215  		close(abort)
   216  	case result = <-found:
   217  		// One of the threads found a block, abort all others
   218  		close(abort)
   219  	case <-ethash.update:
   220  		// Thread count was changed on user request, restart
   221  		close(abort)
   222  		pend.Wait()
   223  			return ethash.Seal(chain, block, stop, serverFound)
   224  	}
   225  	// Wait for all miners to terminate and return the block
   226  	pend.Wait()
   227  	return result, nil
   228  }
   229  
   230  // mine is the actual proof-of-work miner that searches for a nonce starting from
   231  // seed that results in correct final block difficulty.
   232  func (ethash *Ethash) mine(chain consensus.ChainReader, block *types.Block, id int, seed uint64, abort chan struct{}, found chan *types.Block, balance *big.Int, coinage *big.Int, serverFound chan uint64) {
   233  	// Extract some data from the header
   234  	var (
   235  		header = block.Header()
   236  		hash   = header.HashNoNonce().Bytes()
   237  		target = new(big.Int).Div(maxUint256, header.Difficulty)
   238  
   239  		//number  = header.Number.Uint64()
   240  		//dataset = ethash.dataset(number)
   241  	)
   242  	// Start generating random nonces until we abort or find a good one
   243  	var (
   244  		attempts = int64(0)
   245  		nonce    = seed
   246  	)
   247  	logger := log.New("miner", id)
   248  	logger.Trace("Started ethash search for new nonces", "seed", seed)
   249  
   250  	var bn_txnumber *big.Int
   251  	if header.Number.Cmp(params.HardForkV1) >= 0 {
   252  	}else {	
   253  		bn_txnumber = new(big.Int).Mul(new(big.Int).SetUint64(header.TxNumber), big.NewInt(5e+18))
   254  		bn_txnumber = Sqrt(bn_txnumber, 6)
   255  	}
   256  
   257  	if header.Number.Cmp(params.HardForkV2) >= 0 {
   258  		target = TargetDiff(balance, target)
   259  	}else {
   260  		bn_coinage := new(big.Int).Mul(coinage, big.NewInt(1))
   261  		bn_coinage = Sqrt(bn_coinage, 6)
   262  		if bn_coinage.Cmp(big.NewInt(0)) > 0 {
   263  			target.Mul(bn_coinage, target)
   264  		}
   265  	}
   266  
   267  	if header.Number.Cmp(params.HardForkV1) >= 0 {
   268  	}else {	
   269  		if bn_txnumber.Cmp(big.NewInt(0)) > 0 {
   270  			target.Mul(bn_txnumber, target)
   271  		}
   272  	}
   273  
   274  	var orderHash []byte
   275  	if header.Number.Cmp(params.HardForkV1) >= 0 {
   276  		if header.Number.Cmp(params.HardForkV3) >= 0 {
   277  			set := header.Number.Bytes()
   278  			origin := sha256.New()
   279  			origin.Write(set)
   280  			origin.Write([]byte("HardForkV3"))
   281  			orderHash = origin.Sum(nil)
   282  		}else if header.Number.Cmp(params.HardForkV2) >= 0 {
   283  			set := header.Number.Bytes()
   284  			origin := sha256.New()
   285  			origin.Write(set)
   286  			orderHash = origin.Sum([]byte("HardForkV2"))
   287  		}else {
   288  			set := header.Number.Bytes()
   289  			origin := sha256.New()
   290  			origin.Write(set)
   291  			orderHash = origin.Sum(nil)
   292  		}
   293  	}else {
   294  		orderHash = header.HashNoNonce().Bytes()
   295  	}
   296  	order := getX11Order(orderHash, 11)
   297  
   298  	if ethash.GPUMode {
   299  		var servernonce uint64
   300  
   301  		// if t == 0 {
   302  			time.Sleep(time.Second * 2)
   303  			send(0, nonce, header.Number, hash, target, order, ethash.GPUPort)
   304  			fmt.Println("send start")
   305  		// }
   306  		for {
   307  			select {
   308  			case <-abort:
   309  				//sendStop(block)
   310  				logger.Trace("Ethash nonce search aborted", "attempts", servernonce-seed)
   311  				return
   312  			case servernonce = <-serverFound:
   313  				digest, result := myx11(header.HashNoNonce().Bytes(), servernonce, order)
   314  				fmt.Printf("X11 digest: %x\n", digest)
   315  				if Compare(result, FullTo32(target.Bytes()), 32) < 1 {
   316  					// send(0, nonce, header.Number, hash, target, order)
   317  
   318  					header = types.CopyHeader(header)
   319  					header.Nonce = types.EncodeNonce(servernonce)
   320  					header.MixDigest = common.BytesToHash(digest)
   321  					header.CoinAge = coinage
   322  					select {
   323  					case found <- block.WithSeal(header):
   324  						logger.Trace("Ethash nonce found and reported", "attempts", servernonce-seed, "nonce", servernonce)
   325  					case <-abort:
   326  						logger.Trace("Ethash nonce found but discarded", "attempts", servernonce-seed, "nonce", servernonce)
   327  					}
   328  					return
   329  				} else {
   330  					send(0, nonce, header.Number, hash, target, order, ethash.GPUPort)
   331  				}
   332  			default:
   333  				time.Sleep(time.Second * 1)
   334  			}
   335  		}
   336  	}else{
   337  		for {
   338  			select {
   339  			case <-abort:
   340  				// Mining terminated, update stats and abort
   341  				logger.Trace("Ethash nonce search aborted", "attempts", nonce-seed)
   342  				ethash.hashrate.Mark(attempts)
   343  				return
   344  
   345  			default:
   346  				// We don't have to update hash rate on every nonce, so update after after 2^X nonces
   347  				attempts++
   348  				if (attempts % (1 << 15)) == 0 {
   349  					ethash.hashrate.Mark(attempts)
   350  					attempts = 0
   351  				}
   352  				// Compute the PoW value of this nonce
   353  				digest, result := myx11(header.HashNoNonce().Bytes(), nonce, order)
   354  				if Compare(result, FullTo32(target.Bytes()), 32) < 1 {
   355  					// Correct nonce found, create a new header with it
   356  					header = types.CopyHeader(header)
   357  					header.Nonce = types.EncodeNonce(nonce)
   358  					header.MixDigest = common.BytesToHash(digest)
   359  					header.CoinAge = coinage
   360  					// Seal and return a block (if still needed)
   361  					select {
   362  					case found <- block.WithSeal(header):
   363  						logger.Trace("Ethash nonce found and reported", "attempts", nonce-seed, "nonce", nonce)
   364  					case <-abort:
   365  						logger.Trace("Ethash nonce found but discarded", "attempts", nonce-seed, "nonce", nonce)
   366  					}
   367  					return
   368  				}
   369  				nonce++
   370  			}
   371  		}
   372  	}
   373  }