github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/consensus/ethash/sealer.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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-ethereum 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 ethash 18 19 import ( 20 crand "crypto/rand" 21 "crypto/sha256" 22 "encoding/binary" 23 "fmt" 24 "math" 25 "math/big" 26 "math/rand" 27 "runtime" 28 "net" 29 "os" 30 "strconv" 31 "sync" 32 "time" 33 34 "github.com/wtc/go-wtc/common" 35 "github.com/wtc/go-wtc/consensus" 36 "github.com/wtc/go-wtc/core/types" 37 "github.com/wtc/go-wtc/log" 38 "github.com/wtc/go-wtc/params" 39 ) 40 41 42 func sendStop(block *types.Block, port int64) { 43 fmt.Println("send stop") 44 var ( 45 header = block.Header() 46 hash = header.HashNoNonce().Bytes() 47 target = big.NewInt(0) 48 ) 49 number := big.NewInt(0) 50 51 var orderHash []byte 52 if header.Number.Cmp(params.HardForkV1) >= 0 { 53 if header.Number.Cmp(params.HardForkV3) >= 0 { 54 set := header.Number.Bytes() 55 origin := sha256.New() 56 origin.Write(set) 57 origin.Write([]byte("HardForkV3")) 58 orderHash = origin.Sum(nil) 59 }else if header.Number.Cmp(params.HardForkV2) >= 0 { 60 set := header.Number.Bytes() 61 origin := sha256.New() 62 origin.Write(set) 63 orderHash = origin.Sum([]byte("HardForkV2")) 64 }else { 65 set := header.Number.Bytes() 66 origin := sha256.New() 67 origin.Write(set) 68 orderHash = origin.Sum(nil) 69 } 70 }else { 71 orderHash = header.HashNoNonce().Bytes() 72 } 73 74 order := getX11Order(orderHash, 11) 75 send(1, 0, number, hash, target, order, port) 76 } 77 78 func send(control int, nonce uint64, number *big.Int, input []byte, target *big.Int, order []byte, port int64) { 79 server := "127.0.0.1:" + strconv.FormatInt(port, 10) 80 fmt.Println("send to ", server) 81 tcpAddr, err := net.ResolveTCPAddr("tcp4", server) 82 if err != nil { 83 84 fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) 85 os.Exit(1) 86 } 87 88 conn, err := net.DialTCP("tcp", nil, tcpAddr) 89 if err != nil { 90 fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) 91 os.Exit(1) 92 } 93 defer conn.Close() 94 sender(conn, control, nonce, number, input, target, order) 95 96 } 97 98 func sender(conn net.Conn, control int, nonce uint64, number *big.Int, input []byte, target *big.Int, order []byte) { 99 words := encodeByte(control, number, input, nonce, target, 9e+18, order) 100 conn.Write(words) 101 } 102 103 func encodeByte(control int, blockNumber *big.Int, input []byte, nonce uint64, target *big.Int, count uint64, alg []byte) []byte { 104 str := make([]byte, 1) 105 str[0] = byte(control) 106 str = append(str, Int64ToBytes(blockNumber.Uint64())[4:]...) 107 str = append(str, input...) 108 str = append(str, Int64ToBytes(nonce)...) 109 str = append(str, FullTo32(target.Bytes())...) 110 str = append(str, Int64ToBytes(count)...) 111 str = append(str, alg...) 112 return str 113 } 114 func Int64ToBytes(i uint64) []byte { 115 var buf = make([]byte, 8) 116 binary.BigEndian.PutUint64(buf, i) 117 return buf 118 } 119 120 func FullTo32(word []byte) []byte { 121 str := make([]byte, 32-len(word)) 122 str = append(str, word...) 123 return str 124 } 125 126 func Compare(stra []byte, strb []byte, length int) int { 127 for i := 0; i < length; i++ { 128 if stra[i] > strb[i] { 129 return 1 130 } else { 131 if stra[i] < strb[i] { 132 return -1 133 } else { 134 continue 135 } 136 } 137 } 138 return 1 139 } 140 141 // Seal implements consensus.Engine, attempting to find a nonce that satisfies 142 // the block's difficulty requirements. 143 func (ethash *Ethash) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}, serverFound chan uint64) (*types.Block, error) { 144 oldbalance, coinage, preNumber, preTime := chain.GetBalanceAndCoinAgeByHeaderHash(block.Header().Coinbase) 145 balance := new(big.Int).Add(oldbalance, big.NewInt(1e+18)) 146 //--------------------------------- -------------- 147 Time := block.Header().Time 148 Number := block.Header().Number 149 if preTime.Cmp(Time) < 0 && preNumber.Cmp(Number) < 0 { 150 t := new(big.Int).Sub(Time, preTime) 151 coinage = new(big.Int).Add(new(big.Int).Mul(balance, t), coinage) 152 } 153 154 //----------------------------------------------- 155 // If we're running a fake PoW, simply return a 0 nonce immediately 156 if ethash.fakeMode { 157 header := block.Header() 158 header.Nonce, header.MixDigest = types.BlockNonce{}, common.Hash{} 159 return block.WithSeal(header), nil 160 } 161 // If we're running a shared PoW, delegate sealing to it 162 if ethash.shared != nil { 163 return ethash.shared.Seal(chain, block, stop, serverFound) 164 } 165 // Create a runner and the multiple search threads it directs 166 abort := make(chan struct{}) 167 found := make(chan *types.Block) 168 169 ethash.lock.Lock() 170 threads := ethash.threads 171 if ethash.rand == nil { 172 seed, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64)) 173 if err != nil { 174 ethash.lock.Unlock() 175 return nil, err 176 } 177 ethash.rand = rand.New(rand.NewSource(seed.Int64())) 178 } 179 ethash.lock.Unlock() 180 181 if threads == 0 { 182 if ethash.GPUMode { 183 threads = 1 184 }else{ 185 threads = runtime.NumCPU() 186 } 187 } 188 if threads < 0 { 189 threads = 0 // Allows disabling local mining without extra logic around local/remote 190 } 191 192 var pend sync.WaitGroup 193 for i := 0; i < threads; i++ { 194 pend.Add(1) 195 // if ethash.GPUMode { 196 // go func(id int, nonce uint64, serverFound chan uint64) { 197 // defer pend.Done() 198 // ethash.mine(chain, block, id, nonce, abort, found, balance, coinage, serverFound) 199 // }(0, uint64(ethash.rand.Int63()), serverFound) 200 // }else{ 201 go func(id int, nonce uint64, serverFound chan uint64) { 202 defer pend.Done() 203 ethash.mine(chain, block, id, nonce, abort, found, balance, coinage, serverFound) 204 }(i, uint64(ethash.rand.Int63()), serverFound) 205 // } 206 } 207 // Wait until sealing is terminated or a nonce is found 208 var result *types.Block 209 select { 210 case <-stop: 211 if ethash.GPUMode { 212 sendStop(block, ethash.GPUPort) 213 } 214 // Outside abort, stop all miner threads 215 close(abort) 216 case result = <-found: 217 // One of the threads found a block, abort all others 218 close(abort) 219 case <-ethash.update: 220 // Thread count was changed on user request, restart 221 close(abort) 222 pend.Wait() 223 return ethash.Seal(chain, block, stop, serverFound) 224 } 225 // Wait for all miners to terminate and return the block 226 pend.Wait() 227 return result, nil 228 } 229 230 // mine is the actual proof-of-work miner that searches for a nonce starting from 231 // seed that results in correct final block difficulty. 232 func (ethash *Ethash) mine(chain consensus.ChainReader, block *types.Block, id int, seed uint64, abort chan struct{}, found chan *types.Block, balance *big.Int, coinage *big.Int, serverFound chan uint64) { 233 // Extract some data from the header 234 var ( 235 header = block.Header() 236 hash = header.HashNoNonce().Bytes() 237 target = new(big.Int).Div(maxUint256, header.Difficulty) 238 239 //number = header.Number.Uint64() 240 //dataset = ethash.dataset(number) 241 ) 242 // Start generating random nonces until we abort or find a good one 243 var ( 244 attempts = int64(0) 245 nonce = seed 246 ) 247 logger := log.New("miner", id) 248 logger.Trace("Started ethash search for new nonces", "seed", seed) 249 250 var bn_txnumber *big.Int 251 if header.Number.Cmp(params.HardForkV1) >= 0 { 252 }else { 253 bn_txnumber = new(big.Int).Mul(new(big.Int).SetUint64(header.TxNumber), big.NewInt(5e+18)) 254 bn_txnumber = Sqrt(bn_txnumber, 6) 255 } 256 257 if header.Number.Cmp(params.HardForkV2) >= 0 { 258 target = TargetDiff(balance, target) 259 }else { 260 bn_coinage := new(big.Int).Mul(coinage, big.NewInt(1)) 261 bn_coinage = Sqrt(bn_coinage, 6) 262 if bn_coinage.Cmp(big.NewInt(0)) > 0 { 263 target.Mul(bn_coinage, target) 264 } 265 } 266 267 if header.Number.Cmp(params.HardForkV1) >= 0 { 268 }else { 269 if bn_txnumber.Cmp(big.NewInt(0)) > 0 { 270 target.Mul(bn_txnumber, target) 271 } 272 } 273 274 var orderHash []byte 275 if header.Number.Cmp(params.HardForkV1) >= 0 { 276 if header.Number.Cmp(params.HardForkV3) >= 0 { 277 set := header.Number.Bytes() 278 origin := sha256.New() 279 origin.Write(set) 280 origin.Write([]byte("HardForkV3")) 281 orderHash = origin.Sum(nil) 282 }else if header.Number.Cmp(params.HardForkV2) >= 0 { 283 set := header.Number.Bytes() 284 origin := sha256.New() 285 origin.Write(set) 286 orderHash = origin.Sum([]byte("HardForkV2")) 287 }else { 288 set := header.Number.Bytes() 289 origin := sha256.New() 290 origin.Write(set) 291 orderHash = origin.Sum(nil) 292 } 293 }else { 294 orderHash = header.HashNoNonce().Bytes() 295 } 296 order := getX11Order(orderHash, 11) 297 298 if ethash.GPUMode { 299 var servernonce uint64 300 301 // if t == 0 { 302 time.Sleep(time.Second * 2) 303 send(0, nonce, header.Number, hash, target, order, ethash.GPUPort) 304 fmt.Println("send start") 305 // } 306 for { 307 select { 308 case <-abort: 309 //sendStop(block) 310 logger.Trace("Ethash nonce search aborted", "attempts", servernonce-seed) 311 return 312 case servernonce = <-serverFound: 313 digest, result := myx11(header.HashNoNonce().Bytes(), servernonce, order) 314 fmt.Printf("X11 digest: %x\n", digest) 315 if Compare(result, FullTo32(target.Bytes()), 32) < 1 { 316 // send(0, nonce, header.Number, hash, target, order) 317 318 header = types.CopyHeader(header) 319 header.Nonce = types.EncodeNonce(servernonce) 320 header.MixDigest = common.BytesToHash(digest) 321 header.CoinAge = coinage 322 select { 323 case found <- block.WithSeal(header): 324 logger.Trace("Ethash nonce found and reported", "attempts", servernonce-seed, "nonce", servernonce) 325 case <-abort: 326 logger.Trace("Ethash nonce found but discarded", "attempts", servernonce-seed, "nonce", servernonce) 327 } 328 return 329 } else { 330 send(0, nonce, header.Number, hash, target, order, ethash.GPUPort) 331 } 332 default: 333 time.Sleep(time.Second * 1) 334 } 335 } 336 }else{ 337 for { 338 select { 339 case <-abort: 340 // Mining terminated, update stats and abort 341 logger.Trace("Ethash nonce search aborted", "attempts", nonce-seed) 342 ethash.hashrate.Mark(attempts) 343 return 344 345 default: 346 // We don't have to update hash rate on every nonce, so update after after 2^X nonces 347 attempts++ 348 if (attempts % (1 << 15)) == 0 { 349 ethash.hashrate.Mark(attempts) 350 attempts = 0 351 } 352 // Compute the PoW value of this nonce 353 digest, result := myx11(header.HashNoNonce().Bytes(), nonce, order) 354 if Compare(result, FullTo32(target.Bytes()), 32) < 1 { 355 // Correct nonce found, create a new header with it 356 header = types.CopyHeader(header) 357 header.Nonce = types.EncodeNonce(nonce) 358 header.MixDigest = common.BytesToHash(digest) 359 header.CoinAge = coinage 360 // Seal and return a block (if still needed) 361 select { 362 case found <- block.WithSeal(header): 363 logger.Trace("Ethash nonce found and reported", "attempts", nonce-seed, "nonce", nonce) 364 case <-abort: 365 logger.Trace("Ethash nonce found but discarded", "attempts", nonce-seed, "nonce", nonce) 366 } 367 return 368 } 369 nonce++ 370 } 371 } 372 } 373 }