はじめに
これは Ethereum Advent Calendar 2018 の3日目です。
2日目は Morinikiz さんです。
自己紹介
この記事について
Solidity ではメソッドの overload が可能なのですが、truffle で素直にテストを書いたらエラーになった、という事がありました。
今回はその際の回避方法について説明していきます。
準備
環境
$ truffle version
Truffle v4.1.14 (core: 4.1.14)
Solidity v0.4.24 (solc-js)
Solidity
overload しているメソッドを含む、このようなコントラクトを準備します。
pragma solidity ^0.4.22;
contract OverloadContract {
mapping(address => uint256) internal voteMap;
event Vote(
address indexed _to,
uint256 _count
);
event Clear(
address indexed _to,
uint256 _clearCount
);
function vote(address _to) external {
voteMap[_to]++;
emit Vote(_to, 1);
}
function vote(address _to, uint256 _count) external {
voteMap[_to] += _count;
emit Vote(_to, _count);
}
function clear() external {
uint256 count = voteMap[msg.sender];
voteMap[msg.sender] = 0;
emit Clear(msg.sender, count);
}
}
テストコード
全てのメソッドを走らせるだけのシンプルなテストを用意します。
const OverloadContract = artifacts.require("OverloadContract")
contract('OverloadContract', (accounts) => {
let obj
const voteTo = accounts[1]
before(async () => {
obj = await OverloadContract.new()
})
it('vote', async () => {
await obj.vote(voteTo)
})
it('vote with count', async () => {
await obj.vote(voteTo, 10)
})
it('clear', async () => {
await obj.clear({from: voteTo})
})
})
テストする
$ truffle test test/OverloadContract.test.js
Using network 'development'.
Contract: OverloadContract
1) vote
> No events were emitted
✓ vote with count (151ms)
✓ clear (55ms)
2 passing (379ms)
1 failing
1) Contract: OverloadContract
vote:
Error: Invalid number of arguments to Solidity function
at Object.InvalidNumberOfSolidityArgs (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/errors.js:25:1)
at SolidityFunction.validateArgs (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/function.js:74:1)
at SolidityFunction.toPayload (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/function.js:90:1)
at SolidityFunction.sendTransaction (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/function.js:163:1)
at SolidityFunction.execute (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/function.js:256:1)
at /usr/local/lib/node_modules/truffle/build/webpack:/packages/truffle-contract/contract.js:204:1
at new Promise (<anonymous>)
at /usr/local/lib/node_modules/truffle/build/webpack:/packages/truffle-contract/contract.js:155:1
at process._tickCallback (internal/process/next_tick.js:68:7)
Error: Invalid number of arguments to Solidity function
すなわちメソッドの引数が異なるよ!というエラーが返ってきます。
見ると vote(voteTo)
が失敗して vote(voteTo, 10)
が成功している。
つまり contract.vote
は引数2つの方が採用されていて、vote(voteTo)
だと引数が足らずにエラーとなっているようです。
こうなると overload したメソッドのテストが書けないので、困ってしまいます。
エラーを回避
[]
で引数を指定する
どちらの vote
を使うか引数指定によって切り替える事ができるので、それを利用できます。
const OverloadContract = artifacts.require("OverloadContract")
contract('OverloadContract', (accounts) => {
let obj
const owner = accounts[0]
const voteTo = accounts[1]
before(async () => {
obj = await OverloadContract.new({from: owner})
})
it('vote', async () => {
await obj.contract.vote['address'](voteTo, {from: owner})
})
it('vote with count', async () => {
await obj.contract.vote['address,uint256'](voteTo, 10, {from: owner})
})
it('clear', async () => {
await obj.clear({from: voteTo})
})
})
web3 1.0 系を使う
試してみたところ web3 1.0 系 であれば引数の数によって呼び出したい Solidity function を切り替えてくれるようで、こちらも利用できそうです。
truffle test で利用できる web3 は 0.20 系なので、1.0 系を使うように書く必要があります。
const OverloadContract = artifacts.require("OverloadContract")
const Web3 = require('web3')
contract('OverloadContract', (accounts) => {
let contract
const owner = accounts[0]
const voteTo = accounts[1]
before(async () => {
const web3Newer = new Web3(web3.currentProvider)
const obj = await OverloadContract.new({from: owner})
contract = new web3Newer.eth.Contract(obj.abi, obj.address)
})
it('vote', async () => {
await contract.methods.vote(voteTo).send({from: owner})
})
it('vote with count', async () => {
await contract.methods.vote(voteTo, 10).send({from: owner})
})
it('clear', async () => {
await contract.methods.clear().send({from: voteTo})
})
})
去年こちらにあるような事例が報告されていたのですが、どこかで解消された模様?
おわりに
これで安心して、自作したメソッドを網羅するスマートコントラクトのテストコードが書けそうです。
truffle の進化によってこのあたり解消する可能性もあるので、その際は truffle 標準なやり方にシフトするのが良いかと思います。
明日は
Hirata Takahiro さんです。