이번 포스팅에서는 블록체인 개발 키트를 사용하여 간단한 배송 계약을 만들어보겠습니다.
요구사항은 아래와 같습니다.
Pending
Shipped
로 변경된 후 이벤트 발생 Delivered
로 설정된 후 이벤트 발생 // 배송 상태는 pending, shipped, deliverd 세가지만 올 수있습니다.
enum ShippingStatus { Pending, Shipped, Delivered }
// enum으로 정의된 배송상태는 외부에 의해 변경이 되면 안되므로 private으로 선언합니다.
// status를 출력하면 이넘으로 정의된 pending, shipped, deliverd만 오게 됩니다.
ShippingStatus private status;
// 배송상태가 변경 될 때마다 description을 통해 어떤 이벤트가 발생되었는지 로그에 기록합니다.
event LogNewAlert(string description);
// 배송계약이 호출되면 생성자는 배송상태를 pending으로 초기 지정합니다.
constructor() public {
status = ShippingStatus.Pending;
}
// 배송이 시작되면 호출되는 함수
function Shipped() public {
status = ShippingStatus.Shipped;
// 함수가 호출되면 이벤트가 발생. 로그에 기록
emit LogNewAlert("Your package has been shipped");
}
// 배송이 완료되면 호출되는 함수
function Delivered() public {
status = ShippingStatus.Delivered;
emit LogNewAlert("Your package has arrived");
}
// 상태를 리턴 이 함수는 현재 상태를 변경할 수 없습니다.
function getStatus(ShippingStatus _status) internal pure returns (string memory) {
// Check the current status and return the correct name
if (ShippingStatus.Pending == _status) return "Pending";
if (ShippingStatus.Shipped == _status) return "Shipped";
if (ShippingStatus.Delivered == _status) return "Delivered";
}
// 상품의 배송상태를 리턴
function Status() public view returns (string memory) {
ShippingStatus _status = status;
return getStatus(_status);
}
이더리움 네트워크에 배포 할 수 있도록 마이그레이션을 추가하겠습니다.
migrations 디렉토리에 새 파일을 추가 후
아래와 같이 작성합니다.
const Shipping = artifacts.require("Shipping");
module.exports = function (deployer) {
deployer.deploy(Shipping);
};
그리고 배포를 진행하면 아래와 같이 계약내용을 알 수 있습니다.
[Execute command] 3_deploy_contracts.js ===================== [Execute command] Deploying 'Shipping' -------------------- [Execute command] > transaction hash: 0x36f0d59874901ced83c53c21948a5240df241368bee851ca65e9fa64aff475e4 [Execute command] - Blocks: 0 Seconds: 0 [Execute command] > Blocks: 0 Seconds: 0 [Execute command] > contract address: 0x9f1e3C8e5e9E392F8e99266Bf2bd500d634974Ff > block number: 21 > block timestamp: 1642918829 > account: 0xa043eC380Ffe97ED8C7426C7033265613Ccb1dEE > balance: 99.93014478 > gas used: 243707 (0x3b7fb) > gas price: 20 gwei > value sent: 0 ETH > total cost: 0.00487414 ETH[Execute command] [Execute command] - Saving migration to chain. [Execute command] > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.00487414 ETH Summary ======= > Total deployments: 3 > Final cost: 0.01849098 ETH [Execute command] [Execute command] Finished running command [Azure Blockchain] Deploy succeeded
이제 계약이 잘 작성되었는지 테스트를 해보겠습니다.
테스트는 javaScript로 작성하겠습니다.
테스트코드를 작성하기 전에 async/await 에 대해 알아보겠습니다
스마트 컨트렉트는 비동기방식으로 대부분 이루어집니다.
비동기 방식을 처리하는 방법들에는 콜백함수, promise, async/await가 있습니다.
이를 사용하지 않는다면 함수가 끝나기 전에 다음 프로세스로 진행 될 수 있기 때문입니다.
이 테스트 코드에서는 async / await를 사용하겠습니다.
async는 promise객체를 반환합니다. 그리고 awite는 단어르 보면 알수 있듯이 '기다리다'입니다.
즉 promise가 이행될 때까지 기다리겠다는 의미입니다.
이를 참고하여 아래 코드를 작성하겠습니다.
const ShippingStatus= artifacts.require("Shipping");
contract('Shipping', () => {
it("should return the status Pending", async ()=> {
const instance = await ShippingStatus.deployed();
const status = await instance.Status();
assert.equal(status, "Pending"); // 예상되는 결과
});
it("should return the status Shipped", async ()=> {
const instance = await ShippingStatus.deployed();
await instance.Shipped();
const status = await instance.Status();
assert.equal(status, "Shipped"); // 예상되는 결과
});
it("should return the status Delivered", async ()=> {
const instance = await ShippingStatus.deployed();
await instance.Delivered();
const status = await instance.Status();
assert.equal(status, "Delivered"); // 예상되는 결과
});
});
다음은 이벤트가 잘 작동하는지를 테스트 해보아야합니다.
이벤트 테스트를 실행하기 위해선 라이브러리 설치가 필요합니다.
npm install truffle-assertions
명령어를 입력하여 라이브러리를 설치합니다.
const truffleAssert = require('truffle-assertions');
를 정의합니다.
다음은 작성한 이벤트가 잘 작동되는 지 확인하는 코드입니다.
it('should return correct event description', async()=>{
const instance = await ShippingStatus.deployed();
const delivered = await instance.Delivered();
truffleAssert.eventEmitted(delivered, 'LogNewAlert', (event) =>{
return event.description == 'Your package has arrived';
});
});
터미널에 truffle test
를 입력합니다.
위와 같이 테스트를 모두 통과한 것을 볼 수 있습니다.