Facebook Libra focus on account create

Apisak Srihamat
4 min readJul 19, 2019

--

วันนี้เรามาทำความเข้าใจ account ที่สร้างขึ้นโดย libra cli testnet กันครับ ในการทดสอบประมาณอาทิตย์นึงที่ผ่านมาพบว่า account หายไปเมื่อ quit ออกจาก libra cli testnet แล้วเข้ามาใหม่ ทดลองใช้คำสั่ง account list แล้วไม่พบ account ค้างอยู่แต่เมื่อ create account ใหม่กลับได้ค่าเงินที่สร้างไว้กลับมาได้

เริ่มทดสอบ โดยสร้าง account ขึ้นมา เป็น account#0 จดจำ address ไว้นะครับ e55c … 53fe
ทดลอง check เงินของ account#0
ทดลอง mint 1,000 coins แล้ว check เงินของ account#0 แล้ว quit ออกมา
กลับเข้า libra cli testnet ใหม่ แล้วทดลอง list account ดู ไม่พบ account
Create account อีกครั้ง พบว่าได้ address เดิม จากนั้น query balance จะยังคงได้ 1,000
ทดลอง restart/shutdown PC แล้วกลับเข้ามาที่ Libra cli testnet อีกครั้ง พบว่าเมื่อ create account#0 ยังคงมี balance 1,000 อยู่

มาถึงตรงนี้เราสามารถเข้าใจได้ว่า Libra testnet มีการใช้ค่าและหรือวิธีการบางอย่างที่เกี่ยวข้องกับเครื่อง PC นั้นๆในการ create account ซึ่งแม้จะมีการ restart/shutdown เครื่อง PC นั้นๆไปแล้ว running number ก็จะยังคงทำให้ได้ address key เดิมเสมอๆ

เมื่อเปิด code ของ Command Account ที่เป็นภาษา rust ก็จะพบว่ามีการสร้าง account ขึ้นมาใหม่ด้วยคำสั่ง client.create_next_account

Rust command AccountCommandCreate
function create_next_account ของ client

จะเห็นว่า 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 มาดูว่ามันมีการเปลี่ยนแปลงอย่างไร

function new_address ของ wallet (with print debug)
จะเห็นความแตกต่างของ address ก่อนละหลังจากการ increment key_leaf ในขั้นตอนนี้พอเข้าใจได้แล้วว่ามีการคำนวน (derivation) hash เพื่อไว้สำหรับเป็น address ของ account#1 (ถัดไป) ไว้เรียบร้อยแล้ว

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 เป็นดังนี้

  1. Leaf Nodes: เก็บและตรวจสอบ hash values (append เท่านั้น ไม่มี delete/update)
  2. Internal Nodes: non-leaf node เก็บ hash ที่ derived จากซ้ายและขวา
  3. Placeholder Nodes: ใช้ในขั้นตอนการคำนวน proof leaf node
  4. Frozen Nodes: เมื่อ sub-tree นั้นๆได้ผ่านการ proof แล้ว (ไม่มี placeholder) และทุกๆ leaf node ถูก append จนครบแล้วจะกลายเป็น frozen (hash value จะไม่เปลี่ยนแล้ว)
  5. Non-frozen Nodes: เป็น node ที่มี placeholder อยู่ใน sub tree ของ node นั้นๆ
ตัวอย่างของ Merkel accumulator 5 leaves

โดยจริงๆแล้ว Account Info นั้นจะถูกเก็บใน tree ซ้อน tree อีกทีนึง อ้างอิง official libra storage

ผมวาดรูปย่อแสดงความสัมพัธ์ของข้อมูล Merkle Tree ที่ระบบ Libra เก็บอยู่

ค่อนข้างเป็นข้อมูลที่ซับซ้อนพอสมควร เราย้อนกลับมา focus ที่ function private_child ของ key_factory กันก่อนนะครับ ถ้ามีเวลาเราจะไปคุยกันเรื่อง Merkle Tree และ Node ของ Libra ต่อ

ผมทดสอบโดย debug ด้วยการ print ค่าตัวแปรง่ายๆ ออกมาดู :)
ผลลัพธ์ที่ได้จากการ print debug
INFO_PREFIX ที่ทำให้ได้ Info มา ซึ่งอนาคต 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 ชุดเดิมๆต่อเนื่องไปเรื่อยๆนั่นเองครับ

ผลลัพธ์การทดสอบ clone libra source code 2 ครั้ง แล้วทำการ compare file client.mnemonic ครับ

ภายหลังจากได้ 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 หายไปได้ยังไง :)

function insert_account_data ของ object client (with print debug)
ผลลัพธ์ของการเรียก account create ติดต่อกับ 3 ครั้ง (with print debug) จะเห็นว่า address_to_ref_id เป็นเพียง vector ที่พักค่า address และ id ไว้เพื่ออ้างอิงได้ในอนาคต
คำอธิบายการ implement key_factory และ wallet โดย libra

Ref: https://github.com/libra/libra/tree/master/client/libra_wallet

จากคำอธิบายนี้จะเห็นว่าในช่วงท้ายมีการให้ข้อมูลแผนพัฒนาในอนาคตของ Libra

  1. Support rotating authentication keys
  2. 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)

Facebook Libra focus on create testnet-like

Facebook Libra focus on consensus (Part 2)

--

--

Apisak Srihamat

Master of Science AIT, Embedded systems course UC Irvine, Bachelor of Computer Engineering KMITL, Love innovation ideas.