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

Updated: 30/04/2018 at 21:00

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.

Được đề cập trong bài viết
Bình luận
Đang tải
Mới cập nhật

Một cú sụt giảm mạnh đã phủ bóng lên thị trường tiền điện tử vào thứ Năm, khi Bitcoin (BTC) phá vỡ cấu trúc tăng ngắn hạn và thách thức ngưỡng hỗ trợ tâm lý quan trọng quanh $100.000. Đợt bán tháo ồ ạt đã nhanh chóng lan rộng, kích... ...

Thị trường tiền điện tử bất ngờ chao đảo trong phiên giao dịch ngày thứ Năm, sau khi Circle – công ty đứng sau đồng stablecoin USDC – chính thức lên sàn tại Sở Giao dịch Chứng khoán New York (NYSE). Sự kiện này dường như đã kích hoạt làn... ...

Theo báo cáo, BlackRock đã mua 2.704 Bitcoin với giá trị khoảng 283,9 triệu đô la vào ngày 5 tháng 6, cùng với 28.239 ETH trị giá 73,2 triệu đô la. Tổng giá trị mua trong đợt này của công ty lên tới 357 triệu đô la. Tài sản đang... ...

Dòng tiền của các tổ chức và phí giao dịch Ethereum tăng, tương phản với hoạt động mạng lưới chậm chạp và sự thận trọng trên thị trường hợp đồng tương lai Ether. TVL của Ethereum giảm tương phản với phí mạng lưới tăng Ether gặp phải khó khăn để... ...

James Wynn, một trader ẩn danh nổi tiếng nhờ việc biến các khoản đầu tư vào memecoin thành hàng triệu đô la, vừa tiết lộ đã mất 100 triệu đô la chỉ trong vài ngày sau chuỗi giao dịch đòn bẩy đầy rủi ro trên nền tảng Hyperliquid. Wynn, người... ...

Sau khi Maker (MKR) đổi tên thành SKY và triển khai tính năng staking, làn sóng quan tâm mới đã thu hút thêm nhiều trader cùng sự xuất hiện của một nhóm cá voi hoàn toàn mới. Tuy nhiên, bất chấp những tín hiệu tích cực, giá MKR vẫn giảm... ...

Giá Bitctoin (BTC) đã được củng cố trong phạm vi kể từ ngày 30 tháng 5. Theo dữ liệu kỹ thuật và thanh khoản, quá trình củng cố của Bitcoin có thể tiếp tục trong vài ngày nữa trừ khi các mức chính bị phá vỡ. Bitcoin phải lấy lại... ...

Elon Musk chính thức không còn muốn “đóng vai phụ” tại Washington. Vào thứ Năm, ông đã úp mở khả năng thành lập một đảng chính trị mới. “Đã đến lúc thành lập một đảng chính trị mới tại Mỹ để thực sự đại diện cho 80% người dân ở vị... ...

Giá Ethereum (ETH) gần đây dao động trong một vùng nhạy cảm, đặc biệt là sau khi tăng lên trên $2.600. Nguyên nhân là do giá gần đây đã tương tác với đường kháng cự giảm dần, một phần của mô hình nêm. Đợt kiểm tra lại ngưỡng kháng cự... ...

Cardano (ADA) tiếp tục giao dịch trong trạng thái squeeze hẹp, khi nỗ lực bảo vệ vùng hỗ trợ ngang tại mốc 0,63 đô la, đồng thời vẫn bị giới hạn bởi đường xu hướng giảm kéo dài. Diễn biến giá hiện tại cho thấy thế giằng co rõ rệt... ...

Xem thêm bài viết
Chọn chế độ hiển thị:
Bình thường Bảo vệ mắt Dark Mode