[Solidity] Blockchain & Solidity 101* (BarcampSK)
ตามธรรมเนียมเมื่อจบงาน Barcamp แล้วต้องมีการเขียนบล็อกแชร์ความรู้ให้กับคนใน community หลังจากที่ดองบทความนี้มานาน ได้เวลาปล่อยได้ซะที
จริงๆ อยากจะแบ่งเป็น 2 บทความคือแยกระหว่าง Blockchain กับ Solidity แต่ถ้าให้พูดถึงเรื่อง Blockchain แล้วละก็มันคงจะยาวมากๆ (หากอธิบายสั้นๆ ก็จะเกิดคำถามมากมายตามมา) เพราะฉะนั้นผมแนะนำให้อ่านบทความของพี่หนูเนยตามลิงก์นี้ครับ https://nuuneoi.com/blog/blog.php?read_id=900 ซึ่งเขียนอธิบายไว้อย่างละเอียดและควรค่าแก่การอ่านมาก ๆ
มีคนเคยพูดกับผมว่า การที่จะมาเป็น Blockchain Developer นั้น จะไม่มีคำว่า Junior หรือ Senior แต่จะมีแค่ตำแหน่ง Master เท่านั้น ซึ่งหมายความว่าโค้ดของเรานั้นจะมีข้อผิดพลาดไม่ได้เลย เพราะมันเกี่ยวข้องกับมูลค่า และหาก deploy ไปแล้ว โค้ดก็จะทำงานอย่างนั้นตลอดไป ยากต่อการแก้ไขในภายหลัง เพราะฉะนั้นโค้ดจะต้อง work perfectly ตั้งแต่วันแรกที่ deploy
ภาษา solidity เป็นภาษาที่ค่อนข้างใหม่ และมี Bug อยู่พอสมควร ณ ตอนที่เขียนบทความนี้ ตัวภาษาและ compiler ยังอยู่ที่เวอร์ชัน 0.4.25 และนอกจากตัวภาษาที่มีปัญหา เครื่องมือต่างๆ ที่ใช้ในการเขียนหรือพัฒนา Smart Contract ก็ล้วนจะมีปัญหายิบย่อย เพราะมีหลายตัวที่ยังอยู่ในเวอร์ชัน Beta (web3, solc, truffle, ganache, metamask, hd-wallet, infura, geth, parity, etc…)
Smart contract คืออะไร
Smart contract คือ account ที่ถูกควบคุมโดย code
ซึ่งจะประกอบด้วย 3 ส่วนสำคัญคือ
- balance
- storage
- code
balance คือ จำนวนของ ether ที่อยู่ใน account นี้
storage คือ ข้อมูลที่อยู่ใน smart contract ซึ่งสามารถเก็บข้อมูลได้หลายชนิด เช่น uint, string, array เป็นต้น
code คือ machine code สำหรับ account นี้ (ไม่สามารถอ่านแล้วเข้าใจได้โดยง่าย)
Solidity Programming Language
- เขียนอยู่ในรูปของไฟล์ .sol
- คล้ายกับ JavaScript
- แต่เป็นภาษาแบบ Strongly typed
จากรูปแสดงให้เห็นว่าภาษา Solidity เมื่อถูก compile จะได้ output ออกมาเป็น 2 ส่วนซึ่งก็คือ byte code (ส่วนที่เป็น machine code ที่กล่าวถึงก่อนหน้านี้) และ ABI ซึ่งก็คือ interface สำหรับติดต่อกับ Ethereum blockchain ซึ่งใช้ในฝั่งของ client
Contract คล้ายกับ Class ใน OOP
หน้าตาของภาษา Solidity
Class ก็คือ Contract ส่วน Instance ก็คือ Contract Account
จากโค้ดด้านบน เรามี contract ที่ชื่อว่า Inbox เก็บตัวแปรชื่อว่า message ซึ่งเป็นตัวแปรของ contract มีฟังก์ชัน 2 ฟังก์ชันคือ getMessage และ setMessage ซึ่งทั้ง 2 ฟังก์ชันนี้สามารถเรียกใช้จากภายนอก contract ได้ (เป็นฟังก์ชันแบบ public)
เมื่อเรามาแยกส่วนประกอบของการนิยามฟังก์ชันจะเป็นดังรูปโดยในส่วนของ Function Type สามารถดูได้จากตารางนี้
- public ใครก็เรียก function นี้ได้ ไม่ว่าจะเป็น EOA หรือ Smart contract
- private เฉพาะ contract นี้เท่านั้นที่สามารถเรียกได้
- view และ constant เรียกใช้งานแล้วไม่มีการแก้ไขตัวแปรใน contract (แก้ไข: ปัจจุบัน ไม่มีฟังก์ชันประเภท constant แล้วตั้งแต่เวอร์ชัน 0.5.0 ขึ้นไป)
- pure ไม่แก้ไขและไม่อ่านตัวแปรของ contract (แก้ไข :สามารถอ่านค่าตัวแปรที่เป็นประเภท constant และ immutable ได้)
- payable ผู้เรียกสามารถส่งเงินเป็น ether ขณะเรียกฟังก์ชันนั้นๆ ได้
ในการ demo เราจะให้ Remix ซึ่งเป็น online editor ทำการ deploy ลงบน JavaScript VM ซึ่งอยู่ใน browser ซึ่งตัว Remix มีความสามารถในการ compile solidity file ให้เป็น byte code และ ABI อยู่แล้ว ซึ่งอำนวยความสะดวกให้นักพัฒนาได้เป็นอย่างดี
เราจะสังเกตว่า smart contract เมื่อกี้ที่ deploy ไปแล้วจะมีฟังก์ชัน getMessage และ message ออกมา ซึ่งหากลิงคลิกดูแล้วปรากฎว่าให้ผลลัพธ์เดียวกันคือ return ค่าของ message ออกมา ซึ่งหมายความว่าตัวแปรใน contract ทุกตัวที่ประกาศออกมาเป็น public ตัว solidity จะทำการ auto generate ฟังก์ชัน get มาให้เราโดยอัตโนมัติ
การสร้าง smart contract จำเป็นต้องมี external account เป็นคนสร้าง (contract owner) ซึ่งไม่ต้องระบุฟิลด์ to โดย ethereum จะเข้าใจว่ามันคือการ deploy smart contract ใหม่ขึ้นไปบน ethereum blockchain
เราสามารถที่จะ deploy ไปยังหลายๆ ethereum network ได้ ซึ่งแต่ละ network ก็จะแยกออกจากกันโดยเด็ดขาด smart contract ไม่สามารถคุยกันข้าม network ได้ แม้กระทั้งการ deploy ไปยัง network เดียวกัน ก็นับว่าเป็นคนละ instance กันสำหรับ contract นั้นๆ (ไม่มีความเกี่ยวข้องกัน)
เมื่อเราจะติดต่อกับ smart contract ที่อยู่บน ethereum blockchain หากมีการกระทำที่มีการแก้ไขค่าของตัวแปร จะมีค่าใช้จ่ายเกิดขึ้น เพราะจะมีกระบวนการ PoW ในการ verify ข้อมูลใหม่เกิดขึ้น และจะต้องรอ block time ประมาณ 10–15 วินาที (กรณีที่ใช้งานบน public network)
การเรียกใช้ฟังก์ชันนั้นมีอยู่สองแบบคือการ call ฟังก์ชันและการ send transaction
call function: ใช้สำหรับขอข้อมูลโดยไม่มีการแก้ไขข้อมูลใน ethereum blockchain โดยการเรียกฟังก์ชันประเภทนี้จะไม่มีค่าใช้จ่าย
send transaction: ใช้เมื่อต้องการแก้ไขข้อมูลใน ethereum blockchain ซึ่งต้องสร้างเป็น transaction และส่งออกไปยัง miner โดยจะใช้เวลาในการ execute (รอ PoW) โดยฟังก์ชันประเภทนี้จะ return transaction hash กลับมา นี่เป็นเหตุผลว่าทำไมเราถึงไม่สามารถ set ค่าตัวแปรพร้อมกับสั่งให้ return ค่ากลับมาได้พร้อมๆ กัน และเมื่อมันเป็นการส่ง transaction มันย่อมจะมีค่าใช้จ่าย
หากต้องการ set ค่าและให้มีการ return ค่าออกมา นักพัฒนามักจะใช้วิธีการ emit event ออกมา ซึ่งจะไม่กล่าวในบทความนี้
ในการเขียน smart contract หน่วยเงินที่เล็กที่สุดของโลก ethereun คือหน่วย wei (ผมออกเสียงว่าเวย์) โดยภาษานี้จะไม่มีเลขทศนิยม ซึ่งขนาดของตัวแปร uint ที่ใหญ่ที่สุดคือ 256 bit หรือ 32 bytes ซึ่งใหญ่มากเมื่อเทียบกับภาษาอื่นๆ
สามารถเข้าไปลอง convert หน่วยเงินได้ที่เว็บไซต์ https://etherconverter.online/ ซึ่งหน่วยที่นิยมใช้กันบ่อยๆ คือ ether, gwei และ wei
Gas price และ Gas limit คืออะไร?
ในการส่ง transaction (deploy ก็ถือว่าเป็นการส่ง transction) จะมีค่าธรรมเนียมที่ต้องจ่าย หรือที่เราเรียกกันว่า gas
gasPrice คือราคา gas ต่อ 1 unit ซึ่งผู้ส่ง transaction จะเป็นคนจ่ายให้ miner เพื่อให้ miner ทำการ process transaction นั้นๆ โดยราคาของ gas จะแตกต่างกันออกไปตามช่วงเวลาซึ่งขึ้นอยู่กับความหนาแน่นของ ethereum network ในขณะนั้น สามารถตรวจสอบราคา gas ในปัจจุบันได้ที่ https://ethgasstation.info/
สำหรับ gasLimit คือ จำนวนของ gas ที่ลิมิตไว้ในการส่ง transaction เพื่อไม่ให้จำนวน gas ที่ใช้งานมีจำนวนสูงเกินไป ซึ่งอาจทำให้ผู้ส่ง transaction ต้องเสียเงินมากกว่าที่ควรจะเป็น
จริงๆ แล้วเราสามารถที่จะคำนวณและประมาณจำนวน gas ที่ใช้งานในการส่ง transaction ได้ โดยสามารถดูได้จากลิงก์ด้านล่างนี้
https://docs.google.com/spreadsheets/d/1n6mRqkBz3iWcOlRem_mO09GtSKEKrAsfO7Frgx18pNU/edit#gid=0
ยกตัวอย่างเช่น ฟังก์ชัน doMath มีการ บวก ลบ คูณ และเช็คว่าค่าทั้งสองมีค่าเท่ากันหรือไม่ หากดูจากตารางจะพบว่า operation ADD ใช้ 3 gas, SUBTRACT ใช้ 3 gas, MULTIPLY ใช้ 5 gas และ EQ ใช้ 3 gas รวมทั้งหมดเป็น 14 gas
เมื่อเราได้จำนวน gas ทั้งหมดที่ใช้งาน เราสามารถที่จะนำราคา gas ต่อ 1 unit คูณกับจำนวน gas ก็จะได้ราคา gas ที่ต้องจ่ายในการส่ง transaction นั้น (หากการเรียกฟังก์ชันมีการส่ง ether ด้วยจะต้องนำค่า gas มารวมด้วย) ซึ่งในการพัฒนา smart contract ต้องคำนึงถึงค่า gas ที่ user ต้องจ่ายด้วย ทั้งนี้เราสามารถใช้ web3 ในการ estimate ค่า gas ได้โดยไม่ต้องมาคำนวณเอง
เอาล่ะ คราวนี้พอจะทราบคร่าวๆ แล้วว่า gasPrice กับ gasLimit คืออะไร
สาหรับคนที่ต้องการรู้รูปแบบการทำงานของ blockchain แบบ visualize สามารถกดดูได้จากลิ้งก์ด้านล่างนี้
https://andersbrownworth.com/blockchain/
สามารถรับชม Live facebook ได้ที่
https://www.facebook.com/BarcampSongkhla/videos/200311664204331
สุดท้ายนี้ หากบทความนี้มีข้อผิดพลาดหรือแสดงความคิดเห็นเพิ่มเติมตรงไหนรบกวนคอมเมนต์บอกใต้บทความนี้ได้เลยครับ ผมจะทำการรีบแก้ไขให้เร็วที่สุดครับ