배송계약 작성하기

이번 포스팅에서는 블록체인 개발 키트를 사용하여 간단한 배송 계약을 만들어보겠습니다.

요구사항은 아래와 같습니다.

  1. 계약이 만들어지면 배송상태가 Pending
  2. 배송이 되면 배송상태가 Shipped로 변경된 후 이벤트 발생
  3. 배달이 완료되면 배송상태가 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 에 대해 알아보겠습니다

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를 입력합니다.

위와 같이 테스트를 모두 통과한 것을 볼 수 있습니다.

좋은 웹페이지 즐겨찾기