Libraryを利用したContractをデプロイする時はLibraryのアドレスをリンカーに教えないとContractがデプロイできません。(できても正常に動きません)
TruffleでLibraryとContractをlinkしてデプロイする方法はTruffleの公式ドキュメントにさらーっと書いてるだけなのでcontractの作成からtestまでの流れをまとめました。
今回作るContractはSolidityのlibraryにサンプルとして載ってるlibrary Setとcontract Cです。contract Cは名前が一文字だけだとうまくTruffleでコンパイルできなかったので、UseLibという名前に変更してます。
library Setとそれを使うcontract UseLibのソースは次の通りです。これをcontracts/以下に別々のファイルSet.solとUseLib.solとしてそれぞれ作成します。
- Set.sol
pragma solidity ^0.4.18;
library Set {
// We define a new struct datatype that will be used to
// hold its data in the calling contract.
struct Data {
mapping(uint => bool) flags;
}
// Note that the first parameter is of type "storage
// reference" and thus only its storage address and not
// its contents is passed as part of the call. This is a
// special feature of library functions. It is idiomatic
// to call the first parameter 'self', if the function can
// be seen as a method of that object.
function insert(Data storage self, uint value) public
returns (bool)
{
if (self.flags[value])
return false; // already there
self.flags[value] = true;
return true;
}
function remove(Data storage self, uint value) public
returns (bool)
{
if (!self.flags[value])
return false; // not there
self.flags[value] = false;
return true;
}
function contains(Data storage self, uint value) public
constant returns (bool)
{
return self.flags[value];
}
}
- UseLib.sol
pragma solidity ^0.4.18;
import 'contracts/Set.sol';
contract UseLib {
Set.Data knownValues;
function register(uint value) public {
// The library functions can be called without a
// specific instance of the library, since the
// "instance" will be the current contract.
require(Set.insert(knownValues, value));
}
// In this contract, we can also directly access knownValues.flags, if we want.
function contains(uint value) public constant returns(bool) {
return Set.contains(knownValues, value);
}
}そして、これらをデプロイするためのmigrationのソースです。linkerへの指示はこのmigrationファイルで設定します。
- 2_deploy_library_set.js
var Set = artifacts.require("Set");
var UseLib = artifacts.require("UseLib");
module.exports = function(deployer) {
// Use deployer to state migration tasks.
deployer.deploy(Set);
deployer.link(Set, UseLib)
deployer.deploy(UseLib);
};最後は正常にデプロイできたか確認するためのテストです。
- test_uselib.js
var UseLib = artifacts.require("UseLib");
contract('UseLibTest', function(accounts) {
it("Set value and contains check.", function() {
var strage;
return UseLib.deployed().then(function(instance) {
strage = instance;
return strage.register(5, {from: accounts[0]});
}).then(function () {
return strage.contains(5);
}).then(function(message) {
assert.equal(message, true, "value 5 is contains");
return strage.contains(3);
}).then(function(message) {
assert.equal(message, false, "value 3 is not contains");
});
});
});Truffleではコンパイル後、contractをデプロイする直前にlibrary addressの識別子(今回だと__Set__________)を実アドレスに置き換えてるみたいです。