// Copyright (c) 2017-2026 Lethean (https://lt.hn) // // Licensed under the European Union Public Licence (EUPL) version 1.2. // SPDX-License-Identifier: EUPL-1.2 package mining import ( "bytes" "encoding/binary" "encoding/hex" "testing" "dappco.re/go/core/blockchain/types" "dappco.re/go/core/blockchain/wire" ) func testnetGenesisHeader() types.BlockHeader { return types.BlockHeader{ MajorVersion: 1, Nonce: 101011010221, PrevID: types.Hash{}, MinorVersion: 0, Timestamp: 1770897600, Flags: 0, } } func testnetGenesisRawTx() []byte { u64s := [25]uint64{ 0xa080800100000101, 0x03018ae3c8e0c8cf, 0x7b0287d2a2218485, 0x720c5b385edbe3dd, 0x178e7c64d18a598f, 0x98bb613ff63e6d03, 0x3814f971f9160500, 0x1c595f65f55d872e, 0x835e5fd926b1f78d, 0xf597c7f5a33b6131, 0x2074496b139c8341, 0x64612073656b6174, 0x20656761746e6176, 0x6e2065687420666f, 0x666f206572757461, 0x616d726f666e6920, 0x696562206e6f6974, 0x207973616520676e, 0x6165727073206f74, 0x6168207475622064, 0x7473206f74206472, 0x202d202e656c6966, 0x206968736f746153, 0x6f746f6d616b614e, 0x0a0e0d66020b0015, } u8s := [2]uint8{0x00, 0x00} buf := make([]byte, 25*8+2) for i, v := range u64s { binary.LittleEndian.PutUint64(buf[i*8:], v) } buf[200] = u8s[0] buf[201] = u8s[1] return buf } func TestHeaderMiningHash_Good(t *testing.T) { // Build the genesis block from the known raw coinbase transaction. rawTx := testnetGenesisRawTx() dec := wire.NewDecoder(bytes.NewReader(rawTx)) minerTx := wire.DecodeTransaction(dec) if dec.Err() != nil { t.Fatalf("decode genesis tx: %v", dec.Err()) } block := types.Block{ BlockHeader: testnetGenesisHeader(), MinerTx: minerTx, } got := HeaderMiningHash(&block) // The header mining hash is computed with nonce=0, so manually compute // it to get the expected value. block.Nonce = 0 blob := wire.BlockHashingBlob(&block) want := wire.Keccak256(blob) if got != want { t.Errorf("HeaderMiningHash:\n got: %s\n want: %s", hex.EncodeToString(got[:]), hex.EncodeToString(want[:])) } } func TestHeaderMiningHash_Good_NonceIgnored(t *testing.T) { // HeaderMiningHash must produce the same result regardless of the // block's current nonce value. rawTx := testnetGenesisRawTx() dec := wire.NewDecoder(bytes.NewReader(rawTx)) minerTx := wire.DecodeTransaction(dec) if dec.Err() != nil { t.Fatalf("decode genesis tx: %v", dec.Err()) } block1 := types.Block{ BlockHeader: testnetGenesisHeader(), MinerTx: minerTx, } block2 := block1 block2.Nonce = 999999 h1 := HeaderMiningHash(&block1) h2 := HeaderMiningHash(&block2) if h1 != h2 { t.Errorf("HeaderMiningHash changed with different nonce:\n nonce=%d: %x\n nonce=%d: %x", block1.Nonce, h1, block2.Nonce, h2) } } func TestCheckNonce_Good_LowDifficulty(t *testing.T) { // Build a genesis block and compute its header hash. rawTx := testnetGenesisRawTx() dec := wire.NewDecoder(bytes.NewReader(rawTx)) minerTx := wire.DecodeTransaction(dec) if dec.Err() != nil { t.Fatalf("decode genesis tx: %v", dec.Err()) } block := types.Block{ BlockHeader: testnetGenesisHeader(), MinerTx: minerTx, } headerHash := HeaderMiningHash(&block) // With difficulty=1, any nonce should produce a valid solution. ok, err := CheckNonce(headerHash, 0, 1) if err != nil { t.Fatalf("CheckNonce: %v", err) } if !ok { t.Error("CheckNonce should pass with difficulty=1") } } func TestCheckNonce_Good_HighDifficulty(t *testing.T) { // With extremely high difficulty, nonce=0 should NOT produce a valid solution. rawTx := testnetGenesisRawTx() dec := wire.NewDecoder(bytes.NewReader(rawTx)) minerTx := wire.DecodeTransaction(dec) if dec.Err() != nil { t.Fatalf("decode genesis tx: %v", dec.Err()) } block := types.Block{ BlockHeader: testnetGenesisHeader(), MinerTx: minerTx, } headerHash := HeaderMiningHash(&block) // With difficulty = max uint64, virtually no hash passes. ok, err := CheckNonce(headerHash, 0, ^uint64(0)) if err != nil { t.Fatalf("CheckNonce: %v", err) } if ok { t.Error("CheckNonce should fail with max difficulty") } }