gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/consensus/lightvalid/light.go (about)

     1  // Copyright 2018 The aquachain Authors
     2  // This file is part of the aquachain library.
     3  //
     4  // The aquachain 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 aquachain 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 aquachain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // The lightvalid package is a lightweight version of aquahash meant only for
    18  // testing a nonce on a *trusted* block. It is primarily used in the
    19  // open-aquachain-pool to validate POW (only the nonce is inputed by user)
    20  package lightvalid
    21  
    22  import (
    23  	"encoding/binary"
    24  	"errors"
    25  	"math/big"
    26  
    27  	"gitlab.com/aquachain/aquachain/common"
    28  	"gitlab.com/aquachain/aquachain/crypto"
    29  	"gitlab.com/aquachain/aquachain/params"
    30  )
    31  
    32  var NoMixDigest = common.Hash{}
    33  
    34  // maxUint256 is a big integer representing 2^256-1
    35  var maxUint256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
    36  
    37  var (
    38  	// ErrNoVersion is returned if the block/header has no version
    39  	ErrNoVersion = errors.New("header has no version")
    40  
    41  	// ErrDifficultyZero is returned if difficulty is not set (use CalcDifficulty)
    42  	ErrDifficultyZero = errors.New("difficulty is zero")
    43  
    44  	// ErrMixDigestNonZero is returned if mix digest is nonzero. this may change in future hard forks
    45  	ErrMixDigestNonZero = errors.New("invalid mix digest")
    46  
    47  	// ErrPOW is returned if pow difficulty is not valid
    48  	ErrPOW = errors.New("invalid proof of work")
    49  )
    50  
    51  func New() *Light {
    52  	return &Light{}
    53  }
    54  
    55  type Light struct{}
    56  
    57  type LightBlock interface {
    58  	Difficulty() *big.Int
    59  	HashNoNonce() common.Hash
    60  	Nonce() uint64
    61  	MixDigest() common.Hash
    62  	NumberU64() uint64
    63  	Version() params.HeaderVersion
    64  }
    65  
    66  // Verify checks whether the block's nonce is valid. Use VerifyWithError for the actual error.
    67  func (l *Light) Verify(block LightBlock) bool {
    68  	return l.VerifyWithError(block) == nil
    69  }
    70  
    71  // VerifyWithError returns an error if block is not valid
    72  func (l *Light) VerifyWithError(block LightBlock) error {
    73  
    74  	version := block.Version()
    75  	if version == 0 || version > crypto.KnownVersion {
    76  		return ErrNoVersion
    77  	}
    78  
    79  	// check difficulty is nonzero
    80  	difficulty := block.Difficulty()
    81  	if difficulty.Cmp(common.Big0) == 0 {
    82  		return ErrDifficultyZero
    83  	}
    84  
    85  	// avoid mixdigest malleability as it's not included in a block's "hashNononce"
    86  	if block.MixDigest() != NoMixDigest {
    87  		return ErrMixDigestNonZero
    88  	}
    89  
    90  	// generate block hash
    91  	seed := make([]byte, 40)
    92  	copy(seed, block.HashNoNonce().Bytes())
    93  	binary.LittleEndian.PutUint64(seed[32:], block.Nonce())
    94  	result := crypto.VersionHash(byte(version), seed)
    95  
    96  	// check number set from generated hash, is less than target diff
    97  	target := new(big.Int).Div(maxUint256, difficulty)
    98  	if new(big.Int).SetBytes(result).Cmp(target) <= 0 {
    99  		return nil
   100  	}
   101  	return ErrPOW
   102  }