Miniscript-based scripting language for Bitcoin contracts
Miniscript เป็นภาษาสคริปต์ย่อยของบิตคอยน์ที่ออกแบบโดย Blockstream ในปี 2019 เพื่อให้สามารถเขียนเงื่อนไขการใช้จ่ายของบิตคอยน์ได้ โดยมีโครงสร้างที่เข้าใจง่ายและปลอดภัยกว่า Script แบบเดิม ๆ (หมายถึง Bitcoin Script แบบเดิมที่เป็นภาษา stack-based ซึ่งยากต่อการวิเคราะห์และใช้งานร่วมกัน (เช่น การเขียน multisig ที่มีเงื่อนไขซับซ้อน) ) Miniscript เข้ามาแก้ไขปัญหาพวกนี้โดยการกำหนดโครงสร้างของ script ให้เป็น Tree ทำให้ง่ายต่อการวิเคราะห์, ตรวจสอบ, รวมสคริปต์เข้าด้วยกัน, และคำนวณค่า fees ได้อย่างอัตโนมัติ
สรุปง่ายๆ ว่า Miniscript ช่วยให้ผู้พัฒนาสามารถเขียนสคริปต์ที่เข้าใจง่ายขึ้น วิเคราะห์ได้ และสร้างระบบ multisig หรือ escrow ที่ซับซ้อนได้อย่างมีประสิทธิภาพและปลอดภัย
การออกแบบของ Miniscript ช่วยให้นักพัฒนาสามารถ วิเคราะห์และคอมไพล์สคริปต์อัตโนมัติ ได้ Wallet รุ่นใหม่จึงไม่จำเป็นต้องเขียนโค้ดเฉพาะเพื่อรับกับสคริปต์แต่ละแบบอีกต่อไป ตัวอย่างเช่น Wallet สามารถตรวจสอบได้ว่าในการใช้จ่ายเหรียญใดบ้างต้องมีลายเซ็นต์หรือข้อมูลอะไรบ้าง (witness data) และยังสามารถประเมินต้นทุนการใช้จ่ายได้ล่วงหน้าอีกด้วย นอกจากนี้ Miniscript ยังอนุญาตให้เขียนเงื่อนไขการใช้จ่ายได้หลากหลายแบบ เช่น การผสมเงื่อนไขลายเซ็นต์, hash lock, หรือ time lock แบบต่างๆ ไว้ในสคริปต์เดียวกันได้
โครงสร้างและ Syntax เบื้องต้นของ Miniscript
Miniscript นิยามสคริปต์ในรูปแบบขององค์ประกอบ (fragments) แต่ละตัวแทนคำสั่ง Script ย่อยๆ ที่มีหน้าที่ชัดเจน โดยนำมาต่อกันเป็น tree ตามเงื่อนไขในระดับนโยบาย ทำให้สามารถวิเคราะห์อย่างเป็นระบบได้ โดยแต่ละ fragment นั้นมีชื่อเฉพาะ เช่น pk(key)
(requiring signature จากคีย์), sha256(H)
(requiring เปิดเงื่อนไข hash), older(n)
/after(n)
(time-lock), รวมถึงตัวเชื่อมเชิงตรรกะเช่น and_v
, or_d
, or_i
, thresh
เป็นต้น
ตัวอย่างการใช้งานตัวดำเนินการใน Miniscript
and_v(X,Y)
: หมายถึงทั้งเงื่อนไข X และ Y ต้องเป็นจริง (คล้ายกับ AND) ในระดับ Bitcoin Script จะเทียบเท่ากับการวางผลลัพธ์ของ X บนสแต็ก ตามด้วยผลลัพธ์ของ Y ([X] [Y]
)or_d(X,Z)
: หมายถึงต้องเป็นเงื่อนไข X หรือ Z ก็ได้ (คล้ายกับ OR) การแปลงเป็น Bitcoin Script จะได้[X] IFDUP NOTIF [Z] ENDIF
ซึ่งเป็นวิธีเขียน OR แบบมี fallback และมี property พิเศษเรื่อง “dissatisfiable” (สามารถตอบสนองเงื่อนไขให้ผิดได้อย่างสมบูรณ์)or_i(X,Z)
: เป็นอีกวิธีของ OR ที่แปลงเป็นIF [X] ELSE [Z] ENDIF
มีรูปแบบผลลัพธ์ต่างกันในแง่ขนาดสคริปต์และ witnessthresh(k, X₁,...,Xₙ)
: กำหนดว่าเงื่อนไขย่อยทั้งหมด X₁..Xₙ ต้องเป็นจริงอย่างน้อย k ในจำนวนนั้น (k-of-n) ใน Bitcoin Script จะถูกแปลงเป็นการรวมผลลัพธ์ย่อยเข้าด้วยกัน เช่น[X1] [X2] ADD ... [Xn] ADD ... <k> EQUAL
เพื่อเช็คว่าจำนวนเงื่อนไขที่เป็นจริงเท่ากับ kWrappers เช่น
v:X
(VERIFY),s:X
(SWAP),c:X
(CHECKSIG),d:X
(DUP-IF),j:X
(SIZE-IF), เป็นต้น ใช้เปลี่ยนแปลงพฤติกรรมของ fragment ที่อยู่ถัดไป โดยมีการแมปเป็น Opcode เฉพาะ fragment แต่ละอัน เช่นpk(key)
จะแปลเป็น<key> OP_CHECKSIG
,pkh(key)
แปลเป็นDUP HASH160 <hash160> EQUALVERIFY CHECKSIG
ตามลำดับ
โครงสร้างของ Miniscript จึงง่ายต่อการตรวจสอบคุณสมบัติ เช่น มันแบ่งการทำงานเป็น 4 ประเภทหลัก (Base, Verify, Key, Wrapped) เพื่อกำหนดเงื่อนไขการใช้สแต็กและความปลอดภัยอย่างชัดเจน ข้อนี้ทำให้เรามั่นใจได้ว่าสคริปต์ที่ได้จะไม่ก่อปัญหาด้าน malleability หรือ op-limit ต่าง ๆ ที่อาจเกิดกับ Bitcoin Script แบบเดิม
ตัวอย่าง
Miniscript เหมาะสำหรับใช้สร้างเงื่อนไขการใช้จ่ายที่ซับซ้อน เช่น การแบ่งเงินแบบ Escrow หรือ HTLC (Hashed Time-Locked Contract) เป็นต้น โดยเขียนเป็นโค้ดที่อ่านง่าย เช่น:
Escrow contract (A และ B หรือ C คนเดียว): สมมติต้องการสัญญาว่า เหรียญจะถูกใช้จ่ายได้เมื่อมี ลายเซ็นต์ของ A กับ B พร้อมกัน หรือ มีลายเซ็นต์ของ C คนเดียว แบบใดก็ได้ เราสามารถเขียนด้วย Miniscript ได้ตัวอย่างเช่น:
( pk(A) && pk(B) ) || pk(C)
ความหมายคือให้ทั้ง A และ B ต้องเซ็นต์ (AND) หรือไม่ก็ให้ C เซ็นต์เพียงคนเดียวก็ได้ (OR) ใน Blockly Miniscript แบบ infix นี้ &&
หมายถึง and_v
(AND แบบ Verify) ส่วน ||
หมายถึง OR แบบปกติ เมื่อนำมาคอมไพล์เป็น Bitcoin Script แล้วจะเทียบเท่ากับคำสั่ง stack ของ A และ B แล้วทำ BOOLOR กับ C วิธีนี้ช่วยให้เราเขียน escrow สลับซับซ้อนได้ง่ายขึ้น
HTLC (Lightning/Atomic Swap): ตัวอย่างมาตรฐานของ HTLC คือ ผู้รับ (A) จะได้เหรียญเมื่อเปิดเผยค่า preimage H หรือมิฉะนั้นจะคืนเงินกลับไปยังผู้ส่ง (B) หลังผ่านเวลา เราเขียนได้เป็น
( pk(A) && sha256(H) ) || ( pk(B) && older(10) )
ความหมายคือ เงื่อนไขแรก (pk(A) && sha256(H))
หมายถึง “ลายเซ็นต์ของ A พร้อมกับการเปิดเผย preimage ที่มีค่า SHA256 เป็น H” (A ได้เหรียญได้ทันทีเมื่อเปิด H ถูก) และ เงื่อนไขที่สอง (pk(B) && older(10))
หมายถึง “ลายเซ็นต์ของ B หลังจากผ่านเวลา 10 บล็อกแล้ว” (B ได้เงินคืนหลังเวลาที่กำหนด) เราสามารถเขียนสั้นๆ ด้วย infix &&
และ ||
ดังตัวอย่างใน Minsc playground วิธีนี้ช่วยให้สร้าง HTLC ได้ชัดเจน เทียบกับการเขียน Script ด้วยมือจะซับซ้อนมากกว่า (นอกจากนี้ Lightning Network ยังใช้ HTLC ที่คล้ายกันซึ่งอาจใช้ hash160 หรือ block time ก็ได้ ขึ้นกับเงื่อนไข เช่น BOLT#3 ใช้นโยบายแบบ or_d(pk(primary), and_v(v:pk(recovery), older(12960)))
)
นอกจากตัวอย่างข้างต้นแล้ว เราสามารถใช้ Miniscript สร้าง multi-signature หรือ Threshold อื่นๆ ได้เช่นกัน เช่น ตัวอย่างด้านล่างคือ Escrow แบบต้องการลายเซ็นต์จาก 2 ใน 3 ฝ่าย (ผู้ซื้อ, ผู้ขาย, หรือนายประกัน)
2 of [ pk(buyer_pk), pk(seller_pk), pk(arbiter_pk) ]
ข้อดีของ Miniscript คือเราแค่กำหนดเงื่อนไขในรูปนโยบายหรือโค้ดข้างต้น โปรแกรมจะช่วยคอมไพล์เป็นสคริปต์ Bitcoin ที่เหมาะสมให้โดยอัตโนมัติ
การแปลง Miniscript เป็น Bitcoin Script
Miniscript แต่ละ fragment มีการแมปกับชุดคำสั่ง Script ชัดเจน สามารถเรียกใช้ไลบรารีหรือคอมไพล์เลอร์เพื่อแปลงเป็นสคริปต์จริงได้โดยตรง ตัวอย่างเช่น สคริปต์ Miniscript ต่อไปนี้:
or_b(pk(key1), s:pk(key2))
จะถูกแปลงเป็น Bitcoin Script ตามตัวอย่างด้านบน:
<key1> OP_CHECKSIG OP_SWAP <key2> OP_CHECKSIG OP_BOOLOR
(ส่วนโค้ด OP_SWAP
มาจาก wrapper s:
โดยสลับตำแหน่งสแต็กก่อนเช็คลายเซ็นต์) ในเอกสารอ้างอิงของ Miniscript จะมีตารางแสดงการแมปทุก fragment และ wrapper กับ Script อยู่ เด้ะทิ้ง link ไว้ไปอ่านกันต่อข้างล่างนะ เมื่อได้สคริปต์ Bitcoin แล้ว ก็สามารถนำไปทำ P2WSH หรือ Tapscript และสร้างที่อยู่รับเหรียญได้โดยอัตโนมัติ ตัวอย่างข้างต้นนำไปสู่เงื่อนไขที่หากแต่ละ key เซ็นต์แล้วผลลัพธ์เป็นการ OR ด้วย OP_BOOLOR ตามลำดับ
ไลบรารีอย่าง rust-miniscript (ของ Blockstream) ก็สามารถแปลงนโยบาย (policy) เป็น Miniscript และสุดท้ายเป็น Bitcoin Script ได้เสมอ ทำให้การสร้าง wallet descriptor ยืดหยุ่นและปลอดภัยขึ้น โดยทั่วไป เมื่อเราเขียน Miniscript ใดๆ ขึ้นมา (หรือเขียนโพลิซีให้คอมไพล์เป็น Miniscript) เราจะได้ Script เดิมแบบ deterministic เสมอ ซึ่งช่วยให้ระบบการสร้าง witness (ลายเซ็นต์กับข้อมูลช่วยเหลือ) และการวิเคราะห์ต่าง ๆ ทำได้ง่าย
ใครสนใจแล้วอยากลองเขียน ผมแนะนำ https://min.sc/#threshold-operator ลองเข้าไปเล่นดูครับผม
Last updated