Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new feature suggest: PoW Rune #3739

Open
studyzy opened this issue May 9, 2024 · 3 comments
Open

new feature suggest: PoW Rune #3739

studyzy opened this issue May 9, 2024 · 3 comments

Comments

@studyzy
Copy link

studyzy commented May 9, 2024

Rune protocol is a popular Bitcoin ecological token protocol recently, but Rune's Mint adopts a first-come-first-served method, which cannot reflect fairness. Here I propose a POW-based rune improvement protocol. In this protocol, mint must be based on pow proof, and the number of mint is determined by the hash value of the pow result, so that everyone can mint tokens more fairly.
The changes to the pow rune are as follows:

1. Modification of etching definition

1.1 Remove premine, everyone mints fairly.

1.2 HashSequence

The etching definition contains the hash type, which can be concatenated in multiple ways. The enumeration of hash types is as follows:

#[derive(Debug)]
pub enum HashType {
    SHA256 = 1,
    SHA3_256,
    RIPEMD160,
    KECCAK256,
    BLAKE2B,
    BLAKE2S,
    SCRYPT,
    ETHASH,
    X11,
    NEOSCRYPT,
    EQUIHASH,
    LBRY,
    PENTABLAKE,
    QUARK,
    SKEIN,
    WHIRLPOOL,
    YESCRYPT,
    ZR5,
}

1.3 CommitWindow

CommitWindow defines the height range of submission. For example, if the CommitWindow of a Rune is 100, when performing POW calculation and minting rune, based on the hash of the 1000th block, this mint transaction must be submitted and packaged before the height of 1000+100=1100. Mint beyond the CommitWindow will be considered invalid.

1.4 BaseZero

Defines BaseZero, which requires at least how many zeros to be considered successful

pub struct Etching {
    pub divisibility: Option<u8>,
    //pub premine: Option<u128>,
    pub rune: Option<Rune>,
    pub spacers: Option<u32>,
    pub symbol: Option<char>,
    pub terms: Option<Terms>,
    pub turbo: bool,

    // new fileds for pow
    hash_sequence: Vec<HashType>,
    commit_window: u32,
    base_zero: u8,
}

2. Submit when minting:

submit fields:runeId, blockHeight, nonce

#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq)]
pub struct Mint {
  pub rune_id: RuneId,
  pub block_height: u64,
  pub nonce: u32,
}

How to calculate how many runes are minted?

let hash_sequence = get_hash_sequence(rune_id); //Query the Etching definition of rune_id and obtain its hash_sequence
let block_hash = get_block_hash(block_height); //Get the block hash based on the block height
let hash = calc_hash(hash_sequence, block_hash, nonce); //Concatenate block_hash and nonce, and use the hash algorithm corresponding to hash_sequence to calculate the final POW hash value.

Count how many zeros are in front of the hash, subtract min0, there are n left, then the number is 2^n, the code is as follows:

fn calc_mint_amount(hash: &[u8], base_zero: u8) -> u64 {
    // Calculate how many zeros are at the beginning of the hash in binary
    let mut zero_count = 0;
    for &b in hash {
        if b == 0 {
            zero_count += 8;
        } else {
            for i in (0..8).rev() {
                if (b >> i) & 1 == 0 {
                    zero_count += 1;
                } else {
                    break;
                }
            }
            break;
        }
    }
    if zero_count < base_zero {
        return 0;
    }
    // Calculate the final amount
    let amount = 1 << (zero_count - base_zero);
    return amount;
}

Other logics such as Transfer and Cenotaph remain unchanged.
In order to distinguish between the existing rune protocol and the pow rune protocol, we can adjust the magic number of the pow rune, such as changing OP_13 to OP_14, so as to achieve mutual non-interference with the existing rune protocol.

@summraznboi
Copy link

This looks like an interesting proposal! First comment, there is no need to use a new rune protocol, use can just add the 3 new tags as part of Terms. Secondly and more important, once a valid hash is found and broadcast into mempool, that hash can be reused by all until the commitment window is reached. This means in practice when someone finds a valid hash, that is just another starting window for an open mint. You need to include fields that are unique per transaction to avoid this replay attack.

@studyzy
Copy link
Author

studyzy commented May 10, 2024

Good idea, we can just add 3 new tags as part of Terms, and when calculate hash, include committer address.

let hash_sequence = get_hash_sequence(rune_id); //Query the Etching definition of rune_id and obtain its hash_sequence
let block_hash = get_block_hash(block_height); //Get the block hash based on the block height
let address = get_address(tx); //Parse mint transaction to get user address
let hash = calc_hash(hash_sequence, block_hash, address, nonce); //Concatenate block_hash, address and nonce, and use the hash algorithm corresponding to hash_sequence to calculate the final POW hash value.

At the same time, we can check hash result already exist when calculate mint amount:

fn calc_mint_amount(hash: &[u8], base_zero: u8) -> u64 {
    // Check if hash already exists
    if exists(hash) {
        return 0;
    }
    // Calculate how many zeros are at the beginning of the hash in binary
    // ...
}

After this change, nobody can replay.

@summraznboi
Copy link

I think minimally you'll have to define clearly what is the address for a transaction, since technically you can have multiple rune outputs from a single mint transaction. Moreover, it can't be address, but scriptPubKey (aka output script), since all addresses map to scriptPubKey but not the other way around.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants