美文网首页
区块链Solidity中library的使用和部署

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

作者: SeanC52111 | 来源:发表于2018-08-30 22:15 被阅读0次

    在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”中获取,然后部署到区块链上。

    相关文章

      网友评论

          本文标题:区块链Solidity中library的使用和部署

          本文链接:https://www.haomeiwen.com/subject/gftjwftx.html