【一步步一起学DApp开发】(三)Solidity语言讲解 | 用Solidity编写智能合约 下

简介: 【一步步一起学DApp开发】(三)Solidity语言讲解 | 用Solidity编写智能合约

控制结构

  • if-else
  • while
  • for
  • break\continue
  • return
  • ?:
  • 等等
//结构上和其他语法没有什么差异
contract sample {
  int a = 12;
  int[] b;
  function sample() {
    if(a == 12) {}
    else if(a==34){}
    else {}
    var temp = 10;
    while(temp<20)
    {
      if(temp==17){break;}
      else {continue;}
    }
    temp++;
  }
  for(var m=0;m<b.length;m++){
  }
}

用new 操作符创建合约

一个合约可以使用new关键字来创建一个新合约。

例如:

contract sample1 {
  int a;
  function assign(int b){
    a = b;
  }
}
contract sample2 {
  function sample2(){
    sample1 s = new sample1(); //注意写法
    s.assign(12);
  }
}

异常

异常的抛出分为自动和手动。

若你想手动抛出异常,可以使用throw手动抛出。

注意,异常抛出后,会撤销对状态和余额的所有改变。

contract sample {
  function myFunction () {
    throw;
  }
}

函数调用

  • 内部函数调用:一个函数在同一个合约中调用另一个函数
  • 外部函数调用:一个函数调用另一个合约的函数。

外部函数调用–this关键字

合约sample1

contract sample1 {
  int a;
  function sample1(int b) payable {
    a = b;
  }
  function assign(int c){
    a = c;
  }
  function makePayment(int d) payable {
    a = d;
  }
}

合约sample2

contract sample2 {
  function hello() {}
  function sample2(address addressOfContract){
    sample1 s = (new sample1).value(12)(23);
    s.makePayment(22);
    s.makePayment.value(45)(12);
    s.makePayment.value(4).gas(900)(12);
    this.hello(); //利用this调用外部合约函数
    sample1 s2 = sample1(addressOfContract);
    s2.makePayment(112);
  }
}

注意:使用this关键字进行的调用称为外部调用。在函数中,this关键字代表当前合约实例

合约功能——深入理解合约

可见性

可见性定义了谁可以看到它,函数和状态变量有四种可见性:external、public、internal和private

  • 函数可见性,默认为 public
  • 状态变量可见性,默认为 internal
  • external:外部函数只能由其他合约调用,或者通过交易调用——this.f()
  • public:公共函数和状态变量可以用所有可行办法访问
  • internal:内部函数和状态变量只可以内部访问,即从当前合约内和继承它的合约访问。不可以使用this访问它
  • private:私有函数和状态变量类似于内部函数,但是继承合约不可以访问它们

示例

contract sample1 {
  int public b = 78;
  int internal c = 90;
  function sample1() {
    this.a();//外部访问
    b = 21;//内部访问
  }
  function a() external {}
}
contract sample2 {
  int internal d = 9;
  int private e = 90;
}
//sample3 继承 sample2
contract sample3 is sample2 {
  sample1 s;
  function sample3() {
    s = new sample1();
    s.a();//外部访问
  }
}

函数修改器(较难理解)

先看一个修改器的例子:

contract sample {
    int a = 90;
    modifier myModifier1(int b) {
        int c = b;
        _;
        c = a;
        a = 1;
    }
    modifier myModifier2 {
        int c = a;
        _;
    }
    modifier myModifier3 {
        a = 96;
        return;
        _;
        a = 99;
    }
    modifier myModifier4 {
        int c = a;
        _;
    }
    function myFunction() myModifier1(a) myModifier2 myModifier3 returns (int d) {
        a = 2;
        return a;
    }
}

注:

  • 在修改器中,无论下一个修改器体或者函数体二者哪个先到达,都会被插入到“_;”出现的地方。

回退函数

即一个合约中唯一一个未命名函数。

  • 不能有实参
  • 不能有返回值
  • 如果其他函数都不能匹配给定的函数标识符,那么就执行回退函数
  • 如果你想让你的合约接收以太币,就必须实现回退函数
contract sample {
  function() payable {
  }
}

继承

即使一个合约继承自其他多个合约,在区块链上也只会创建一个合约。

父合约的代码总是会被复制到最终合约里。

  • 关键字 is

示例

contract sample1 {
  function a(){}
  function b() {}
}
//合约2继承自合约1
contract sample2 is sample1{
  function b() {}
}
contract sample3{
  function sample3(int b){
  }
}
//合约4继承自合约1与合约2
contract sample4 is sample1,sample2 {
  function a(){}
  function c() {
    a();
    //执行合约1中的a方法
    sample1.a();
    //执行合约2中的b方法
    b();
  }
}

关键字super

  • 用于引用最终继承链中的下一个合约
    示例
contract sample1{
}
contract sample2{
}
contract sample3 is sample2{
}
contract sample4 is sample2{
}
contract sample5 is sample4{
  function myFunc(){}
}
contract sample6 is sample1,sample2,sample3,sample4,sample5 {
  function myFunc() {
  //执行sample5中的myFunc方法
    super.myFunc();
  }
}

抽象合约

  • 仅包含函数原型而不包含函数实现的合约
  • 抽象合约不能被编译
  • 如果一个合约继承自抽象合约且不重写,那么它自己也是抽象合约

示例

contract sample1{
  function a() returns (int b);
}
contract sample2{
  function myFunc(){
    sample1 s = sample();
    s.a();
  }
}

库的目的是在一个特定地址中只部署一次,其其代码可供复用。

示例-使用solidity的math库:

library math
{
  function addInt(int a,int b) return (int c){
    return a+b;
  }
}
contract sample {
  function data() returns (int d){
    return math.addInt(1,2);//调用math库中的addInt方法
  }
}

使用场景

  • 如果有许多合约,这些合约有一些共同的代码,那么可以把它们共同的代码部署成一个库。这么做的好处是这样能节省gas。因为gas的大小依赖于合约的规模。

返回多个值

示例:

contract sample{
  function a() returns (int a,string c){
      return (1,"m");
  }
  function b(){
    int A;
    string memory B;
    (A,B) = a();// A =1,B = "m"
    (A,)  = a();// A =1
    (,B) = a(); //B = "m"
  }
}

全局变量

  • 特殊变量
  • 特殊函数

1、区块和交易属性

  • block.blockhash(uint blockNumber) returns (bytes32) //区块哈希值
  • block.coinbase(address) //当前区块矿工的地址
  • block.difficulty(uint) //当前区块的难度值
  • block.gaslimit(uint) //当前区块的gas上限,定义了整个区块中的所有交易最多能消耗多少gas
  • block.number(uint) //当前区块的序号
  • block.timestamp(uint) //当前区块的时间戳
  • msg.gas(uint) //当前剩余的gas
  • msg.sender(address) //当前调用发起人的地址
  • msg.sig(bytes4) //调用数据的前四个字节
  • msg.value(uint) //这个消息所附带的货币量,单位为wei
  • now(uint) //当前区块的时间戳,等同于block.timestamp
  • tx.gasprice(uint) //交易的gas价格
  • tx.origin(address) //交易的发起人

2、地址类型相关

  • .balance(uint256) //地址余额,单位为wei
  • .send(uint256 amount) returns(bool) //发送指定数量的wei到地址

3、合约相关

  • this //当前合约
  • selfdestruct(address recipient) //销毁当前合约,把其中的资金发送到指定地址

以太币单位

一个数字可以用wei、finney、szabo、Ether等单位转换为不同面值的以太币。默认使用wei为单位。

存在、真实性和所有权合约的证明

下面我们要实现一个“证明文件所有权”的合约。

分以下几步来进行:

  • 1、成对存储文件的哈希和文件所有者的名字,用以实现所有权证明(PoO)
  • 2、成对存储文件的哈希和区块的时间戳,用以实现文件在某个特定时间存在的证明(PoE)
  • 3、存储哈希自身,用以证明文件的真实性。如果文件被修改,其哈希也会被改变。更改过的文件的哈希会使得合约无法发现文件,从而证明文件被修改过。

代码如下:

contract Proof{
  struct FileDetails {
    uint timestamp;
    string owner;
  }
  mapping (string => FileDetails) files;
  event logFileAddedStatus(bool status,uint timestamp,string owner,string fileHash);
  //存储文件所有者
  function set(string owner,string fileHash){
    if(files[fileHash].timestamp==0){
      files[fileHash] = FileDetails(block.timestamp,owner);
      //触发一个事件以至于前端应用知道文件的存在
      logFileAddedStatus(true,block.timestamp,owner,fileHash);
    }else {
    //告诉前端文件存在,但是不能存储
      logFileAddedStatus(false,block.timestamp,owner,fileHash);
    }
  }
  //获取文件信息
  function get(string fileHash) returns (uint timestamp,string owner){
    return (files[fileHash].timestamp,files[fileHash].owner);
  }
}

编译和部署合约

这里,我们使用solcjs和Browser Solidity ,其中solcjs允许在node.js中以编程方式编译Solidity,而Browser Solidity是一个适用于小型合约的IDE。

至此,我们将Solidity语言进行了基本的讲解,下一节中我们将介绍如何使用web3.js开发DApp前端。


相关文章
|
7月前
|
前端开发 JavaScript 数据挖掘
《Solidity 简易速速上手小册》第9章:DApp 开发与 Solidity 集成(2024 最新版)(下)
《Solidity 简易速速上手小册》第9章:DApp 开发与 Solidity 集成(2024 最新版)
61 1
|
4月前
|
存储 安全 编译器
Metamask项目方给Solidity程序员的16个安全建议
文章是Metamask项目方Consensys在2020年发布的关于智能合约安全的博文,提供了16条Solidity程序员的安全建议,包括正确使用assert()、require()、revert()函数,避免使用tx.origin进行授权,注意整数除法舍入问题等,以帮助开发者提高智能合约的安全性。
43 0
|
7月前
|
存储 供应链 安全
《Solidity 简易速速上手小册》第1章:Solidity 和智能合约简介(2024 最新版)
《Solidity 简易速速上手小册》第1章:Solidity 和智能合约简介(2024 最新版)
207 1
|
7月前
|
存储 前端开发 安全
《Solidity 简易速速上手小册》第9章:DApp 开发与 Solidity 集成(2024 最新版)(上)
《Solidity 简易速速上手小册》第9章:DApp 开发与 Solidity 集成(2024 最新版)
107 0
|
存储 前端开发 Unix
一文聊透 Solidity 语法:助你成为智能合约专家(二)
一文聊透 Solidity 语法:助你成为智能合约专家
108 0
|
存储 Rust JavaScript
一文聊透 Solidity 语法:助你成为智能合约专家(一)
一文聊透 Solidity 语法:助你成为智能合约专家
248 0
|
存储 区块链 数据库
Solidity开发智能合约
一个简单的智能合约 在Solidity中,一个合约由一组代码(合约的函数)和数据(合约的状态)组成。合约位于以太坊区块链上的一个特殊地址。
1521 0
|
Rust 安全 JavaScript
新手必看!Rust 初学者如何编写 Gear 智能合约(1)
本文将主要说明如何使用 Rust 在 Gear 区块链网络上创建一个简单的去中心化应用程序。
363 0
新手必看!Rust 初学者如何编写 Gear 智能合约(1)
|
存储 编译器 区块链
【一步步一起学DApp开发】(三)Solidity语言讲解 | 用Solidity编写智能合约 上
【一步步一起学DApp开发】(三)Solidity语言讲解 | 用Solidity编写智能合约
573 0
|
Java 区块链
【智能合约】Solidity 进阶编程 | 注意一下合约中的细节
目录 1. 内置的全局变量 2. 错误处理 3. 访问函数 4. 创建合约 5. 合约继承 6. 修饰器modifier 最后
256 0
【智能合约】Solidity 进阶编程 | 注意一下合约中的细节