solidity函数类型及truffle使用

2018-02-07 03:31:38

1、solidity类的多继承、重写

solidity类具有多继承的特性:

pragma solidity ^0.4.19

contract Animal1 {  
    uint age;
}

contract Animal2 {  
    string weight;
}

contract Dog is Animal1, Animal2 {  
    /** Dog 会继承 Animal1 及 Animal2 两个类 */
}

重写与其他语言相通,即子类的同名函数会覆盖从父类继承的方法:

pragma solidity ^ 0.4 .19;

contract Animal {  
    function testFunc() public pure returns(string) {
        return "Animal testFunc";
    }
}

/** 子类重写了从父类继承过来的方法,会以子类的方法为基准 */
contract Dog is Animal {  
    function testFunc() public pure returns(string) {
        return "Dog testFunc";
    }
}

2、solidity函数的访问权限

solidity函数分为四种访问权限:

  • private: 私有函数。内部正常访问,外部无法访问,子类无法继承。
  • internal: 内部函数。内部正常访问,外部无法访问,子类可继承。
  • public: 公共函数。内部正常访问,外部正常访问,子类可继承。
  • external: 外部函数。内部不能访问,外部正常访问,子类可继承。
pragma solidity ^0.4.19;

contract Animal {  
    /** public  公有:外部、内部、子类都可使用 */
    function testPublic() public pure returns (string) {
        return "public";
    }
    /** private 私有:合约内部可以正常访问 */
    function testPrivate() private pure returns (string) {
        return "private";
    }
    /** internal 内部:合约内部可以正常访问 */
    function testInternal() internal pure returns (string) {
        return "internal";
    }
    /** external 外部:只能供外部访问 */
    function testExternal() external pure returns (string) {
        return "external";
    }
    /** 未做任何修改时,使用pure */ 
    function f() public pure {
        testPublic();
        testInternal();
        testPrivate();
        //testExternal(); // 报错,只能供外部访问
    }
}

contract Dog is Animal {  
    /** 继承 public、internal、external 类型的函数 */
}

// Dog.testPublic() 继承,可用
// Dog.testInternal() 继承,不可用(internal函数外部无法访问)
// Dog.testExternal() 继承,可用
// Dog.f() 继承,可用

3、solidity函数中pureviewconstant的区别

solidity函数的完整声明格式为:

function 函数名(参数)  public|private|internal|external  pure|view|constant  无返回值|returns (返回值类型)  

首先来个测试案例,根据编辑器提示补齐函数类型,然后总结不同之处:

pragma solidity ^0.4.19;

contract Animal {  
    string homeAddress = "北京市";
    uint weight;

    /** pure */
    function getAge() public pure returns (uint) {
        return 30;
    }

    /** view */
    function getCurrentAddress() public view returns (address) {
        return msg.sender;
    }

    /** view */
    function getHomeAddress() public view returns (string) {
        return homeAddress;
    }

    function setWeight(uint w) public {
        weight = w;
    }

    /** constant/view都行 */
    function getWeight() public constant returns (uint) {
        weight = 200;
        return weight;
    }
}

结论如下:

  • 只有当函数有返回值的情况下,才需要使用pureviewconstant
  • pure: 当函数返回值为自变量而非变量时,使用pure
  • view: 当函数返回值为全局变量或属性时,使用view
  • constant: 可以理解为view的旧版本,与view是等价的

如果一个函数有返回值,函数中正常来讲需要有 pureviewconstant关键字,如果没有,在调用函数的过程中,需要主动去调用底层的call方法。

注:如果一个函数中带了关键字viewconstant,就不能修改状态变量的值。但凡是是带了这两个关键字,区块链就默认只是向区块链读取数据,读取数据不需要花gas,但是不花gas就不可能修改状态变量的值。写入数据或者是修改状态变量的值都需要花费gas。

4、truffle初识

truffle是以太坊solidity编程语言的开发框架。

1.安装truffle

cnpm i -g truffle

2.创建项目工程

mkdir truffle && cd truffle  
truffle init  

3.项目结构
contracts目录下存的是solidity合约代码 migrations中存的是js脚本 test中存的是测试用例

4.编写代码、部署、调试
contracts中新建Hello.sol文件,代码如下:

pragma solidity ^0.4.17;

contract Hello {

    string weight = "18cm";
    string height = "180cm";

    function getAge() public pure returns (uint){
        return 30;
    }

    function getWeight() public view returns (string) {
        return  weight;
    }

    function getHeight() public constant returns (string) {
        return height;
    }

    function test() public returns (uint) {
        return 250;
    }
}

注意:

  • 类名Hello需要跟文件名Hello.sol保存一致
  • Migrations.sol文件不能删除

然后在migrations目录下添加对应的js脚本2_depoly_hello.js:

var myHello = artifacts.require("./Hello.sol");

module.exports = function(deployer) {  
  deployer.deploy(myHello);
};

代码添加完后,打开终端,切换到项目所在路径,执行:

//启动测试网络
truffle develop

//编译
compile

//将合约部署到本地测试网络,成功后会返回合约地址(如:0x75c35c980c0d37ef46df04d31a140b65503c0eed)
migrate 

//通过合约地址,得到合约对象,赋值给变量c
var c;  
Hello.at('0x75c35c980c0d37ef46df04d31a140b65503c0eed').then((obj) => {  
    c = obj;
})

//调用合约暴露的方法
c.getAge()

//如果合约中暴露出的有返回值的函数,没有用 pure/view/constant 声明,则需要调用底层的 call 方法才能调用方法
//如上面代码中的test方法
c.test.call()

//修改完代码,编译后,重新部署时需重置之前的合约
migrate --reset  

补充:调用migrate编译之后会build文件夹,存储的是编译之后生成的json文件,而这个json文件就是合约部署在虚拟机中的形式。

编译生成的的json文件中,有两个重要的额键值:

abi:通俗讲,abiapi类似,都是接口abi是合约的二进制接口。

bytecode:是合约代码的16进制码

通过abibytecode就能完成合约的部署。

5、基本值类型、引用类型

uint为值类型,只能深拷贝 string为引用类型,既可以深拷贝,也可以浅拷贝

uintstring深拷贝(默认的声明方式即为深拷贝):

string a = "100";  
uint b = 100;

// 浅拷贝
// string aa 等同于 string memory aa
function m(string aa) private {  
    aa = "1000";
}
function n(uint bb) private {  
    bb = 1000;
}

function f() public {  
    m(a)
    n(b)
}

string类型浅拷贝(加storage关键字):

string a = "100";  
function f() public {  
    m(a)
}

// 深拷贝
// memory(深拷贝)、 storage(浅拷贝)
// 当函数参数为 storage 类型时,函数类型只能为 private 或 internal,否则报错
function m(string storage aa) private {  
    //aa = "1000"; // string不能直接修改,需要转换为可变的字节数组
    bytes(aa)[0] = '6';
}

function getA() public view returns (string) {  
    return a;
}
区块链学习 - solidity合约部署

区块链原理 通过https://anders.com/blockchain/hash.html可以直观的了解hash、block(区块)、blockchain(区块链)、distributed(分布)、tokens(代币)各个概念。 开发环境配置 1、 MetaMask钱包 1.MetaMask是什么? MetaMask是一款在谷歌浏览器Chrome上使用的插件类型的以太坊钱包,该钱包不需要下载,只需要在谷歌浏览器添加对应的扩展程序即可,非常轻量级,使用起来也非常方便。 2.MetaMask安装 chrome浏览器安装MetaMask,直接用MetaMask创建钱包或者通过myetherwallet.com创建钱包,然后用MetaMask导入钱包私钥即可。 开发测试时,最好新建一个测试钱包,万一自己的币搞没就裂了~~ 3.MetaMask常用功能 如上图所示,第一个为正式网络,也就是ETH的公链,真实的币就存在公链上。后两个是两个测试网络,点击后便会切换到测试网络,钱包的地址也会随之改变。为了测试方便,在测试网络的钱包中免费获取一些测试用的代币。 4.测试代币获取 在Ropsten Test

基于React+truffle的完整智能合约构建

内容:使用solidity的truffle框架开发智能合约,前端使用react框架,最终完成智能合约从前端到后端,从开发到部署的完整流程。 1、truffle安装 在nodejs安装完成的环境下,全局安装truffle:cnpm i -g truffle。 Truffle Boxes是truffle框架集成的脚手架工具,可以使用这个脚手架快捷的生成完备的DAPP的项目结构,其中集成了前端视图、编译压缩工具等。可以在http://truffleframework.com/boxes/中查看并选择合适的模板来进行项目初始化。 2、项目初始化 这里我在http://truffleframework.com/boxes/上选择react模板来开发DAPP,直接在终端执行truffle unbox React即可完成项目的初始化,期间需要安装nodejs依赖,耐心等待即可(都没个安装进度提示,差评!)。 ludis@MacBook -> ~/Desktop/golang -> mkdir truffle && cd