สวัสดีค่ะ คุณผู้อ่านทุกท่าน กลับมาพบกันอีกครั้งกับซีรีย์ “มาพัฒนา DApp ง่าย ๆ ด้วย Truffle กันเถอะ” ตอนนี้เป็นตอนที่ 2 แล้วนะคะ 🙂
ก่อนที่จะไปกันต่อ หากคุณผู้อ่านยังไม่อ่าน หรือลืมเนื้อหาตอนแรกไปแล้ว ผู้เขียนขอแนะนำให้อ่านบทความ “มาพัฒนา DApp ง่าย ๆ ด้วย Truffle กันเถอะ ตอนที่ 1: What and Why?” เพื่อเข้าใจถึงความเป็นมาและความสำคัญของ Truffle ก่อนนะคะ
ถึงตรงนี้แล้ว เรามาเริ่มต้นสร้าง DApp ขึ้นมาตัวหนึ่งด้วย Truffle กันเลยค่ะ ผู้เขียนจะขอยกตัวอย่างระบบง่าย ๆ ดังภาพนี้ …
จะเห็นได้ว่า มันมีลักษณะเหมือนเป็น Ecommerce ตัวหนึ่ง …ใช่แล้วค่ะ เราจะสร้าง Ecommerce แบบง่าย ๆ ที่ทำงานร่วมกับ Blockchain กัน
สำหรับในบทความตอนนี้ เราจะยังไม่ได้เห็นภาพเสร็จสมบูรณ์ดังภาพข้างบนนะคะ เราจะมาสร้างโปรเจคและเขียน Smart Contract ที่เป็นระบบเบื้องหลังกันก่อน
ขั้นตอนในส่วนนี้ก็จะมีดังนี้ค่ะ
- ติดตั้ง Truffle และ Code Editor
- สร้าง Project ใหม่ด้วย Truffle
- เขียน Smart Contract
- Compile Smart Contract ด้วย Truffle
เพื่อไม่ให้เป็นการเสียเวลา…มาเริ่มกันเลย!
Install Truffle
เตรียมซอฟต์แวร์ที่ต้องใช้ให้พร้อม สำหรับการติดตั้ง Truffle ในเครื่อง เราต้องใช้โปรแกรม NPM ช่วยติดตั้ง หากคุณผู้อ่านยังไม่มีโปรแกรม NPM ก็ต้องติดตั้ง Node.js ในเครื่องก่อน (NPM จะติดมาพร้อมกับโปรแกรม Node.js) โดยดาวน์โหลดได้ที่ https://nodejs.org/en/download/
เมื่อติดตั้งเสร็จ ให้คุณผู้อ่านเปิด Command Line แล้วพิมพ์คำสั่งนี้เพื่อติดตั้ง Truffle
npm install -g truffle
หลังจากนั้น หากต้องการตรวจสอบว่าติดตั้ง Truffle สำเร็จหรือไม่ ลองพิมพ์คำสั่ง
truffle version
หาก Command Line แสดงผลลัพธ์ลักษณะนี้ออกมา แสดงว่าติดตั้ง Truffle เรียบร้อย
Truffle v5.0.12 (core: 5.0.12) Solidity v0.5.0 (solc-js) Node v10.15.3 Web3.js v1.0.0-beta.37
จากผลลัพธ์ จะแสดงเวอร์ชันของส่วนประกอบทั้ง 4 ตัว ได้แก่ ตัว Truffle เอง, ตัวคอมไพล์ Solidity ซึ่งก็คือ solc , Node.js, และ Web3 (ตัวที่ใช้ติดต่อกับ Ethereum) ตามลำดับค่ะ
Prepare a code editor
การพัฒนา DApp ด้วย Truffle นั้น คุณผู้อ่านสามารถใช้โปรแกรม Code Editor ใดก็ได้ตามที่ถนัดเลยค่ะ แต่หากคุณผู้อ่านหาที่ถูกใจไม่ได้ ผู้เขียนขอแนะนำให้คุณผู้อ่านใช้โปรแกรมตัวหนึ่งที่ชื่อว่า Visual Studio Code นะคะ สามารถดาวน์โหลดได้ที่เว็บ https://code.visualstudio.com/ เลย 🙂
จากผู้เขียนเคยใช้ Visual Studio Code เป็น Code Editor ที่ดีมาก ๆ เลยค่ะ มันใช้งานง่าย สามารถพัฒนาโปรแกรมทุกภาษา ไม่เว้นแต่ภาษา Solidity ที่เราใช้เขียน Smart Contract กัน มี Plugin มากมายให้ติดตั้งเพื่อเพิ่มความสามารถให้โปรแกรมตามที่ต้องการได้ เชื่อมต่อกับ Git ได้ แถมมี Command Line ในตัวอีกด้วย
Create new folder
หลังจากที่เราติดตั้งโปรแกรมที่ต้องใช้เสร็จเรียบร้อย เมื่อจะทำโปรเจคใหม่ เราต้องสร้างโฟลเดอร์เก็บงานของเราก่อน ให้คุณผู้อ่านเปิด Command Line แล้วสร้างโฟลเดอร์ด้วยคำสั่ง
mkdir simple_ecommerce_contract
เข้าไปที่โฟลเดอร์ด้วยคำสั่ง
cd simple_ecommerce_contract
และสุดท้าย ก็เริ่มโปรเจค Truffle ด้วยคำสั่ง
truffle init
Truffle จะเริ่มโครงสร้างให้ เมื่อเสร็จแล้วจะขึ้นข้อความดังนี้
✔ Preparing to download ✔ Downloading ✔ Cleaning up temporary files ✔ Setting up box Unbox successful. Sweet! Commands: Compile: truffle compile Migrate: truffle migrate Test contracts: truffle test
เมื่อเข้าไปดูที่โฟลเดอร์ จะมีโฟลเดอร์และไฟล์ดังนี้
. ├── contracts ├── migrations ├── test └── truffle-config.js
จากโครงสร้างข้างบนจะเห็นได้ว่า ตอนนี้ simple_ecommerce_contract
ของเราจะมีไฟล์และโฟลเดอร์ดังนี้
- โฟลเดอร์
contracts
ทำหน้าที่เก็บโค้ด Smart Contract ที่เราเขียน (นามสกุล .sol) - โฟลเดอร์
migration
ทำหน้าที่เก็บ Script ที่ใช้ส่ง (เรียกว่าการ Deploy) Smart Contract ไปยัง Ethereum ของเรา - โฟลเดอร์
test
ทำหน้าที่เก็บ Script ที่ช่วยทดสอบการทำงานของ Smart Contract - และไฟล์
truffle-config.js
ช่วยกำหนด Network ที่จะ Deploy ตามที่เราต้องการ รวมถึงการ Compile โค้ดของ Smart Contract เช่น เวอร์ชันของตัวคอมไพล์
Implement smart contracts
หลังจากสร้างโปรเจค Truffle เรียบร้อย ก็มาเริ่มเขียน Smart Contract กันเลยค่ะ
ระบบ Ecommerce จะต้องมีเรื่องเงินเข้ามาเกี่ยวข้อง เพราะฉะนั้นเราต้องสร้างเหรียญที่ใช้ใน Ecommerce ของเราก่อนค่ะ
วิธีการสร้างก็คือ สร้างไฟล์ชื่อ Token.sol
ในโฟลเดอร์ contracts
โดยให้ในไฟล์มีโค้ดดังต่อไปนี้
pragma solidity >=0.4.25 <0.6.0; contract Token { mapping (address => uint256) public balanceOf; constructor(uint256 initialSupply) public { balanceOf[msg.sender] = initialSupply; } function transfer(address _from, address _to, uint256 _value) public returns (bool success) { require(balanceOf[_from] >= _value); // Check if the sender has enough require(balanceOf[_to] + _value >= balanceOf[_to]); // Check for overflows balanceOf[_from] -= _value; balanceOf[_to] += _value; return true; } }
จากโค้ดเป็นการสร้างเหรียญแบบง่าย ๆ ขึ้นมา มันประกอบด้วยตัวแปร balanceOf และฟังก์ชัน transfer ไว้เก็บจำนวนเหรียญที่แต่ละ Account มี และส่งเหรียญจาก Account หนึ่งไปอีก Account หนึ่งตามลำดับ แค่ว่า ถึงจะเป็นเหรียญที่ส่งไปส่งมาได้ มันก็ไม่มีค่าในโลกจริงค่ะ ไม่ควรใช้ในโลกจริงนะคะ ใช้ได้แค่ในระบบนี้เท่านั้น ฮ่า ๆ
เสร็จแล้ว ให้สร้าง Smart Contract สำหรับระบบ Ecommerce ของเรา โดยสร้างไฟล์ชื่อ Shop.sol
ในโฟลเดอร์เดียวกันค่ะ
สำหรับ Smart Contract นี้ ผู้เขียนให้ประกอบด้วย 3 ฟังก์ชันด้วยกัน คือ
- ฟังก์ชันเพิ่มสินค้าในฐานข้อมูล
- ฟังก์ชันรับรายละเอียดของสินค้า
- ฟังก์ชันสั่งซื้อสินค้า
โค้ดที่ได้จะเป็นดังด้านล่างค่ะ
pragma solidity >=0.4.25 <0.6.0; import "./Token.sol"; contract Shop { struct Product { string name; string imgPath; uint256 price; uint256 quantity; address seller; } event AddedProduct(uint256 pid, address seller, uint256 timestamp); event BuyProduct(uint256 pid, address buyer, uint256 timestamp); mapping (uint256 => Product) products; mapping (uint256 => address[]) buying; Token token; constructor (address _tokenAddress) public { token = Token(_tokenAddress); } function addProduct( uint256 _pid, string memory _name, uint256 _price, uint256 _quantity, string memory _imgPath, uint256 timestamp ) public { products[_pid] = Product({ name: _name, imgPath: _imgPath, price: _price, quantity: _quantity, seller: msg.sender }); emit AddedProduct(_pid, msg.sender, timestamp); } function getProduct(uint256 _pid) public view returns (string memory, uint256, uint256, string memory, address) { Product memory product = products[_pid]; return (product.name, product.price, product.quantity, product.imgPath, product.seller); } function buyProduct(uint256 _pid, uint256 _timestamp) public { require(products[_pid].quantity > 0, "Product is sold out"); Product storage product = products[_pid]; address _buyer = msg.sender; token.transfer(_buyer, product.seller, product.price); product.quantity -= 1; buying[_pid].push(_buyer); emit BuyProduct(_pid, _buyer, _timestamp); } }
ถึงตอนนี้โฟลเดอร์ contracts
ของเราก็จะมี 3 Smart Contract ด้วยกัน
contracts ├── Migrations.sol ├── Shop.sol └── Token.sol
คุณผู้อ่านอาจสงสัยว่าทำไมถึงมี Migration เพิ่มขึ้นมา ทั้งที่สร้างเพียง 2 Smart Contract ตรงนี้จะขออธิบายในบทความตอนถัดไปค่ะ
Compile smart contracts
อย่างที่รู้กันว่า ในการส่ง Smart Contract เข้าระบบ Ethereum นั้น เราจะต้องส่งเป็น ABI และ Bytecode ซึ่งสองสิ่งนี้เกิดจากการ Compile smart contracts
เพราะฉะนั้น เมื่อเขียนเสร็จแล้ว อย่ารอช้า! Compile เลยค่ะ!
contracts ├── Migrations.sol ├── Shop.sol └── Token.sol
มีตั้ง 3 ไฟล์ เยอะจัง… ต้องทำคำสั่ง Compile ทั้ง 3 ตัวเลยหรือ?… ไม่ค่ะ Truffle สามารถทำได้ในคำสั่งเดียว!
truffle compile
เพียงแค่พิมพ์คำสั่งนี้ลงไปในครั้งเดียว Truffle จะ compile smart contracts ทั้งหมดที่อยู่ในโฟลเดอร์ทันที ดังผลลัพธ์ข้างล่างค่ะ ง่ายใช่ไหมละคะ?
Compiling your contracts... =========================== > Compiling ./contracts/Migrations.sol > Compiling ./contracts/Shop.sol > Compiling ./contracts/Token.sol > Artifacts written to /home/icegotcha/Data/truffle-example/simple_ecommerce_contract/build/contracts > Compiled successfully using: - solc: 0.5.0+commit.1d4f565a.Emscripten.clang
เมื่อ compile เรียบร้อย คุณผู้อ่านก็จะเห็นว่ามีโฟลเดอร์เพิ่มขึ้นมาในโปรเจคเรา นั่นก็คือ build/contracts
ภายในจะมีไฟล์ JSON เต็มไปหมด Truffle เรียกไฟล์เหล่านั้นว่า Artifact ค่ะ พวกมันคือผลลัพธ์จากการ Compile ซึ่ง Truffle จะรวบรวมทุกอย่างที่ Compile ด้วย solc ได้ เช่น ABI, bytescode, sourcemap, ASM เป็นต้น
Conclusion
Truffle ช่วยให้การพัฒนา Smart Contract เป็นเรื่องที่ง่าย ไม่ว่าจะเขียน Smart Contract สักกี่ตัว Truffle ก็จัดการ Compile ให้อยู่ในทุกรูปแบบ เพียงแค่เราพิมพ์คำสั่งเดียวเท่านั้น
สำหรับบทความตอนนี้ ผู้เขียนก็ขอจบตอนเพียงเท่านี้นะคะ ในบทความตอนถัดไป ผู้เขียนจะพูดถึงเรื่องการส่งสิ่งที่ได้จากการ Compile นี้ไปยัง Ethereum ของเรา ก่อนที่จะพัฒนาเว็บแอปดังภาพแรกที่ได้แสดงไปตอนต้น ซึ่งจะแสดงในตอนถัดไปอีกตอนค่ะ
ขอขอบคุณคุณผู้อ่านที่อ่านบทความมาถึงตรงนี้ด้วยนะคะ แล้วพบกันใหม่ สวัสดีค่ะ 🙂