Trang chủ Blockchain Hợp Đồng Thông Minh (Smart Contract) Lập trình smart contract: Phần 5 — Viết test case cho smart contracts

Lập trình smart contract: Phần 5 — Viết test case cho smart contracts

Tiếp tục loạt bài thực tế phát triển dApp, giờ chúng ta sẽ nâng độ khó lên một chút xíu khi đi vào hoàn thiện nội dung của smart contracts và viết test case kiểm thử.

Smart contracts

Events

Các smart contracts được thực thi trong môi trường của EVM, hoàn toàn tách biệt với môi trường bên ngoài. Để có thể trigger một sự kiệu ra bên ngoài EVM ta gửi các events được định nghĩa trước:

//New job append
 event NewJob(
 uint256 indexed id,
 address creator,
 uint256 salary,
 uint256 timeOut);

//An woker start working
 event TakeJob(
 uint256 indexed id,
 address indexed labor);

Các event này có thể lắng nghe thông qua các filter cung cấp bởi web3js, việc này sẽ cung cấp thêm thông tin, trigger các hệ thống third party hoặc đơn giản là điều chỉnh lại front-end.

Modifier

Để smart contract của mình bảo mật hơn, mình thêm các modifier. Mục tiêu là kiểm tra arguments trước khi method được trigger (Ethereum là một hệ hoàn toàn thụ động, không có khả năng tự tính toán).

//Transaction must contant Ethereum
 modifier onlyHaveFund {
 require(msg.value > MINIUM_SALARY);
 _;
 }

Trên đây bạn có thể đọc thấy modifier rất rõ nghĩa, với modifier này mình check số Ethereum có trong transaction. Biến msg sẽ chứa vài thông tin hữu ích của transaction (eg. msg.sender: address của người gửi, msg.value: số ethereum tính bằng wei). Để biết rõ thêm global variable các bạn xem ở đây.

Smart contract

Mình viết lại smart contract, thêm hai function mới takeJob() và viewJob():

//Take job

function

takeJob (uint256 jobId)

public onlyValidMortgage(jobId) onlyValidId(jobId) onlyValidJob(jobId)

{

//Trigger event to log labor

TakeJob(jobId, msg.sender);



//Change working state

jobData[jobId].start = block.timestamp;

}



//Veiw job data

function

viewJob(uint256 jobId)

public onlyValidId(jobId) constant returns (

uint256 id,

address creator,

uint256 salary,

uint256 start,

uint256 end,

uint256 timeOut,

bytes title,

bytes description)

{

Job memory jobReader = jobData[jobId];

return (jobReader.id,

jobReader.creator,

jobReader.salary,

jobReader.start,

jobReader.end,

jobReader.timeOut,

jobReader.title,

jobReader.description);

}

Trong phần struct mình cũng update thêm các biến liên quan tới thời gian, và để tiện xử lý mình sẽ sữ dụng Unix timestamp (Solidity không có kiểu datime nên dùng Unix time là tiện nhất):

uint256 start;

uint256 end;

uint256 timeOut;

Chúng ta có toàn bộ mã nguồn như sau:

pragma solidity ^0.4.18;





contract PartTime {



//Job structure

struct Job {

uint256 id;

address creator;

uint256 salary;

uint256 start;

uint256 end;

uint256 timeOut;

bytes title;

bytes description;

}



//New job append

event NewJob(uint256 indexed id,

address creator,

uint256 salary,

uint256 timeOut);



//An woker start working

event TakeJob(

uint256 indexed id,

address indexed labor);



//Minium accept salary

uint256 constant public MINIUM_SALARY = 0.1 ether;



//The number of jobs

uint256 public totalJob;



//Mapped data

mapping (uint256 => Job) public jobData;



//Transaction must contant Ethereum

modifier onlyHaveFund {

require(msg.value > MINIUM_SALARY);

_;

}



//Valid timeOut should be greater than 3 days

modifier onlyValidTimeOut(uint256 timeOut) {

require(timeOut > 3 days);

_;

}



//Check valid job Id

modifier onlyValidId(uint256 jobId) {

require(jobId < totalJob);

_;

}



//Mortgage should be greater than 1/10

modifier onlyValidMortgage(uint256 jobId) {

require(msg.value > jobData[jobId].salary/10);

_;

}



//Check is it a taked job

modifier onlyValidJob(uint256 jobId) {

require(jobData[jobId].end == 0);

require(jobData[jobId].start == 0);

_;

}



//Append new job to mapping

function

createJob (uint256 timeOut, bytes title, bytes description)

public onlyHaveFund onlyValidTimeOut(timeOut) payable returns(uint256 jobId)

{

// Saving a little gas by create a temporary object

Job memory newJob;



// Assign jobId

jobId = totalJob;



newJob.id = jobId;

newJob.id = timeOut;

newJob.title = title;

newJob.description = description;

newJob.salary = msg.value;

newJob.creator = msg.sender;



//Trigger event

NewJob(jobId, msg.sender, msg.value, timeOut);



// Append newJob to jobData

jobData[totalJob++] = newJob;



return jobId;

}



//Take job

function

takeJob (uint256 jobId)

public onlyValidMortgage(jobId) onlyValidId(jobId) onlyValidJob(jobId)

{

//Trigger event to log labor

TakeJob(jobId, msg.sender);



//Change working state

jobData[jobId].start = block.timestamp;

}



//Veiw job data

function

viewJob(uint256 jobId)

public onlyValidId(jobId) constant returns (

uint256 id,

address creator,

uint256 salary,

uint256 start,

uint256 end,

uint256 timeOut,

bytes title,

bytes description)

{

Job memory jobReader = jobData[jobId];

return (jobReader.id,

jobReader.creator,

jobReader.salary,

jobReader.start,

jobReader.end,

jobReader.timeOut,

jobReader.title,

jobReader.description);

}



}

Và mình viết thêm test case bằng JavaScript:

var Partime = artifacts.require("./PartTime.sol");



function createTx(from, to, value = 0, gas = 1000000, gasPrice = 20000000) {

return {

from: from,

to: to,

gas: gas,

gasPrice: gasPrice,

value: value

};

}



contract('Partime', function (accounts) {



it('should have 0 total part time job', function () {

return Partime.deployed().then(function (instance) {

return instance.totalJob.call();

}).then(function (totalJob) {

assert.equal(totalJob.valueOf(), 0, 'Total job was not equal to 0');

});

});



it('should able to add new job', function () {

return Partime.deployed().then(function (instance) {

return instance.createJob(((new Date()).getTime() / 1000 + 432000),

"This is tittle",

"This is description",

createTx(accounts[0], instance.address, web3.toWei('1', 'ether')));

}).then(function (totalJob) {

assert.equal(typeof (totalJob.valueOf()), 'object', 'Transaction was not triggered success');

});

});



it('should have total part time job geater than 0', function () {

return Partime.deployed().then(function (instance) {

return instance.totalJob.call();

}).then(function (totalJob) {

assert.equal(totalJob.valueOf() > 0, true, 'Total job was equal to 0' );

});

});



});

Bạn chú ý thấy mình đang thêm 1 job mới:

return instance.createJob(((new Date()).getTime() / 1000 + 432000),

"This is tittle",

"This is description",

createTx(accounts[0], instance.address, web3.toWei('1', 'ether')));

Đoạn code này có nghĩa là mình tạo ra 1 job có

  • Timeout: 5 ngày
  • Title: This is tittle
  • Description: This is description
  • Value: 1 Ethereum

Thực thi kiểm thử:

Smart contracts

Mình đã update source code tại https://github.com/chiro-hiro/part-time-dapp. Các bạn có thể clone về hoặc fork về viết cùng mình cho vui.

Dislaimer: Đây là thông tin cung cấp dưới dạng blog cá nhân, không phải thông tin tổng hợp hay lời khuyên đầu tư. Chúng tôi không chịu trách nhiệm về các quyết định đầu tư của bạn.

MỚI CẬP NHẬT

Glif tung ra chương trình 75 triệu point, có thể chuyển đổi thành token...

Trong bối cảnh chương trình point (điểm) ngày càng trở nên phổ biến như một cách khen thưởng cho mức độ tương tác và...

Bitwise nộp đơn đăng ký Ethereum ETF giao ngay cho SEC Hoa Kỳ

Bitwise đã nộp đơn đăng ký Ethereum ETF giao ngay cho SEC vào ngày 28 tháng 3. Công ty đã gửi biểu mẫu S-1 cho Bitwise...
XRP

Tỷ lệ giá trên doanh thu của XRP gần gấp đôi Nvidia

Tỷ lệ giá trên doanh thu của token XRP gần gấp đôi so với Nvidia, một trong những cổ phiếu được giao dịch nhiều...
SBF ngoi tu

Cái kết cho Sam Bankman-Fried: 25 năm tù

Từng một thời nắm trong tay hàng tỷ đô la, xây dựng một đế chế cường thịnh trong thị trường tiền điện tử nhưng...
solana

Tương lai của Solana có trở nên mờ mịt sau phán quyết SEC Hoa...

Vào thứ 4, tương lai của Solana trở nên u ám khi Thẩm phán Katherine Polk Failla của Quận Nam New York, Hoa Kỳ...

Tìm hiểu chi tiết về EIP-4844, Proto-Danksharding và Blob

EIP-4844 là bản nâng cấp Ethereum được thiết kế để giảm chi phí giao dịch, đặc biệt là trên Layer 2 và cải thiện...

OI của Dogecoin tăng lên 2 tỷ USD khi giá đạt mức cao nhất...

Dogecoin (DOGE) đã tăng lên mức cao nhất kể từ tháng 12/2021 vào ngày thứ Năm trong bối cảnh tâm lý lạc quan và...

BlobScriptions là gì mà khiến Ethereum L2 tắc nghẽn và phí tăng hơn 10.000%?

Sau khi Dencun được triển khai thành công trên mainnet Ethereum với kỳ vọng cao rằng sẽ giúp giảm phí giao dịch L2 nhờ...

4 loại tiền điện tử có thể đạt mức ATH mới trong tháng 4

Tháng 3 là một tháng đặc biệt đối với thị trường tiền điện tử khi các nhà đầu tư chứng kiến giá Bitcoin đạt...

Avalanche chọn nhóm 15 startup Web3 đầu tiên cho chương trình tăng tốc Codebase

Avalanche đã chọn nhóm đầu tiên, bao gồm 15 startup web3 giai đoạn đầu, cho chương trình tăng tốc Codebase sau khi nhận được gần 250 đơn đăng ký từ hơn 30 quốc gia.  After receiving nearly 250...
near

Tiếp theo là gì cho NEAR khi các đường EMA vừa hình thành golden...

Giá NEAR đang cho thấy những dấu hiệu phục hồi đầy hứa hẹn, với số lượng giao dịch tăng trở lại sau lần giảm...
fantom

Fantom (FTM) chạm trán với mức kháng cự – Giá có thể ngăn chặn...

Hành động giá của Fantom (FTM) đang đối diện với một số ngưỡng kháng cự trong xu hướng tăng, dẫn đến nguy cơ giảm...

Prisma Finance bị hack, thiệt hại ban đầu là 11 triệu USD và có...

Giao thức DeFi hàng đầu Prisma Finance đã trở thành nạn nhân của một vụ hack tinh vi, dẫn đến khoản lỗ đáng kinh...

Liệu meme coin Poodl Inu (POODL) có thể tồn tại đến khi nào –...

 Thế giới tiền điện tử đã xuất hiện rất nhiều meme coin, điều thường thu hút rất nhiều người mới gia nhập thị trường....

CEO Blackrock ngạc nhiên trước phản ứng bán lẻ mạnh mẽ dành cho Bitcoin...

Các quỹ Bitcoin ETF giao ngay đã chứng kiến ​​dòng vốn ròng 243,4 triệu USD, tương đương 3.534,7 BTC vào ngày 27 tháng 3....
BNB

Dự báo giá BNB: Hợp nhất hay cú hích mới trên 645 đô la?

Giá BNB có thể đang chuẩn bị cho một giai đoạn hợp nhất, được biểu thị bằng số lượng giao dịch ổn định trong...