测试智能合约 (solidity/truffle)

Test for smart contract (solidity/truffle)

我有这些代码行

// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;

contract wasteManagement2 {
    struct Route{
        string date; //struct date{ uint day; uint month; uint year;}
        // eg. monday
        string vehicle;
        string driver; //struct driver { string name, string lname, uint id}
        string location;
        string routebinId;
    }

    mapping (uint => Route) public routes;
    uint public routeCount;

    constructor()  {
        routeCount = 0;
    }

    function setRoute(string memory _date,string memory _vehicle, string memory _driver, string memory _location, string memory _routebinId) public{
        routes[routeCount] = Route (_date,_vehicle, _driver, _location, _routebinId);
        routeCount++;
    }

    function getRoute(uint _routeCount) public view returns(Route memory){
        return routes[_routeCount];
    }
}

并且我想测试一下合同,如果发生 6000 多个不同的注册管理机构,它将如何运作,需要花费多少。提前致谢。

这是目前的测试文件:

const Routes = artifacts.require("Routes");

contract ("Routes", (accounts) => {
    before(async () =>  {
        instance = await Routes.deployed()
    })

    it ('ensures that the array is empty', async () => {
        let count =  await instance.setRoute()
        assert.equal(count, 0, 'The array should be empty')
    })
})

Stack Exchange:

有手动计算gas成本的解释

I'm using the Yellow Paper, Appendix G, page 25 as reference.

The cost of gas to deploy your contract can be calculated like this:

21000 because all transactions pay this (Gtransaction) 32000 because is a contract creation (Gcreate) Your transaction will have input data, which will cost you in gas:

4 for each byte with value zero in your input data (Gtxdatazero) 68 for each non zero byte in your input data (Gtxdatanonzero) Initialising variables and running the constructor, costs you:

20000 for each SSTORE when the storage value is set to non-zero(Gsset) 5000 for each SSTORE when the storage value is set to zero (Gsreset) additional gas for each OPCODE your constructor is executing (see reference) Finally, you have to pay to store your code, and that will cost you:

200 for each byte of code you store on the state. When you compile your code, you get your bytecode, and that's where > you can find all the OPCODES your smart contract executes.

You will also get your running (or deployed) bytecode, which is the > code that will be stored on the state. It's equal to the bytecode minus the initialisation and constructor code (that are not stored in the state).

How to know the code size using a truffle javascript test file You can use the following code in a js file inside the test folder:

var YourContract = artifacts.require("YourContract");

contract('YourContract', function(accounts) {
  it("get the size of the contract", function() {
    return YourContract.deployed().then(function(instance) {
      var bytecode = instance.constructor._json.bytecode;
      var deployed = instance.constructor._json.deployedBytecode;
      var sizeOfB  = bytecode.length / 2;
      var sizeOfD  = deployed.length / 2;
      console.log("size of bytecode in bytes = ", sizeOfB);
      console.log("size of deployed in bytes = ", sizeOfD);
      console.log("initialisation and constructor code in bytes = ", sizeOfB - sizeOfD);
    });  
  });
});

Afterwards, run truffle test.

如果您想自动执行此过程,article on Medium 也可能有所帮助:

Measuring Gas Cost In order to determine how much gas (many cycles) of the EVM (Ethereum virtual machine) each option takes, we need to measure them. There are many useful blockchain features such as a system function called gasleft() that reports how much gas is left for the running contract, and it is also possible to pass functions to other functions. We can use these features to provide a function that will measure the gas cost of a given function, fun:

function GasCost(string memory name, 
    function () internal returns (string memory) fun) 
    internal returns (string memory) 
{
    uint u0 = gasleft();
    string memory sm = fun();
    uint u1 = gasleft();
    uint diff = u0 - u1;
    return concat(name, " GasCost: ", stringOfUint(diff), 
                " returns(", sm, ")");
}

我将展示如何计算调用函数的成本,然后您必须为 6000 个注册表执行 for 循环。假设您正确初始化合约:

const result = await instance.setRoute()

如果你console.log(result你得到这个对象

result {
  tx: '0x1550f6f4f3e7abe0e2d39a43127714e4422e548e6a45d54a3fe12c2ed8b1c180',
  receipt: {
    transactionHash: '0x1550f6f4f3e7abe0e2d39a43127714e4422e548e6a45d54a3fe12c2ed8b1c180',
    transactionIndex: 0,
    blockHash: '0x6d13903f40a7b3c989b79accf70d5bb1f7ef673ee59a0eb534b09d375db1bd7e',
    blockNumber: 1249,
    from: '0xd76536f6b5722f78d444ba0c3b8aae84b7a226ba',
    to: '0xde7b6dd9d647e4249f85ac15e5f7c88e7e424fa',
    gasUsed: 31167,
    cumulativeGasUsed: 31167,
    contractAddress: null,
    logs: [],
    status: true,
    logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    rawLogs: []
  },
  logs: []
}

要获取 gas 成本,请编写一个函数:

const getGas = async (result) => {
  const tx = await web3.eth.getTransaction(result.tx);
  const gasUsed = toBN(result.receipt.gasUsed);
  const gasPrice = toBN(tx.gasPrice);
  const gas = gasUsed.mul(gasPrice);
  return gas;
};

toBN 是辅助函数:

const toBN = (value) => web3.utils.toBN(value);

终于得到gas费用:

const result = await instance.setRoute()
const gas = await getGas(result);