簡體   English   中英

無法在 sha256 hash 工作證明中獲得 4 個前導零(Java)

[英]Not able to get 4 leading zeros in sha256 hash proof of work- ever (Java)

我正在構建一個區塊鏈應用程序。

當我在 main 中運行測試時,無論我做什么,無論我給它多少時間,當我記錄不同的東西時,我都無法得到 4 個前導零,因此完成了 4 的難度級別。我看到二進制哈希的日志,並且很多時候它們具有重復元素,例如 1111,但在我的時間被擊中並且難度降低到三之前,從來沒有 0000。 我不知道為什么。

我從在線資源中借用了 hash 算法,並針對在線哈希檢查了它的 output 並進行了檢查。

我知道每個難度級別都會成倍增加,但 2^4 仍然只有 16,而且我看到其他重復數字(1111、1010、除 0000 之外的任何組合)。 有什么理由會出現這種情況嗎?

我想提供豐富的代碼而不是短缺。 從邏輯上講,如果所有數字都同樣可能,為什么隨機出現,它不會出現 0000* (例如,在某些時候為 0000101011)。 因此,不可能有四個零,但為什么呢? 我多次等待 100 秒,然后看到其他數字重復出現。 當難度達到三時,我看到它每次在點上准確地擊中 4 或 3 或 2 秒。 當我從難度 5(創世區塊)開始時,它永遠不會解決——我敢肯定,即使我讓它在一夜之間運行。 那么可能會發生什么?

package privblock.gerald.ryan;

import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Arrays;
import java.util.Date; // gets time in ms.
import privblock.gerald.ryan.util.CryptoHash;

/**
 * 
 * @author Gerald Ryan Block Class of blockchain app
 *
 *         Description: The block hash is the result of the timestamp, the
 *         last_hash, the data, the difficulty and the nonce
 *
 */
public class Block {
    long timestamp;
    String lastHash;
    String hash;
    String[] data;
    int difficulty;
    int nonce;


// Millisecond basis
    ;
    static long MILLISECONDS = 1;
    static long SECONDS = 1000 * MILLISECONDS;
    static long MINE_RATE = 2 * SECONDS;

    /**
     * A block is a unit of storage for a blockchain that supports a cryptocurrency.
     * 
     * @param timestamp
     * @param lastHash
     * @param hash
     * @param data
     * @param difficulty
     * @param nonce
     */
    public Block(long timestamp, String lastHash, String hash, String[] data, int difficulty, int nonce) {
        super();
        this.timestamp = timestamp;
        this.lastHash = lastHash;
        this.hash = hash;
        this.data = data;
        this.difficulty = difficulty;
        this.nonce = nonce;
    }

    public String toString() {
        return "\n-----------BLOCK--------\ntimestamp: " + this.timestamp + "\nlastHash: " + this.lastHash + "\nhash: "
                + this.hash + "\ndifficulty: " + this.getDifficulty() + "\nNonce: " + this.nonce
                + "\n-----------------------\n";
    }

    /**
     * Mine a block based on given last block and data until a block hash is found
     * that meets the leading 0's Proof of Work requirement.
     * 
     * @param last_block
     * @param data
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static Block mine_block(Block last_block, String[] data) throws NoSuchAlgorithmException {
        long timestamp = new Date().getTime();
        String last_hash = last_block.getHash();
        int difficulty = Block.adjust_difficulty(last_block, timestamp);
        int nonce = 0;
        String hash = CryptoHash.getSHA256(timestamp, last_block.getHash(), data, difficulty, nonce);

        String proof_of_work = CryptoHash.n_len_string('0', difficulty);
//      System.out.println("Proof of work " + proof_of_work);
        String binary_hash = CryptoHash.hex_to_binary(hash);
//      System.out.println("binary hash " + binary_hash);
        String binary_hash_work_end = binary_hash.substring(0, difficulty);
//      System.out.println("binary_Hash_work_end " + binary_hash_work_end);
        System.out.println("Difficulty: " + difficulty);
        while (!proof_of_work.equalsIgnoreCase(binary_hash_work_end)) {
//          System.out.println("Working");
            nonce += 1;
            timestamp = new Date().getTime();
            difficulty = Block.adjust_difficulty(last_block, timestamp);
            hash = CryptoHash.getSHA256(timestamp, last_block.getHash(), data, difficulty, nonce);

            proof_of_work = CryptoHash.n_len_string('0', difficulty);
            binary_hash = CryptoHash.hex_to_binary(hash);
            binary_hash_work_end = binary_hash.substring(0, difficulty);
//          System.out.println(binary_hash_work_end);
//          System.out.println(binary_hash);
//          System.out.println(proof_of_work);
        }
        System.out.println("Solved at Difficulty: " + difficulty);
//      System.out.println("Proof of work requirement " + proof_of_work);
//      System.out.println("binary_Hash_work_end " + binary_hash_work_end);
//      System.out.println("binary hash " + binary_hash);
        System.out.println("BLOCK MINED");

        return new Block(timestamp, last_hash, hash, data, difficulty, nonce);
    }

    /**
     * Generate Genesis block
     * 
     * @return
     */
    public static Block genesis_block() {
        long timestamp = 1;
        String last_hash = "genesis_last_hash";
        String hash = "genesis_hash";
        String[] data = { "buy", "privcoin" };
        int difficulty = 4;
        int nonce = 0;
        return new Block(timestamp, last_hash, hash, data, difficulty, nonce);
    }

    /**
     * Calculate the adjusted difficulty according to the MINE_RATE. Increase the
     * difficulty for quickly mined blocks. Decrease the difficulty for slowly mined
     * blocks.
     * 
     * @param last_block
     * @param new_timestamp
     */
    public static int adjust_difficulty(Block last_block, long new_timestamp) {
        long time_diff = new_timestamp - last_block.getTimestamp();

//      System.out.println(time_diff);
        if (time_diff < MINE_RATE) {
//          System.out.println("Increasing difficulty");
            return last_block.getDifficulty() + 1;
        } else if (last_block.getDifficulty() - 1 > 0) {
//          System.out.println("Decreasing difficulty");
            return last_block.getDifficulty() - 1;
        } else {
            return 1;
        }
    }

    /**
     * Validate block by enforcing following rules: - Block must have the proper
     * last_hash reference - Block must meet the proof of work requirements -
     * difficulty must only adjust by one - block hash must be a valid combination
     * of block fields
     * 
     * @param last_block
     * @param block
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static boolean is_valid_block(Block last_block, Block block) throws NoSuchAlgorithmException {
        String binary_hash = CryptoHash.hex_to_binary(block.getHash());
        char[] pow_array = CryptoHash.n_len_array('0', block.getDifficulty());
        char[] binary_char_array = CryptoHash.string_to_charray(binary_hash);
        if (!block.getLastHash().equalsIgnoreCase(last_block.getHash())) {
            System.out.println("The last hash must be correct");
            return false;
            // Throw exception the last hash must be correct
        }
        if (!Arrays.equals(pow_array, Arrays.copyOfRange(binary_char_array, 0, block.getDifficulty()))) {
            System.out.println("Proof of work requirement not met");
            return false;
            // throw exception - proof of work requirement not met
        }
        if (Math.abs(last_block.difficulty - block.difficulty) > 1) {
            System.out.println("Block difficulty must adjust by one");
            return false;
            // throw exception: The block difficulty must only adjust by 1
        }
        String reconstructed_hash = CryptoHash.getSHA256(block.getTimestamp(), block.getLastHash(), block.getData(),
                block.getDifficulty(), block.getNonce());
        if (!block.getHash().equalsIgnoreCase(reconstructed_hash)) {
            System.out.println("The block hash must be correct");
            System.out.println(block.getHash());
            System.out.println(reconstructed_hash);
            return false;
            // throw exception: the block hash must be correct
        }
        System.out.println("You have mined a valid block");
        return true;
    }

    public int getDifficulty() {
        return difficulty;
    }

    public long getTimestamp() {
        return timestamp;
    }

    public String getHash() {
        return hash;
    }

    public String getLastHash() {
        return lastHash;
    }

    public String[] getData() {
        return data;
    }

    public int getNonce() {
        return nonce;
    }

    public static void main(String[] args) throws NoSuchAlgorithmException {
//      String md = CryptoHash.getSHA256("foobar");
        Block genesis = genesis_block();
        System.out.println(genesis.toString());
//      Block bad_block = Block.mine_block(genesis, new String[] { "watch", "AOT" });
//      bad_block.lastHash = "evil data";
//      System.out.println(bad_block.toString());
        Block good_block = mine_block(genesis, new String[] { "foo", "bar" });
        System.out.println(good_block.toString());
//      System.out.println(mine_block(new_block, new String[] { "crypto", "is", "fun" }).toString());
//      System.out.println(Block.is_valid_block(genesis, bad_block)); // returns false as expected
        System.out.println(Block.is_valid_block(genesis, good_block));
        System.out.println(CryptoHash.hex_to_binary(good_block.getHash()));
        Block good_block2 = mine_block(good_block, new String[] { "bar", "foo" });
        Block good_block3 = mine_block(good_block2, new String[] { "bar", "foo" });
        Block good_block4 = mine_block(good_block3, new String[] { "bar", "foo" });
//      Block good_block5 = mine_block(good_block4, new String[] {"bar", "foo"});
//      Block good_block6 = mine_block(good_block5, new String[] {"bar", "foo"});
    }

}

package privblock.gerald.ryan.util;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;

public class CryptoHash {
    static HashMap<Character, String> HEX_TO_BIN_TABLE;
    static {
        HEX_TO_BIN_TABLE = new HashMap<Character, String>();
        HEX_TO_BIN_TABLE.put('0', "0000");
        HEX_TO_BIN_TABLE.put('1', "0001");
        HEX_TO_BIN_TABLE.put('2', "0010");
        HEX_TO_BIN_TABLE.put('3', "0011");
        HEX_TO_BIN_TABLE.put('4', "0100");
        HEX_TO_BIN_TABLE.put('5', "0101");
        HEX_TO_BIN_TABLE.put('6', "0110");
        HEX_TO_BIN_TABLE.put('7', "0111");
        HEX_TO_BIN_TABLE.put('8', "1000");
        HEX_TO_BIN_TABLE.put('9', "1001");
        HEX_TO_BIN_TABLE.put('a', "1010");
        HEX_TO_BIN_TABLE.put('b', "1011");
        HEX_TO_BIN_TABLE.put('c', "1100");
        HEX_TO_BIN_TABLE.put('d', "1101");
        HEX_TO_BIN_TABLE.put('e', "1110");
        HEX_TO_BIN_TABLE.put('f', "1111");
    }

    public static String getSHA256(String... sarray) throws NoSuchAlgorithmException {
        String s = concat(sarray);
//      System.out.printf("Hashing \"%s\"\n", s);
        MessageDigest md;
        md = MessageDigest.getInstance("SHA-256");
        byte[] b = md.digest(s.getBytes(StandardCharsets.UTF_8));
        BigInteger number = new BigInteger(1, b);
        StringBuilder hexString = new StringBuilder(number.toString(16));
        while (hexString.length() < 32) {
            hexString.insert(0, '0');
        }
        String mds = hexString.toString();
//      System.out.printf("hash is:\n%s\n", mds);
        return hexString.toString();

    }

    public static String getSHA256(long timestamp, String last_hash, String[] data, int difficulty, int nonce)
            throws NoSuchAlgorithmException {
        String s = "";

        s += Long.toString(timestamp);
        s += last_hash;
        s += concat(data);
        s += Integer.toString(difficulty);
        s += Integer.toString(nonce);
//      System.out.printf("Hashing \"%s\"\n", s);
        MessageDigest md;
        md = MessageDigest.getInstance("SHA-256");
        byte[] b = md.digest(s.getBytes(StandardCharsets.UTF_8));
        BigInteger number = new BigInteger(1, b);
        StringBuilder hexString = new StringBuilder(number.toString(16));
//      System.out.println(hexString);
        while (hexString.length() < 32) {
            hexString.insert(0, '0');
        }
        String messageDigestString = hexString.toString();
//      System.out.printf("hash is:\n%s\n", messageDigestString);
        return hexString.toString();
    }
    
    public static char[] n_len_array(char c, int n) {
        char[] ch = new char[n];
        for (int i = 0; i<n; i++) {
            ch[i] = c;
        }
        return ch;
    }
    
    public static String n_len_string(char c, int n) {
        String s = "";
        for (int i = 0; i<n; i++) {
            s += c;
        }
        return s;
    }

    public static String concat(String... args) {
        String s = "";
        for (String $ : args) {
            s += $;
        }
//      System.out.println(s);
        return s;
    }

    public static char[] string_to_charray(String str) {
        char[] ch = new char[str.length()];

        for (int i = 0; i < str.length(); i++) {
            ch[i] = str.charAt(i);
        }
        return ch;
    }

    public static String string_to_hex(String arg) {
        return String.format("%064x", new BigInteger(1, arg.getBytes(StandardCharsets.UTF_8)));
    }

    public static String hex_to_binary(String hex_string) {
        String binary_string = "";
        for (int i = 0; i < hex_string.length(); i++) {
            binary_string += HEX_TO_BIN_TABLE.get(hex_string.charAt(i));
        }
        return binary_string;
    }

    public static String string_to_binary(String raw_string) {
        String hex_string = string_to_hex(raw_string);
        String bin_string = hex_to_binary(hex_string);
        return bin_string;
    }
    


}

ps 這是我創建的日志示例。 我也創建了其他更清潔的日志,但這顯示了我們正在使用的內容。 第一項表示以毫秒為單位的時間。 第二個代表hash的前四位,在它的正下方,后面是難度級別要求字符串(第二項需要是什么,長度n=難度級別)。 The hash just never leads with four zeros, ever, so my hash function or call to the function must be broken in some way.

6479
1000
1000001010111011100110111010100100111010101001111110010101011101101101110000110100110110110000001010001000000010110001100111100111010100110001001001110111011010011100110000011111110100000100000100000010100001000110000111000101100010001111011000110011111101
0000
6479
0101
0101110111010100101010100000001011100011000001110001011011001101001111101011010011000111101101111111001001001010100110101101100111111011001011100101111000011100010001000000000011000111010000101101001000001010101010111001010000101001110011111101011011011000
0000
6479
1000
1000000001000101001110001110110000110111001101100001011000111010111110001011011010011111111101011001110011001001111011011110110010101010101100011011001001110001100010010101001011100001101011011101010000000100111100011011110100000101100111010100100110011101
0000
6479

我解決了這個問題。 它確實經常返回 4 個前導零,但結構化的代碼將它們剪掉(因為它認為它們沒有意義)。 我通過記錄注意到長度並不總是固定的 64 字節/256 位字符串。 這是 output:

256
1101111000010000100001110001010001010000001010111001100011010011110010001001010001010010100110111000110010000010001110110100100101000000001111111110011100000001010100000111001000111101010001010100110100000000111000100001000000010010010111011110110011110111
256
011001111101001000011111011001111110010110000011001011111010001011010110010100001011010011010010111101100010010111000010110010110111110001010101100000000101001000111110100111011100001110010010101011011000000101100001101110101101010001110000111111110000
252
0001100101110011101000000011000101011100111101110100111110100101110110011100010110001011000110010011110110011001100111010001100100011001011000001011100011011011011011101000111000011100100011011011011000101010011101000110101011000110011100111010000011000011
256
1100110001001001110001100111100010101100100010110111100111001010011011111111100010100110110000010000101000010111111010010101110001100010101010111111111111001011010111010100001010000010111100100100111000010101011000110000100000100111010001000011000000010000
256

這樣就解決了,或者至少我理解了這個問題。 睡眠的作用真是太神奇了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM