关于PoP

概要

Proof of PIN(PoP)是 MetaID 中的一个有趣概念,我们参考了比特币的挖矿原理制定了 PoP 机制。PoP值反映的是用户在MetaID 世界的“工作量”证明。在 MetaID 世界中,用户最小的“工作量”是发送一条 PIN,因此每条 PIN 都有一个哈希值,并且该将用户的PIN与其所在的区块难度结合。PoP 值反映了如下两个维度:

  • 用户创建MetaID 数据的数量概况:创建 MetaID PIN越多,获得高难度的 PoP 值的概率越高

  • 用户创建 MetaID 数据的算力消耗:PoP 值和MetaID 数据所在区块链算力情况挂钩,算力越高越容易获得难度高的 PoP 值

PIN 如同 SHA256 算力,PoP 如同难度哈希,算力越高则越大概率获得高难度的哈希值。

通过验证用户相关的PoP值,我们可以快速评价一个用户在 MetaID 世界的贡献度,也让 PIN有了等级和稀有度的概念。

计算方法

PoP 是通过区块的 MerkleRootPINID 用SHA256联合哈希,然后再与 **BlockHash**相乘,从而生成一个新的值。具体公式为:

PoP = hash(PIN_ID + Merkle_Root) * Block_Hash

得出的原始的哈希值然后进行8进制转换,转换后的结果即为 PoP。

PoP 值的难度概念

PoP值的难度级别是类似区块哈希,以前缀 "0" 的位数定义的。预设的 "0"数量越多,表示该PoP的难度级别越高。任何有效的 PoP 至少需要包含21个前缀 "0"。

PoP 难度等级

对于难度等级,按照比特币目前的算力推算MetaID PoP 可分为 了11个等级。从等级1开始,PoP值前缀需要拥有22个 "0" 才能满足等级1,需要23个 "0" 才能达到等级2,以此类推,数量的增加直接反映在 PoP 稀有度等级的提升。

以下的计算代码

package pop

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"math/big"
	"strconv"
)

func CalculateHash(pinid string, merkleRoot string) string {
	h := sha256.New()
	h.Write([]byte(pinid + merkleRoot))
	return hex.EncodeToString(h.Sum(nil))
}

func CalculateProductToHexStr(blockhash string, pinHash string) string {
	blockhashByte, _ := hex.DecodeString(blockhash)
	blockhashInt, _ := new(big.Int).SetString(blockhash, 16)
	pinHashByte, _ := hex.DecodeString(pinHash)
	pinHashInt, _ := new(big.Int).SetString(pinHash, 16)
	popByte := new(big.Int).Mul(blockhashInt, pinHashInt).Bytes()
	//计算总位数:32+32=64
	totalLen := len(blockhashByte) + len(pinHashByte)
	//需要补0的位数
	remainingLen := totalLen - len(popByte)
	for i := 0; i < remainingLen; i++ {
		popByte = append([]byte{0}, popByte...)
	}
	return hex.EncodeToString(popByte)
}

func ConvertToOctalHex(productHex string) (string, int64) {
	productByte, _ := hex.DecodeString(productHex)
	
	//转二进制
	bList := make([]string, 0)
	for _, b := range productByte {
		binaryB := fmt.Sprintf("%b", b)
		bList = append(bList, fmt.Sprintf("%08s", binaryB))
	}
	productBinaryStr := ""
	for _, b := range bList {
		productBinaryStr += b
	}
	productBinaryStr = productBinaryStr[:510]

	bCount := int64(0)
	for _, b := range productBinaryStr {
		if b == '0' {
			bCount++
		} else {
			break
		}
	}

	//二进制str转8进制str
	octal := ""
	for i := 0; i < len(productBinaryStr); i += 3 {
		binaryStr := productBinaryStr[i : i+3]
		num, err := strconv.ParseInt(binaryStr, 2, 64)
		if err != nil {
			fmt.Println("ParseInt error:", err)
			return "", 0
		}
		octal += strconv.FormatInt(num, 8)
	}
	return octal, bCount
}

func GenPop(pinid, merkleRoot, blockHash string) (string, int64) {
	//计算pinHash
	pinHash := CalculateHash(pinid, merkleRoot)
	//blockhash * pinHash
	productHexStr := CalculateProductToHexStr(blockHash, pinHash)
	//转8进制
	octal, bCount := ConvertToOctalHex(productHexStr)
	
	return octal, bCount
}

PoP计算测试用例:

func Test_pop(t *testing.T) {
	pinid := "77aac2ae323748dee3b8b1ae6b7c33c1c4466f568c572ea488f584f041f0de4ei0"    // 64 char hash
	merkleRoot := "e56011a241cb196fc4efbeafef051ca901761ffb569a43146582f9133bfd41d2" // 64 char hash
	blockhash := "000000000000000004c2db0441a47fd3574992d508b8d9d866a789d371aa5060"  // real block hash
	pop, bCountZero := GenPop(mockPinId, merkleRoot, blockHash)

	fmt.Println("POP:", octal)
	fmt.Println("POP-0:", bCountZero)
}

Last updated