美文网首页
以太坊数据调用

以太坊数据调用

作者: 小朴同学 | 来源:发表于2019-02-18 10:51 被阅读13次

    手机端使用以太坊的方式

    对以太坊区块链数据的操作,你必须是一个全节点,并实时的进行数据的交互。但是如果手机端当做一个全节点去处理,是一个不现实的问题。所以解决方式就是一个全节点开启JSON-RPC服务,供手机端进行调用,然后这个节点处理手机端的数据请求。这个时候就需要了解JSON-RPC API,以便调用。

    1. 普通的交易和余额查询及其他

      • 具体内容参考JSON-RPC官方文档
      • 交易的发出使用eth_sendrawtransaction
      • 余额的查询使用eth_getbalance
      • 具体使用方式参考官方文档
      • 注意由于个人私钥非常重要,所以交易的个人签名相关必须在本地处理
    2. 智能合约的调用

      • 智能合约的调用
      • 一些查询操作是用eth_call方法
      • 一些需要改变合约内部数值的操作,需要当做一个交易处理使用eth_sendrawtransaction
      • 智能合约调用与普通的交易的异同
        • 首先toAddress是合约地址
        • 其次交易可选项data字段需要放入一些特殊的数据
        • 最后普通的查询不消耗gas
      • 智能合约data字段的处理
      具体理论参考[Ethereum-Contract-ABI]文档
      具体例子:如下
      // 先获得方法ID(Method ID)
       获得的方式是
       1. 例如:function baz(uint32 x, bool y) returns (bool r) { r = x > 32 || y; }
       2. 如果想调用这个方法则先获得方法ID,即对baz(uint32,bool)做KECCAK256hash计算,然后取计算结果的前四个字节,也就是hash值的前八位,然后拼接0x,就是这个方法的ID.
       keccak256(@"baz(uint32,bool)") = cdcd77c0992ec5bbfc459984220f8c45084cc24d9b6efed1fae540db8de801d2
       前八位即cdcd77c0,拼接0x = 0xcdcd77c0,所以这个方法的ID就是0xcdcd77c0。
       // 对传递的参数进行处理
       1. 第一个参数以uint32的参数,如果传入69,则首先将69转化为十六进制的0x45
       然后与32字节的总长度为64的(0x0000000000000000000000000000000000000000000000000000000000000000)进行相加 = 0x0000000000000000000000000000000000000000000000000000000000000045
       2. 第二个参数bool的参数,如果传入true,则为0x1。(如果传入false则为0x0)
       然后与32字节的总长度为64的(0x0000000000000000000000000000000000000000000000000000000000000000)进行相加 = 0x0000000000000000000000000000000000000000000000000000000000000001
       3. 与方法ID结果拼接0x是16进制的标志,在拼接时不参与拼接,最后在结果前拼接0x
       即最后的结果是cdcd77c0 + 0000000000000000000000000000000000000000000000000000000000000045 + 0000000000000000000000000000000000000000000000000000000000000001
       = 0xcdcd77c000000000000000000000000000000000000000000000000000000000000000450000000000000000000000000000000000000000000000000000000000000001
       4. 这个时候eth_call的data字段就处理完毕了,你就可以去调用这个合约的这个方法了
       如果没有特殊情况,这就是调用的方式。最后把第3步得到的结果值赋予data字段即可。
       
       [注意]
       1. 方法ID的获取的特殊处理
          1)如果函数中有uint,int字段,则在进行做KECCAK256hash计算时用uint256替代,int256不用这么做。
          2)如果函数中有fixed, ufixed字段,则进行计算时用fixed128x19替代,如果本身就是fixed128x19字段,那么就用这个字段。
          3)例如:如果function baz(uint x, bool y) ,则在应该处理baz(uint256,bool)这个字段,其他情况同样操作。
       2. 参数中有动态类型(dynamic type)时的处理
          1)string,bytes为动态,因为长度不固定,如果bytes10则为静态
          2)uint256[]为动态
          3)处理当有动态和静态参数时,先拼接静态最后拼接动态,然后加上偏移量
          4)怎么确定偏移量的具体值有点不清楚。动态类型的处理还可以
       3. 一个简单的例子
          // vote(uint vot, uint contrastIndex, string name)
           // uint 使用uint256替代
           NSData *voteData = [@"vote(uint256,uint256,string)" dataUsingEncoding:NSUTF8StringEncoding];
           NSData *voteKeccak256Data = [SecureData KECCAK256:voteData];
           Hash *voteHash = [Hash hashWithData:voteKeccak256Data];
           NSString *voteMethodID = [voteHash.hexString substringToIndex:10];
           
           // 选择1
           NSString *value1 = @"0000000000000000000000000000000000000000000000000000000000000001";
           // 和第0个对比
           NSString *value2 = @"0000000000000000000000000000000000000000000000000000000000000000";
           // 第三个参数名字 string类型,这个在特殊一些
           *
           1. 首先string是动态类型,首先添加
           0000000000000000000000000000000000000000000000000000000000000060
           2. 其次是字符的长度‘xiaolongxia’ 为11 - 0xb
           000000000000000000000000000000000000000000000000000000000000000b
           3. 字符的编码不够的话,右边拼接(不是左边拼接)
           ‘xiaolongxia’ 的编码是7869616f6c6f6e67786961
           7869616f6c6f6e67786961000000000000000000000000000000000000000000
           4. 组装起来就是string类型的处理
           *
           // 首先是添加偏移量的值,因为是动态类型编码
           NSString *addString = @"0000000000000000000000000000000000000000000000000000000000000060";
           // 其次是字符长度的编码
           NSString *lengString = @"000000000000000000000000000000000000000000000000000000000000000b";
           // 最后是字符的编码
           NSData *nameData = [@"xiaolongxia" dataUsingEncoding:NSUTF8StringEncoding];
           NSString *namHexString = [SecureData dataToHexString:nameData];
           namHexString = [namHexString substringFromIndex:2];
           namHexString = [self fillZeroTo32ByteWithValue:namHexString];
           totalString = [NSString stringWithFormat:@"%@%@%@%@%@%@",voteMethodID, value1, value2, addString, lengString,nameTotal];
      
      • data字段的处理,动态类型的偏移量,还有点不明确,暂时先到这。有待补充
      **补充偏移量的确定**
      1.  首先解释动态类型,即长度不固定,可长可短的变量。
          定义首先bytes,string, 数组(type[])是动态类型。例如:uint256[],是动态的,uint256[10]就是静态的,因为uint256是静态的,然后数组的个数也确定了,所以uint256[10]是静态的。
          bytes是动态的,但是bytes10就是静态的,因为bytes10代表着长度确定为10个。
          所以动态的可以定位为bytes,string,T[](T代表着任意类型),bytes[K] 或者string[K](K>0)。其他所以类型都是静态的。
      2. 偏移量的确定。
          函数:f(uint,uint32[],bytes10,bytes) 
          传入的值:(0x123, [0x456, 0x789], "1234567890", "Hello, world!")
          具体编码如下:
          1. 首先获得methodID,对f(uint256,uint32[],bytes10,bytes)的编码取前4个字节,8个长度为8be65246 即0x8be65246
          2. 参数的处理
          1)第一个参数uint类型,值为0x123所以结果是 <参数部分的第1个字段>
              0x0000000000000000000000000000000000000000000000000000000000000123
          2)第二个参数uint32[]类型,是动态类型,这里先放一个偏移量字段值为0,代表数值不定 <参数部分的第2个字段>
              0x0000000000000000000000000000000000000000000000000000000000000000
          3)第三个字段是bytes10,值为"1234567890",对这个字符串进行编码得到0x3132333435363738393 <参数部分的第3个字段>
              0x3132333435363738393000000000000000000000000000000000000000000000
          4)第四个字段是bytes是动态类型,这里先放一个偏移量字段值为0,代表数值不定 <参数部分的第4个字段>
              0x0000000000000000000000000000000000000000000000000000000000000000
          5)处理第二个参数,作为一个动态类型
              (1)是一个数组,有两个元素,所以第一值为  <参数部分的第5个字段>
                  0x0000000000000000000000000000000000000000000000000000000000000002
              (2)第二个值为数组第一个元素 0x456,所以值为 <参数部分的第6个字段>
                  0x0000000000000000000000000000000000000000000000000000000000000456
              (3)第三个值为数组第二个元素 0x789,所以值为 <参数部分的第7个字段>
                  0x0000000000000000000000000000000000000000000000000000000000000789
              (4)第二个参数的值处理完毕,这个时候考虑当时预留的偏移量,在第 5)步开始前,有4个64位的,4个32字节的数据,如果4*32转化为16进制的话是8*16即0x80,所以这个字段偏移量为0x80,所以值为
                  0x0000000000000000000000000000000000000000000000000000000000000080
          6)处理第四个参数,做一个动态类型
              (1)是一个字符,字符为"Hello, world!",长度为13,所以值为 <参数部分的第8个字段>
                  0x000000000000000000000000000000000000000000000000000000000000000d
              (2)字符的编码为0x48656c6c6f2c20776f726c6421,所以值为 <参数部分的第9个字段>
                  0x48656c6c6f2c20776f726c642100000000000000000000000000000000000000
              (3)第四个参数处理完毕,考虑此时第四个参数的偏移量,在第 6)步开始前,有7个64位的,7个32字节的数据,如果7*32转化为16进制的话是14*16即0xe0,所以这个字段偏移量为0xe0,所以值为
                  0x00000000000000000000000000000000000000000000000000000000000000e0
          3. 所以拼接的最后结果是
              方法ID编码:
                  0x8be65246
              第一参数的值:
                  0000000000000000000000000000000000000000000000000000000000000123
              第二参数的偏移量:
                  0000000000000000000000000000000000000000000000000000000000000080
              第三参数的值:
                  3132333435363738393000000000000000000000000000000000000000000000
              第四参数的偏移量:
                  00000000000000000000000000000000000000000000000000000000000000e0
              第二参数的值:
                  0000000000000000000000000000000000000000000000000000000000000002
                  0000000000000000000000000000000000000000000000000000000000000456
                  0000000000000000000000000000000000000000000000000000000000000789
              第四参数的值:
                  000000000000000000000000000000000000000000000000000000000000000d
                  48656c6c6f2c20776f726c642100000000000000000000000000000000000000
              即最终确定的data值为
                  0x8be6524600000000000000000000000000000000000000000000000000000000000001230000000000000000000000000000000000000000000000000000000000000080313233343536373839300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004560000000000000000000000000000000000000000000000000000000000000789000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000
      
      • 对事件调用的补充
        参考以太坊事件log分析

      • 返回的结果如果有类似发送数据这种情况,会同样处理,所以对结果值的解析,可以参考发送值的拼接处理

    3. 网络请求
      网络请求就是普通的数据接口调用,基本都是数据字段的拼接。具体调用方式参考Etherscan供开发apiINFURA api

    参考资料
    JSON-RPC官方文档
    Etherscan供开发api
    INFURA api
    Solidity官方调用规范文档
    Ethereum-Contract-ABI

    相关文章

      网友评论

          本文标题:以太坊数据调用

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