github.com/aquanetwork/aquachain@v1.7.8/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  // lightvalid package is a lightweight version of aquahash meant only for testing a nonce on a trusted block
    18  package lightvalid
    19  
    20  import (
    21  	"encoding/binary"
    22  	"errors"
    23  	"math/big"
    24  
    25  	"gitlab.com/aquachain/aquachain/common"
    26  	"gitlab.com/aquachain/aquachain/crypto"
    27  	"gitlab.com/aquachain/aquachain/params"
    28  )
    29  
    30  var NoMixDigest = common.Hash{}
    31  
    32  // maxUint256 is a big integer representing 2^256-1
    33  var maxUint256 = new(big.Int).Exp(big.NewInt(2), big.NewInt(256), big.NewInt(0))
    34  
    35  func New() *Light {
    36  	return &Light{}
    37  }
    38  
    39  type Light struct{}
    40  
    41  type LightBlock interface {
    42  	Difficulty() *big.Int
    43  	HashNoNonce() common.Hash
    44  	Nonce() uint64
    45  	MixDigest() common.Hash
    46  	NumberU64() uint64
    47  	Version() params.HeaderVersion
    48  }
    49  
    50  // Verify checks whether the block's nonce is valid.
    51  func (l *Light) Verify(block LightBlock) bool {
    52  
    53  	version := block.Version()
    54  	if version == 0 || version > crypto.KnownVersion {
    55  		return false
    56  	}
    57  
    58  	// check difficulty is nonzero
    59  	difficulty := block.Difficulty()
    60  	if difficulty.Cmp(common.Big0) == 0 {
    61  		return false
    62  	}
    63  
    64  	// avoid mixdigest malleability as it's not included in a block's "hashNononce"
    65  	if block.MixDigest() != NoMixDigest {
    66  		return false
    67  	}
    68  
    69  	// generate block hash
    70  	seed := make([]byte, 40)
    71  	copy(seed, block.HashNoNonce().Bytes())
    72  	binary.LittleEndian.PutUint64(seed[32:], block.Nonce())
    73  	result := crypto.VersionHash(byte(version), seed)
    74  
    75  	// check number set from generated hash, is less than target diff
    76  	target := new(big.Int).Div(maxUint256, difficulty)
    77  	return new(big.Int).SetBytes(result).Cmp(target) <= 0
    78  }
    79  
    80  var (
    81  	ErrNoVersion        = errors.New("header has no version")
    82  	ErrDifficultyZero   = errors.New("difficulty is zero")
    83  	ErrMixDigestNonZero = errors.New("invalid mix digest")
    84  	ErrPOW              = errors.New("invalid proof of work")
    85  )
    86  
    87  // VerifyWithError returns an error
    88  func (l *Light) VerifyWithError(block LightBlock) error {
    89  
    90  	version := block.Version()
    91  	if version == 0 || version > crypto.KnownVersion {
    92  		return ErrNoVersion
    93  	}
    94  
    95  	// check difficulty is nonzero
    96  	difficulty := block.Difficulty()
    97  	if difficulty.Cmp(common.Big0) == 0 {
    98  		return ErrDifficultyZero
    99  	}
   100  
   101  	// avoid mixdigest malleability as it's not included in a block's "hashNononce"
   102  	if block.MixDigest() != NoMixDigest {
   103  		return ErrMixDigestNonZero
   104  	}
   105  
   106  	// generate block hash
   107  	seed := make([]byte, 40)
   108  	copy(seed, block.HashNoNonce().Bytes())
   109  	binary.LittleEndian.PutUint64(seed[32:], block.Nonce())
   110  	result := crypto.VersionHash(byte(version), seed)
   111  
   112  	// check number set from generated hash, is less than target diff
   113  	target := new(big.Int).Div(maxUint256, difficulty)
   114  	if new(big.Int).SetBytes(result).Cmp(target) <= 0 {
   115  		return nil
   116  	}
   117  	return ErrPOW
   118  }