Facebook Libra focus on query balance

Apisak Srihamat
3 min readJul 22, 2019

--

วันนี้เรามาทำความเข้าใจการตรวจสอบเงินใน libra ด้วยคำสั่ง query balance นะครับ

เริ่มจากการสร้าง account ด้วยคำสั่ง account create หลังจากนั้นสร้าง coins ด้วยคำสั่ง account mint ถ้ายังไม่เคย mint แต่เรารู้มาจาก stories เรื่อง Facebook Libra focus on account create แล้วว่าเงินที่สร้างไว้ที่เครื่องใดจะยังคงอยู่กับ account นั้นๆเสมอนะครับ ในกรณีนี้ผมเคย mint เงินไว้ที่ account#0 แล้วเพราะฉะนั้นผมสามารถ create account แล้ว query balance 0 เพื่อตรวจเช็คยอด coins ได้เลย

เริ่มเข้าใช้งาน libra client (connected with testnet) สร้าง account#0 และ query balance 0 ได้เลยเนื่องจากได้ mint ไว้ก่อนหน้าแล้วครับ

ว่าแต่ค่า balance ของ account#0 นี้ได้มาได้อย่างไรกันนะ เปิด function QueryCommandGetBalance ที่เขียนด้วยภาษา rust ขึ้นมาพบว่ามีการเรียกใช้งาน get_balance ของ object client ครับ ซึ่งเท่าที่ดู code ค่อนข้างตรงไปตรงมา โดยไปเรียก function get_account_address_from_parameter เพื่อให้ได้ address ของ account ที่กำลังต้องการ query balance หลังจากนั้นจึงเรียก function get_account_resource_and_update เมื่อได้ response กลับมาจึงนำ balance มาแสดงให้ผู้ใช้งานทราบ

function QueryCommandGetBalance
function get_balance ของ object client
function get_account_resource_and_update ของ object client

มาถึงตรงนี้จะเห็นว่ามันไม่ได้ง่ายๆตรงไปตรงมาอย่างที่คิดไว้ตั้งแต่แรก เพราะว่าจะมีการเรียก function get_account_state_and_update ของ object client ไป get account status จาก validator และ update status ของ account นั้นๆก่อนถ้าหากเป็นการ cached ไว้

function get_account_state_and_update ของ object client

ว่าแต่ account มีกี่ status กันนะ ? เมื่อเปิด code ดูก็พบว่ามี 3 AccountStatus

  1. Local: เป็น account ที่ อยู่ใน local cache เท่านั้นไม่ได้คงอยู่ (persisted) บน chain
  2. Persisted: เป็น account ที่ persisted บน chain แล้ว
  3. Unknown: เป็น account ที่ไม่ทราบสถานะ คาดว่าเป็นเพราะ client ไม่สามารถติดต่อสื่อสารกับ validator ได้
enum AccountStatus defined in the libra’s library (lib.rs)

เมื่อเข้าใจ status ของ account แล้วก็กลับมาทำความเข้าใจ function get_account_state_and_update ของ object client กันต่อครับ

function get_account_state_and_update ของ object client (With print debug)
ผลลัพธ์ของการ print debug ซึ่งจะเห็นว่า address ของ account อยู่ใน Raw data นั่นเอง

ผลลัพธ์ของการ print debug ทำให้ผมเข้าใจได้ว่ามีการเก็บข้อมูล Raw data ที่น่าจะนำ bits&bytes มาแปลงเป็นข้อมูลได้ และ … ว้าววววว มันฉลาดพอที่จะสามารถ decode ด้วย Helper methods AccountResource ให้เราสามารถอ่าน structure ข้างในได้เลยอัตโนมัติ

ไปต่อครับ! เมื่อดู code ต่อไปจะเห็นว่ามีการเรียกใช้ function get_account_blob ของ object grpc_client เพื่อรับ account state ล่าสุดจาก validator ผ่าน function get_with_proof_sync ซึ่งก็จะไปเรียก get_with_proof_async นั่นล่ะ แต่ว่ามีการเพิ่มขั้นตอนการ wait (synchronize) และเรียกซํ้าเข้าไป :)

function get_account_blob ของ object grpc_client
function get_with_proof_sync ของ object grpc_client

เมื่ออ่านมาถึง function get_with_proof_async ผมสนใจ UpdateToLatestLedgerRequest จึงทำการ print debug ออกมาดูว่า request ที่ส่งไปมีค่าอะไรอยู่ข้างใน ก็พบว่ามี client_known_version และ address ของ account#0

function get_with_proof_async ของ grpc_client (req คืออะไรหว่า print debug ดูสักหน่อยละกัน)
Result of print debug when query balance 0

จะเห็นว่ามี comment TODO ที่กล่าวถึงการวางแผนระยะยาวสำหรับ client_known_version เพื่อให้ทำงานกับ validator set change ได้ มี 2 เรื่องที่น่าสนใจในจุดนี้

  1. การวางแผนระยะยาวในการพัฒนาแสดงให้เห็นถึงประสบการณ์ของทีมพัฒนาของ libra ซึ่งน่าจะมาจาก facebook ที่มองถึงเรื่อง compatibility ที่จะเป็นโจทย์ใหญ่ในการบริหารจัดการระบบในระยะยาว ซึ่งนักพัฒนาหลายๆท่านไม่ได้คิดถึงจุดนี้กันสักเท่าไหร่เพราะส่วนใหญ่ต้องการให้ product ออกสู่ท้องตลาดโดยเร็วที่สุด ซึ่งในความเป็นจริงแล้วมันคงต้อง balance ให้ไม่ช้าเกินไปและไม่ไวเกินไปจนลืมสิ่งที่สำคัญครับ เพราะถ้าช้าเกินไปก็ไม่ทันกินแต่ถ้าไวจนลืมสิ่งสำคัญไปก็ไม่ดี :)
  2. การออกแบบให้มี client_known_version ทำให้ผมคิดถึง client unknown version ในทางกลับกัน เช่น ถ้าเราสร้าง client กันเองมันจะไม่สนับสนุนใช่ไหม ? (หมายถึงช่วง go live แล้วนะครับไม่ใช่ testnet) หรือสุดท้ายก็จะต้องมีการออกมาตรฐานสำหรับการพัฒนา ? และหรือจะต้องมีวิธีที่จะขออนุญาติเปลี่ยนจาก unknown เป็น known ?

อย่างไรก็ตามใน code function get_with_proof_async ของ grpc_client นั้นมีการเรียกใช้ UpdateToLatestLedger ซึ่งจุดนี้เป็นการส่งข้อมูลไป admission control แล้วนะครับ ในขั้นตอน admission control นี้เนื่องจากอาจทำให้บทความยาวมากๆ ขอทำความเข้าใจเรื่องนี้ในบทความแยกออกไป (ถ้ามี) นะครับ อ้างอิงคำอธิบายจาก libra

เมื่อได้รับ response มาก็จะมีการนำ response มา verify client known version, ledger info signature และ matching sub response vs request ซึ่งเราคงยังไม่ลงรายละเอียดเรื่องนี้ ให้เข้าใจว่าภายหลังจาก verify แล้วจะถือว่าข้อมูลที่ได้มาจาก response นั้นเชื่อถือได้แล้วครับ

ว่าแต่ไหนๆก็ไหนๆลอง print debug response มาดูหน่อยดีกว่าว่ามีอะไรบ้างกันนะ ผมย้อนกลับไปที่ function get_with_proof_sync เพื่อที่จะ print response ออกมาดู

function get_with_proof_sync (with print debug).
result of print debug การเรียกใช้คำสั่ง query balance

ว้าววววววว Result แสดงถึงโครงสร้างข้อมูล Response จาก validator ที่น่าสนใจที่จะทำความเข้าใจมันต่อไป เพียงแต่วันนี้เวลาหมด ราตรีสวัสดิ์ครับ :)

บทความอื่นๆเกี่ยวกับการทำความเข้าใจ source code libra มีดังนี้ครับ

Facebook Libra on Windows is easy

Facebook Libra focus on account create

Facebook Libra focus on account mint

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.