区块链solidity中library的使用和部署

在Solidity中什么是library?
大家可能听说过DRY原则(don’t repeat yourself)。在大型程序中,代码的重用是十分重要的,并且代码重用可以提高整体代码的可维护性和可读性。在solidity具体编程的时候,DRY原则可能不像其他语言一样显而易见。

Solidity提供了Library的概念来实现代码重用,它可以被多个不同的智能合约调用。大家可以把library想象成在面向对象语言中的static类中的static函数。 Library在部署到区块链上时是很类似普通的智能合约的。这也允许大家可以使用别人部署的Library,但要十分小心的是使用非自己建立的、部署的library需要承担一定的安全风险。

现在我们看看如何构建一个Library并使用它!

建立和使用Library
我们要建立一个使用Library的合约来维护一个由人名到年龄的mapping结构。我们使用library关键字来创建一个library,这和创建contract十分类似。但不像contract,在library中我们不能定义任何storage类型的变量。因为library只是意味着代码的重用而不是进行state的状态管理。
 

// Code for StringToUintMap.sol

pragma solidity ^0.4.15;

library StringToUintMap {
    struct Data {
        mapping (string => uint8) map;
    }

    function insert(
        Data storage self,
        string key,
        uint8 value) public returns (bool updated)
    {
        require(value > 0);

        updated = self.map[key] != 0;
        self.map[key] = value;
    }

    function get(Data storage self, string key) public returns (uint8) {
        return self.map[key];
    }
}

在以上的library代码中,我们定义了一个名为Data的struct,它包含了一个由string到uint8的mapping结构,进行插入和获取的函数insert和get。我们传入了storage类型的Data,这样EVM就不需要在内存中再进行创建一个copy,而是直接从storage中传入一个引用。

让我们使用这个library建立一个合约来管理这个mapping结构吧!
 

// Code for PersonsAge.sol

pragma solidity ^0.4.15;

import { StringToUintMap } from "../libraries/StringToUintMap.sol";

contract PersonsAge {

    StringToUintMap.Data private _stringToUintMapData;

    event PersonAdded(string name, uint8 age);
    event GetPersonAgeResponse(string name, uint8 age);

    function addPersonAge(string name, uint8 age) public {
        StringToUintMap.insert(_stringToUintMapData, name, age);

        PersonAdded(name, age);
    }

    function getPersonAge(string name) public returns (uint8) {
        uint8 age = StringToUintMap.get(_stringToUintMapData, name);

        GetPersonAgeResponse(name, age);

        return age;
    }
}

首先我们使用import来导入我们想使用的library。

import { StringToUintMap } from "../libraries/StringToUintMap.sol";

在合约中,我们建立了一个private的变量StringToUintMap.Data,其类型是一个struct。我们定义了两个合约函数。第一个是addPersonAge。它的输入时name和age,然后调用StringToUintMap.insert将struct从storage中传入,最后触发PersonAdded事件。
函数getPersonAge调用了StringToUintMap.get来从mapping中获取age,然后触发GetPersonAgeResponse事件。

因此,我们可以看到创建library代码并使用它非常简单。但是问题是,当我们部署合约时,我们需要首先部署library的代码,然后在部署合约之前指向已部署的库地址。这个过程称为链接。

部署Library和合约
我们使用web3.py库与区块链进行交互,区块链使用testrpc模拟。
 

import json
import web3
import random
import time
import os

from web3 import Web3, HTTPProvider
from solc import compile_source
from web3.contract import ConciseContract

# Solidity source code
source_file_name = 'contract.sol'
with open(source_file_name, 'r') as f:
	source = f.read()

compiled_sol = compile_source(source) # Compiled source code
contract_id1, contract_interface1 = compiled_sol.popitem()
contract_id2, contract_interface2 = compiled_sol.popitem()
#contract_id, contract_interface = compiled_sol.popitem()
# web3.py instance
w3 = Web3(HTTPProvider('http://localhost:8545'))

# set pre-funded account as sender
w3.eth.defaultAccount = w3.eth.accounts[0]

# Instantiate and deploy contract
Lib = w3.eth.contract(abi=contract_interface1['abi'], bytecode=contract_interface1['bin'])

# Submit the transaction that deploys the contract
tx_hash = Lib.constructor().transact()

# Wait for the transaction to be mined, and get the transaction receipt
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)

libraryaddr = tx_receipt.contractAddress

os.system("solc -o ~/ --bin --overwrite --libraries StringToUintMap:"+libraryaddr+" contract.sol")

binfilename = "PersonsAge.bin"
with open(binfilename) as f:
	binstr = f.read()

Greeter = w3.eth.contract(abi=contract_interface2['abi'], bytecode=binstr)
# Create the contract instance with the newly-deployed address
tx_hash = Greeter.constructor().transact()
# Wait for the transaction to be mined, and get the transaction receipt
tx_receipt = w3.eth.waitForTransactionReceipt(tx_hash)

greeter = w3.eth.contract(
    address=tx_receipt.contractAddress,
    abi=contract_interface2['abi'],
)

greeter.functions.addPersonAge("Alice",20).transact({'gasPrice':1,'gas':3000000})

我们将library的code和contract代码一起写入contract.sol文件。首先Lib被部署到区块链上,然后通过tx_receipt中的contractAddress获得了部署library的地址。之后调用

os.system("solc -o ~/ --bin --overwrite --libraries IncMTree:"+libraryaddr+" contract.sol")

来编译和链接library库到contract.sol中的PersonsAge合约。
之后就可以将编译好的合约的bytecode从“PersonsAge.bin”中获取,然后部署到区块链上。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值