美文网首页
solidity学习

solidity学习

作者: arthur25 | 来源:发表于2019-01-16 10:43 被阅读10次

    资料整理于以太坊Dapp开发教程案例

    本文以参考教程中《游戏:僵尸军团》的所有实例代码作为笔记记录

    关于随机数安全性的讨论

    contract ZombieFactory {
    
        uint dnaDigits = 16;
        uint dnaModulus = 10 ** dnaDigits;
    
        struct Zombie {
            string name;
            uint dna;
        }
        
        // 定义 public 数组,
        Zombie[] public zombies;
    
        // 如果说 contract 相当于 class,那么这里的 function 相当于 class 的方法。
        function _createZombie(string _name, uint _dna) private {
            zombies.push(Zombie(_name, _dna));
        }
    
    }
    

    变量

        在 Solidity 中,变量是被永久地保存在合约中的。也就是说它们被写入以太币区块链中,想象成写入一个数据库。变量有两种类型 private 和 public 的类型。变量默认是 private 类型。private 指的是其它的合约不可以从这个变量中读取数据。public 指的是其它的合约可以从这个变量中读取数据(但不能写入数据)。
    

    函数

        Solidity 不仅变量有 private 和 public 类型之分,函数也有 private 和 public 类型之分。Solidity 定义的函数的类型默认为 public。 这就意味着任何一方 (或其它合约) 都可以调用你合约里的函数。
        显然,不是什么时候都需要这样,而且这样的合约易于受到攻击。 所以将自己的函数定义为私有是一个好的编程习惯,只有当你需要外部世界调用它时才将它设置为公共。
        记住,我们有一个规范,局部及形参我们在前面加上前缀”_”来于public或external区分。
    
        我们定义一个 private _createZombie 函数用于创建并保存僵尸对象。创建一个僵尸对象,就是调用事先定义好的数据结构的变量 Zombie。保存就是,把创建好的僵尸对象,push 到事先定义好的数组 zombies 中。现在调用 _createZombie 函数就可以创建僵尸对象,并将对象保存在以太坊“数据库”上了。
    

    补充

    我们有决定函数何时和被谁调用的可见性修饰符: private 意味着它只能被合约内部调用; internal 就像 private 但是也能被继承的合约调用; external 只能从合约外部调用;最后 public 可以在任何地方调用,不管是内部还是外部。
    
    我们也有状态修饰符, 告诉我们函数如何和区块链交互: view 告诉我们运行这个函数不会更改和保存任何数据; pure 告诉我们这个函数不但不会往区块链写数据,它甚至不从区块链读取数据。这两种在被从合约外部调用的时候都不花费任何gas(但是它们在被内部其他函数调用的时候将会耗费gas)。
    
    然后我们有了自定义的 modifiers。 对于这些修饰符我们可以自定义其对函数的约束逻辑,这些修饰符可以同时作用于一个函数定义上。
    

    payable 修饰符

    payable 方法是让 Solidity 和以太坊变得如此酷的一部分 —— 它们是一种可以接收以太的特殊函数。
    
    先放一下。当你在调用一个普通网站服务器上的API函数的时候,你无法用你的函数传送美元——你也不能传送比特币。
    
    但是在以太坊中, 因为钱 (以太), 数据 (事务负载), 以及合约代码本身都存在于以太坊。你可以在同时调用函数 并付钱给另外一个合约。
    
    这就允许出现很多有趣的逻辑, 比如向一个合约要求支付一定的钱来运行一个函数
    
    contract OnlineStore {
      function buySomething() external payable {
        // 检查以确定0.001以太发送出去来运行函数:
        require(msg.value == 0.001 ether);
        // 如果为真,一些用来向函数调用者发送数字内容的逻辑
        transferThing(msg.sender);
      }
    }
    
    在这里,msg.value 是一种可以查看向合约发送了多少以太的方法,另外 ether 是一个內建单元。
    
    这里发生的事是,一些人会从 web3.js 调用这个函数 (从DApp的前端), 像这样 :
    
    // 假设 `OnlineStore` 在以太坊上指向你的合约:
    OnlineStore.buySomething().send(from: web3.eth.defaultAccount, value: web3.utils.toWei(0.001))
    
    注意这个 value 字段, JavaScript 调用来指定发送多少(0.001)以太。如果把事务想象成一个信封,你发送到函数的参数就是信的内容。 添加一个 value 很像在信封里面放钱 —— 信件内容和钱同时发送给了接收者。
    
    注意: 如果一个函数没标记为payable, 而你尝试利用上面的方法发送以太,函数将拒绝你的事务。
    

    监听事件

    cryptoZombies.events.NewZombie()
    .on("data", function(event) {
      let zombie = event.returnValues;
      console.log("一个新僵尸诞生了!", zombie.zombieId, zombie.name, zombie.dna);
    }).on('error', console.error);
    
    注意这段代码将在 任何 僵尸生成的时候激发一个警告信息——而不仅仅是当前用用户的僵尸。如果我们只想对当前用户发出提醒呢?
    

    使用 indexed

    合约中:

    event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
    
    在这种情况下, 因为_from 和 _to 都是 indexed,这就意味着我们可以在前端事件监听中过滤事件
    
    cryptoZombies.events.Transfer({ filter: { _to: userAccount } })
    .on("data", function(event) {
      let data = event.returnValues;
      // 当前用户更新了一个僵尸!更新界面来显示
    }).on('error', console.error);
    

    查询过去事件

    我们甚至可以用 getPastEvents 查询过去的事件,并用过滤器 fromBlock 和 toBlock 给 Solidity 一个事件日志的时间范围("block" 在这里代表以太坊区块编号):
    
    cryptoZombies.getPastEvents("NewZombie", { fromBlock: 0, toBlock: 'latest' })
    .then(function(events) {
      // events 是可以用来遍历的 `event` 对象 
      // 这段代码将返回给我们从开始以来创建的僵尸列表
    });
    

    相关文章

      网友评论

          本文标题:solidity学习

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