Facebook Libra focus on account create
วันนี้เรามาทำความเข้าใจ account ที่สร้างขึ้นโดย libra cli testnet กันครับ ในการทดสอบประมาณอาทิตย์นึงที่ผ่านมาพบว่า account หายไปเมื่อ quit ออกจาก libra cli testnet แล้วเข้ามาใหม่ ทดลองใช้คำสั่ง account list แล้วไม่พบ account ค้างอยู่แต่เมื่อ create account ใหม่กลับได้ค่าเงินที่สร้างไว้กลับมาได้
มาถึงตรงนี้เราสามารถเข้าใจได้ว่า Libra testnet มีการใช้ค่าและหรือวิธีการบางอย่างที่เกี่ยวข้องกับเครื่อง PC นั้นๆในการ create account ซึ่งแม้จะมีการ restart/shutdown เครื่อง PC นั้นๆไปแล้ว running number ก็จะยังคงทำให้ได้ address key เดิมเสมอๆ
เมื่อเปิด code ของ Command Account ที่เป็นภาษา rust ก็จะพบว่ามีการสร้าง account ขึ้นมาใหม่ด้วยคำสั่ง client.create_next_account
จะเห็นว่า new address จะถูกสร้างโดย wallet object function new_address ส่วน get_account_data_from_address น่าจะมีการส่งข้อมูล account นี้ไปให้ validator (a.k.a testnet) ทราบว่ามีความพยายามสร้าง account address นี้ขึ้น ผมเริ่มสงสัยเล็กน้อยว่า address จะมีการซํ้าได้หรือป่าว และถ้าซํ้าจะทำยังไงหว่า ? เพราะยังไม่มี code handle กรณี address ซํ้ากันให้เห็น แต่ในระหว่างที่สงสัยเรื่องนี้ ผมก็ทดลอง print debug child, address มาดูว่ามันมีการเปลี่ยนแปลงอย่างไร
key_factory จะมีหน้าที่ไปค้นหา key (hash) จาก Merkle Tree และมีการ increment key_leaf ทุกครั้ง หลังจากนั้นจะทำการ insert address และ key_leaf ไว้ใน address_map
ในส่วนของ LeafNode ภายใน Merkle Tree ของ Libra ก็เป็นเรื่องที่น่าสนใจนะครับเพราะเป็นส่วน core ของระบบเลย แต่เรามาพูดถึง LeafNode กันก่อนนะครับ เนื่องจากมีการอ้างอิงถึงใน code หนึ่ง LeafNode จะแสดงถึง account เดียวเท่านั้น คล้ายๆกับการเก็บข้อมูลใน storage แต่ละ LeafNode จะมี key นึง ซึ่งจริงๆแล้วคือ hash ของ account address ซึ่งจะใช้ค่านี้ล่ะครับ เพื่อเป็น hash ของ account blob ความแตกต่างของมันเพียงแค่ LeafNode ไม่ได้มีค่าอยู่เสมอถ้ามันพึ่งจะถูก load เข้ามาใน memory ซึ่งอยู่ในขั้นตอนที่เรียกว่า non-inclusion proof.
ในส่วนของ Merkle Tree นั้นมีชนิดของ node เป็นดังนี้
- Leaf Nodes: เก็บและตรวจสอบ hash values (append เท่านั้น ไม่มี delete/update)
- Internal Nodes: non-leaf node เก็บ hash ที่ derived จากซ้ายและขวา
- Placeholder Nodes: ใช้ในขั้นตอนการคำนวน proof leaf node
- Frozen Nodes: เมื่อ sub-tree นั้นๆได้ผ่านการ proof แล้ว (ไม่มี placeholder) และทุกๆ leaf node ถูก append จนครบแล้วจะกลายเป็น frozen (hash value จะไม่เปลี่ยนแล้ว)
- Non-frozen Nodes: เป็น node ที่มี placeholder อยู่ใน sub tree ของ node นั้นๆ
โดยจริงๆแล้ว Account Info นั้นจะถูกเก็บใน tree ซ้อน tree อีกทีนึง อ้างอิง official libra storage
ค่อนข้างเป็นข้อมูลที่ซับซ้อนพอสมควร เราย้อนกลับมา focus ที่ function private_child ของ key_factory กันก่อนนะครับ ถ้ามีเวลาเราจะไปคุยกันเรื่อง Merkle Tree และ Node ของ Libra ต่อ
ทดสอบการ print debug บนเครื่องอื่นๆ พบว่า info ได้รับการแปลงจาก static string ไปเป็น vector และ extend ต่อด้วย vector 0 (le_n) นั้นเหมือนกัน แล้วใช้ HKDF’s expand secret key ซึ่งจะได้ secert key ที่แตกต่างกันไปเนื่องจาก HKDF’s expand ใช้ seed (unique client.mnemonic file) จึงทำให้เครื่องคอมพิวเตอร์แต่ละเครื่องได้ค่า secret key ที่แตกต่างกัน แต่เนื่องจาก Libra เครื่องเดิมจะเริ่มคำนวนใหม่ด้วย unique client.mnemonic file เดิมเสมอก็จะเริ่มต้นได้ค่า secret key เป็น series เดิมไปเรื่อยๆ (Ref: https://tools.ietf.org/html/rfc5869 )
โดยในการทดสอบ git clone libra มากกว่า 1 folder ในเครื่องคอมพิวเตอร์เดียวกันพบว่าจะได้ source code เดิมแต่ได้รับ file client.mnemonic ที่มี content ที่แตกต่างกันทำให้เมื่อเรา create account ด้วย code ใน folder นั้นเราจะได้ address ของ account ที่แตกต่างกันใน folder libra ที่ clone git มา แต่เมื่อเรา create account เพิ่มอีกจาก folder เดิมก็จะได้ address ชุดเดิมๆต่อเนื่องไปเรื่อยๆนั่นเองครับ
ภายหลังจากได้ address ของ account นั้นแล้วจะเรียก function insert_account_data ของ object client เพื่อทำการ เก็บค่า address และ id ของ account ไว้ใน vector address_to_ref_id เพื่ออ้างอิงถึงได้ในอนาคต แต่เนื่องจาก address_to_ref_id เป็นเพียง vector ที่จะหายไปเมื่อเรา quit/restart/shutdown ในที่สุดเราก็เข้าใจว่า account หายไปได้ยังไง :)
Ref: https://github.com/libra/libra/tree/master/client/libra_wallet
จากคำอธิบายนี้จะเห็นว่าในช่วงท้ายมีการให้ข้อมูลแผนพัฒนาในอนาคตของ Libra
- Support rotating authentication keys
- Wallet library ยังควรเพิ่มความเข้าใจ input เพื่อ mapping AuthenticationKeys ไปใช้เป็น PrivateKeys
จุดน่าสนใจอย่างนึงคือปัจจุบัน client testnet ไม่ได้ถูกออกแบบมาให้ Node (a.k.a. Partner) เช่น สถาบันการเงินหรือองค์กรต่างๆ สามารถสร้างบริการที่สามารถสร้าง account ให้ฐานลูกค้าของตนเองได้ เพราะ ปัจจุบัน design structure wallet เป็น object ที่ถูกเรียกจาก client แล้วใครล่ะจะมาช่วยระบุตัวตนด้วย ID card หรือ passport ตามที่ควรจะเป็นใน white paper ของ Libra ? Calibra คงไม่สามารถรองรับผู้คนทั่วทั้งโลกได้ด้วยองค์กรเดียว หรือต่อให้สามารถรองรับได้ด้วย technology แต่การเพิ่มจำนวนจะมีขีดจำกัดกลุ่มบุคคลบางกลุ่มที่ไม่สามารถเข้าถึง technology นั้นๆได้ จะทำให้ผิดวัตถุประสงค์ของ Libra ที่ต้องการเป็นสกุลเงินสำหรับทุกๆคน
หากผู้มีสิทธิสร้าง account เช่น สถาบันการเงินหรือองค์กรต่างๆ ยังคงให้บริการรับสร้าง account ที่สาขา (ซึ่งมีอยู่แล้ว) Libra ยังคงจะมีการพัฒนาต่อไปให้ application สามารถจดจำ address_to_ref_id และเริ่ม create account จาก address_to_ref_id ล่าสุดได้ เป็น client สำหรับ node เช่น สถาบันการเงินหรือองค์กรย่อยต่างๆ สามารถอำนวยความสะดวกได้โดยเฉพาะในช่วงแรกๆเพื่อเพิ่มความเร่งให้สามารถให้บริการสร้าง account และระบุตัวตนได้สะดวกรวดเร็วขึ้น
หาก Libra ไม่กระจายการควบคุม account ให้กับสถาบันการเงินหรือองค์กรต่างๆ มีความเป็นไปได้ที่แต่ละสถาบันการเงินหรือองค์กรต่างๆ จะพยายามหาทางออกของตนเอง
บทความอื่นๆเกี่ยวกับการทำความเข้าใจ source code libra มีดังนี้ครับ
Facebook Libra on Windows is easy
Facebook Libra focus on account mint
Facebook Libra focus on query balance
Facebook Libra focus on admission control (Part 1)
Facebook Libra focus on admission control (Part 2)
Facebook Libra focus on mempool
Facebook Libra focus on consensus (Part 1)