一种非常简单的模拟Solidity智能合约交易的方法

Posted MateZero

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一种非常简单的模拟Solidity智能合约交易的方法相关的知识,希望对你有一定的参考价值。

一种非常简单的模拟Solidity智能合约交易的方法

我们知道,在MetaMask调用合约时,会模拟执行一次,如果调用失败,会提前显示失败并问你是否要强制执行。这个功能很有用的,那么我们自己能不能实现类似的功能呢?

答案是肯定的,并且也相当简单。

示例合约

我们先看测试合约:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract MockTest 
    uint public x = 5;

    address public owner;

    constructor() 
        owner = msg.sender;
    

    modifier onlyOwner 
        require(msg.sender == owner, "only owner");
        _;
    

    function changeX(uint _x) external onlyOwner returns(uint value, address sender) 
        x = _x;
        return (_x * _x,msg.sender);
    

合约很简单,只有管理员能改变x的值并且进行相关计算(操作)。这里只是简单计算了x的平方来模拟合约中复杂的操作过程。

那我们有时候想自己模拟运行一下,并得到相应的操作结果,能否实现呢?

答案就在下方 -_- !

模拟方法

请看下面的单元测试文件:

const  expect,assert  = require("chai");
const  ethers  = require("hardhat");

describe("Mock test", function () 

    let instance;

    beforeEach(async () => 
        const MockTest = await ethers.getContractFactory("MockTest");
        instance = await MockTest.deploy();
    );

    it("Call without owner will be failed" , async () => 

        let data = instance.interface.encodeFunctionData("changeX",[9]);
        let AddressOne = ethers.utils.getAddress("0x" + "0".repeat(39) + "1");

        let transaction = 
            from:AddressOne,
            to:instance.address,
            data
        ;
        try 
            await ethers.provider.call(transaction);
        catch(e) 
            assert.equal(e.message,"VM Exception while processing transaction: reverted with reason string 'only owner'");
            return;
        
        throw("Test Failed");
    );

    it("Call with owner will be successful", async () => 

        let data = instance.interface.encodeFunctionData("changeX",[9]);
        let owner = await instance.owner();

        let transaction = 
            from:owner,
            to:instance.address,
            data
        ;
        let result =  await ethers.provider.call(transaction);
        const value,sender = instance.interface.decodeFunctionResult("changeX",result);
        expect(value).to.be.equal(81);
        expect(sender).to.be.equal(owner);
        expect(await instance.x()).to.be.equal(5);
    );
);

运行单元测试的结果为:

  Mock test
    ✔ Call without owner will be failed (40ms)
    ✔ Call with owner will be successful


  2 passing (619ms)

那么,有的小伙伴要问了,如果别人把这个owner设置为私有变量,我怎么去获取这个owner呢?

记住,私有变量只是对链上合约不可见,对链下是没有办法隐藏的。以太坊一切可是公开透明的。

例如我们可以通过观察合约部署者,平常具有管理员权限的函数的调用,直接读取相应插槽等方法来获取这个owner

以上是关于一种非常简单的模拟Solidity智能合约交易的方法的主要内容,如果未能解决你的问题,请参考以下文章

使用 Browser-solidity 在 Go-Ethereum 上进行简单的智能合约部署

使用ethers.js部署Solidity智能合约

Solidity实现简单的智能合约

我们可以在智能合约中使用 Solidity 获取过去区块中记录的交易信息吗?

智能合约语言 Solidity 教程系列8 - Solidity API(特殊的变量及函数)

智能合约语言 Solidity 教程系列8 - Solidity API(特殊的变量及函数)