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

Solidity Library详解
本文深入探讨Solidity中的Library概念,解释其如何实现代码重用,提高智能合约的可维护性和可读性。通过实例展示了Library的创建和使用,以及部署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”中获取,然后部署到区块链上。

根据区块链网络中心化程度的不同,分化出3种不同应用场景下的区块链:(1)全网公开,无用户授权机制的区块链,称为公有链;(2)允许授权的节点加入网络,可根据权限查看信息,往往被用于机构间的区块链,称为联盟链或行业链;(3)所有网络中的节点都掌握在一家机构手中,称为私有链。联盟链私有链也统称为许可链,公有链称为非许可链。  公有区块链系统 公有链中,任何节点无须任何许可便可随时加入或脱离网络。从最早的比特币系统人手介绍公有链系统的发展现状。 点对点电子现金系统:比特币与传统分布式系统的C/S , B/S或三层架构不同,比特币系统基于P2P网络,所有节点对等,且都运行同样的节点程序。节点程序总体上分为两部分:一部分是前台程序,包括钱包或图形化界面;另一部分是后台程序,包括挖矿、区块链管理、脚本引擎及网络管理等。区块链管理:涉及初始区块链下载、连接区块、断开区块、校验区块保存区块,以及发现最长链条的顶区块。内存池管理:即交易池管理。节点将通过验证的交易放在一个交易池中,并准备好将其放入下一步挖到的区块中。邻接点管理:当一个新比特币节点初始启动时,它需要发现网络中的其他节点,并与至少一个节点连接。共识管理:比特币中的共识管理包括挖矿、区块验证交易验证规则。比特币采用PoW共识机制,依赖机器进行哈希运算来获取记账权,同时每次达成共识需要全网共同参与运算,允许全网50%节点出错。密码模块:比特币采用RIMEMDSHA-256算法及Base-58编码生成比特币地址。签名模块:比特币采用椭圆曲线secp256k1及数字签名算法ECDSA来实现数字签名并生成公钥。脚本引擎:比特币的脚本语言是一种基于堆栈的编程脚本,共有256个指令,是非图灵完备的运算平台,没有能力计算任意带复杂功能的任务。本课程从零到一带领你实践一个小型公链。 智能合约,Smart Contract,是一种旨在以信息化方式传播、验证或执行合同的计算机协议。 区块链领域的智能合约有以下特点:规则公开透明,合约内的规则以及数据对外部可见;所有交易公开可见,不会存在任何虚假或者隐藏的交易。 所以我们常说区块链技术具有“公开透明”“不可篡改”的特点,这些其实都是智能合约赋予区块链的。 程序员的世界里一致有个认知:相较于程序机器,人更加不可控。人会作恶,但是代码并不会主观主动作恶。 而传统的契约行为,都是由人来制定规则,由人去执行。当然,遇到边界问题或者异常,也是由人去做界定。 但有了智能合约之后,这些就变得不一样了。 开发者通过智能合约去制定一套规则,然后发布到线上,人与智能合约进行交互,由机器去完成业务的部分,这样就规避了由人来做执行时可能造成的作弊行为。 静态类型的编程语言——Solidity,是以太坊的智能合约实现的编程语言,运行在以太坊的虚拟机 Ethereum Virtual Machine(EVM)上。 借由 Solidity,开发人员能够编写出可自我执行的应用程序,该程式可被视为一份具权威性且永不可悔改的交易合约,对已具备程式编辑能力的人而言,编写 Solidity 的难易度就如同编写一般的编程语言。 关于智能合约的应用,大名鼎鼎的 ICO 就是其中之一。除了 ICO 之外,与物联网结合赋能智能家居、投票等等,都是智能合约的应用场景。换言之,能够用机器去实现既定的规则、提高效率,且能够规避人类的作弊行为的场景,基本都是智能合约的应用场景。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值