ประกาศแนวคิดการออกแบบของ V God โดยให้รายละเอียดข้อดีและข้อเสียที่เป็นไปได้ของ Ethereum
ที่นี่ที่นี่การพิมพ์ซ้ำนี้ได้รับการพิสูจน์อักษรแล้ว ฉันขอแสดงความขอบคุณต่อ Kim ผู้แปลต้นฉบับ
เวลาในการเขียนข้อความต้นฉบับนั้นไม่แน่นอน แต่ก็ถือได้ว่าเป็นจุดเริ่มต้นในการสะท้อนแนวคิดการออกแบบของ Ethereum และวิวัฒนาการของ Ethereum ในช่วงไม่กี่ปีที่ผ่านมา ไม่เพียงสะท้อนถึงนวัตกรรมเท่านั้น แต่ยังสะท้อนถึงการขาดการพิจารณาอีกด้วย
โดยหลักการแล้ว
โดยหลักการแล้ว
การออกแบบโปรโตคอล Ethereum เป็นไปตามหลักการดังต่อไปนี้:
Sandwich Complex Model (หรือแปลว่า "แบบจำลองเลเยอร์ที่ซับซ้อน"): เราเชื่อว่าโปรโตคอลพื้นฐานของ Ethereum ควรเรียบง่ายที่สุดเท่าที่จะเป็นไปได้ และการออกแบบอินเทอร์เฟซควรเข้าใจง่าย (ไม่ว่าจะเป็นการเขียนโปรแกรมระดับสูงที่เน้นนักพัฒนา ส่วนต่อประสานภาษาหรือส่วนต่อประสานการใช้งานที่เน้นผู้ใช้) ส่วนที่ซับซ้อนที่หลีกเลี่ยงไม่ได้ควรวางไว้ในชั้นกลาง ชั้นกลางไม่ได้เป็นส่วนหนึ่งของฉันทามติหลักและมองไม่เห็นสำหรับผู้ใช้ปลายทาง ซึ่งรวมถึง: คอมไพเลอร์ภาษาระดับสูง, สคริปต์ซีเรียลไลเซชันของพารามิเตอร์และดีซีเรียลไลเซชัน, แบบจำลองโครงสร้างข้อมูลหน่วยเก็บข้อมูล, อินเทอร์เฟซหน่วยเก็บข้อมูล leveldb และโปรโตคอลเครือข่าย แน่นอนว่าเส้นแบ่งความแตกต่างนั้นไม่ชัดเจน และบางครั้งต้องมีการปรับเปลี่ยนตามความเหมาะสม
เสรีภาพ: ผู้ใช้ไม่ควรถูกจำกัดไม่ให้ใช้โปรโตคอล Ethereum และไม่ควรพยายามสนับสนุนหรือไม่สนับสนุนสัญญาหรือธุรกรรม Ethereum บางอย่าง สิ่งนี้คล้ายกับหลักการชี้นำเบื้องหลังแนวคิดเรื่อง "ความเป็นกลางสุทธิ" โปรโตคอลการทำธุรกรรม Bitcoin ไม่เป็นไปตามหลักการนี้: โปรโตคอลการทำธุรกรรม Bitcoin ไม่สนับสนุน "วัตถุประสงค์นอกห้องปฏิบัติการ" (เช่น การจัดเก็บข้อมูล เมตาโปรโตคอล) ของบล็อกเชน (บันทึกการพิสูจน์อักษร: จุดประสงค์ดั้งเดิมคือการใช้ ยาสำหรับอาการนอกเหนือจากข้อบ่งใช้ที่ได้รับการอนุมัติ เช่น การใช้ยาแก้ไอเพื่อรักษาอาการปวดหัว ในที่นี้ แปลเป็น "การใช้ที่ผิดวิธี" และบางครั้ง บางคนใช้การเปลี่ยนแปลงชั้นของสารกึ่งโปรโตคอล (เช่น จำกัดความยาวของ ฟิลด์ OP_RETURN ถึง 40 ไบต์) เพื่อโจมตีแอปพลิเคชันที่ใช้บล็อกเชนในลักษณะที่ "ไม่ได้รับอนุญาต") ดังนั้นใน Ethereum เราจึงสนับสนุนวิธีการใช้เฉพาะค่าธรรมเนียมการทำธุรกรรมเพื่อให้ได้สิ่งจูงใจที่เข้ากันได้อย่างคร่าวๆ ยิ่งผู้ใช้ใช้ทรัพยากรมากขึ้นในเครือข่ายทั้งหมด ราคาที่พวกเขาต้องจ่ายก็จะยิ่งสูงขึ้น แม้ว่าพวกเขาจะแบกรับค่าใช้จ่ายเองก็ตาม (เช่น Pigou ภาษี).
ลักษณะทั่วไป: คุณสมบัติและ opcodes ของโปรโตคอล Ethereum ควรเพิ่มแนวคิดระดับต่ำ (เช่น อนุภาคมูลฐาน) เพื่อให้สามารถรวมกันได้ตามต้องการ รวมถึงการรวมสิ่งที่ดูเหมือนไร้ประโยชน์ในปัจจุบัน แต่อาจมีประโยชน์ในอนาคต นอกจากนี้ แนวคิดระดับต่ำยังทำให้มีประสิทธิภาพมากขึ้นได้ด้วยการถอดฟังก์ชันการทำงานที่ไม่จำเป็นออกไป ตัวอย่างของการปฏิบัติตามหลักการนี้คือการเลือกรหัส LOG ของเราเป็นวิธีการให้ข้อมูลแก่ dapp แทนที่จะบันทึกธุรกรรมและข้อความทั้งหมดเหมือนเมื่อก่อน ในยุคแรก แนวคิดของ "ข้อความ (ข้อความ)" เป็นชุดของแนวคิดต่างๆ อย่างสมบูรณ์ ซึ่งรวมถึง "การเรียกใช้ฟังก์ชัน (การเรียกฟังก์ชัน)" และ "ข้อมูลเหตุการณ์ (เหตุการณ์) ที่น่าสนใจสำหรับผู้สังเกตการณ์ภายนอก" และทั้งสองคือ แยกกันได้อย่างสมบูรณ์
ไม่มีฟีเจอร์ใดเป็นฟีเจอร์ที่ใหญ่ที่สุด: เพื่อให้เป็นไปตามหลักการทั่วไป เราปฏิเสธที่จะฝังกรณีการใช้งานขั้นสูงเหล่านั้นให้เป็นส่วนหนึ่งของโปรโตคอล แม้ว่าจะเป็นกรณีการใช้งานที่ใช้บ่อย เราจะไม่ทำเช่นนั้น หากต้องการนำกรณีการใช้งานเหล่านี้ไปใช้จริงๆ สามารถสร้างโปรโตคอลย่อยภายในสัญญาได้ (เช่น สกุลเงินย่อยที่ใช้ Ethereum, Bitcoin/Litecoin/Dogecoin sidechains เป็นต้น) ตัวอย่างเช่น Ethereum ไม่มีฟังก์ชัน "ล็อคเวลา" ที่คล้ายกับ Bitcoin อย่างไรก็ตาม ฟังก์ชันนี้สามารถจำลองผ่านโปรโตคอลต่อไปนี้: ผู้ใช้ส่งแพ็กเก็ตข้อมูลที่ลงนามไปยังสัญญาเฉพาะสำหรับการประมวลผล และถ้าแพ็กเก็ตข้อมูลถูกต้องในสัญญาเฉพาะ ฟังก์ชันที่เกี่ยวข้องจะถูกดำเนินการ
ไม่ไม่ชอบความเสี่ยง: เรายินดีรับความเสี่ยงที่สูงขึ้นหากความเสี่ยงที่เพิ่มขึ้นก่อให้เกิดประโยชน์ที่สามารถวัดผลได้ (เช่น การเปลี่ยนสถานะทั่วไป การลดเวลาบล็อกลง 50 เท่า ประสิทธิภาพที่เป็นเอกฉันท์ ฯลฯ)
ชื่อระดับแรก
โปรโตคอลเลเยอร์บล็อคเชน
ชื่อเรื่องรอง
บัญชี ไม่ใช่ UTXO 1
Bitcoin และตัวแปรมากมายเก็บข้อมูลยอดคงเหลือของผู้ใช้ในโครงสร้าง UTXO และสถานะทั้งหมดของระบบประกอบด้วยชุดของ "ผลลัพธ์ที่ไม่ได้ใช้" (คุณสามารถคิดว่า "ผลลัพธ์ที่ไม่ได้ใช้" เหล่านี้เป็นเหรียญ) (หมายเหตุการพิสูจน์อักษร: ดีกว่า คำอุปมาอาจเป็น "เช็ค".). UTXO แต่ละตัวมีเจ้าของและแอตทริบิวต์ค่าของตัวเอง การทำธุรกรรมจะสร้าง UTXO ใหม่หลายรายการในขณะที่ใช้ UTXO หลายรายการ และการทำธุรกรรมจะเป็นไปตามข้อกำหนดด้านความถูกต้องต่อไปนี้:
1. ข้อมูลอ้างอิงแต่ละรายการต้องถูกต้องและไม่ได้ใช้ 2. ลายเซ็นของการทำธุรกรรมต้องตรงกับลายเซ็นของเจ้าของข้อมูลแต่ละรายการ 3. มูลค่ารวมของข้อมูลนำเข้าต้องเท่ากับหรือมากกว่ามูลค่ารวมของข้อมูลออก .
คำอธิบายภาพ
- การทำบัญชีสามรายการที่ใช้โดย Bitcoin -
อย่างไรก็ตาม Ethereum ละทิ้งโครงร่าง UTXO และหันไปใช้วิธีที่ง่ายกว่า: ใช้แนวคิดของรัฐ (สถานะ) เพื่อจัดเก็บชุดบัญชี แต่ละบัญชีมียอดคงเหลือของตัวเอง และข้อมูลเฉพาะของ Ethereum (รหัสและหน่วยความจำภายใน) หากยอดเงินในบัญชีของผู้เริ่มต้นธุรกรรมเพียงพอที่จะครอบคลุมค่าธรรมเนียมการทำธุรกรรม การทำธุรกรรมนั้นถูกต้อง และจำนวนเงินที่สอดคล้องกันจะถูกหักออกจากบัญชีของผู้เริ่มต้นและเครดิตไปยังบัญชีผู้รับ ในบางกรณี หากมีรหัสที่ต้องดำเนินการในบัญชีผู้รับ ธุรกรรมจะทริกเกอร์การดำเนินการของรหัส จากนั้นหน่วยความจำภายในของบัญชีอาจเปลี่ยนแปลง และอาจสร้างข้อความเพิ่มเติมเพื่อส่งไปยังบัญชีอื่น ทำให้มีรายการใหม่เกิดขึ้น
แม้ว่า Ethereum จะไม่นำแนวคิดของ UTXO มาใช้ แต่ UTXO ก็มีข้อดีบางประการ:
การปกป้องความเป็นส่วนตัวในระดับที่สูงขึ้น:หากผู้ใช้ใช้ที่อยู่ใหม่สำหรับทุกธุรกรรม การเชื่อมโยงบัญชีจะทำได้ยาก เหมาะสำหรับระบบสกุลเงินที่ต้องการความปลอดภัยสูง แต่ไม่เหมาะสำหรับ Dapp ใดๆ เนื่องจากโดยปกติแล้ว dapps จำเป็นต้องติดตามสถานะการผูกมัดที่ซับซ้อนของผู้ใช้ และสถานะของ dapps ไม่สามารถแบ่งง่ายๆ ได้เหมือนกับสถานะในระบบสกุลเงิน
ศักยภาพในการปรับขนาด:ตามทฤษฎีแล้ว UTXO นั้นเหมาะสมกว่าสำหรับแผนการปรับขนาดบางประเภท (กระบวนทัศน์ความสามารถในการปรับขนาด) เนื่องจากผู้ถือเท่านั้นที่จำเป็นต้องมีหลักฐานของ Merkel ที่สามารถพิสูจน์ความเป็นเจ้าของสกุลเงินของพวกเขาได้ แม้ว่าทุกคน (รวมถึง TA เอง) ข้อมูลนี้จะถูกลืม และนี่ บุคคลได้รับความเสียหายจริง ๆ และผู้อื่นไม่ได้รับผลกระทบ ในระบบบัญชี Ethereum หากทุกคนสูญเสียส่วนของ Merkle tree ที่สอดคล้องกับบัญชี บัญชีนั้นจะไม่สามารถประมวลผลข้อความใดๆ ที่อาจส่งผลกระทบต่อมัน รวมถึงข้อความที่ส่งถึงมันด้วย และจะไม่สามารถประมวลผลได้ มัน. อย่างไรก็ตาม UTXO ไม่ใช่วิธีเดียวที่สามารถขยายได้ และยังมีวิธีขยายโดยไม่ต้องพึ่งพา UTXO (ไม่มีส่วนขยายที่นี่ หมายเหตุของผู้แปล)
ประโยชน์ของบัญชีมีดังนี้:
ประหยัดพื้นที่ได้มาก: หากบัญชีมี 5 UTXO พื้นที่ที่ต้องการจะลดลงจาก 300 ไบต์เป็น 30 ไบต์เมื่อเปลี่ยนจากโหมด UTXO เป็นโหมดบัญชี การคำนวณเฉพาะมีดังนี้: 300 = (20+32+8) * 5 (20 คือจำนวนไบต์ของที่อยู่ 32 คือจำนวนของไบต์ TX id และ 8 คือจำนวนของไบต์ที่อยู่ในนิกาย) 30 = 20 + 8 + 2 ( 20 คือไบต์ของที่อยู่, 8 คือไบต์ของมูลค่าบัญชี, 2 คือ nonce 2 ไบต์); แต่การบันทึกจริงนั้นไม่ใหญ่นัก เนื่องจากบัญชีต้องถูกจัดเก็บไว้ในแผนผัง Patricia นอกจากนี้ ธุรกรรมใน Ethereum ยังมีขนาดเล็กกว่าธุรกรรมใน Bitcoin (100 ไบต์ใน Ethereum, 200-250 ไบต์ใน Bitcoin) เนื่องจากแต่ละธุรกรรมต้องการเพียงสร้างข้อมูลอ้างอิงหนึ่งรายการ หนึ่งลายเซ็น และหนึ่งเอาต์พุต
ความสามารถในการแลกเปลี่ยนที่แข็งแกร่งขึ้น: โครงสร้าง UTXO ไม่มีแนวคิดของเลเยอร์บล็อกเชน ดังนั้นไม่ว่าจะเป็นทางเทคนิคหรือทางกฎหมาย การสร้างบัญชีแดง/บัญชีดำและแยกความแตกต่างตามแหล่งที่มาของ "ผลลัพธ์ที่ถูกต้อง" เหล่านี้ไม่สามารถนำไปใช้ได้จริง
ความเรียบง่าย: การเข้ารหัส Ethereum นั้นง่ายกว่าและเข้าใจง่ายกว่า โดยเฉพาะอย่างยิ่งเมื่อมีสคริปต์ที่ซับซ้อนเข้ามาเกี่ยวข้อง แม้ว่าแอปพลิเคชันแบบกระจายอำนาจใด ๆ สามารถนำไปใช้กับ UTXO ได้ (อย่างไม่เต็มใจ) แต่วิธีนี้ทำให้สคริปต์มีอำนาจในการจำกัดประเภทของ UTXO ที่ UTXO ที่กำหนดสามารถส่งออกได้และเงื่อนไขการใช้งาน (ตัวอย่างเช่น จำเป็นต้องมี Merkle tree Proof เพื่อช่วยให้สคริปต์ แอปพลิเคชันที่เกี่ยวข้องเปลี่ยนสถานะรูท) ดังนั้นการติดตั้ง UTXO จึงซับซ้อนกว่าวิธีที่ Ethereum ใช้บัญชี
ไคลเอ็นต์แบบไลท์: ไคลเอนต์แบบไลท์สามารถเข้าถึงข้อมูลทั้งหมดที่เกี่ยวข้องกับบัญชีได้ตลอดเวลาโดยการสแกนแผนผังสถานะในทิศทางที่กำหนด ในกระบวนทัศน์ UTXO ธุรกรรมแต่ละรายการจำเป็นต้องใช้การอ้างอิงที่แตกต่างกัน ซึ่งเป็นงานหนักอย่างไม่ต้องสงสัยสำหรับแอปพลิเคชัน dapp ที่รันเป็นเวลานานซึ่งใช้กลไกการแพร่กระจายสถานะรูท UTXO ที่กล่าวถึงข้างต้น
เราเชื่อว่าประโยชน์ของบัญชีมีมากกว่าทางเลือกอื่น โดยเฉพาะอย่างยิ่งสำหรับ Dapps ที่เราต้องการสนับสนุนซึ่งอาจมีสถานะและรหัสตามอำเภอใจ นอกจากนี้ เพื่อให้สอดคล้องกับหลักการชี้นำของ "ไม่มีฟีเจอร์ใดเป็นฟีเจอร์ที่ใหญ่ที่สุด" เราเชื่อว่าหากผู้ใช้ใส่ใจในความเป็นส่วนตัวจริงๆ พวกเขาสามารถสร้าง "mixer and coinjoin" ที่เข้ารหัสผ่านโปรโตคอลแพ็กเก็ตข้อมูลที่ลงนามในสัญญา การชำระเงินที่คลุมเครือ เส้นทาง
จุดอ่อนของวิธีการบัญชีคือเพื่อป้องกันการโจมตีซ้ำ (การโจมตีซ้ำ ซึ่งหมายความว่าธุรกรรมเดียวกันถูกดำเนินการซ้ำ ๆ ) แต่ละธุรกรรมจะต้องมี "nonce" (หมายเลขซีเรียล) ดังนั้น แต่ละบัญชีต้องมีค่า nonce ที่อัปเดตตามเวลาจริง และธุรกรรมใหม่แต่ละรายการจะเพิ่มค่า nonce ของบัญชีทีละ 1 เป็นค่า nonce ของตัวเอง (และอัปเดตค่า nonce ของบัญชีตามค่านี้หลังจากประมวลผลธุรกรรม) (หมายเหตุการพิสูจน์อักษร : ใน โหมดบัญชี หากธุรกรรมไม่ได้แนบตัวระบุสิ้นเปลืองนี้ ธุรกรรมสามารถดำเนินการซ้ำได้ เพื่อให้บัญชีรับสามารถรวบรวมบัญชีซ้ำแล้วซ้ำอีกโดยไม่ต้องเสียค่าใช้จ่ายใด ๆ ในขณะที่บัญชีผู้ส่งจะถูกดูดแห้ง ; ไม่มีบัญชี Ethereum เพิ่มขึ้นเมื่อธุรกรรมเริ่มต้นได้รับการประมวลผล ซึ่งช่วยแก้ปัญหานี้ได้) ซึ่งหมายความว่าแม้แต่บัญชีที่ไม่ได้ใช้งานแล้วก็ไม่สามารถลบออกจากสถานะบัญชีได้ วิธีแก้ไขปัญหานี้อย่างง่ายคือการให้ธุรกรรมมีหมายเลขบล็อก ทำให้ไม่สามารถกู้คืนได้หลังจากระยะเวลาหนึ่ง และรีเซ็ต nonce ทุก ๆ ครั้ง
หากคุณต้องการลบบัญชีที่อยู่ในสถานะ (เช่น บัญชีที่ไม่ได้ใช้งานเป็นเวลานาน) คุณต้อง "ping" บัญชีเหล่านั้นออกก่อน และค่าใช้จ่ายในการสแกนโปรโตคอลบล็อกเชนทั้งหมดนั้นสูงมาก เราไม่ได้ใช้กลไกนี้ในเวอร์ชัน 1.0 และเวอร์ชัน 1.1 ขึ้นไปอาจใช้กลไกนี้
หมายเหตุการพิสูจน์อักษร: นี่คือเหตุผลทางเทคนิคสำหรับปัญหา "การระเบิดของสถานะ" ที่ Ethereum จะต้องเผชิญในอนาคต: ข้อมูลสถานะทั้งหมดจะต้องได้รับการเก็บรักษาไว้อย่างสมบูรณ์ และบัญชีไม่สามารถลบได้อย่างสมเหตุสมผล ในฐานะที่เป็นโปรโตคอล blockchain โหนดของ Ethereum จะต้องไม่เพียงแค่บรรลุฉันทามติในลำดับการทำธุรกรรม (ธุรกรรม) เท่านั้น แต่ยังต้องบรรลุฉันทามติในสถานะทั่วโลก (รูปแบบของการแสดงออกคือรากสถานะต้องรวมอยู่ในบล็อก ส่วนหัว ดังนั้นในการลบสถานะจำเป็นต้องได้รับความเห็นชอบจากเครือข่ายทั้งหมดมิฉะนั้นจะตกเป็นฝ่าย
บทความนี้บทความนี้。
Merkel Patricia Tree (MPT)
Merkle Patricia tree/trie ซึ่งคิดขึ้นโดย Alan Reiner และใช้งานในโปรโตคอล Ripple เป็นโครงสร้างข้อมูลหลักของ Ethereum ใช้เพื่อจัดเก็บสถานะบัญชีทั้งหมด และแต่ละบล็อคข้อมูลธุรกรรมและใบเสร็จในรูปแบบ . MPT เป็นการรวมกันของ Merkle tree และ Patricia tree และโครงสร้างที่สร้างขึ้นโดยการรวมต้นไม้ทั้งสองนี้มีคุณสมบัติดังต่อไปนี้:
ค่าแฮชรูทที่สอดคล้องกับชุดของคู่คีย์-ค่าใดๆ นั้นไม่ซ้ำกัน หากคุณต้องการอ้างอย่างผิดๆ ว่าคู่คีย์-ค่ามีอยู่ในทรีหนึ่งๆ ก็จะมองเห็นได้อย่างแน่นอน (เว้นแต่ผู้โจมตีจะมีการคำนวณประมาณ 2^128 พลัง).
ความซับซ้อนของเวลาในการเพิ่ม ลบ และเปลี่ยนคู่คีย์-ค่าเป็นลอการิทึม
MPT มอบ "ลายนิ้วมือ" ที่มีประสิทธิภาพและง่ายต่อการอัปเดตซึ่งแสดงถึงโครงสร้างสถานะทั้งหมด คำอธิบายโดยละเอียดเพิ่มเติมของ MPT: https://github.com/ethereum/wiki/wiki/Patricia-Tree
การตัดสินใจออกแบบเฉพาะสำหรับ MPT มีดังนี้:
โหนดมีสองประเภท: โหนด KV และโหนดแยก การมีอยู่ของโหนด KV ช่วยปรับปรุงประสิทธิภาพ เนื่องจากหากต้นไม้กระจัดกระจายในบางภูมิภาค โหนด KV สามารถใช้เป็น "ทางลัด" เพื่อบีบอัดความสูงของต้นไม้ได้ (อ่านคำอธิบายโดยละเอียดของ MPT สำหรับรายละเอียดเพิ่มเติม)
โหนดแยกเป็นเลขฐานสิบหก ไม่ใช่เลขฐานสอง: สิ่งนี้ทำให้การค้นหามีประสิทธิภาพมากขึ้น ตัวเลือกที่เราทราบตอนนี้ไม่เหมาะ เนื่องจากประสิทธิภาพการค้นหาของแผนผังฐานสิบหกสามารถจำลองเป็นเลขฐานสองโดยการจัดเก็บโหนดเป็นแบทช์ อย่างไรก็ตาม การนำโครงสร้างทรี MPT ไปใช้นั้นเกิดข้อผิดพลาดได้ง่ายและทำให้รากของรัฐไม่ตรงกันเป็นอย่างน้อย ดังนั้นเราจึงตัดสินใจระงับการเปลี่ยนแปลงไว้จนกว่าจะถึง 1.1
ไม่มีความแตกต่างระหว่างค่าว่างและค่าไม่เป็นสมาชิก: สิ่งนี้ทำเพื่อลดความซับซ้อนของตรรกะ ค่า (ยอดคงเหลือ) ของบัญชีที่ไม่ได้เปิดใช้งานใน Ethereum ค่าเริ่มต้นเป็น 0 และสตริงว่างจะแสดงด้วย 0 อย่างไรก็ตาม ควรเน้นย้ำว่าการทำเช่นนี้เป็นการเสียสละส่วนรวมและไม่เหมาะสม
ความแตกต่างระหว่างโหนดปลายทางและโหนดที่ไม่ใช่เทอร์มินัล: ในทางเทคนิคแล้ว ไม่จำเป็นต้องระบุโหนด "ไม่ว่าจะเป็นโหนดเทอร์มินัล" เนื่องจากทรีทั้งหมดใน Ethereum ใช้เพื่อเก็บข้อมูลความยาวคงที่ (เช่น ความยาวคีย์) แต่ตามลำดับ เพื่อเพิ่มความเก่งกาจ เราจะยังคงเพิ่มโลโก้นี้ โดยหวังว่าการใช้งาน MPT ของ Ethereum จะสามารถนำมาใช้กับสกุลเงินดิจิตอลอื่น ๆ ได้เช่นเดียวกับที่เป็นอยู่
ใช้ SHA3(k) เป็นคีย์ใน "โครงสร้างความปลอดภัย" (โครงสร้างสถานะและโครงสร้างการจัดเก็บบัญชี): การใช้ SHA3(k) คุณต้องการสร้างบัญชีจำนวนมาก (บัญชีสามารถสร้างโครงสร้างสถานะได้ถึง 64 ระดับ!) และซ้ำๆ โทรรหัส SLOAD และ SSTORE ทำให้การโจมตี DoS ยากขึ้นมาก โปรดทราบว่าสิ่งนี้ทำให้ยากต่อการระบุแผนผัง หากคุณต้องการให้ไคลเอ็นต์ของคุณสามารถระบุได้ วิธีที่ง่ายที่สุดคือรักษาการแมปฐานข้อมูล sha3(k) -> k
หมายเหตุการพิสูจน์อักษร: ความหมายในที่นี้คือ หากใช้ k เป็นคีย์ของ Merkle tree เพื่อเก็บข้อมูล การกระจายข้อมูลอาจเบาบางมาก และผู้โจมตีสามารถวางแผนบัญชีที่ต้องใช้เส้นทางทรีลึกในการจัดเก็บ และกำหนดเป้าหมายบัญชีเหล่านี้ได้อย่างง่ายดาย การเรียกการดำเนินการเข้าถึงสถานะซ้ำๆ กันทำให้โหนดในเครือข่ายโอเวอร์โหลด อย่างไรก็ตาม ผลลัพธ์ของฟังก์ชันแฮชจะถูกแจกจ่ายแบบสุ่ม การใช้ sha3(k) เป็นคีย์สามารถทำให้การกระจายคีย์มีความสม่ำเสมอมากขึ้นและความสูงของต้นไม้จะสั้นลง ) .
คุณลักษณะนี้ยังมีข้อดีและข้อเสีย ในแง่หนึ่ง หมายความว่าการโจมตีแบบ DoS จะยากขึ้น ในทางกลับกัน มันยังทำให้เส้นทางการเข้าถึงแผนผังสถานะของธุรกรรมในบล็อกไม่ค่อยทับซ้อนกัน ดังนั้น การค้นหาแต่ละครั้งทั้งสองจึงเป็น ความซับซ้อนของกรณีที่เลวร้ายที่สุด
นอกจากนี้ สิ่งนี้ยังทำให้ MPT ไม่เหมาะสมที่จะบรรลุ "ภาวะไร้สัญชาติ" (ตัวบล็อกเองมีข้อมูลที่จำเป็นสำหรับการตรวจสอบ และผู้ตรวจสอบไม่จำเป็นต้องมีสถานะส่วนกลาง) เนื่องจากเส้นทางการเข้าถึงของรัฐไม่ทับซ้อนกัน และ ประสิทธิภาพของพื้นที่ของหลักฐานก็เป็นกรณีที่แย่ที่สุดเช่นกัน แน่นอนว่าอาจกล่าวได้ว่าประสิทธิภาพพื้นที่ของหลักฐานต้นไม้ Merkle นั้นไม่สูงพอ
RLP
RLP (คำนำหน้าความยาวแบบเรียกซ้ำ): คำนำหน้าความยาวแบบเรียกซ้ำ
การเข้ารหัส RLP เป็นรูปแบบการทำให้เป็นอนุกรมหลักใน Ethereum และใช้ในทุกที่: บล็อก ธุรกรรม สถานะบัญชี และข้อความโปรโตคอลเครือข่าย ดูคำอธิบายอย่างเป็นทางการของ RLP สำหรับรายละเอียด: https://github.com/ethereum/wiki/wiki/RLP
RLP ตั้งใจให้เป็นรูปแบบการซีเรียลไลเซชันที่ง่ายมาก ซึ่งมีวัตถุประสงค์เพื่อจัดเก็บอาร์เรย์ไบต์ที่ซ้อนกัน3 ซึ่งแตกต่างจากโซลูชันที่มีอยู่เช่น protobuf และ BSON RLP ไม่ได้กำหนดประเภทข้อมูลเฉพาะใดๆ เช่น บูลีน (บูลีน) ทศนิยม (จุดลอยตัว) สองเท่าหรือจำนวนเต็ม (จำนวนเต็ม) มันเพียงแค่จัดเก็บโครงสร้างในรูปแบบของอาร์เรย์ที่ซ้อนกัน และขึ้นอยู่กับโปรโตคอลที่จะกำหนดความหมายของอาร์เรย์ นอกจากนี้ RLP ยังไม่รองรับการรวบรวมแผนที่อย่างชัดเจน คำแนะนำกึ่งทางการคือให้ใช้อาร์เรย์ที่ซ้อนกันของ [[k1, v1], [k2, v2], ...] เพื่อแสดงคอลเลกชั่นคู่คีย์-ค่า, k1, k2 ... ตามมาตรฐานการเรียงลำดับสำหรับสตริง
รูปแบบที่มีฟังก์ชันเหมือนกับ RLP คือ protobuf หรือ BSON ซึ่งเป็นอัลกอริทึมที่ใช้กันมาตลอด อย่างไรก็ตาม ใน Ethereum เราชอบใช้ RLP เพราะ: (1) ง่ายต่อการติดตั้ง (2) รับประกันความสอดคล้องของไบต์อย่างแน่นอน
หลายภาษาไม่มีการเรียงลำดับคอลเลคชันคู่คีย์-ค่าที่ชัดเจน และรูปแบบทศนิยมมีกรณีพิเศษมากมายที่อาจส่งผลให้เกิดการเข้ารหัสที่แตกต่างกันและแฮชที่แตกต่างกันสำหรับข้อมูลเดียวกัน ด้วยการพัฒนาโปรโตคอลภายใน เราสามารถมั่นใจได้ว่าได้รับการออกแบบโดยคำนึงถึงเป้าหมายเหล่านี้ (นี่เป็นหลักการทั่วไปที่ใช้กับส่วนอื่นๆ ของโค้ดด้วย เช่น เครื่องเสมือน) วิธีการเข้ารหัสที่ใช้โดย BitTorrent, bencode อาจเป็นทางเลือกแทน RLP อย่างไรก็ตาม ใช้วิธีการเข้ารหัสแบบทศนิยม ซึ่งด้อยกว่าไบนารี RLP เล็กน้อย
อัลกอริทึมการบีบอัด
ทั้งโปรโตคอลเครือข่ายและฐานข้อมูลใช้อัลกอริธึมการบีบอัดแบบกำหนดเองเพื่อจัดเก็บข้อมูล อัลกอริทึมสามารถอธิบายได้ดังนี้: ใช้การเข้ารหัสความยาวรัน 4 สำหรับ 0 ในขณะที่รักษาค่าอื่นๆ (ยกเว้นกรณีพิเศษบางกรณี เช่น sha3(' ') ) ตัวอย่างเช่น:
ก่อนอัลกอริทึมการบีบอัดจะมีอยู่ มีกรณีพิเศษ ในหลาย ๆ ที่ในโปรโตคอล Ethereum ตัวอย่างเช่น sha3 มักถูกกำหนดใหม่เพื่อให้ sha3(' ')=' ' ไม่จำเป็นต้องเก็บรหัสในบัญชี ซึ่งสามารถบันทึกได้ 64 ไบต์ อย่างไรก็ตาม เมื่อเร็ว ๆ นี้ กรณีพิเศษเหล่านี้ทั้งหมดที่ทำให้โครงสร้างข้อมูลของ Ethereum บวมได้ถูกลบออกไปแล้ว และมีการเพิ่มฟังก์ชันการเก็บรักษาข้อมูลลงในเลเยอร์นอกโปรโตคอลบล็อกเชนแทน เช่น ในโปรโตคอลเครือข่ายและแทรกการใช้งานฐานข้อมูลผู้ใช้ สิ่งนี้จะเพิ่มความสามารถในการทำให้เป็นโมดูล ลดความซับซ้อนของเลเยอร์ฉันทามติ และทำให้การอัปเดตอย่างต่อเนื่องของอัลกอริทึมการบีบอัดค่อนข้างง่ายในการปรับใช้ (ตัวอย่างเช่น สามารถแยกความแตกต่างและปรับใช้ตามหมายเลขเวอร์ชันของโปรโตคอลเครือข่าย)
การใช้ต้นไม้ (trie)
ข้อควรจำ: การทำความเข้าใจความรู้ส่วนนี้จำเป็นต้องให้ผู้อ่านเข้าใจหลักการของ Bloom filter 5 สามารถดูคำแนะนำได้ที่: http://en.wikipedia.org/wiki/Bloom_filter
ส่วนหัวของบล็อกแต่ละอันใน Ethereum blockchain มีตัวชี้ไปยังต้นไม้สามต้น: ต้นไม้สถานะ ต้นไม้ธุรกรรม และต้นไม้ใบเสร็จ
ต้นไม้สถานะแสดงถึงสถานะทั้งหมดหลังจากประมวลผลบล็อก
โครงสร้างธุรกรรมแสดงถึงธุรกรรมทั้งหมดในบล็อกและธุรกรรมเหล่านี้ได้รับการจัดทำดัชนีโดยดัชนีเป็นคีย์ (เช่น k0: ธุรกรรมที่ดำเนินการครั้งแรก, k1: ธุรกรรมที่ดำเนินการครั้งที่สอง)
แผนผังใบเสร็จรับเงินแสดงถึงใบเสร็จรับเงินที่สอดคล้องกันสำหรับธุรกรรมแต่ละรายการ
การรับธุรกรรมเป็นโครงสร้างข้อมูลที่เข้ารหัส RLP:
ใน:
medstate: หลังจากประมวลผลธุรกรรมแล้ว รากของต้นไม้สถานะ
gas_used: ปริมาณก๊าซที่ใช้หลังจากประมวลผลธุรกรรม
บันทึก: เป็นรายการขององค์ประกอบ [ที่อยู่, [หัวข้อ1, หัวข้อ2...], ข้อมูล] จำนวนมาก องค์ประกอบเหล่านี้สร้างขึ้นโดย opcodes LOG0 ... LOG4 ถูกเรียกใช้ระหว่างการดำเนินการธุรกรรม (ประกอบด้วยการโทรหลักและการโทรย่อย) ที่อยู่คือที่อยู่ของสัญญาที่สร้างบันทึก หัวข้อมีค่าสูงสุดสี่ค่า 32 ไบต์ ข้อมูลเป็นคำของ อาร์เรย์ส่วนขนาดใดก็ได้
logbloom: ตัวกรอง Bloom ประกอบด้วยที่อยู่และหัวข้อของบันทึกทั้งหมดในธุรกรรม
หมายเหตุ:
หมายเหตุ:
UTXO: เอาต์พุตของธุรกรรมที่ไม่ได้ใช้ ตามตัวอักษร: เอาต์พุตของธุรกรรมที่ยังไม่ได้ใช้งาน นั่นคือ เอาต์พุตของธุรกรรมที่ไม่ได้อ้างอิงโดยธุรกรรมใด ๆ เป็นอินพุต เป็นโครงสร้างข้อมูลที่ใช้ในโปรโตคอล Bitcoin เพื่อเก็บข้อมูลมูลค่า (ความเป็นเจ้าของ) —— บันทึกการพิสูจน์อักษร
Nonce ตัวย่อของ Number used one หรือ Number one ในการเข้ารหัส Nonce เป็นค่าสุ่มตามอำเภอใจหรือไม่เกิดซ้ำซึ่งใช้เพียงครั้งเดียวและทั้งเวกเตอร์เริ่มต้นและฟังก์ชันแฮชที่เข้ารหัสในเทคโนโลยีการเข้ารหัสมีบทบาทสำคัญ ใน แอปพลิเคชันการสื่อสารของโปรโตคอลการตรวจสอบความถูกต้องต่างๆ ทำให้มั่นใจได้ว่าข้อมูลการตรวจสอบความถูกต้องจะไม่ถูกนำมาใช้ซ้ำเพื่อต่อสู้กับการโจมตีซ้ำ (Replay Attack) ——หมายเหตุของผู้แปล
อาร์เรย์ที่ซ้อนกัน: สร้างอาร์เรย์และเติมข้อมูลด้วยอาร์เรย์อื่นๆ เช่น สัตว์เลี้ยงอาร์เรย์:
var cats : String[] = ["Cat","Beansprout", "Pumpkin", "Max"];
var dogs : String[] = ["Dog","Oly","Sib"];
var pets : String = [cats, dogs];——หมายเหตุของผู้แปล
run-long-encoding: การเข้ารหัสทางสถิติ เทคนิคหลักคือการตรวจจับลำดับบิตหรืออักขระซ้ำๆ และแทนที่ด้วยจำนวนครั้งที่เกิดขึ้น (สารานุกรมไป่ตู้) - หมายเหตุของผู้แปล
ชื่อระดับแรก
รางวัลสำหรับบล็อกลุง
โปรโตคอล GHOST เป็นนวัตกรรมที่โดดเด่นซึ่งเสนอครั้งแรกในเดือนตุลาคม 2013 โดย Yonatan Sompolinsky และ Aviv Zohar นี่เป็นความพยายามอย่างจริงจังครั้งแรกในการแก้ปัญหาที่เกี่ยวข้องกับการสร้างบล็อกอย่างรวดเร็ว
ความตั้งใจของ GHOST คือการแก้ปัญหาดังกล่าว: เวลาในการบล็อกที่สั้นลง (และทำให้ความเร็วในการยืนยันเร็วขึ้น) จะนำไปสู่การบล็อกจำนวนมากขึ้นที่ "ล้าสมัย" และทำให้มีความปลอดภัยน้อยลง - เนื่องจากต้องใช้เวลาในการเผยแพร่บล็อกในเครือข่าย หากผู้ขุด A ขุดบล็อกและเผยแพร่ไปยังเครือข่ายทั้งหมด และระหว่างทางของการแพร่ภาพ B ก็ขุดบล็อกด้วย จากนั้นบล็อกของ B ก็ล้าสมัย และการทำเหมืองในปัจจุบันของ B ไม่ได้มีส่วนช่วยรักษาความปลอดภัยของเครือข่าย
นอกจากนี้ยังมีปัญหาการรวมศูนย์: ถ้า A เป็นกลุ่มการขุดที่มี 30% ของกำลังการประมวลผล B มี 10% ของกำลังการประมวลผล A มีเวลา 70% ในการสร้างบล็อกที่ล้าสมัย (เพราะอีก 30% ของเวลาจะสร้างบล็อกล่าสุด ถือได้ว่า TA "ได้" ข้อมูลของบล็อกล่าสุดทันทีโดยไม่ต้องรอการส่งผ่านบล็อก) ในขณะที่ B มีเวลา 90% ในการสร้างบล็อกที่ล้าสมัย หากช่วงเวลาระหว่างการผลิตบล็อกสั้นมาก อัตราความล้าสมัยจะสูงขึ้น และ A จะทำให้การขุดมีประสิทธิภาพมากขึ้นด้วยพลังการประมวลผลที่มากขึ้น ดังนั้นหากบล็อกถูกสร้างขึ้นเร็วเกินไป มันจะนำไปสู่การผูกขาดของพูลการขุดโดยพฤตินัยด้วยพลังการประมวลผลเครือข่ายขนาดใหญ่ได้อย่างง่ายดาย
จากข้อมูลของ Sompolinsky และ Zohar GHOST แก้ปัญหาการลดลงของความปลอดภัยเครือข่ายที่เกิดจากบล็อกที่ล้าสมัยในกระบวนการคำนวณว่าเชนใดเป็นเชนที่ยาวที่สุด นั่นคือ ไม่เพียงแต่บล็อกหลักและบล็อกก่อนหน้าเท่านั้น แต่ยังรวมถึงบล็อกหลักประกันที่ล้าสมัย (ใน Ethereum เราเรียกมันว่า "บล็อกลุง") ด้วยเช่นกัน เพื่อคำนวณว่าบล็อกใดมีงานรวมที่ใหญ่ที่สุด ไปที่การพิสูจน์
เพื่อแก้ปัญหาที่สอง: ปัญหาการรวมศูนย์ เราได้ใช้กลยุทธ์อื่น: รางวัลบล็อกมีให้สำหรับบล็อกที่ล้าสมัยเช่นกัน: รางวัลสำหรับการขุดบล็อกที่ล้าสมัยคือ 7/8 ของรางวัลพื้นฐานของบล็อก บล็อกหลานชายของบล็อกเวลาจะ รับรางวัล 1/32 ของฐานเป็นเงินรางวัล อย่างไรก็ตาม ค่าธรรมเนียมการทำธุรกรรมจะไม่ถูกมอบให้กับลุงและหลานชาย
ใน Ethereum บล็อกที่ล้าสมัยสามารถรวมเป็นบล็อกรองได้เฉพาะบล็อกที่สืบทอดโดยตรงภายใน 7 รุ่นของบล็อกพี่น้อง เหตุผลของข้อจำกัดนี้คือ ประการแรก หากโปรโตคอล GHOST ไม่จำกัดระยะทางระหว่างยุคของบล็อกที่ล้าสมัย ก็จะใช้จ่ายจำนวนมากในการคำนวณความถูกต้องของบล็อกที่ล้าสมัย ประการที่สอง นโยบายแรงจูงใจไม่จำกัดสำหรับบล็อกที่ล้าสมัย จะทำให้นักขุดสูญเสียความกระตือรือร้นในการขุดบนเชนหลัก ท้ายที่สุด การคำนวณแสดงให้เห็นว่านโยบายการให้รางวัลบล็อกล้าสมัยที่จำกัดไว้ที่เลเยอร์ 7 ให้ผลลัพธ์ที่ต้องการมากที่สุดโดยไม่มีผลข้างเคียงเชิงลบ
สามารถดูโปรแกรมจำลองการวัดความเสี่ยงจากการรวมศูนย์ได้ที่นี่: https://github.com/ethereum/economic-modeling/blob/master/ghost.py
การสนทนาในระดับที่สูงขึ้นสามารถพบได้ที่นี่: https://blog.ethereum.org/2014/07/11/toward-a-12-second-block-time/
หมายเหตุการพิสูจน์อักษร: รูปแบบทางเทคนิคของ "รวม" ที่นี่คือ: บล็อกหลานอ้างอิงค่าแฮชของบล็อกของบล็อกลุงในส่วนหัวของบล็อก จากนั้นรวมส่วนหัวของบล็อกของบล็อกลุงในเนื้อหาของบล็อก
การตัดสินใจออกแบบสำหรับอัลกอริทึม blocktime รวมถึง:
บล็อกเวลา 12 วินาที: เลือก 12 วินาที เนื่องจากนานกว่าช่วงเวลาขั้นต่ำของการดีเลย์ของเครือข่ายแล้ว ในปี 2013 บทความเกี่ยวกับการวัดเวลาแฝงของเครือข่าย Bitcoin ระบุว่า 12.6 วินาทีเป็นเวลาสำหรับบล็อกที่สร้างขึ้นใหม่เพื่อเผยแพร่ไปยัง 95% ของโหนด อย่างไรก็ตาม กระดาษยังระบุด้วยว่าเวลาในการแพร่กระจายนั้นเป็นสัดส่วนกับบล็อก ขนาด ดังนั้นในสกุลเงินที่เร็วกว่า เราคาดว่าเวลาในการเผยแพร่จะลดลงอย่างมาก ช่วงเวลาการแพร่กระจายคงที่ประมาณ 2 วินาที อย่างไรก็ตาม เพื่อความปลอดภัย ในการวิเคราะห์ของเรา เราถือว่าการแพร่กระจายของบล็อกใช้เวลา 12 วินาที
ข้อจำกัดภายใน 7 รุ่นของบรรพบุรุษ: จุดประสงค์ของการออกแบบนี้คือการเก็บบล็อกจำนวนเล็กน้อยและล้างบล็อกก่อนหน้า มีการแสดงช่วงที่อ้างอิงถึง 7 รุ่นเพื่อให้ได้เอฟเฟกต์ที่ต้องการมากที่สุด
ข้อจำกัดการสืบทอด 1 รุ่น: (เช่น c(c(p(p(p(p(head))))) ไม่ถูกต้องหาก c = child และ p = parent): นี่เป็นเป้าหมายการออกแบบเพื่อความเรียบง่าย และที่กล่าวมาข้างต้น เครื่องจำลองแสดงให้เห็นว่าสิ่งนี้ไม่ก่อให้เกิดความเสี่ยงในการรวมศูนย์ที่สำคัญ (หมายเหตุการพิสูจน์อักษร: ประโยคนี้เข้าใจยาก ความหมายหนึ่งที่เป็นไปได้คือ: ลูกหลานของบล็อกลุงไม่สามารถใช้เป็นบล็อกลุงได้ นั่นคือ เฉพาะรุ่นของกิ่งด้านข้างของห่วงโซ่หลักเท่านั้นที่สามารถใช้เป็นบล็อกลุง .)
บล็อคลุงต้องถูกต้อง: บล็อคลุงต้องเป็นส่วนหัวที่ถูกต้อง ไม่ใช่บล็อคที่ถูกต้อง นอกจากนี้ยังทำเพื่อความง่ายโดยทำให้โมเดลบล็อกเชนเป็นโครงสร้างข้อมูลเชิงเส้น (โดยไม่ต้องเปลี่ยนเป็น DAG) อย่างไรก็ตาม การกำหนดให้บล็อกลุงเป็นบล็อกที่ถูกต้องก็มีผลเช่นกัน
ชื่อระดับแรก
อัลกอริทึมการปรับปรุงความยาก
ปัจจุบัน Ethereum ดำเนินการอัปเดตความยากโดยใช้กฎต่อไปนี้:
เป้าหมายการออกแบบของกฎการอัปเดตความยากมีดังนี้:
อัปเดตอย่างรวดเร็ว: ควรปรับเวลาระหว่างบล็อกอย่างรวดเร็วด้วยการเพิ่มหรือลดกำลังแฮช
ความผันผวนต่ำ: หากพลังการขุดคงที่ ความยากไม่ควรผันผวนอย่างรุนแรง
ง่าย: การใช้อัลกอริทึมควรค่อนข้างง่าย
หน่วยความจำเหลือน้อย: อัลกอริทึมไม่ควรใช้บล็อกประวัติมากเกินไป และใช้ "ตัวแปรหน่วยความจำ" ให้น้อยที่สุดเท่าที่จะเป็นไปได้ สมมติว่ามีสิบบล็อกล่าสุด ให้เพิ่มตัวแปรหน่วยความจำที่จัดเก็บไว้ในส่วนหัวของบล็อกทั้งสิบนี้ และบล็อกเหล่านี้สามารถใช้สำหรับการคำนวณอัลกอริทึมได้
Unbreakable: อัลกอริทึมไม่ควรให้แรงจูงใจมากเกินไปแก่นักขุดในการยุ่งเกี่ยวกับเวลาประทับหรือพูลเหมืองเพื่อเพิ่มหรือลบพลังการคำนวณซ้ำ ๆ
ชื่อระดับแรก
ค่าน้ำมันและค่าธรรมเนียม
ธุรกรรมทั้งหมดใน Bitcoin นั้นใกล้เคียงกัน ดังนั้นต้นทุนเครือข่ายจึงจำลองเป็นหน่วยเดียว การทำธุรกรรมใน Ethereum นั้นซับซ้อนกว่า ดังนั้นค่าธรรมเนียมการทำธุรกรรมจึงต้องคำนึงถึงหลายแง่มุมของบัญชี รวมถึงต้นทุนแบนด์วิธเครือข่าย ต้นทุนการจัดเก็บ และต้นทุนการคำนวณ ไม่น้อย ภาษาโปรแกรม Ethereum เป็นภาษาทัวริงที่สมบูรณ์ ดังนั้นการทำธุรกรรมจึงสามารถใช้แบนด์วิธ พื้นที่จัดเก็บ และค่าใช้จ่ายในการคำนวณเท่าใดก็ได้ จำนวนเงินที่จะถูกใช้งานนั้นไม่สามารถคาดการณ์ได้อย่างน่าเชื่อถือ (เนื่องจากสิ่งที่เรียกว่า "ปัญหาการหยุดชะงักของทัวริง" ) ) (หมายเหตุการพิสูจน์อักษร: นั่นคือ ไม่มีวิธีที่เชื่อถือได้ในการยืนยันว่าโปรแกรมใด ๆ ที่ปฏิบัติการได้บนเครื่องทัวริงจะยุติลงภายในจำนวนขั้นตอนที่จำกัด) การป้องกันการโจมตีแบบปฏิเสธการให้บริการโดยใช้ลูปไม่สิ้นสุดคือเป้าหมายหลักของเรา
กลไกพื้นฐานของค่าธรรมเนียมการทำธุรกรรม Ethereum มีดังนี้:
ธุรกรรมแต่ละรายการต้องระบุปริมาณก๊าซที่ต้องการใช้ (นั่นคือ ระบุมูลค่าของสตาร์ทแก๊ส) และค่าธรรมเนียมที่ยินดีจ่ายสำหรับแต่ละหน่วยของก๊าซ (นั่นคือ ราคาก๊าซ) หักออกจากบัญชี (หมายเหตุการพิสูจน์อักษร: startgas ที่นี่คือขีด จำกัด ของแก๊สที่เราคุ้นเคยในตอนนี้)
การดำเนินการทั้งหมดระหว่างการดำเนินการธุรกรรม ซึ่งรวมถึงการอ่านและเขียนฐานข้อมูล การส่งข้อความ และการคำนวณในแต่ละขั้นตอนจะใช้ปริมาณก๊าซจำนวนหนึ่ง
หากการทำธุรกรรมเสร็จสมบูรณ์และมูลค่าก๊าซที่ใช้น้อยกว่าค่าขีดจำกัดที่ระบุ การทำธุรกรรมจะดำเนินการตามปกติ และมูลค่าก๊าซที่เหลือจะถูกกำหนดให้กับตัวแปร gas_rem หลังจากการทำธุรกรรมเสร็จสิ้น ผู้ส่งจะได้รับอีเธอร์ที่ส่งคืนพร้อมกับ มูลค่าของ gas_rem * ราคาก๊าซ รางวัลสำหรับผู้ขุดคือ (startgas - gas_rem) * ราคาก๊าซของอีเธอร์
หากแก๊สหมดในระหว่างการดำเนินการธุรกรรม การดำเนินการทั้งหมดจะถูกคืนค่ากลับสู่สถานะเดิม แต่ธุรกรรมยังคงใช้ได้ แต่ผลลัพธ์เดียวของธุรกรรมคือต้องจ่ายเงินให้นักขุดด้วยมูลค่าของ startgas * ราคาแก๊ส และ อีกอันยังคงไม่เปลี่ยนแปลง
เมื่อสัญญาส่งข้อความไปยังสัญญาอื่น คุณสามารถกำหนดขีดจำกัดของการดำเนินการย่อยที่เกิดจากข้อความได้ หากการดำเนินการย่อยหมดลง การดำเนินการย่อยจะได้รับการกู้คืน แต่ยังคงใช้ก๊าซอยู่ (หมายเหตุการพิสูจน์อักษร: ณ เวลาพิสูจน์อักษรบทความนี้ (9 กรกฎาคม 2021) สิ่งนี้ไม่ได้เปลี่ยนแปลง แต่อาจเปลี่ยนแปลงได้ในอนาคต ดู "คุณสมบัติ EVM ที่ควรค่าแก่การพิจารณานำออก》)
ต้องปฏิบัติตามประเด็นที่กล่าวถึงข้างต้น เช่น
หากธุรกรรมไม่จำเป็นต้องระบุขีดจำกัดแก๊ส ผู้ใช้ที่ประสงค์ร้ายสามารถส่งธุรกรรมที่มีขั้นตอนหลายพันล้านขั้นตอน ไม่มีใครสามารถประมวลผลธุรกรรมดังกล่าวได้ เนื่องจากอาจใช้เวลานานในการประมวลผลธุรกรรมดังกล่าว แต่ไม่มีใครสามารถแจ้งให้นักขุดบนเครือข่ายทราบล่วงหน้าได้ ซึ่งจะนำไปสู่การถูกปฏิเสธการให้บริการ
อีกทางเลือกหนึ่งนอกเหนือจากการนับปริมาณก๊าซที่เข้มงวดคือการจำกัดเวลา แต่ไม่น่าจะมีประโยชน์เพราะเป็นเรื่องส่วนตัวเกินไป (คอมพิวเตอร์บางเครื่องเร็วกว่าเครื่องอื่น และแม้ว่าคอมพิวเตอร์ของทุกคนจะเหมือนกัน แต่ก็ยังเป็นไปได้ที่จะทำงานผิดพลาดได้)
ควรตั้งค่าทั้งหมดของ startgas * gasprice ในตอนเริ่มต้น เพื่อที่บัญชีจะไม่ "ล้มละลาย" ในระหว่างการดำเนินการธุรกรรมและไม่สามารถชำระค่าธรรมเนียมก๊าซต่อไปได้ การตรวจสอบยอดคงเหลือในขณะที่ดำเนินการก็ไม่ได้ผลเช่นกัน เนื่องจากบัญชีสามารถวางยอดคงเหลือไว้ที่อื่นได้
หากการดำเนินธุรกรรมไม่สามารถย้อนกลับได้อย่างสมบูรณ์ (ย้อนกลับ) ในกรณีที่ก๊าซไม่เพียงพอ สัญญาจะต้องใช้มาตรการความปลอดภัยที่เข้มงวดเพื่อป้องกันไม่ให้สัญญาเปลี่ยนแปลง
หากไม่มีข้อจำกัดย่อย บัญชีที่เป็นอันตรายสามารถทำการปฏิเสธการโจมตีบริการในสัญญาอื่นได้ ผู้โจมตีสามารถบรรลุฉันทามติกับสัญญาของเหยื่อ จากนั้นแทรกลูปไม่สิ้นสุดที่จุดเริ่มต้นของกระบวนการคำนวณ จากนั้นส่งข้อความไปยังสัญญาของเหยื่อหรือความพยายามใด ๆ เพื่อแก้ไขสัญญาของเหยื่อ ธุรกรรมทั้งหมดจะถูกล็อกตาย (หมายเหตุการพิสูจน์อักษร: ประโยคนี้เข้าใจยากเช่นกัน)
การกำหนดให้ผู้ส่งธุรกรรมชำระค่าน้ำมันแทนสัญญาช่วยเพิ่มความสามารถในการปฏิบัติงานของนักพัฒนาอย่างมาก Ethereum รุ่นแรก ๆ จ่ายค่าก๊าซโดยสัญญา ซึ่งนำไปสู่ปัญหาที่ค่อนข้างร้ายแรง: แต่ละสัญญาต้องใช้รหัส "ผู้เฝ้าประตู" เพื่อให้แน่ใจว่าข้อความขาเข้าแต่ละข้อความมีอีเธอร์เพียงพอสำหรับสัญญาที่จะใช้
การคำนวณปริมาณการใช้ก๊าซมีลักษณะดังต่อไปนี้:
สำหรับการทำธุรกรรมใด ๆ จะมีการเรียกเก็บค่าธรรมเนียมพื้นฐาน 21,000 น้ำมัน ค่าธรรมเนียมเหล่านี้สามารถใช้เป็นค่าใช้จ่ายในการเรียกใช้อัลกอริทึมเส้นโค้งวงรีที่ออกแบบมาเพื่อกู้คืนที่อยู่ของผู้ส่งจากลายเซ็น เช่นเดียวกับฮาร์ดไดรฟ์และพื้นที่แบนด์วิธที่ใช้เพื่อจัดเก็บธุรกรรม
ธุรกรรมสามารถรวม "ข้อมูล" ได้ไม่จำกัดจำนวน opcodes บางตัวในเครื่องเสมือนที่อนุญาตให้สัญญาที่ได้รับธุรกรรมดังกล่าวเข้าถึงข้อมูลได้ กฎ "ปริมาณการใช้คงที่" สำหรับข้อมูลคือ: 4 แก๊สต่อศูนย์ไบต์, 68 แก๊สต่อไบต์ที่ไม่ใช่ศูนย์ สูตรนี้เกิดขึ้นเนื่องจากธุรกรรมส่วนใหญ่ที่ส่งโดยผู้ใช้ไปยังสัญญาประกอบด้วยชุดของพารามิเตอร์ 32 ไบต์ ซึ่งส่วนใหญ่มีไบต์ศูนย์นำหน้าหลายตัว โครงสร้างนี้อาจดูไม่มีประสิทธิภาพ แต่เนื่องจากอัลกอริธึมการบีบอัด ทำให้มีประสิทธิภาพมากทีเดียว เราหวังว่าโครงสร้างนี้สามารถแทนที่กลไกอื่นๆ ที่ซับซ้อนมากขึ้นซึ่งรวมพารามิเตอร์อย่างเคร่งครัดตามจำนวนไบต์ที่คาดไว้ ส่งผลให้ความซับซ้อนของขั้นตอนการคอมไพล์เพิ่มขึ้นอย่างมาก นี่เป็นข้อยกเว้นสำหรับรุ่นแซนวิชคอมเพล็กซ์ แต่ก็เป็นรุ่นที่เหมาะสมเนื่องจากอัตราส่วนต้นทุนต่อผลประโยชน์
การใช้รหัสการดำเนินการ SSTORE ที่ใช้ในการตั้งค่ารายการจัดเก็บบัญชีคือ: 1) เมื่อเปลี่ยนค่าศูนย์เป็นค่าที่ไม่ใช่ศูนย์ จะใช้ก๊าซ 20,000 แก๊ส 2) การเปลี่ยนค่าศูนย์เป็นค่าศูนย์ หรือค่าที่ไม่ใช่ ค่าศูนย์เป็นค่าที่ไม่ใช่ศูนย์ ใช้ 5,000 แก๊ส 3) เปลี่ยนค่าที่ไม่ใช่ศูนย์เป็นค่าศูนย์และใช้ 5,000 แก๊ส นอกจากนี้ จะได้รับเงินคืน 15,000 แก๊สหลังจากดำเนินการธุรกรรมสำเร็จ (นั่นคือการทำธุรกรรม ดำเนินการโดยไม่ต้องใช้แก๊สหมด) วงเงินสูงสุดของเงินคืนคือ 50% ของก๊าซทั้งหมดที่ใช้โดยการทำธุรกรรม สิ่งนี้ทำให้ผู้คนมีแรงจูงใจเล็กน้อยในการล้างรายการที่เก็บไว้ เราสังเกตเห็นว่าเนื่องจากขาดสิ่งจูงใจดังกล่าว พื้นที่จัดเก็บของสัญญาจำนวนมากจึงไม่ถูกใช้อย่างมีประสิทธิภาพ ซึ่งนำไปสู่การขยายอย่างรวดเร็วของข้อมูลที่เก็บไว้ การออกแบบนี้ให้ประโยชน์ส่วนใหญ่ของรูปแบบ "การเช่าอย่างต่อเนื่องสำหรับรายการจัดเก็บ" โดยไม่สูญเสียการรับประกันว่าสัญญาเมื่อจัดตั้งขึ้นแล้วสามารถดำรงอยู่ได้อย่างไม่มีกำหนด กลไกการคืนเงินที่ล่าช้าเป็นสิ่งที่จำเป็น เนื่องจากสามารถป้องกันการโจมตีแบบปฏิเสธการให้บริการ: ผู้โจมตีสามารถส่งธุรกรรมโดยใช้น้ำมันปริมาณเล็กน้อย และล้างรายการจัดเก็บจำนวนมากในรอบจนกว่าน้ำมันจะหมด ซึ่งสิ้นเปลือง พลังการประมวลผลการตรวจสอบจำนวนมาก แต่จริง ๆ แล้วมันไม่ได้ล้างพื้นที่เก็บข้อมูลจริง ๆ และไม่เสียค่าใช้จ่ายมาก ขีดจำกัด 50% คือเพื่อให้แน่ใจว่านักขุดที่ทำธุรกรรมยังสามารถกำหนดขีดจำกัดบนของเวลาในการคำนวณเพื่อดำเนินการธุรกรรมได้
(หมายเหตุการพิสูจน์อักษร: ก่อนอื่น ปริมาณการใช้ก๊าซของรหัสการเข้าถึงสถานะเช่น SSTORE มีการเปลี่ยนแปลงหลายครั้งด้วยการฮาร์ดฟอร์กของ Ethereum ตั้งแต่เดือนกรกฎาคม 2021 ค่าล่าสุดสามารถพบได้ใน "ภาพรวมของเนื้อหาการอัปเกรดของเบอร์ลิน"; ในอนาคตอันใกล้นี้ ค่าของ opcode นี้จะเปลี่ยนแปลงต่อไป ประการที่สอง กลไกการคืนเงินค่าก๊าซที่นี่ไม่ได้เปิดใช้งานเพื่อบรรเทาปัญหาการขยายข้อมูลของรัฐ แต่ทำให้ปัญหาแย่ลง เนื่องจากผู้คนสามารถเปลี่ยนค่าของ ราคาก๊าซ เมื่อราคาก๊าซต่ำ ข้อมูลขยะจำนวนมากจะถูกเขียน และเมื่อราคาก๊าซสูง ข้อมูลเหล่านี้จะถูกล้างเพื่อให้ได้ก๊าซ นี่คือหลักการของ "GasToken" ได้รับการยืนยันแล้วว่าจะมีการเปลี่ยนกลไกการคืนเงินก๊าซในส้อม "London" โปรดดู "ตัวอย่างการอัปเกรด Ethereum "London"》。)
ข้อมูลข้อความที่จัดทำโดยสัญญาไม่มีค่าใช้จ่าย เนื่องจากไม่จำเป็นต้องคัดลอกข้อมูลใด ๆ ระหว่างการโทรข้อความ ข้อมูลการโทร (ข้อมูลการโทร) จึงถือได้ว่าเป็นตัวชี้ไปยังหน่วยความจำของสัญญาหลัก ซึ่งจะไม่เปลี่ยนแปลงเมื่อกระบวนการรองดำเนินการ
หน่วยความจำเป็นอาร์เรย์ที่สามารถขยายได้ไม่จำกัด อย่างไรก็ตาม การขยายหน่วยความจำ 32 ไบต์ทุกครั้งจะใช้ค่าแก๊ส 1 ค่า และน้อยกว่า 32 ไบต์จะนับเป็น 32 ไบต์ (หมายเหตุสำหรับการพิสูจน์อักษร: โดยทั่วไปแล้วหน่วยความจำจะแปลว่าหน่วยความจำ แต่ในบริบทของ Ethereum มันเป็นหนึ่งในสามประเภทของ EVM เนื่องจากการจัดเก็บข้อมูล ดังนั้นจึงไม่ได้แปลเพื่อแสดงลักษณะเฉพาะของมัน)
เวลาในการคำนวณของ opcodes บางตัวขึ้นอยู่กับพารามิเตอร์อย่างมาก และการคำนวณค่าโสหุ้ยของก๊าซจะเปลี่ยนแปลงแบบไดนามิก ตัวอย่างเช่น ค่าใช้จ่ายของ EXP เป็นเลขชี้กำลัง (10 แก๊ส + 10 แก๊ส/ไบต์ เช่น x^0 = 1 แก๊ส x^1 ... x^255 = 2 แก๊ส x^256 ... x^65535 = 3 แก๊ส ฯลฯ) คัดลอก opcodes (เช่น CALLDATACOPY, CODECOPY, EXTCODECOPY) มีค่าโสหุ้ย 1 แก๊ส + 1 แก๊ส/32 ไบต์ (ปัดเศษขึ้น กฎสำหรับ LOG opcode คล้ายกัน) ไม่รวมค่าโสหุ้ยของการขยายหน่วยความจำที่นี่ หากมีการรวมเข้าด้วยกัน มันจะกลายเป็นเวกเตอร์โจมตีสี่เหลี่ยม (50,000 CALLDATACOPY, ใช้ 50,000 แก๊สในแต่ละครั้ง, จำนวนการคำนวณควรเป็น 50,000^2 แต่ถ้าคุณไม่ใช้กฎการชาร์จแบบไดนามิก คุณจะต้องจ่ายแก๊สประมาณ 50,000 เท่านั้น ).
Opcode CALL (และ CALLCODE ) มีค่าใช้จ่ายเพิ่มเติม 9000 ก๊าซ หากค่าไม่ใช่ศูนย์ เนื่องจากการถ่ายโอนค่าใด ๆ จะทำให้พื้นที่จัดเก็บประวัติของโหนดเก็บถาวรเพิ่มขึ้นอย่างมาก โปรดทราบว่าปริมาณการใช้จริงของการดำเนินการคือ 6700 แต่บนพื้นฐานนี้ เราจะเพิ่มค่าก๊าซที่กำหนดให้กับเครื่องรับโดยอัตโนมัติ และค่านี้มีค่าอย่างน้อย 2300 สิ่งนี้ทำเพื่อให้กระเป๋าเงินที่รับธุรกรรมมีก๊าซเพียงพอในการสร้างบันทึก (หมายเหตุการพิสูจน์อักษร: ดู "คุณสมบัติ EVM ที่ควรค่าแก่การพิจารณานำออก》)
อีกส่วนที่สำคัญของกลไกก๊าซคือเศรษฐศาสตร์ที่รวมอยู่ในราคาก๊าซเอง ใน Bitcoin แนวทางเริ่มต้นคือการเก็บค่าธรรมเนียมโดยสมัครใจโดยผู้ขุดจะทำหน้าที่เป็นผู้เฝ้าประตูและกำหนดค่าธรรมเนียมขั้นต่ำแบบไดนามิก ใน Ethereum ผู้ส่งธุรกรรมจะได้รับอนุญาตให้กำหนดจำนวนก๊าซเท่าใดก็ได้ วิธีนี้เป็นที่นิยมมากในชุมชน Bitcoin เนื่องจากเป็นศูนย์รวมของ "เศรษฐกิจตลาด": ช่วยให้ผู้ขุดและผู้ค้าสามารถกำหนดราคาตามอุปสงค์และอุปทาน อย่างไรก็ตาม ปัญหาของแนวทางนี้คือการประมวลผลธุรกรรมไม่เป็นไปตามหลักการของตลาด แม้ว่าการประมวลผลธุรกรรมอาจถูกมองว่าเป็นบริการที่นักขุดมอบให้แก่ผู้ส่ง (ซึ่งฟังดูง่าย) แต่ในความเป็นจริงแล้ว ธุรกรรมทุกรายการที่ประมวลผลโดยนักขุดจะต้องถูกประมวลผลโดยทุก ๆ โหนดในเครือข่าย ดังนั้นการประมวลผลธุรกรรมส่วนใหญ่จึงมีค่าใช้จ่ายทั้งหมด โดยหน่วยงานบุคคลที่สาม ไม่ใช่คนงานเหมืองที่ตัดสินใจว่าจะทิ้งมันหรือไม่ ดังนั้นปัญหา "โศกนาฏกรรมของส่วนรวม" จึงมีโอกาสเกิดขึ้นได้มาก
ชื่อระดับแรก
เครื่องเสมือน
Ethereum Virtual Machine เป็นเครื่องมือที่ดำเนินการรหัสธุรกรรม และยังเป็นความแตกต่างหลักระหว่าง Ethereum และระบบอื่นๆ โปรดทราบว่าควรพิจารณาเครื่องเสมือนแยกต่างหากจาก "รูปแบบสัญญาและข้อความ" ตัวอย่างเช่น OPcode ของ SIGNEXTEND เป็นฟังก์ชันของเครื่องเสมือน แต่ในความเป็นจริง "สัญญาสามารถเรียกสัญญาอื่น ๆ และระบุขีดจำกัดก๊าซสำหรับการโทรย่อย" เป็นส่วนหนึ่งของ "รูปแบบสัญญาและข้อความ"
เป้าหมายการออกแบบของ EVM มีดังนี้:
เรียบง่าย: ใช้ opcodes น้อยและต่ำที่สุดเท่าที่จะเป็นไปได้, ประเภทข้อมูลให้น้อยที่สุดเท่าที่จะเป็นไปได้, โครงสร้างเครื่องเสมือนให้น้อยที่สุดเท่าที่จะเป็นไปได้,
ผลลัพธ์นั้นชัดเจน: ในข้อกำหนดเฉพาะของ VM ไม่มีที่ว่างสำหรับความกำกวมที่เป็นไปได้ และผลลัพธ์ควรถูกกำหนดโดยสมบูรณ์ นอกจากนี้ขั้นตอนการคำนวณควรแม่นยำเพื่อให้สามารถวัดปริมาณการใช้ก๊าซได้
ประหยัดพื้นที่: ส่วนประกอบ EVM ควรมีขนาดกะทัดรัดที่สุดเท่าที่จะเป็นไปได้
เฉพาะสำหรับการใช้งานตามวัตถุประสงค์: แอปพลิเคชันที่สร้างขึ้นบน VM ควรสามารถจัดการที่อยู่ 20 ไบต์และค่าเข้ารหัสแบบกำหนดเอง 32 บิต มีการดำเนินการแบบโมดูโลสำหรับการเข้ารหัสแบบกำหนดเอง บล็อกการอ่านและข้อมูลธุรกรรม และความสามารถ เช่น การโต้ตอบสถานะ
ง่ายและปลอดภัย: เพื่อป้องกันไม่ให้ VM ถูกใช้ประโยชน์ ควรสร้างชุดแบบจำลองต้นทุนการใช้ก๊าซได้ง่าย
การเพิ่มประสิทธิภาพที่เป็นมิตร: ควรปรับให้เหมาะสมได้ง่ายเพื่อให้สามารถสร้างการคอมไพล์แบบทันเวลาพอดี (JIT) และ VM เวอร์ชันเร่งความเร็วได้
ในขณะเดียวกัน EVM ยังมีการออกแบบพิเศษดังต่อไปนี้:
ความแตกต่างระหว่างที่เก็บข้อมูลชั่วคราว/ถาวร: ก่อนอื่นเรามาดูว่าที่เก็บข้อมูลชั่วคราวและที่เก็บข้อมูลถาวรคืออะไร ที่เก็บข้อมูลชั่วคราว: มีอยู่ในทุกอินสแตนซ์ของ VM และหายไปหลังจากการดำเนินการ VM สิ้นสุดลง ที่เก็บข้อมูลถาวร: มีอยู่ในเลเยอร์สถานะของ blockchain สมมติว่าต้นไม้ต่อไปนี้ถูกดำเนินการ (S สำหรับการจัดเก็บถาวร, M สำหรับการจัดเก็บชั่วคราว):
A โทรหา B;
B ตั้ง BS[0]=5, BM[0]=9;
B เรียก C;
ซีโทรหาบี
ในตอนนี้ ถ้า B พยายามอ่าน BS[0] จะได้ข้อมูลที่เก็บไว้ใน B ก่อน ซึ่งก็คือ 5 แต่ถ้า B พยายามอ่าน BM[0] จะได้ 0 เนื่องจาก BM เป็นที่เก็บข้อมูลชั่วคราว และการอ่าน เมื่อมีการดึงข้อมูล จะเป็นอินสแตนซ์ใหม่ของเครื่องเสมือน ในการโทรภายใน (การโทรภายใน) หากคุณตั้งค่า BM[0] = 13 และ BS[0] = 17 ดังนั้นทั้งการโทรภายในและการเรียกของ C จะสิ้นสุดลงและกลับสู่การโทรภายนอก (การโทรภายนอก) ของ B ในขณะนี้ ให้อ่าน "Taking M" คุณจะเห็น BM[0] = 9 (ค่านี้ถูกตั้งค่าในอินสแตนซ์สุดท้ายของการดำเนินการ VM เดียวกัน), BS[0] = 17 หากการโทรภายนอกของ B สิ้นสุดลง และ A โทรหา B อีกครั้ง เราจะเห็น BM[0] = 0 และ BS[0] = 17 จุดประสงค์ของความแตกต่างนี้คือ: 1. แต่ละอินสแตนซ์การดำเนินการถูกจัดสรรด้วยพื้นที่หน่วยความจำ ซึ่งจะไม่ถูกลดขนาดลงโดยการวนซ้ำ ซึ่งทำให้การตั้งโปรแกรมอย่างปลอดภัยง่ายขึ้น 2. จัดเตรียมรูปแบบในหน่วยความจำที่สามารถดำเนินการได้อย่างรวดเร็ว: เนื่องจากต้องมีการแก้ไขแผนผัง การอัปเดตที่เก็บข้อมูลจึงจำเป็นต้องช้า
โหมดสแต็ก/หน่วยความจำ: ในยุคแรกๆ มีสถานะการประมวลผลสามประเภท (ยกเว้นตัวนับโปรแกรมที่ชี้ไปยังคำสั่งถัดไป): สแต็ก (สแต็ก ซึ่งเป็นสแต็ก LIFO มาตรฐานขนาด 32 ไบต์) หน่วยความจำ (หน่วยความจำ อาร์เรย์ไบต์ชั่วคราว ที่สามารถขยายได้ไม่จำกัด), ไอเทมเก็บของ (คลังเก็บของ, คลังถาวร). ในด้านพื้นที่เก็บข้อมูลชั่วคราว ทางเลือกอื่นนอกจากสแต็กและหน่วยความจำคือกระบวนทัศน์แบบหน่วยความจำเท่านั้น หรือไฮบริดของรีจิสเตอร์และหน่วยความจำ (ไม่มีความแตกต่างระหว่างสองสิ่งนี้มากนัก โดยพื้นฐานแล้วรีจิสเตอร์เป็นหน่วยความจำประเภทหนึ่ง) ในกรณีนี้ แต่ละคำสั่งจะมีอาร์กิวเมนต์สามตัว เช่น ADD R1 R2 R3: M[R1] = M[R2] + M[R3] เหตุผลในการเลือกกระบวนทัศน์สแต็กนั้นชัดเจน มันทำให้โค้ดเล็กลง 4 เท่า
ขนาดคำ 32 ไบต์: ในโครงสร้างส่วนใหญ่ เช่น Bitcoin ขนาดคำคือ 4 หรือ 8 ไบต์ 4 หรือ 8 ไบต์จำกัดเกินไปสำหรับที่อยู่หน่วยความจำและการคำนวณการเข้ารหัส เป็นการยากที่จะสร้างแบบจำลองก๊าซที่ปลอดภัยโดยไม่จำกัดขนาด 32 ไบต์เป็นขนาดในอุดมคติเพราะเพียงพอสำหรับจัดเก็บค่าขนาดใหญ่และที่อยู่ที่จำเป็นสำหรับอัลกอริธึมการเข้ารหัสจำนวนมาก โดยไม่ใหญ่เกินไปจนทำให้ขาดประสิทธิภาพ
เรามีเครื่องเสมือนเป็นของตนเอง: เครื่องเสมือนของเราได้รับการพัฒนาในภาษาต่างๆ เช่น java, Lisp และ Lua เราคิดว่ามันคุ้มค่าที่จะพัฒนาเครื่องเสมือนเฉพาะเนื่องจาก: 1) ข้อมูลจำเพาะ VM ของเรานั้นง่ายกว่าเครื่องเสมือนอื่น ๆ มาก เนื่องจากเครื่องเสมือนอื่น ๆ ยอมจ่ายน้อยกว่าสำหรับความซับซ้อน กล่าวคือ สามารถเปลี่ยนได้ง่ายกว่า อย่างไรก็ตาม ทุก ๆ บิตเพิ่มเติม ความซับซ้อนในโครงการของเราสร้างอุปสรรคในการพัฒนาที่เข้มข้นขึ้นและแนะนำข้อบกพร่องด้านความปลอดภัยที่อาจเกิดขึ้น เช่น ข้อผิดพลาดที่เป็นเอกฉันท์ซึ่งทำให้ความซับซ้อนของเรามีค่าใช้จ่ายสูง 2 ) VM ของเรามีความเชี่ยวชาญมากขึ้น เช่น รองรับ 32 ไบต์ 3) เราจะไม่มีความซับซ้อนภายนอก การพึ่งพาซึ่งจะทำให้การติดตั้งของเราล้มเหลว 4) กลไกการตรวจสอบที่สมบูรณ์สามารถเจาะจงไปยังข้อกำหนดด้านความปลอดภัยพิเศษได้ แม้แต่การใช้ VM ภายนอกก็ไม่ได้ช่วยประหยัดงานมากนัก
มีการใช้ตัวแปรขนาดหน่วยความจำที่ขยายได้: ขนาดหน่วยความจำคงที่เป็นข้อจำกัดที่ไม่จำเป็น เล็กเกินไปหรือใหญ่เกินไป หากขนาดหน่วยความจำคงที่ จำเป็นต้องตรวจสอบว่าการเข้าถึงเกินขอบเขตทุกครั้งที่มีการเข้าถึงหน่วยความจำหรือไม่ ซึ่งเห็นได้ชัดว่าไม่มีประสิทธิภาพ
1024 ขีดจำกัดความลึกของการโทร: ภาษาโปรแกรมจำนวนมากหยุดทำงานเนื่องจากความลึกของการโทรนั้นลึกเกินไปก่อนที่หน่วยความจำจะล้น ดังนั้นจึงไม่เพียงพอที่จะใช้ขีด จำกัด ของบล็อกแก๊สเป็นขีด จำกัด
Untyped: เพียงเพื่อความกะทัดรัด อย่างไรก็ตาม DIV, SDIV, MOD, SMOD ใช้รหัส opcodes ที่ลงนามหรือไม่ได้ลงนาม (ปรากฏว่าลงนามและไม่ได้ลงนามจะเทียบเท่ากับ opcodes ADD และ MUL) กรณีง่าย ๆ เช่น a * b -> (a * b) / 2^32, a / b -> a * 2^32 / b ที่ความยาว 32 บิต, +, - และ * เป็นจำนวนเต็มคงที่
หมายเหตุการพิสูจน์อักษร: มีย่อหน้าต่อไปนี้ในการแปลต้นฉบับด้วย แต่ย่อหน้าที่เกี่ยวข้องถูกลบในเวอร์ชันปัจจุบันของข้อความต้นฉบับ: ไม่มีการจำกัดขนาดสแต็ก: ไม่มีเหตุผลพิเศษ! ในหลายกรณี การออกแบบนี้ไม่จำเป็นอย่างยิ่ง เนื่องจาก ค่าใช้จ่ายของก๊าซและฝาครอบก๊าซของบล็อกจะทำหน้าที่เป็นตัวจำกัดการใช้ทรัพยากรแต่ละอย่างเสมอ
ฟังก์ชันและวัตถุประสงค์ของ opcode บางตัวใน VM นี้เข้าใจได้ง่าย แต่บางตัวไม่เข้าใจ และนี่คือเหตุผลพิเศษบางประการ:
ADDMOD,MULMOD: ในกรณีส่วนใหญ่ mulmod(a, b, c) = a * b % c แต่ในอัลกอริทึมเส้นโค้งวงรี จะใช้การดำเนินการโมดูลัส 32 ไบต์ และการดำเนินการโดยตรงของ a * b % c นั้นเป็นจริง การดำเนินการ ((a * b) % 2^256) % c จะให้ผลลัพธ์ที่แตกต่างไปจากเดิมอย่างสิ้นเชิง ฉันทามติในการคำนวณ a * b %c ของค่า 32 ไบต์ในพื้นที่ 32 ไบต์นั้นยากและน่าเบื่อหน่าย
SIGNEXTEND: วัตถุประสงค์ของ opcode ของ SIGNEXTEND คือเพื่ออำนวยความสะดวกในการแปลงประเภทจากจำนวนเต็มที่มีเครื่องหมายมากเป็นจำนวนเต็มที่มีเครื่องหมายน้อย จำนวนเต็มขนาดเล็กที่มีลายเซ็นมีประโยชน์เนื่องจากเครื่องเสมือนแบบทันเวลาพอดีในอนาคตอาจมีความสามารถในการตรวจจับบล็อกโค้ดที่รันเป็นเวลานานซึ่งจัดการกับจำนวนเต็ม 32 ไบต์เป็นหลัก และจำนวนเต็มขนาดเล็กที่มีลายเซ็นสามารถเพิ่มความเร็วในการประมวลผล
SHA3: ในโค้ด Ethereum นั้น SHA3 ถูกใช้กันอย่างแพร่หลายในฐานะวิธีการทำแผนที่แฮชข้อมูลที่มีความปลอดภัย มีความแข็งแรงสูง และมีความยาวผันแปรได้ โดยทั่วไป เมื่อใช้หน่วยความจำ คุณจะต้องใช้ฟังก์ชันแฮชเพื่อป้องกันการชนกันที่เป็นอันตราย และคุณต้องใช้ฟังก์ชันแฮชเมื่อตรวจสอบ Merkle tree และโครงสร้างข้อมูล Ethereum ที่คล้ายกัน ที่สำคัญ ฟังก์ชันแฮชที่คล้ายกับ SHA3 เช่น SHA256, ECRECVOR, RIPEM160 จะไม่ถูกรวมไว้ในรูปแบบของ opcode แต่อยู่ในรูปแบบของสัญญาหลอก จุดประสงค์ของการดำเนินการนี้คือการจัดหมวดหมู่ให้แยกจากกัน และเมื่อเราพบระบบ "ปลั๊กอินเนทีฟ" ที่เหมาะสมในภายหลัง ก็จะสามารถเพิ่มสัญญาดังกล่าวได้มากขึ้นโดยไม่ต้องใช้ส่วนขยาย opcode
ORIGIN: ORIGIN opcode ให้บริการโดยผู้ส่งธุรกรรม และหน้าที่หลักคือการอนุญาตให้สัญญาส่งคืนก๊าซที่จ่ายไป
COINBASE: บทบาทหลักของ COINBASE คือ: 1) อนุญาตให้ sub-coin มีส่วนร่วมในการรักษาความปลอดภัยของเครือข่าย 2) ช่วยให้นักขุดสามารถทำหน้าที่เป็นระบบเศรษฐกิจแบบกระจายอำนาจเพื่อตั้งค่าแอปพลิเคชันย่อยตามฉันทามติ เช่น Schellingcoin
PREVHASH: PREVHASH สามารถใช้เป็นแหล่งสุ่มแบบกึ่งปลอดภัย นอกจากนี้ยังอนุญาตให้สัญญาประเมินการพิสูจน์สถานะต้นไม้ Merkle ของบล็อกก่อนหน้าโดยไม่ต้องใช้โครงสร้างแบบเรียกซ้ำ "Ethereum light client" ที่มีความซับซ้อนสูง
EXTCODESIZE,EXTCODECOPY: หน้าที่หลักคือการให้สัญญาตรวจสอบรหัสของสัญญาอื่น ๆ ตามแม่แบบ และแม้แต่จำลองรหัสก่อนที่จะโต้ตอบกับสัญญาอื่น ๆ ดู: https://lesswrong.com/lw/aq9/decision_theories_a_less_wrong_primer/
JUMPDEST: เมื่อปลายทางการข้ามถูกจำกัดไว้เพียงไม่กี่ดัชนี (โดยเฉพาะอย่างยิ่ง ความซับซ้อนในการคำนวณของการกระโดดปลายทางแบบไดนามิกคือ O (บันทึก (จำนวนของปลายทางการท้าทายที่ถูกต้อง)) ในขณะที่การกระโดดแบบสแตติกจะคงที่เสมอ) เครื่องเสมือน JIT จะง่ายกว่า ดำเนินการ. ดังนั้นเราจึงจำเป็นต้อง: 1) จำกัดปลายทางการข้ามตัวแปรที่ถูกต้อง 2) สนับสนุนการใช้การกระโดดแบบคงที่มากกว่าการกระโดดแบบไดนามิก เพื่อให้บรรลุเป้าหมายทั้งสองนี้ เราได้ตั้งกฎต่อไปนี้: 1) การกระโดดทันทีหลังจากการพุชสามารถกระโดดได้ทุกที่ ไม่ใช่แค่การกระโดดอีกครั้ง 2) การกระโดดอื่นๆ สามารถกระโดดไปที่ JUMPDEST เท่านั้น ข้อจำกัดในการข้ามเป็นสิ่งที่จำเป็นเพื่อให้สามารถระบุได้ว่าการกระโดดปัจจุบันเป็นการกระโดดแบบคงที่หรือการกระโดดแบบไดนามิกโดยดูที่การดำเนินการก่อนหน้าในรหัส การขาดความจำเป็นในการกระโดดแบบคงที่คือสิ่งที่กระตุ้นการใช้งาน การปิดใช้งานการกระโดดเข้าสู่ข้อมูลพุชยังเพิ่มความเร็วในการคอมไพล์และดำเนินการ JIT VM
LOG: LOG เป็นบันทึกเหตุการณ์
CALLCODE: opcode นี้อนุญาตให้สัญญาใช้รายการพื้นที่เก็บข้อมูลของตัวเองเพื่อเรียก "ฟังก์ชัน" ของสัญญาอื่นในพื้นที่สแต็กและหน่วยความจำแยกต่างหาก สิ่งนี้ทำให้สามารถใช้งานรหัสไลบรารีมาตรฐานบนบล็อกเชนได้อย่างยืดหยุ่น
SELFDESTRUCT: อนุญาตให้สัญญาลบตัวเองหากไม่จำเป็นต้องมีอยู่อีกต่อไป SELFDESTRUCT ไม่ได้ดำเนินการทันที แต่หลังจากดำเนินการธุรกรรมแล้ว เนื่องจากการอนุญาตให้ SELFDESTRUCT ย้อนกลับหลังจากการดำเนินการจะเพิ่มความซับซ้อนของการแคชอย่างมาก ซึ่งไม่เอื้อต่อการนำ VM ไปใช้อย่างมีประสิทธิภาพ
ลิงค์ต้นฉบับ:
(เกิน)
ลิงค์ต้นฉบับ:
https://eth.wiki/en/fundamentals/design-rationale
ผู้เขียน: Vitalik
แปลและพิสูจน์อักษร: kim & A Jian


