智能合约和solidity简介

原文链接:郭老师的备课资料

智能合约

首先要强调的是,以太坊和比特币的区别。比特币主要用途是用于进行交易,定位是数字货币的支付功能。以太坊相比比特币是一个巨大的提升,将区块链的应用边界从货币和支付扩大到了更广的领域(通过智能合约实现)。

区块链2.0是更宏观的对整个市场去中心化,利用区块链技术来转换许多不同的数字资产,通过转让来创建不同资产的价值。区块链技术的去中心化账本功能可以被用来创建、确认、转移各种不同类型的资产及合约。几乎所有类型的金融交易都可以被改造成在区块链上使用,包括股票、私募股权、众筹、债券和其他类型的金融衍生品如期货、期权等。

那什么是智能合约呢?

智能合约不是一定要用区块链来实现,很久之前就已经出现了:比如微信和支付宝的信用卡自动还款,也是一种智能合约。当还款日到了,还款条件也满足(支付宝的余额宝、微信支付余额或者银行储蓄卡中余额充足),系统会自动进行还款,这些都是智能合约,也没有使用区块链技术。

而使用区块链的话,结合不可篡改数据无法删除、修改,只能新增,保证了历史的可追溯,同时作恶的成本将很高,因为其作恶行为将被永远记录,同时拥有高可靠行,我们不用担心系统在条件被满足时不执行合约;然后就是去中心化和给我们带来的全网备份,完备的记录完全可以支持支持事后的审计,避免了中心化因素的影响。所以可以想象,以太坊通过在区块链上提供了图灵完备语言,打开了多么大的一个市场。

举一个例子,看看以太坊上的应用:
在这里插入图片描述
谜恋猫是世界首款区块链游戏。“区块链”是支持类似比特币这样的加密货币的运作技术基础。尽管谜恋猫不是数字货币,但它也能提供同样的安全保障:每一只谜恋猫都是独一无二的,而且100%归您所有。它无法被复制、拿走、或销毁。

迷恋猫官方将他们设计的迷恋猫合约发布到了以太坊上,并公布了合约内容,其中规定了0代猫只能有他们的CEO、COO来产生,并限定的0代猫最多产生的数量,以及玩家之间如何交易猫,两只猫咪之间如何繁育、猫咪备孕周期等等规则,以上规则已经在以太坊上做了公证,以后只能按照这套规则来进行游戏。

在区块链平台上的每只猫咪其实只是存在以太坊中的一段猫咪基因编码,该段基因编码决定了猫咪的属性、外貌等,迷恋猫官方在以太坊之外,提供了一个网站,在网站上将这些猫咪根据其基因编码展示出来。玩家可以使用自己的以太坊帐户去购买这些猫咪,并将自己的猫咪去与其他玩家的猫咪繁育以产生下一代猫咪,或者继续将其拍卖,猫咪之间繁育之后产生的下一代猫咪,其基因编码是受其两只上一代猫咪基因编码影响的,由于猫咪的基因编码在以太坊上都是公开的,所以迷恋猫官方并未公布下一代基因编码的生成规则,这样玩家也无法人为的控制,使用两只特定基因的猫来繁育出具有特定稀有属性的下一代。 玩家在以太坊的帐户是由一段特殊的密钥保护的,玩家进行购买猫咪、繁育猫咪操作事,这些操作信息都会被发布到以太坊上时,并且这些操作行为都会使用玩家的密钥进行认证,并在以太坊上记录,其公之于众。所以所有人都可以看到玩家A买了一只猫咪Kitty101,玩家B将他的猫咪Kitty201与他的Kitty202进行了繁育,并生下了一只什么样基因的Kitty301。

在此之后,区块链上发布了不少游戏,而今年暑假的两款游戏(Fomo3d和LastWinner)吸引了大量的眼球,同时也可能预示着在以太坊上游戏开发的没落。Fomo3d的黑客攻击技巧可以参看1和2。

由此可以看到,比太币和以太坊底层框架本身,当前攻击较少;但是在以太坊上,智能合约本身的代码问题是安全的重灾区。

那接下来,我们讨论solodity语言,对智能合约形成一个基本的了解。

可以使用在线的remix IDE来查看智能合约的效果:https://remix.ethereum.org/#optimize=false

基本语法以及使用

  1. test_2.sol 最基本的用法

以下的代码中,除了第一行和第二行中的contract,其实就和其他我们比较熟悉的语言差不多。将代码拷贝到remix之中,然后deploy到链上去,就是智能合约了。

pragma solidity ^0.4.0;
contract C {
    //交换传入值的顺序并返回
    function f(uint key, uint value) returns (uint, uint){ 
        return (value, key);
    }

    function g() public view returns (uint, uint){
        //任意顺序的通过变量名来指定参数值
        return f({value: 2, key: 1});//2,1
    }
    
    function h() public view returns (uint){
        uint a = 3;
        uint b = 4;
        return a+b;
    }
}
  1. 以上是单个合约。那我们来试一下在不同的合约之中进行交互。(test_send.sol和simple_set.sol)
pragma solidity ^0.4.0;

//import 'test_send.sol';

contract SimpleStorage {
    uint storedData;
    function set(uint x) public{
        storedData = x;
    }
    function get() public constant returns (uint retVal) {
        return storedData;
    }
}

contract SimpleSet {

	address instance_address = 0x9351ca1b4cc9c3d11db77374de3987b5abf3d4c8;
	SimpleStorage target = SimpleStorage(instance_address);
    uint readData;
	
    function read() public view returns (uint) {
        readData = target.get();
		return readData;
    }
	
    function write(uint x) {
        target.set(x));
    }
}

可以看到,在simple_set中,可以调用并修改另外一个合约中的数据。下图展示的是先通过simple_set修改storeData的值,然后在simpleStorage中去读取,结果显示了变化。

  1. 铸币(coin_mint.sol)
pragma solidity ^0.4.0;

contract Coin {

//关键字“public”使变量能从合约外部访问。
    address public minter;
    mapping (address => uint) public balances;

//事件让轻客户端能高效的对变化做出反应。
    event Sent(address from, address to, uint amount);

//这个构造函数的代码仅仅只在合约创建的时候被运行。
    function Coin() {
        minter = msg.sender;
    }
    function mint(address receiver, uint amount) {
        if (msg.sender != minter) return;
        balances[receiver] += amount;
    }
    function send(address receiver, uint amount) {
        if (balances[msg.sender] < amount) return;
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        Sent(msg.sender, receiver, amount);
    }
}

对这份合约进行操作,譬如通过账户7578C将合约部署到链上,那么可以查看合约的minter;minter可以自己铸币,相当于是发给任何用户一些币;有币的用户又可以进行转账。
在这里插入图片描述

  1. 复杂的数据类型 (origin_send.sol)

msg.sender和tx.origin

pragma solidity ^0.4.18;
contract Demo {
    event logData(address);
    
    function a(){
        logData(tx.origin);
        logData(msg.sender);
    }
}
contract Demo2{
    Demo demo222;
    function Demo2(address aimAddr) {
        demo222 = Demo(aimAddr);
    }
    function exp(){
        demo222.a();
    }
}

tx.origin是一个address类型,表示交易的发送者,msg.sender则表示为消息的发送者。在同一个合约中,他们是等价的。但是在不同合约中,tx.origin表示用户地址,msg.sender则表示合约地址。

上述代码中有两个合约,需要分别部署。并且demo2在部署时需要传入参数。

接下来看一下address。

以太坊中的地址的长度为20字节,一字节等于8位,一共160位,所以address其实亦可以用uint160来声明。

属性:

<address>.balance, 地址的余额(单位为:wei)
<address>.transfer,发送以太币(单位为:wei)到一个地址,如果失败会停止并抛出异常。

猜你喜欢

转载自blog.csdn.net/z714405489/article/details/83960019