zoukankan      html  css  js  c++  java
  • 以太坊web3开发初步学习

    以太坊web3开发初步学习

    此文是对https://learnblockchain.cn/2018/04/15/web3-html/的学习再理解。

    以太坊智能合约通过使用web3.js前端和智能合约交互。web3.js是以太坊官方的js API, 用户可以通过web3.js提供的API通过http或者IPC与
    本地的或者远程的以太坊节点进行交互。
    主要有以下几种库

    web3-eth //主要用来与以太坊和智能合约交互
    web3-shh //用于控制whisper协议和p2p通信以及广播
    web3-utils // 包含与DApp有关的功能
    
    

    web3和geth(以太坊客户端)通信使用的是JSON—RPC协议。

    首先以一个最基础的solidity合约举例:

    pragma solidity ^0.4.21;
    
    contract InfoContract {
    
       string fName;
       uint age;
    
       function setInfo(string _fName, uint _age) public {
           fName = _fName;
           age = _age;
       }
    
       function getInfo() public constant returns (string, uint) {
           return (fName, age);
       }
    }
    

    web3 provider是指自定义节点,例如私有测试网络。
    Injected web3 连接到嵌入页面的web3,比如连接到MetaMask。
    Javascript VM是本地的js虚拟机环境,仅用于练习合约编写。

    接着就是安装web3。web3安装好之后创建UI前端,包括了输入框。
    <script>标签中间写web.js的代码和智能合约进行交互。

    <script>
        if (typeof web3 !== 'undefined') {
            web3 = new Web3(web3.currentProvider);
        } else {
            // set the provider you want from Web3.providers
            web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));
        }
    </script>
    

    该脚本意思为,如果web3已被定义,就创建web3对象。否则就手动指定provider。
    provider就是钱包,通过RPC web3和钱包进行连接。

    一旦连接钱包,接下来便可以设置以太坊账户。

    web3.eth.defaultAccount = web3.eth.accounts[0];//选择第一个账户。
    

    账户设置好之后,web3通过ABI调用合约函数,通过Remix中出现的ABI,

    info.getInfo(function(error, result){//info是某地址的合约
        if(!error)
            {
                $("#info").html(result[0]+' ('+result[1]+' years old)');
                console.log(result);
            }
        else
            console.error(error);
    });
    
    $("#button").click(function() {//setInfo是info合约的函数,点击button后设置了name和age的值
        info.setInfo($("#name").val(), $("#age").val());
    });
    

    最终,合约向以太坊中输入了name和age。

    小结

    以太坊智能合约,本质上就像一个类库, 类库的方法用于操作和更新类库中的状态变量,这些方法需要外部用户来调用。外部用户调用ABI的时候往往会向其中输入参数。
    这些参数用于更新合约的全局变量。 所以说智能合约的本质是不可篡改的数据库。智能合约的核心就是其状态变量。
    其实智能合约本质就是一个难以篡改的数据库。称之为合约实际上真是误导人。

    其他知识点

    $("#xxid")是id选择器。jquery的知识。
    https://www.cnblogs.com/jokerjason/p/7404649.html

    solidity的事件

    区块链是打包一系列交易的区块组成的链条,每一条交易会包含0到多个日志记录,日志就代表着合约所触发的事件。
    DAPP的应用,如果监听了某事件,当事件发生时,会进行回调。日志和事件在合约内无法被访问,而只能被外部监听。
    事件的定义:

    event EventName(address bidder, uint amount)
    

    该用法和定义函数式一样的,并且在事件合约中同样可以被继承。

    事件监听有什么用?

    定义一个事件,

    event Instructor(string name, uint age); //接收两个参数
    

    在setInfo函数中,触发Instructor事件。

    function setInfo(string _fName, uint _age) public{
      fName = _fName;
      age = _age;
      emit Instructor(_fName, _age);//这是setInfo的参数。
    }
    

    emit表示触发动作。 setInfo函数执行时会触发该事件。在web3前端输入name和age之后,触发Instructor事件
    在web3部分引用事件监听器

    var instructorEvent = info.Instructor();
    

    再写一个回调函数, 这样,代码更新后,再在浏览器上点击update info,便会回调

    instructorEvent.watch(function(error, result) {//该函数有两个返回值,result便是setInfo的返回值。
            if (!error)
                {
                    $("#info").html(result.args.name + ' (' + result.args.age + ' years old)');//这里写的是形参。
                } else {
                    console.log(error);
                }
        });
    

    说白了, event变量写好后,在某个函数中声明,触发的时候, web3如果监听了它,且写了一个watch函数,便可以得到监听的参数。
    这些参数拿到之后再输出到页面上,从而完成更新。

    solidity的事件和日志

    var options = { 
        fromBlock: 0,
        address: web3.eth.defaultAccount, //地址
        topics: ["0x0000000000000000000000000000000000000000000000000000000000000000", null, null]
    };
    web3.eth.subscribe('logs', options, function (error, result) {
        if (!error)
            console.log(result);
    })
        .on("data", function (log) {
            console.log(log);
        })
        .on("changed", function (log) {
    });
    

    solidity局部变量无法使用映射类型。

    有两个函数,funcA和funcB, 在funcA中声明了一个变量C,funcA调用B且C作为B的参数,但是总是报错。
    后来查资料发现对memory 类型的映射赋值,会报错。https://blog.csdn.net/qq_33764491/article/details/80403603
    原因在于solidity的映射的实现是通过

    solidity枚举类型

    和C语言枚举类型的写法一样。

    enum weekday{
      sun,mon,tue,wed,the,fri,sat;
    }
    // weekday.sun 来引用枚举值。
    

    注意,"}"后面没有分号。 使用枚举的时候要是xxx.xxx格式。

    solidity异常通知

    一共有三种,

    assert(bool condition), //如果条件不满足,抛出异常,合约中断,一般使用于内部错误
    require(bool condition) //如果条件不满足,抛出异常,合约中断, 用于函数参数输入的判断和外部函数使用
    require(bool condition, string message) //会抛出日志
    revert() //回滚, 合约中断, 回滚状态改变
    revert(string, reason) //提供一个回滚说明
    
    

    监控器检测到异常之后,要用哪类通知呢?
    这里选择了assert(bool condition)

    assert(Parse_acceptword_to_wordset(accept_word, wset) != RETURNID.ACCEPT_WORD_FORMAT_WRONG);
    

    solidity比较字符串大小

    几乎能搜到的写法都是错误的。不知道是由于solidity的abi库改变了还是别的原因。查看文档发现,要得到字符串的hash值,必须先调用abi.encodePacked()

    keccak256(abi.encodePacked(s1)) == keccak256(abi.encodePacked(s2))
    

    文档建议最好使用bytes来代替string,这样最节省gas。

    solidity无法使用while(1)

    while(1)用法错误,应该使用while(true)

    solidity的日志

    事件是给solidity使用的,于是会有一种比较特殊的方案。

    对外访问,在函数的函数名xx()之后添加

    solidity日志(Event)的使用方法。
    在DAPP的应用中,如果监听了某事件,当某事件发生时,会进行回调。 但是日志在合约内是无法被访问的,即使是创建日志的合约。

    event eventName(address bidder, uint amount)//
    

    使用web3.js和日志进行交互,如果它发生了错误。

    首先要定义一个事件,该事件要能够和合约进行触发
    参考资料 https://www.cnblogs.com/tinyxiong/p/9045274.html

  • 相关阅读:
    接口性能测试方案
    如何选择自动化测试框架
    一维和二维前缀和
    高精度 加减乘除
    归并排序 快速排序
    链表
    二分查找
    表达式求值
    c++ const问题小记
    虚继承总结
  • 原文地址:https://www.cnblogs.com/goto2091/p/13682412.html
Copyright © 2011-2022 走看看