note: certora_tutorials
/02.Lesson_InvestigateViolations (Part 1)
มาลองเรียน Certora กัน
โอเค ผมจะจด note ระหว่างเรียนการเขียน Certora ไปเรื่อยๆ
เริ่มจากบทเรียนนี้เป็นบทเรียนที่จะสอนการ trace error ที่ certora แสดงผล
note: อยู่ดีๆก็รัน certora ที่เป็น vscode extension ไม่ได้แหะ เลยต้องกลับมารัน cli
note2: พอต้องสลับมาเป็น cvl1 ตอนเรียก tutorial เนี่ย จะมี error python นิดหน่อย แต่พอลง package setuptools ก็โอเคละ
โอเค มาเริ่มกัน
เราจะ verify contract อะไร ?
เป็น contract สำหรับการ vote โดยจะแบ่ง actor เป็น 2 role คือ
- voter คือคนที่ vote ได้
- contender คือคนที่ voter ลงคะแนนให้ได้
โอเค มาลองดู spec certora ที่เค้าให้มากัน
เริ่มจาก
// Checks that a voter's "registered" mark is changed correctly -
// if it's false after a function call, it was false before
// if it's true after a function call it either started as true or changed from false to true via registerVoter()
rule registeredCannotChangeOnceSet(method f, address voter) {
env e;
calldataarg args;
uint256 age;
bool voterRegBefore;
bool voted;
uint256 vote_attempts;
bool black_listed;
age, voterRegBefore, voted, vote_attempts, black_listed = getFullVoterDetails(e, voter);
f(e, args);
bool voterRegAfter;
age, voterRegAfter, voted, vote_attempts, black_listed = getFullVoterDetails(e, voter);
assert(voterRegAfter != voterRegBefore =>
(!voterRegBefore && voterRegAfter && f.selector == registerVoter(uint8).selector),
"voter was registered from an unregistered state, by other function than registerVoter()");
}
โอเค มาดูทีละส่วนกัน
(voterRegAfter != voterRegBefore) => (!voterRegBefore && voterRegAfter)
ตรงนี้ใช้ logic ถ้าแล้ว นั่นคือ ถ้า user เคย registered แล้ว จะไม่สามารถกลับไปเป็น not registered ได้อีก โดยใน code จะไม่อนุญาติให้ voterRegBefore = true และ voterRegAfter = false นั่นเอง
f.selector == registerVoter(uint8).selector
โดยมีอีกเงื่อนไขคือ การเปลี่ยนสถานะจาก not registered เป็น registered จะต้องทำได้ผ่าน function ชื่อ registerVoter เท่านั้น
note: จะสังเกตุได้ว่าพวกค่าที่ใช้เป็น input เช่นค่า voter ที่นำไปเป็น input ให้ getFullVoterDetails เค้าจะใส่เป็น parameter ของ rule แทนการประกาศข้างใน rule เหมือนว่าทำแบบนี้แล้วเวลาค่า input โชว์ในเว็บจะหาง่ายดีแหะ
โอเค จริงๆยังมีอีกหลาย rule แต่มา focus rule ที่เราจะต้องมา debug เป็นอันแรกกัน
// Checks that a each voted contender's points received the correct amount of points
rule correctPointsIncreaseToContenders(address first, address second, address third) {
env e;
mathint firstPointsBefore = getPointsOfContender(e, first);
mathint secondPointsBefore = getPointsOfContender(e, second);
mathint thirdPointsBefore = getPointsOfContender(e, third);
vote(e, first, second, third);
assert(getPointsOfContender(e, first) - firstPointsBefore == 3, "first choice received other amount than 3 points");
assert(getPointsOfContender(e, second) - secondPointsBefore == 2, "second choice received other amount than 2 points");
assert(getPointsOfContender(e, third) - thirdPointsBefore == 1, "third choice received other amount than 1 points");
}
จาก rule ด้านบน จะเป็นการเช็คว่า คะแนนที่ vote ไป เป็นไปตามลำดับ 1 2 3 ในการ vote รึเปล่า
note: จะเห็นได้ว่า rule นี้จะเรียก vote ตรงๆเลย ไม่ได้ให้เรียกทุก function โดยใช้ f() เหมือน rule ที่แล้ว
โอเค มาลองรันกัน
certoraRun BordaBug3.sol:Borda --verify Borda:Borda.spec
จะได้ผลลัพธ์คือ
โอเค โดย rule ที่เขียนไว้คือ
mathint firstPointsBefore = getPointsOfContender(e, first);
mathint secondPointsBefore = getPointsOfContender(e, second);
mathint thirdPointsBefore = getPointsOfContender(e, third);
vote(e, first, second, third);
assert(getPointsOfContender(e, first) - firstPointsBefore == 3, "first choice received other amount than 3 points");
assert(getPointsOfContender(e, second) - secondPointsBefore == 2, "second choice received other amount than 2 points");
นั่นคือ เมื่อมีการ vote แล้ว contender second ได้รับคะแนนไปผิดนั่นเอง
โอเค มาดู error trace กัน
เร่ิมจาก parameter ทั้ง 3 คนไม่ได้เป็นคนเดียวกัน ซึ่งโอเค
ต่อมาใน assert error เราจะเห็นว่าค่า diff ได้ 3 แทนที่จะเป็น 2
โดยใน web จะแสดงค่าที่ get ได้จาก contract = 13
และค่าตัวแปรก่อนหน้าจะมีการ vote = 10 ตามรูปด้านล่าง
เอาละ ทำไมค่าถึงเพิ่มขึ้น 3 แทนที่จะเป็น 2 ไปดู code กัน
จาก code จะเห็นว่าไม่ว่าจะเป็นลำดับที่เท่าไหร่ ก็เพิ่มคะแนน 3 หมดเลย ซึ่งไม่ตรงกับ rule ที่เขียนไว้นั่นเอง
เอาละ ประมาณนี้ก่อน
จริงๆส่วนที่ trace error ยากกว่านี้จะเป็นเรื่อง summary หวังว่าบทนี้จะมีสอนนะ lol
Referrence: https://github.com/Certora/Tutorials