ความโปร่งใสของเกม
มันทำงานอย่างไร
โปรโตคอลจะแยกคำมั่นสัญญาสาธารณะออกจากการเปิดเผยเมล็ดพันธุ์ ซึ่งจะป้องกันไม่ให้ผลลัพธ์ถูกเลือกหลังจากการเข้าร่วม.
1. คำมั่นสัญญา
จะมีการเผยแพร่แฮชก่อนผลลัพธ์ แฮชนี้ทำหน้าที่เหมือนซองดิจิทัลที่ปิดผนึก.
2. การจับสลาก
ผลลัพธ์มาจากข้อมูลที่ถูกกำหนดแล้วโดยฟังก์ชันเชิงกำหนด
3. การเปิดเผย
หลังจากผลลัพธ์ เมล็ดพันธุ์และพารามิเตอร์ที่จำเป็นจะถูกจัดเตรียมเพื่อการตรวจสอบ
4. การสืบพันธุ์
เบราว์เซอร์ทำซ้ำแฮชและการจับสลาก การทดสอบจะผ่านต่อเมื่อทุกอย่างตรงกับบันทึก
การทดสอบรูเล็ต
วิธีการคำนวณผลลัพธ์
โรเลตจับคู่สายของเมล็ดพันธุ์กับแคตตาล็อกและน้ำหนักที่ถูกเก็บไว้ในขณะหมุน
- รายการจะถูกจัดเรียงตามกุญแจ กุญแจแต่ละอันและน้ำหนักจะถูกนำเข้าในแค็ตตาล็อกแบบมาตรฐานที่ใช้ในการคำนวณ
- พันธะของการหมุนคือ sha-256 ของโดเมนของโปรโตคอล เมล็ดของเซิร์ฟเวอร์ และแค็ตตาล็อกมาตรฐาน
- คำมั่นสัญญาของโซ่เชื่อมโยงแฮชเริ่มต้น แคตตาล็อก และขนาด; ตำแหน่งพิสูจน์ว่าเมล็ดพันธุ์เป็นของโซ่ที่เผยแพร่แล้ว
- แฮชของผลลัพธ์จะกลายเป็นตัวเลขโมดูลัสผลรวมของน้ำหนัก ตั๋วนี้กำหนดไอเท็มที่ถูกเลือก
รหัสการตรวจสอบ
วางในคอนโซลของเบราว์เซอร์หรือบันทึกเป็นไฟล์ .mjs และรันด้วย Node โค้ดจะทำการคำนวณแฮชและการจับสลากใหม่ด้วยข้อมูลจากหลักฐานและแสดงผลว่าทุกส่วนตรงกันหรือไม่.
ตรวจสอบคำมั่นสัญญาข้างต้นเพื่อกรอกรหัสด้วยข้อมูลจากหลักฐาน.
const proof = {
"serverSeed": "SERVER_SEED",
"commitmentHash": "COMMITMENT_HASH",
"chainCommitment": "CHAIN_COMMITMENT",
"headHash": "HEAD_HASH",
"index": 0,
"size": 1,
"items": [
{
"key": "ITEM_KEY",
"weight": 1
}
]
}
async function sha256(text) {
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text))
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join('')
}
async function verifyReward(proof) {
const items = [...proof.items]
.sort((left, right) => (left.key < right.key ? -1 : left.key > right.key ? 1 : 0))
.map(({ key, weight }) => ({ key, weight }))
const commitment = await sha256(
JSON.stringify(['tgrtslj:reward:commitment:v1', proof.serverSeed, items]),
)
const chain = await sha256(
JSON.stringify(['tgrtslj:reward:commitment-chain:v1', proof.headHash, items, proof.size]),
)
let link = proof.serverSeed
for (let step = 0; step <= proof.index; step += 1) link = await sha256(link)
const resultHash = await sha256(
JSON.stringify(['tgrtslj:reward:weighted-draw:v1', proof.serverSeed, items]),
)
const totalWeight = items.reduce((sum, item) => sum + item.weight, 0)
const ticket = Number(BigInt('0x' + resultHash) % BigInt(totalWeight))
let upperBound = 0
const selected = items.find((item) => ticket < (upperBound += item.weight))
return {
commitmentMatches: commitment === proof.commitmentHash,
chainMatches: chain === proof.chainCommitment,
positionMatches: proof.index < proof.size && link === proof.headHash,
resultHash,
ticket,
item: selected.key,
}
}
console.log(await verifyReward(proof))
การทดสอบสไลด์
วิธีการคำนวณผลลัพธ์
หลักฐานจะสามารถเข้าถึงได้หลังจากการเปิดเผยเท่านั้น เมื่อเมล็ดพันธุ์สามารถเปิดเผยได้อย่างปลอดภัยแล้ว
- แคตตาล็อกและน้ำหนักจะถูกแช่แข็งเมื่อสัญลักษณ์รางวัลถูกมอบให้ แม้ว่าการตั้งค่าจะมีการเปลี่ยนแปลงภายหลัง
- การผูกมัดใช้โดเมนการเข้ารหัสเดียวกันและการสุ่มถ่วงน้ำหนักของรูเล็ตต์เดียวกัน
- ตำแหน่งของเมล็ดพันธุ์จะถูกตรวจสอบกับแฮชเริ่มต้นและคำมั่นสัญญาของเชนที่เผยแพร่ก่อนหน้านี้
- ไอเท็ม แฮชของผลลัพธ์ และเมล็ดพันธุ์ที่เปิดเผยจะต้องสร้างรางวัลที่บันทึกไว้ได้อย่างแม่นยำ
รหัสการตรวจสอบ
วางในคอนโซลของเบราว์เซอร์หรือบันทึกเป็นไฟล์ .mjs และรันด้วย Node โค้ดจะทำการคำนวณแฮชและการจับสลากใหม่ด้วยข้อมูลจากหลักฐานและแสดงผลว่าทุกส่วนตรงกันหรือไม่.
ตรวจสอบคำมั่นสัญญาข้างต้นเพื่อกรอกรหัสด้วยข้อมูลจากหลักฐาน.
const proof = {
"serverSeed": "SERVER_SEED",
"commitmentHash": "COMMITMENT_HASH",
"chainCommitment": "CHAIN_COMMITMENT",
"headHash": "HEAD_HASH",
"index": 0,
"size": 1,
"items": [
{
"key": "ITEM_KEY",
"weight": 1
}
]
}
async function sha256(text) {
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text))
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join('')
}
async function verifyReward(proof) {
const items = [...proof.items]
.sort((left, right) => (left.key < right.key ? -1 : left.key > right.key ? 1 : 0))
.map(({ key, weight }) => ({ key, weight }))
const commitment = await sha256(
JSON.stringify(['tgrtslj:reward:commitment:v1', proof.serverSeed, items]),
)
const chain = await sha256(
JSON.stringify(['tgrtslj:reward:commitment-chain:v1', proof.headHash, items, proof.size]),
)
let link = proof.serverSeed
for (let step = 0; step <= proof.index; step += 1) link = await sha256(link)
const resultHash = await sha256(
JSON.stringify(['tgrtslj:reward:weighted-draw:v1', proof.serverSeed, items]),
)
const totalWeight = items.reduce((sum, item) => sum + item.weight, 0)
const ticket = Number(BigInt('0x' + resultHash) % BigInt(totalWeight))
let upperBound = 0
const selected = items.find((item) => ticket < (upperBound += item.weight))
return {
commitmentMatches: commitment === proof.commitmentHash,
chainMatches: chain === proof.chainCommitment,
positionMatches: proof.index < proof.size && link === proof.headHash,
resultHash,
ticket,
item: selected.key,
}
}
console.log(await verifyReward(proof))

