Gitthereum: เปลี่ยน git ให้เป็น blockchain
Before You Read
บทความนี้ assume ว่า
- ผู้อ่านเคยใช้ git มาบ้างแล้ว และพอจะรู้จัก commit, branch
- ผู้อ่านรู้ว่า Blockchain ทำงานอย่างไร (แค่ในระดับ Concept) รู้จัก Concept ของ Blockchain, Cryptocurrency, Smart Contracts และ Proof-of-Work
สำหรับคนที่ยังไม่มั่นใจข้อ 2 ขอแนะนำ บล็อกของพี่หนูเนย หรือ คลิปวีดิโออธิบาย (โดยอาจารย์ผมเอง)
Introduction เล็กน้อย
สวัสดีครับ นี่เป็นบทความแรกของผมบน medium เลย ก่อนหน้านี้ก็ได้ตามอ่านบทความเทพๆ ของคนอื่นอยู่บ้าง อยากเขียนบ้างมานานแล้ว แต่ไม่มีอะไรจะแชร์สักที 555 วันนี้คิดว่ามีเรื่องที่น่าสนใจจะมาแชร์กันครับ
เรื่องมีอยู่ว่าสุดสัปดาห์ที่ผ่านมา (25–26 ส.ค. 2018) ผมได้มีโอกาสเข้าร่วมแข่งขันในงาน Pizza Hackathon 2018 (ชนะด้วยนะ ไม่อยากจะคุย) เป็นงาน Hackathon เกี่ยวกับ Blockchain ครั้งแรกในไทย โดยในการแข่ง Hackathon มีโจทย์ว่า ให้ hack อะไรก็ได้ที่เกี่ยวกับ Blockchain ไม่จำกัดว่าจะใช้ Blockchain ตัวไหน หรือเอามาทำอะไร
ในบทความนี้ ผมอยากจะมาแชร์สิ่งที่ผมทำในงาน เพราะคิดว่าเป็นโปรเจคเกี่ยวกับ Blockchain ที่ไม่ยาก และน่าสนใจมากๆ
เอาล่ะ ไม่พูดอะไรมาก เข้าเรื่องกันเลยดีกว่าครับ
ไอเดีย และที่มาของไอเดีย
(เตือนก่อนเลยว่า geek มากๆ)
Blockchain
ไอเดียมันเกิดมาจากการมานั่งคิดว่า มีคุณสมบัติอะไรบ้างที่ทำให้ Blockchain เป็น Blockchain ในมุมมองของผมมีคุณสมบัติน่าสนใจ 3 อย่างด้วยกัน คือ
เบรก: ศัพท์เทคนิคกำลังจะมาแล้วนะครับ
1.Distributed Ledger
ในเครือข่าย Blockchain จะมี System State ที่เก็บอยู่บนแต่ละโหนดในเครือข่าย ซึ่ง System State นี้แต่ละโหนดจะพยายามทำให้ System State มีค่าเหมือนกันทั้งเครือข่าย
เช่น สำหรับ BitCoin System State คือจำนวนเงินในแต่ละบัญชี, สำหรับ Ethereum คือจำนวนเงินในแต่ละบัญชี และ State ของ Smart Contract
2.Transaction-based State Mutation
การแก้ไข System State ทุกครั้งถูกบันทึกอยู่ในรูป “การเปลี่ยนแปลง” หรือ Transactions เช่น เพิ่มเงินในบัญชี x ไป 10 แทนที่จะแก้ไขตรงๆ
Transaction เหล่านี้ไม่จำเป็นต้องเป็นการโอนเงินเสมอไป เช่นสำหรับ Ethereum Transaction อาจจะหมายถึงการเรียกใช้ Smart Contract ซึ่งนำไปสู่การแก้ไข State ของ Contract นั้น (สำหรับคนที่เคยเขียน Solidity: การเรียกใช้ฟังก์ชันท่ีไม่ใช่ view/pure function)
3.Transactions has to be validated
มีการทำอะไรบางอย่าง เพื่อตรวจสอบ Transactions ที่เกิดขึ้นในเครือข่าย ว่าเกิดขึ้นอย่างถูกต้องหรือไม่
เช่น หากมี Transaction บอกว่าขอโอนเงิน 10 หน่วยจาก A ไป B จะมีการทำอะไรบางอย่างเพื่อตรวจสอบว่า A มีเงินอยู่ 10 หน่วยจริงๆ เพื่อป้องกันไม่ให้ A โกงโดยการโอนเงินมากกว่าเงินที่ตัวเองมีอยู่
อนึ่ง มีส่วนประกอบหนึ่งของ Blockchain ที่ผมไม่ได้สนใจในบริบทนี้ (แต่ใน gitthereum มีการ implement ลงไปนะ) คือ Consensus Algorithm หรือวิธีการที่ทำให้ทุกคนเชื่อว่า Transaction นี้ผ่านการ validate มาแล้วจริง โดยสำหรับ BitCoin (และ gitthereum) ใช้ Proof-of-work (คำนวณอะไรสักอย่างที่ยากๆ) แต่ก็มีวิธีอื่นๆ เช่น Proof-of-stake (เช่นใน Stellar Network) ตรงนี้ไม่ได้สนใจเพราะว่าคิดว่ามันเป็นสิ่งที่เกิดมาจากข้อ 3
Note: เพื่อให้ง่ายต่อการทำความเข้าใจ ผมใช้การเปรียบเทียบกับ Blockchain ตัวดังๆ เช่น BitCoin อย่างไรก็ตาม Blockchain ไม่ได้ทำ Cryptocurrency ได้อย่างเดียว
ผมสงสัยเหลือเกินว่าทำไมสำหรับผมไอ้ 3 ข้อนี้มันดูคุ้นๆ นัก เหมือนเคยมีที่ไหนมาก่อน
เบรก: ศัพท์เทคนิคมาแล้วนะครับ
git is a Blockchain!
ใช่แล้วครับ เจ้า git ที่เราใช้ทำ version control นี่แหละ เป็นระบบที่มีคุณสมบัติ 3 ข้อนี้ครบ ตรงนี้ขอเปรียบเทียบกับการใช้งานทีละข้อให้ดูเลย
มี System State ที่เก็บอยู่บนแต่ละโหนดในเครือข่าย ซึ่ง System State นี้แต่ละโหนดจะพยายามทำให้ System State มีค่าเหมือนกันทั้งเครือข่าย (Distributed Ledger)
สำหรับ git แล้ว ตัว System State มันคือ content ของไฟล์ใน repository นั่นเอง โดยเพื่อให้ง่ายๆ ผมมองว่า content ของไฟล์ใน branch master คือ System State ที่ทุกๆ คนต้องทำให้เหมือนกัน
การแก้ไข System State ทุกครั้งถูกบันทึกอยู่ในรูป “การเปลี่ยนแปลง” หรือ Transactions เช่น เพิ่มเงินในบัญชี x ไป 10 แทนที่จะแก้ไขตรงๆ
ข้อนี้น่าจะมองเห็นกันง่ายหน่อย หากมองว่า System State คือ content ของไฟล์ใน repository แล้ว Transaction ที่ represent การแก้ไข System State มันคือ Commit ต่างๆ ที่อยู่บน branch นั่นเอง
มีการทำอะไรบางอย่าง เพื่อตรวจสอบ “การแก้ไข” ที่เกิดขึ้นในเครือข่าย ว่าเกิดขึ้นอย่างถูกต้องหรือไม่
อันนี้อาจจะฟังดูเหมือนแถ แต่การตรวจสอบว่าแต่ละ Transaction (commit) ถูกต้องหรือไม่ ก่อนที่จะไปแก้ไข System State ได้ มันคือการที่เรามีการสร้าง Pull Requests และมีการทำ code review เพื่อตรวจสอบโค้ดใน commit กันว่าถูกต้องหรือเปล่า ทำให้เกิดบัคหรือไม่ ก่อนที่จะ merge เข้า branch master เพื่อ แก้ไข System State
บอกแล้วว่า Blockchain ไม่เท่ากับ Cryptocurrency และที่เทพกว่านั้นคือ พวกเราเหล่า Developers แทบทุกคน ใช้ Blockchain ในชีวิตประจำวันมาอยู่แล้ว ก่อนที่จะมีคำว่า Blockchain หรือแม้แต่ BitCoin เสียอีก!
สรุปคือ git เป็น Blockchain ตัวนึง (หรือพูดกลับกันให้งงมากขึ้น คือ Blockchain คือ git ที่ Pull Requests ถูก Merge อัตโนมัติ) เพราะงั้นก็เลยคิดว่าในงานนี้อยากจะเอา git มาทำให้มี Cryptocurrency คล้ายๆ BitCoin หรือถ้าทำทันก็ให้รัน Smart Contract ได้คล้ายๆ เป็น Ethereum ไปเลย
อันเป็นที่มาของโปรเจค gitthereum: เปลี่ยน git ให้เป็น blockchain และบทความนี้ครับ
Design & Implementation
System State
สำหรับ System State เราทำโดยสร้าง Repository ขึ้นมาหนึ่ง Repository (ตอน dev เราสร้างบน GitHub แต่ในอุดมคติแล้วควรมีหลายๆ ที่) ให้มันเก็บไฟล์ที่มีลักษณะตาม System State Structure ที่เราออกแบบไว้ โดยจะถือว่า content ใน branch master เป็น System State ปัจจุบันของระบบ
ในรูปเป็น System State Structure ที่เราออกแบบกันไว้ โดยไฟล์ Balance เป็นไฟล์ที่บอกว่าแต่ละบัญชีมีเงินอยู่เท่าไหร่
ในรูปมี Account พิเศษอยู่อันนึงคือ Account 52BB/81B1/3EE1/12A3
Account นี้เป็น Smart Contract โดยจะมีโค้ด (contract.js) และ state (state.json) เก็บไว้ด้วย
แค่นั้นแหละครับ สร้าง Repository จบ
Transactions
สำหรับ Transactions ที่จะมาแก้ไข System State เราใช้การสร้าง branch ที่ไม่มี parent branch หรือไม่ได้แตกออกมาจาก master (วิธีทำ: git checkout --orphan
) มี Commit ที่ไม่มีการแก้ไขใดๆ เลย (วิธีทำ: git commit --alow-empty
) แต่ใน Commit Message จะบอกว่า Transaction นี้จะทำอะไรบ้าง เช่น โอนเงิน หรือเรียกใช้ smart contract ส่วนวิธีการ publish transactions ก็คือการ push commit นั่นแหละ
Mining, Block and Proof of Work
ใน gitthereum มีการให้ miner มา “ขุด” เงินได้ คล้ายๆ กับ BitCoin หรือ Ethereum โดยการสร้าง block มีขั้นตอนดังนี้
- แตก branch ใหม่จาก master สมมติว่าชื่อ my-block
- เอา Transactions ที่ยังไม่ถูกประมวลผล มาตรวจสอบว่าถูกต้องหรือไม่ (เช่นมีเงินพอโอนหรือเปล่า) mark ไว้ แล้วนำมาใส่ใน branch
- สุดท้ายปิด block ด้วยการสร้าง Commit ที่มีการแก้ไข System State จริงๆ ตามที่ Transactions ที่หยิบมากำหนดไว้ และเพิ่มเงินค่า Block Reward และ Transaction Feeให้กับบัญชีของ miner ด้วย
- Commit Message จะอยู่ในรูป
block <block-number> [nonce=<nonce>]
ตรงนี้ miner ต้องทำ Proof of Work โดยการหา nonce ที่ทำให้ commit hash ขึ้นต้นด้วย ‘55’ (ลอกมาจาก BitCoin) (วิธีทำ:git commit --amend
จะเป็นการ commit ทับ commit ล่าสุด ทำไปเรื่อยๆ จนกว่าจะได้ hash ที่ต้องการ) - พอหา nonce ได้แล้วก็ Merge เข้า branch master เพื่อแก้ไข System State ได้เลย
เพื่อป้องกัน Spoofing เราบังคับว่าทุก Commit ต้องผ่านการ Sign ด้วย gpg key เท่านั้นด้วย ไม่เช่นนั้น miner จะไม่หยิบใส่ block
Syncing Chains Between Peers
อย่างที่รู้ๆ กันว่า Blockchain เป็น Peer-to-Peer network ต้องมีการ sync chain ของแต่ละโหนดให้ตรงกัน ใช้ Gossip Protocol โดยใน gitthereum เราก็มีการใช้ Gossip Protocol และการทำ Chain Syncing เหมือนกัน โดยใช้ remote ของแต่ละโหนดแทนแต่ละ peer ที่โหนดนั้นรู้จัก และการ Sync Chain ก็คือการ fetch worktree ของทุกๆ remote มา (วิธีทำ: git fetch --all
) แล้วเปรียบเทียบ master ของแต่ละ remote ที่ fetch มา แล้วเปลี่ยน master ของโหนดนั้นให้เป็น master ของ remote ที่ยาวที่สุด (วิธีทำ: git reset --hard <remote>/master
)
Smart Contracts
เราสามารถสร้าง smart contract บน gitthereum เขียนด้วย JS ได้ด้วย (ทำทัน เพราะเพื่อนร่วมทีมเทพมาก) โดยสร้าง contract ทำได้โดยการเอา contract code ไปแปะไว้ที่ account ใหม่บน System State ได้เลย
// contract.js
module.exports = {
initialState: { members: [] },
reducer(state, action, context) {
state.members.push(context.sender.id)
if (state.members.length >= 2) {
const random = parseInt(context.hash.substr(0, 4), 16) ^ parseInt(context.minerId.substr(0, 4), 16)
const target = random % state.members.length
context.transferTo(state.members[target], context.balance)
state.members = []
}
return state
}
}
ข้างบนเป็นตัวอย่างโค้ด smart contract บน gitthereum โดยเมื่อมีคนโอนเงินไปที่ contract นี้ (เพราะ contract ก็เหมือน account หนึ่ง) ครบ 2 คน ตัว contract จะสุ่มโอนเงินรวมของทั้ง 2 คน ไปให้คนใดคนหนึ่ง
สำหรับหลักการการทำงานของ smart contract ให้มองว่า smart contract 1 contract คือ 1 account ที่มี code (เป็น JS file) และ state เก็บไว้อยู่บน System State (เป็น JSON file) เพิ่มมา การเรียกใช้ contract นั้น คือการสร้าง Transaction เพื่อจะบอกว่าจะใช้ smart contract อย่างไร (เพราะการเรียกใช้ smart contract มักจะทำเพื่อแก้ไข state ของ contract, ซึ่งมันก็คือการแก้ไข System State นั่นแหละ เพราะ state ของ contract ถูกเก็บอยู่ใน System State ด้วย) เวลา miner สร้าง block ก็คือการเปิดโค้ดของ contract นั้นมารันดู แล้วเปลี่ยน state ของ contract ให้เป็นไปตามผลลัพธ์ของการรันโค้ดนั้น
หลังจากออกแบบระบบทั้งหมดแล้ว สิ่งที่เราทำก็คือเขียน script เพื่อ verify transaction, sync chain, สร้าง transactions, สร้าง block (พร้อม proof-of-work), และ script สำหรับอ่านค่า state ที่ถูกเก็บไว้ใน System State ก็เป็นอันเรียบร้อย โดย script ทั้งหมดเขียนขึ้นด้วยภาษา JavaScript (เพราะ JS มันเทพ นี่ไม่ได้อวยนะ)
แล้วทำไปทำไม?
ตรงนี้บอกเลยว่าตอนคิดไอเดียนี้ไม่ได้คิดเลยว่าทำไปทำไม ทำแล้วจะได้อะไร (มัวคิดคงไม่ได้ทำ 555) ต้องขอบคุณ Hackathon ครั้งนี้ที่บอกว่าเน้น Hack ทำให้กล้าทำเต็มที่ แต่พอทำๆ ไปก็ค้นพบความเทพนิดหน่อย (ไม่ได้เวอร์มากขนาดนั้น) ดังนี้
- พอทำทุกอย่างบน git ทำให้ git log, Git UI client ต่างๆ หรือแม้แต่ GitHub กลายเป็นเครื่องมือที่เอามาใช้ดู State และ Transaction (หน้าที่เดียวกับ Etherscan) ได้เลย ซึ่ง visualize ออกมาได้ดีมากๆ ด้วย
2. การสร้าง UI เพื่อมาใช้ Interact กับ gitthereum สามารถ fork git client มาแก้เพิ่มในส่วนของการสร้าง transaction ได้เลย ทำให้ไม่ต้องทำ Front End มาก
3. แทบทุกอย่างอยู่บน git หมดเลย dependency มีแค่ตัว nodeJS runtime ตรงนี้ก็อาจจะทำให้การ setup ค่อนข้างง่าย
4. Smart Contract เป็น JS!!!(เครื่องหมายตกใจล้านตัว)
สำหรับตัวผมเองแล้วการได้ทำโปรเจคนี้ทำให้ผมเข้าใจ Blockchain มากขึ้นมาก และสำหรับ Developer ที่อยากศึกษา Concept ของ Blockchain การเริ่มจาก git อาจจะเป็น Approach ที่ดีก็ได้
สำหรับคนที่สนใจมากกว่า Concept ที่กล่าวมา และอยากจะศึกษาการทำงานจริงๆ โค้ดทุกอย่าง Open Source อยู่บน GitHub และที่สำคัญตัว Chain ก็อยู่บน GitHub ด้วย (อย่างที่บอกไปว่า Chain ก็คือ Git Repository อันหนึ่ง) วางแผนไว้ว่าถ้าวันหลังถ้าเอาไปรันเป็น Network จริงๆ จะให้ Repository gitthereum/chain เป็น Mirror ของ Chain ใน Mainnet ด้วย 55555
ปิดท้ายนิดหน่อย
ผมต้องบอกว่า การที่ gitthereum ถูกสร้างขึ้นมาได้ภายใน 25 ชั่วโมง มี Cryptocurrency และรัน Smart Contract ได้นั้น มันเกินความคาดหมายของผมที่คิดไว้ตอนแรกมากๆ
ตรงนี้ต้องขอบคุณหลายๆ อย่างจากเพื่อนในทีม (Thai Pangsakulyanont, Chonnipa Kittisiriprasert, Banyat Boonkaew, ละก็พี่ตั้มอีกคนที่หา Account ไม่เจอครับ)
อย่างแรกขอบคุณก่อนเลยที่มาเข้าร่วมทีม 555 ตอนแรกคิดว่าไอเดียของผมคง geek เกินไปจนไม่มีใครอยากทำด้วย (กะทำคนเดียว ซึ่งตอนหลังก็รู้เลยว่าดีแล้วที่ไม่ได้ทำคนเดียว เพราะไม่ทันแน่ๆ 55555)
ต่อไปขอกด Wow ให้กับพลังของพี่ไทย ในการออกแบบ เขียน Diagram และทำให้ทีมสื่อสารกันรู้เรื่อง อันนี้ว้าวมาก ทำให้รู้เลยว่าการสื่อสารสำคัญขนาดไหน
พลังของพี่ไทย + พี่จูน ในการเขียนโค้ดสร้างมันออกมา ตอนแรกคิดว่าแค่ทำให้มันโอนเงินได้ก็น่าจะไม่ทันแล้ว แต่ด้วยความเทพของพี่ๆ ก็เลยโค้ดออกมาได้ทัน
และขอบคุณพี่ๆ สตาฟงาน Pizza Hackathon 2018 ที่จัดงาน Hackathon ที่ให้เกียรติคำว่า Hack เปิดโอกาสให้ geek อย่างผมได้ทำอะไร geekๆ ดังที่เคยอยากทำมานาน