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 }