美文网首页
Solidity初学

Solidity初学

作者: 小陈学coding | 来源:发表于2018-09-19 20:06 被阅读0次

    Lesson 1

        《区块链技术进阶与实战》一书里提到了区块链编写的语言——Solidity,于是我决定去看一看。看到了一个对于初学者,包括刚接触编程的人都很友好的一个学习网站:https://cryptozombies.io/
        接下来我进行一些自己的总结:首先,和c++ java一样,需要引入头文件。Solidity引入头文件的方法就是加上一句pragma solidity ^0.4.19;。Solidity一些地方和python很像,比如x的y次方,都会使用x ** y来表示。但是Solidity的private、public关键字是声明在类型后面的:Zombie[] public zombies;比如这样,声明的就是一个Zombie类型的动态数组。需要注意的是,动态数组使用.push()方法会返回一个值,就是加入的元素的索引。但是下标是从0开始的,所以使用x=array.push(tmp)-1就可以获得刚刚插入的tmp元素的下标。如果是私有类型的方法,在方法名前面还得加上下划线_

    function _createZombie(string _name, uint _dna) private {
            zombies.push(Zombie(_name, _dna));
        }
    

    但是如果是public的方法,就不需要加上这个下划线。

    最后附加上这个网站游戏的通关代码:

    pragma solidity ^0.4.19;
    
    contract ZombieFactory {
    
        event NewZombie(uint zombieId,string name,uint dna);
    
        uint dnaDigits = 16;
        uint dnaModulus = 10 ** dnaDigits;
    
        struct Zombie {
            string name;
            uint dna;
        }
    
        Zombie[] public zombies;
    
        function _createZombie(string _name, uint _dna) private {
            uint id = zombies.push(Zombie(_name, _dna))-1;
            NewZombie(id,_name,_dna);
        } 
    
        function _generateRandomDna(string _str) private view returns (uint) {
            uint rand = uint(keccak256(_str));
            return rand % dnaModulus;
        }
    
        function createRandomZombie(string _name) public {
            uint randDna = _generateRandomDna(_name);
            _createZombie(_name, randDna);
        }
    
    }
    

    (其实在你每一关出错的时候会出现查看正确答案的按钮)
        但是,到这里还没有结束。下面就是介绍以太坊的Web3.js库了,
    下面是使用Web3.js的代码:

    // Here's how we would access our contract:
    var abi = /* abi generated by the compiler */
    var ZombieFactoryContract = web3.eth.contract(abi)
    var contractAddress = /* our contract address on Ethereum after deploying */
    var ZombieFactory = ZombieFactoryContract.at(contractAddress)
    // `ZombieFactory` has access to our contract's public functions and events
    
    // some sort of event listener to take the text input:
    $("#ourButton").click(function(e) {
      var name = $("#nameInput").val()
      // Call our contract's `createRandomZombie` function:
      ZombieFactory.createRandomZombie(name)
    })
    
    // Listen for the `NewZombie` event, and update the UI
    var event = ZombieFactory.NewZombie(function(error, result) {
      if (error) return
      generateZombie(result.zombieId, result.name, result.dna)
    })
    
    // take the Zombie dna, and update our image
    function generateZombie(id, name, dna) {
      let dnaStr = String(dna)
      // pad DNA with leading zeroes if it's less than 16 characters
      while (dnaStr.length < 16)
        dnaStr = "0" + dnaStr
    
      let zombieDetails = {
        // first 2 digits make up the head. We have 7 possible heads, so % 7
        // to get a number 0 - 6, then add 1 to make it 1 - 7. Then we have 7
        // image files named "head1.png" through "head7.png" we load based on
        // this number:
        headChoice: dnaStr.substring(0, 2) % 7 + 1,
        // 2nd 2 digits make up the eyes, 11 variations:
        eyeChoice: dnaStr.substring(2, 4) % 11 + 1,
        // 6 variations of shirts:
        shirtChoice: dnaStr.substring(4, 6) % 6 + 1,
        // last 6 digits control color. Updated using CSS filter: hue-rotate
        // which has 360 degrees:
        skinColorChoice: parseInt(dnaStr.substring(6, 8) / 100 * 360),
        eyeColorChoice: parseInt(dnaStr.substring(8, 10) / 100 * 360),
        clothesColorChoice: parseInt(dnaStr.substring(10, 12) / 100 * 360),
        zombieName: name,
        zombieDescription: "A Level 1 CryptoZombie",
      }
      return zombieDetails
    }
    

        这些代码主要是获取刚才的Solidity代码生成的随机基因数,实际效果是你输入一个名字,它会生成名字相应的僵尸基因对应的样子。
    以上就是完成该网站第一课的内容。

    Lesson 2

        在Solidity中,mapping默认是键值对方式存储数据。下面是mapping的写法:

    //key是地址,value是一个uint类型的值(在Solidity中,address是一个类型)
    mapping (address => uint) public accountBalance;
    

    msg.sender:一个全局变量,可以被所有函数调用。指的是当前调用者(智能合约)的address。使用msg.sender来更新 mapping的例子:

    mapping (address => uint) favoriteNumber;
    
    function setMyNumber(uint _myNumber) public {
      // 更新我们的 `favoriteNumber` 映射来将 `_myNumber`存储在 `msg.sender`名下
      favoriteNumber[msg.sender] = _myNumber;
      // 存储数据至映射的方法和将数据存储在数组相似
    }
    
    function whatIsMyNumber() public view returns (uint) {
      // 拿到存储在调用者地址名下的值
      // 若调用者还没调用 setMyNumber, 则值为 `0`
      return favoriteNumber[msg.sender];
    }
    

    msg.sender拥有以太坊区块链的安全保障,所以安全性较高。
    require:用该方法声明一个function,如果不满足条件就会返回一个error信息。例:

    require(ownerZombieCount[msg.sender] == 0);
    

    继承:

    contract ZombieFeeding is ZombieFactory {
    
    }
    //合约ZombieFeeding 继承了ZombieFactory
    

    在solidity中,你有两个位置能存储数据,一个是storage,一个是memory,相当于电脑的硬盘和RAM,storage是永久存储在区块链中的,而方法外是无法访问到方法内存储在memory中的变量的。
    声明方式如下:

    Sandwich storage mySandwich = sandwiches[_index];
    Sandwich memory anotherSandwich = sandwiches[_index + 1];
    

    Chapter 8 中设置了一个小错误,当你在一个.sol文件中引用另一个.sol文件合约内的private函数的时候,是无法访问到的,这个时候就需要用到internal和external概念了。external和public差不多,但是external是只有外部合约才能调用的,本合约内部无法调用。而internal类似于private,不同的是继承本合约的合约也能访问到。internal和external声明的位置和public,private相同。
    当和区块链中其他的非自己拥有的合约互动的时候,需要用到接口——interface的概念。以下是接口的写法:

    contract NumberInterface {
      function getNum(address _myAddress) public view returns (uint);
    }
    

    对,没错,和你之前想的类似java的interface声明方法不同,根本就没有interface关键字!接口的声明和合约类似,不同的是只声明一个方法,而且没有其他状态变量,并且函数没有函数体。这其实就是一个合约的骨架。
    下面是一个合约调用NumberInterface 中的getNum函数的例子:

    contract MyContract {
      address NumberInterfaceAddress = 0xab38... 
      // ^ The address of the FavoriteNumber contract on Ethereum
      NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);
      // Now `numberContract` is pointing to the other contract
    
      function someFunction() public {
        // Now we can call `getNum` from that contract:
        uint num = numberContract.getNum(msg.sender);
        // ...and do something with `num` here
      }
    }
    

    这样,你就能调用任何别人的声明为public或者external的区块中的函数。
    Lesson2的新增的zombiefeeding.sol文件内容如下:

    pragma solidity ^0.4.19;
    
    import "./zombiefactory.sol";
    
    contract KittyInterface {
      function getKitty(uint256 _id) external view returns (
        bool isGestating,
        bool isReady,
        uint256 cooldownIndex,
        uint256 nextActionAt,
        uint256 siringWithId,
        uint256 birthTime,
        uint256 matronId,
        uint256 sireId,
        uint256 generation,
        uint256 genes
      );
    }
    
    contract ZombieFeeding is ZombieFactory {
    
      address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
      KittyInterface kittyContract = KittyInterface(ckAddress);
    
      // Modify function definition here:
      function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public {
        require(msg.sender == zombieToOwner[_zombieId]);
        Zombie storage myZombie = zombies[_zombieId];
        _targetDna = _targetDna % dnaModulus;
        uint newDna = (myZombie.dna + _targetDna) / 2;
        // Add an if statement here
        if(keccak256(_species) == keccak256("kitty")){
          newDna = newDna - newDna % 100 + 99;
          //replace the last 2 digits of DNA with 99
        }
        _createZombie("NoName", newDna);
      }
    
      function feedOnKitty(uint _zombieId, uint _kittyId) public {
        uint kittyDna;
        (,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
        // And modify function call here:
        feedAndMultiply(_zombieId, kittyDna,"kitty");
      }
    }
    
    

    Lesson 3

    相关文章

      网友评论

          本文标题:Solidity初学

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