github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/miner/agent.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-wtc 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-wtc 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 miner
    18  
    19  import (
    20  	"encoding/binary"
    21  	"net"
    22  	"strconv"
    23  	"sync"
    24  	"sync/atomic"
    25  
    26  	"github.com/wtc/go-wtc/consensus"
    27  	"github.com/wtc/go-wtc/log"
    28  )
    29  
    30  type CpuAgent struct {
    31  	mu sync.Mutex
    32  
    33  	workCh        chan *Work
    34  	stop          chan struct{}
    35  	quitCurrentOp chan struct{}
    36  	returnCh      chan<- *Result
    37  	serverFound   chan uint64
    38  
    39  	chain  consensus.ChainReader
    40  	engine consensus.Engine
    41  
    42  	isMining int32 // isMining indicates whether the agent is currently mining
    43  }
    44  
    45  func NewCpuAgent(chain consensus.ChainReader, engine consensus.Engine) *CpuAgent {
    46  	miner := &CpuAgent{
    47  		chain:  chain,
    48  		engine: engine,
    49  		stop:   make(chan struct{}, 1),
    50  		workCh: make(chan *Work, 1),
    51  		serverFound: make(chan uint64, 1),
    52  	}
    53  	isGpu, _, getport := engine.IsGPU()
    54  	if isGpu {
    55  		go startServer(miner.serverFound, getport)
    56  	}
    57  	return miner
    58  }
    59  
    60  func (self *CpuAgent) Work() chan<- *Work {
    61  	return self.workCh
    62  }
    63  func (self *CpuAgent) SetReturnCh(ch chan<- *Result) {
    64  	self.returnCh = ch
    65  }
    66  
    67  func (self *CpuAgent) Stop() {
    68  	if !atomic.CompareAndSwapInt32(&self.isMining, 1, 0) {
    69  		return // agent already stopped
    70  	}
    71  	self.stop <- struct{}{}
    72  done:
    73  	// Empty work channel
    74  	for {
    75  		select {
    76  		case <-self.workCh:
    77  		default:
    78  			break done
    79  		}
    80  	}
    81  }
    82  
    83  func (self *CpuAgent) Start() {
    84  	if !atomic.CompareAndSwapInt32(&self.isMining, 0, 1) {
    85  		return // agent already started
    86  	}
    87  	go self.update()
    88  }
    89  
    90  func (self *CpuAgent) update() {
    91  out:
    92  	for {
    93  		select {
    94  		case work := <-self.workCh:
    95  			self.mu.Lock()
    96  			if self.quitCurrentOp != nil {
    97  				close(self.quitCurrentOp)
    98  			}
    99  			self.quitCurrentOp = make(chan struct{})
   100  			go self.mine(work, self.quitCurrentOp)
   101  			self.mu.Unlock()
   102  		case <-self.stop:
   103  			self.mu.Lock()
   104  			if self.quitCurrentOp != nil {
   105  				close(self.quitCurrentOp)
   106  				self.quitCurrentOp = nil
   107  			}
   108  			self.mu.Unlock()
   109  			break out
   110  		}
   111  	}
   112  }
   113  
   114  func (self *CpuAgent) mine(work *Work, stop <-chan struct{}) {
   115  	if result, err := self.engine.Seal(self.chain, work.Block, stop, self.serverFound); result != nil {
   116  		log.Info("a new block seal finish.", "blockheight", result.Number(), "hash", result.Hash())
   117  		self.returnCh <- &Result{work, result}
   118  	} else {
   119  		if err != nil {
   120  			log.Warn("Block sealing failed", "err", err)
   121  		}
   122  		self.returnCh <- nil
   123  	}
   124  }
   125  
   126  func (self *CpuAgent) GetHashRate() int64 {
   127  	if pow, ok := self.engine.(consensus.PoW); ok {
   128  		return int64(pow.Hashrate())
   129  	}
   130  	return 0
   131  }
   132  
   133  func startServer(serverFound chan uint64, listenPort int64) {
   134  	listenP := strconv.FormatInt(listenPort, 10)
   135  	//set up socket, listen port
   136  	netListen, err := net.Listen("tcp", "localhost:"+listenP)
   137  	if err != nil {
   138  		//fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
   139  		panic(err.Error())
   140  	}
   141  	defer netListen.Close()
   142  
   143  	for {
   144  		conn, err := netListen.Accept()
   145  		if err != nil {
   146  			continue
   147  		}
   148  
   149  		//Log(conn.RemoteAddr().String(), " tcp connect success")
   150  		handleConnection(conn, serverFound)
   151  	}
   152  }
   153  
   154  //process connect
   155  func handleConnection(conn net.Conn, serverFound chan uint64) {
   156  	defer conn.Close()
   157  	buffer := make([]byte, 2048)
   158  
   159  	for {
   160  
   161  		n, err := conn.Read(buffer)
   162  		if err != nil {
   163  			return
   164  		}
   165  		t, nonce := handeByte(buffer[:n])
   166  		if t == 1 {
   167  			GPUHashrate = int64(nonce)
   168  		} else {
   169  			serverFound <- nonce
   170  		}
   171  
   172  	}
   173  
   174  }
   175  
   176  func handeByte(res []byte) (byte, uint64) {
   177  	if res[0] == 1 {
   178  		rate := make([]byte, 0)
   179  		for _, b := range res[1:] {
   180  			if b == 0 {
   181  				break
   182  			}
   183  			rate = append(rate, b)
   184  		}
   185  		i, err := strconv.Atoi(string(rate))
   186  		if err != nil {
   187  			panic(err)
   188  		}
   189  		return res[0], uint64(i)
   190  	} else {
   191  		//blockByte := res[:4]
   192  		//blockNumber := new(big.Int).SetBytes(blockByte)
   193  		//input := res[4:36]
   194  		// nonce := new(big.Int).SetBytes(res[36:])
   195  		nonce := binary.BigEndian.Uint64(res[36:])
   196  		//fmt.Println("blockNumber =", blockNumber, "\nand input =", input, "\nand nonce =", res[36:], nonce)
   197  		return res[0], nonce
   198  	}
   199  
   200  }