แหล่งเรียนรู้
pragma solidity ^0.4.19;
contract HelloWorld {
}
pragma solidity เอาไว้บอก version ของ compiler
ตัวแปร state
จะถูกจัดเก็บใน contract storage นั้นหมายถึง มันจะถูกเขียนลงไปใน Eth Blockchain
เหมือนกับการเขียนลง Database
ตัวอย่างเช่น
contract Example {
// ตัวแปรนี้จะถูกเก็บอย่างถาวรใน Blockchain
uint myUnsignedInteger = 100; //<- ตัวแปร state
}
ในตัวอย่างนี้เราสร้างตัวแปรชนิด
uint
ที่ชื่อ myUnsignedInteger และกำหนดค่าให้เป็น 100
- uint (Unsigned Integers) ค่า integer ที่ไม่มีเครื่องหมายนั่นคือค่าไม่ติดลบ uint คือ uint256 ซึ่งเราสามารถประกาศเป็น bit ที่น้อยกว่า เช่น uint8, uint16, uint32 แต่ประกาศเพียงแค่ uint ก็เพียงพอ(ในบางกรณี)
- Add (+) บวก
- Subtraction (-) ลบ
- Multiplication (*) คูณ
- Division (/) หาร
- Modulus / remainder (%) หารเอาเศษ เช่น 13%5 จะได้ 3
- exponential (**) ยกกำลัง
เป็นข้อมูลที่มีความซับซ้อนมากขึ้น ใครเคยเขียนภาษา C จะเหมือนกัน
struct Person {
uint age;
string name;
}
ตัวอย่างการสร้าง Struct ของคน
มีอยู่ 2 ประเภทคือ
- Fixed
- Dynamic
Fixed คือประกาศ Arrays ให้มีความยาวที่จำกัด เช่น
uint[2] fix;
Dynamic คือ Arrays ที่ไม่จำกัดขนาด
uint[] dynamic;
<เสริม> Public Arrays
การประกาศ arrays ที่มี keyword public
solidity จะสร้าง getter method อัตโนมัติ
Person[] public people
ซึ่ง keyword public
จะทำให้ array นี้สามารถอ่านได้จาก contract อื่น แต่ไม่สามารถเขียนได้
การประกาศฟังก์ชัน ตัวอย่างเช่น
function eatSomething(string memory _name, uint _amount) public {
}
function ชื่อ eatSomething รับ parameters 2 ตัวคือ string และ uint การตั้งชื่อตัวแปรใน params จะตั้งชื่อให้มี underscore( _ )เพื่อที่จะไม่สับสนกับ Global Variable
public
keyword | ประกาศว่า function นี้ถูกเรียกใช้งานได้ทุกที่และทุกคน
memory
keyword | ต้องประกาศเมื่อเรียกใช้ ตัวแปรที่เป็น Reference Type เช่น Arrays, struct, mapping และ String
สร้าง Arrays ของ Struct ได้แบบนี้
struct Person {
uint age;
string name;
}
Person[] public people;
เราสามารถสร้าง Instance ของ Struct ได้แบบนี้
Person aom = Person(20, "aomm");
ซึ่ง Args ของ Person จะเรียงตาม Struct นั้นคือ 20 = age, aomm = name
เราสามารถเพิ่ม aom
เข้าไปใน Arrays people
ได้โดย
people.push(aom)
<เสริม> Arrays.push() จะ Return ค่า length ของ arrays ออกมา
ใน Solidity ฟังก์ชั่นจะมีค่า visible เริ่มต้น เป็น public
ซึ่งทุกคนและทุก contract
สามารถเข้าถึงและเรียกใช้งานได้
private
keyword จะทำให้ function ถูกเรียกใช้งานได้แค่ภายใน contract นี้เท่านั้น
การตั้ง visible เป็น public
เพราะอาจทำให้ Contract ของเราโดนโจมตีได้
ดังนั้นเราจะกำหนดให้ฟังก์ชันเป็น private
ทุกครั้งเป็นค่าเริ่มต้น
ตัวอย่างการประกาศฟังก์ชันแบบ private
uint[] numbers;
function _addNumber(uint _num) private {
numbers.push(_num);
}
การประกาศ function ที่เป็น private มักจะใช้ชื่อที่นำหน้าด้วย underscore ( _ )
การประกาศ function แบบนี้หมายความว่า function
ภายใน contract
นี้เท่านั้นที่สามารถเรียกใช้ฟังก์ชันนี้ได้
การส่งคืนค่าจาก function สามารถเขียนได้ดังนี้ ซึ่งจะมี Keyword คือ returns
(เติม s ด้วยนะ)
string greeting = "What's up dog";
function sayHello() public returns (string memory) {
return greeting;
}
ใน Solidity การ Return ใน Function จะมีการกำหนด Data type ของข้อมูลที่จะ Return
ในตัวอย่างคือ string
และอย่าลืม
string
เป็น Reference Type ต้องมี keywordmemory
จากตัวอย่างข้างต้น function จะไม่เปลี่ยนค่า/เขียนค่าลง State
หรือสรุปก็คือเป็นการอ่านค่า State
ดังนั้นในกรณีนี้เราจะใช้ Modifier
คือ view
ไว้บอกว่า function นี้มีการยุ่งเกี่ยวกับค่าใน storage (state
)
ตัวอย่าง
string greeting = "What's up dog";
function sayHello() public view returns (string memory) {
return greeting;
}
ใน solidity มี concept ของ pure function
ซึ่ง pure ฟังก์ชันคืออะไร อ่านได้จากบทความด้านบน
สรุปคือ pure function มีข้อกำหนดคือ
- ข้อที่ 1 Pure Function คือ ฟังก์ชันที่ไม่ขึ้นอยู่กับค่าตัวแปรหรือไม่เปลี่ยนแปลงค่าตัวแปร (Variables) ที่อยู่นอก scope ของตัวมัน ข้อที่ 2
- Pure Function จะต้องสามารถคาดการณ์ (Predictability) ค่าที่จะ return ออกมาได้ จาก arguments ที่เราส่งเข้าไป หมายความว่าถ้าเราเรียกฟังก์ชั่นเดิมโดยส่งค่า arguments เข้าไปเหมือนเดิม ไม่ว่าจะเรียกฟังก์ชั่นนั้นกี่ครั้ง ค่าที่ return ออกมายังไงก็ต้องได้ค่าเหมือนเดิมทุกครั้ง
ถ้าเป็น pure function ใน solidity จะมี keyword ชื่อว่า pure
มาดูตัวอย่างกัน
function _multiply(uint a, uint b) private pure returns (uint) {
return a * b;
}
จะเห็นว่า function _multiply
จะไม่ยุ่งเกี่ยวกับ state
ค่าที่มันส่งกลับมาจะขึ้นอยู่กับ params
ที่รับเข้าไป
ดังนั้นเราใส่ keyword pure
เข้าไปปปป
ใน Ethereum มีฟังก์ชันในการทำ Hash อยู่ชื่อว่า keccak256
ซึ่งมันใช้ในหลายวัตถุประสงค์ใน Ethereum
ซึ่ง function keccak256
จะรับ parameters
ตัวเดียวเป็นชนิด byte
ตัวอย่างเช่น
//6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5
keccak256(abi.encodePacked("aaaab"));
//b1f078126895a1424524de5321b339ab00408010b7cf0e6ed451514981e58aa9
keccak256(abi.encodePacked("aaaac"));
จะเห็นว่าแค่เปลี่ยนข้อมูลของ input นิดเดียวก็ทำให้ค่าออกมาเปลี่ยนแปลงไปจากเดิมเยอะมากกก
หมายเหตุ
การสร้างตัวเลขสุ่มที่ปลอดภัยในบล็อคเชนเป็นปัญหาที่ยากมาก อันนี้เป็นการยกตัวอย่าง function
การเปลี่ยนชนิดข้อมูลใน Solidity สามารถทำได้ดังนี้
uint8 a = 5;
uint b = 6;
// error เพราะว่า a * b ให้ค่าเป็น unit ไม่ใช่ uint 8
uint8 c = a * b;
// เราสามารถแปลงให้ b เป็น uint8 ก่อนโดยการทำแบบนี้
// ค่าที่ได้จากการคูณกันจึงเป็น type uint8
uint8 c = a * uint8(b);
Event คือสิ่งที่ทำให้ contract ของเราติดต่อกับส่วน front-end ได้โดยการทำคล้ายๆกับ listening
ตัวอย่างการประกาศ Event
event IntegersAdded(uint x, uint y, uint result);
function add(uint _x, uint _y) public returns (uint) {
uint result = _x + _y;
// เรียกใช้ Event เพื่อให้แอปทราบว่ามีการเรียกใช้ฟังก์ชันนี้
emit IntegersAdded(_x, _y, result);
return result;
}
Keyword
event
ใช้ประกาศ Event และemit
ใช้เรียกใช้งาน Event
และ front-end จะมีการ implement code ประมาณนี้
YourContract.IntegersAdded(function(error, result) {
// do something with result
})