github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/scrypt/scrypt.go (about)

     1  // Copyright (c) 2019 Simplechain
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Lesser General Public License as published by
     5  // the Free Software Foundation, either version 3 of the License, or
     6  // (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    11  // GNU Lesser General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Lesser General Public License
    14  // along with this program. If not, see <http://www.gnu.org/licenses/>.
    15  
    16  // Package scrypt implements the scrypt proof-of-work consensus engine.
    17  package scrypt
    18  
    19  import (
    20  	"math/big"
    21  	"math/rand"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/bigzoro/my_simplechain/common"
    26  	"github.com/bigzoro/my_simplechain/consensus"
    27  	"github.com/bigzoro/my_simplechain/core/types"
    28  	"github.com/bigzoro/my_simplechain/metrics"
    29  	"github.com/bigzoro/my_simplechain/rpc"
    30  )
    31  
    32  var (
    33  	// two256 is a big integer representing 2^256
    34  	two256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
    35  	// SimpleChain scrypt mode, default scrypt mode=0x0
    36  	ScryptMode = uint(0x30)
    37  )
    38  
    39  // Mode defines the type and amount of PoW verification an scrypt engine makes.
    40  type Mode uint
    41  
    42  const (
    43  	ModeNormal Mode = iota
    44  	ModeShared
    45  	ModeTest
    46  	ModeFake
    47  	ModeFullFake
    48  )
    49  
    50  // Config are the configuration parameters of the scrypt.
    51  type Config struct {
    52  	PowMode Mode
    53  }
    54  
    55  // sealTask wraps a seal block with relative result channel for remote sealer thread.
    56  type sealTask struct {
    57  	block   *types.Block
    58  	results chan<- *types.Block
    59  }
    60  
    61  // mineResult wraps the pow solution parameters for the specified block.
    62  type mineResult struct {
    63  	nonce     types.BlockNonce
    64  	mixDigest common.Hash
    65  	hash      common.Hash
    66  
    67  	errc chan error
    68  }
    69  
    70  // hashrate wraps the hash rate submitted by the remote sealer.
    71  type hashrate struct {
    72  	id   common.Hash
    73  	ping time.Time
    74  	rate uint64
    75  
    76  	done chan struct{}
    77  }
    78  
    79  // sealWork wraps a seal work package for remote sealer.
    80  type sealWork struct {
    81  	errc chan error
    82  	res  chan [3]string
    83  }
    84  
    85  // PowScrypt is a consensus engine based on proof-of-work implementing the scrypt
    86  // algorithm.
    87  type PowScrypt struct {
    88  	config Config
    89  
    90  	// Mining related fields
    91  	rand     *rand.Rand    // Properly seeded random source for nonces
    92  	threads  int           // Number of threads to mine on if mining
    93  	update   chan struct{} // Notification channel to update mining parameters
    94  	hashrate metrics.Meter // Meter tracking the average hashrate
    95  
    96  	// Remote sealer related fields
    97  	workCh       chan *sealTask   // Notification channel to push new work and relative result channel to remote sealer
    98  	fetchWorkCh  chan *sealWork   // Channel used for remote sealer to fetch mining work
    99  	submitWorkCh chan *mineResult // Channel used for remote sealer to submit their mining result
   100  	fetchRateCh  chan chan uint64 // Channel used to gather submitted hash rate for local or remote sealer.
   101  	submitRateCh chan *hashrate   // Channel used for remote sealer to submit their mining hashrate
   102  
   103  	// The fields below are hooks for testing
   104  	fakeFail  uint64        // Block number which fails PoW check even in fake mode
   105  	fakeDelay time.Duration // Time delay to sleep for before returning from verify
   106  
   107  	lock      sync.Mutex      // Ensures thread safety for the in-memory caches and mining fields
   108  	closeOnce sync.Once       // Ensures exit channel will not be closed twice.
   109  	exitCh    chan chan error // Notification channel to exiting backend threads
   110  }
   111  
   112  // New creates a full sized scrypt PoW scheme and starts a background thread for
   113  // remote mining, also optionally notifying a batch of remote services of new work
   114  // packages.
   115  func NewScrypt(config Config, notify []string, noverify bool) *PowScrypt {
   116  	pow := &PowScrypt{
   117  		config:   config,
   118  		update:   make(chan struct{}),
   119  		hashrate: metrics.NewMeterForced(),
   120  
   121  		workCh:       make(chan *sealTask),
   122  		fetchWorkCh:  make(chan *sealWork),
   123  		submitWorkCh: make(chan *mineResult),
   124  		fetchRateCh:  make(chan chan uint64),
   125  		submitRateCh: make(chan *hashrate),
   126  		exitCh:       make(chan chan error),
   127  	}
   128  
   129  	go pow.remote(notify, noverify)
   130  	return pow
   131  }
   132  
   133  // NewTester creates a small sized scrypt PoW scheme useful only for testing
   134  // purposes.
   135  func NewTester(notify []string, noverify bool) *PowScrypt {
   136  	pow := &PowScrypt{
   137  		config:   Config{PowMode: ModeTest},
   138  		update:   make(chan struct{}),
   139  		hashrate: metrics.NewMeterForced(),
   140  
   141  		workCh:       make(chan *sealTask),
   142  		fetchWorkCh:  make(chan *sealWork),
   143  		submitWorkCh: make(chan *mineResult),
   144  		fetchRateCh:  make(chan chan uint64),
   145  		submitRateCh: make(chan *hashrate),
   146  		exitCh:       make(chan chan error),
   147  	}
   148  	go pow.remote(notify, noverify)
   149  	return pow
   150  }
   151  
   152  // NewFaker creates a scrypt consensus engine with a fake PoW scheme that accepts
   153  // all blocks' seal as valid, though they still have to conform to the SimpleChain
   154  // consensus rules.
   155  func NewFaker() *PowScrypt {
   156  	return &PowScrypt{
   157  		config: Config{
   158  			PowMode: ModeFake,
   159  		},
   160  	}
   161  }
   162  
   163  // NewFakeFailer creates a scrypt consensus engine with a fake PoW scheme that
   164  // accepts all blocks as valid apart from the single one specified, though they
   165  // still have to conform to the SimpleChain consensus rules.
   166  func NewFakeFailer(fail uint64) *PowScrypt {
   167  	return &PowScrypt{
   168  		config: Config{
   169  			PowMode: ModeFake,
   170  		},
   171  		fakeFail: fail,
   172  	}
   173  }
   174  
   175  // NewFakeDelayer creates a scrypt consensus engine with a fake PoW scheme that
   176  // accepts all blocks as valid, but delays verifications by some time, though
   177  // they still have to conform to the SimplChain consensus rules.
   178  func NewFakeDelayer(delay time.Duration) *PowScrypt {
   179  	return &PowScrypt{
   180  		config: Config{
   181  			PowMode: ModeFake,
   182  		},
   183  		fakeDelay: delay,
   184  	}
   185  }
   186  
   187  // NewFullFaker creates an scrypt consensus engine with a full fake scheme that
   188  // accepts all blocks as valid, without checking any consensus rules whatsoever.
   189  func NewFullFaker() *PowScrypt {
   190  	return &PowScrypt{
   191  		config: Config{
   192  			PowMode: ModeFullFake,
   193  		},
   194  	}
   195  }
   196  
   197  // Close closes the exit channel to notify all backend threads exiting.
   198  func (powScrypt *PowScrypt) Close() error {
   199  	var err error
   200  	powScrypt.closeOnce.Do(func() {
   201  		// Short circuit if the exit channel is not allocated.
   202  		if powScrypt.exitCh == nil {
   203  			return
   204  		}
   205  		errc := make(chan error)
   206  		powScrypt.exitCh <- errc
   207  		err = <-errc
   208  		close(powScrypt.exitCh)
   209  		//walker
   210  		//if powScrypt.remote ==nil{
   211  		//	return
   212  		//}
   213  		//close(powScrypt.remote.requestExit)
   214  		//<-powScrypt.remote.exitCh
   215  	})
   216  	return err
   217  }
   218  
   219  // Threads returns the number of mining threads currently enabled. This doesn't
   220  // necessarily mean that mining is running!
   221  func (powScrypt *PowScrypt) Threads() int {
   222  	powScrypt.lock.Lock()
   223  	defer powScrypt.lock.Unlock()
   224  
   225  	return powScrypt.threads
   226  }
   227  
   228  // SetThreads updates the number of mining threads currently enabled. Calling
   229  // this method does not start mining, only sets the thread count. If zero is
   230  // specified, the miner will use all cores of the machine. Setting a thread
   231  // count below zero is allowed and will cause the miner to idle, without any
   232  // work being done.
   233  func (powScrypt *PowScrypt) SetThreads(threads int) {
   234  	powScrypt.lock.Lock()
   235  	defer powScrypt.lock.Unlock()
   236  
   237  	// Update the threads and ping any running seal to pull in any changes
   238  	powScrypt.threads = threads
   239  	select {
   240  	case powScrypt.update <- struct{}{}:
   241  	default:
   242  	}
   243  }
   244  
   245  // Hashrate implements PoW, returning the measured rate of the search invocations
   246  // per second over the last minute.
   247  // Note the returned hashrate includes local hashrate, but also includes the total
   248  // hashrate of all remote miner.
   249  func (powScrypt *PowScrypt) Hashrate() float64 {
   250  	// Short circuit if we are run the scrypt in normal/test mode.
   251  	if powScrypt.config.PowMode != ModeNormal && powScrypt.config.PowMode != ModeTest {
   252  		return powScrypt.hashrate.Rate1()
   253  	}
   254  	var res = make(chan uint64, 1)
   255  
   256  	select {
   257  	case powScrypt.fetchRateCh <- res:
   258  	case <-powScrypt.exitCh:
   259  		// Return local hashrate only if scrypt is stopped.
   260  		return powScrypt.hashrate.Rate1()
   261  	}
   262  
   263  	// Gather total submitted hash rate of remote sealers.
   264  	return powScrypt.hashrate.Rate1() + float64(<-res)
   265  }
   266  
   267  // APIs implements consensus.Engine, returning the user facing RPC APIs.
   268  func (powScrypt *PowScrypt) APIs(chain consensus.ChainReader) []rpc.API {
   269  	// In order to ensure backward compatibility, we exposes scrypt RPC APIs
   270  	// to both eth and scrypt namespaces.
   271  	return []rpc.API{
   272  		{
   273  			Namespace: "eth",
   274  			Version:   "1.0",
   275  			Service:   &API{powScrypt},
   276  			Public:    true,
   277  		},
   278  		{
   279  			Namespace: "scrypt",
   280  			Version:   "1.0",
   281  			Service:   &API{powScrypt},
   282  			Public:    true,
   283  		},
   284  	}
   285  }