V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
whoami9894
V2EX  ›  Solidity

想请教一个 solidity 以太坊合约的代码问题

  •  1
     
  •   whoami9894 · 2018-12-15 23:37:19 +08:00 · 3791 次点击
    这是一个创建于 2154 天前的主题,其中的信息可能已经有所发展或是发生改变。
    pragma solidity ^0.4.23;
    
    contract Preservation {
    
      // public library contracts 
      address public timeZone1Library;
      address public timeZone2Library;
      address public owner; 
      uint storedTime;
      // Sets the function signature for delegatecall
      bytes4 constant setTimeSignature = bytes4(keccak256("setTime(uint256)"));
    
      event FLAG(string b64email, string slogan);
    
      constructor(address _timeZone1LibraryAddress, address _timeZone2LibraryAddress) public {
        timeZone1Library = _timeZone1LibraryAddress; 
        timeZone2Library = _timeZone2LibraryAddress; 
        owner = msg.sender;
      }
    
      // set the time for timezone 1
      function setFirstTime(uint _timeStamp) public {
        timeZone1Library.delegatecall(setTimeSignature, _timeStamp);
      }
    
      // set the time for timezone 2
      function setSecondTime(uint _timeStamp) public {
        timeZone2Library.delegatecall(setTimeSignature, _timeStamp);
      }
    
      function CaptureTheFlag(string b64email) public{
        require (owner == msg.sender);
        emit FLAG(b64email, "Congratulations to capture the flag!");
      }
    }
    
    // Simple library contract to set the time
    contract LibraryContract {
    
      // stores a timestamp 
      uint storedTime;  
    
      function setTime(uint _time) public {
        storedTime = _time;
      }
    }
    

    对以太坊相关一窍不通,看了不少文章还是有点摸不着头脑....

    这是区块链安全想关的,想请教一下这段合约代码放在 Remix 上编译运行后调用CaptureTheFlag函数前有什么约束吗(这里的目的是调用该函数),我的猜想这里时间戳可能与uint256溢出有关

    第 1 条附言  ·  2018-12-16 00:14:00 +08:00

    大概两个合约相当于两个类?,那么

    • setTime函数在这里是干嘛的

    • 在Remix IDE里调用函数的结果是测试性的?(未写入区块或未连接合约地址?)

    15 条回复    2018-12-16 12:18:08 +08:00
    liangdu
        1
    liangdu  
       2018-12-16 01:38:53 +08:00 via Android
    capturetheflag 的约束在 request 写着了,合约的发起者必须是 owner,owner 通常在初始化的时候设置,你的代码不全,看不出完整业务场景。就你给出的代码来讲,settime 就是给 preservation 合约实例的 librarycontract 成员设置属性值而已,settime 可以破例看做成员方法(ps:智能合约的设计思想不能和面向对象一概而论)
    liangdu
        2
    liangdu  
       2018-12-16 01:46:18 +08:00 via Android   ❤️ 2
    这贴好冷门,答漏了

    remix 是通过跟本地的测试节点进程交互(js 调用 rpc 接口通讯),实现高仿真测试。实际上可以理解为就是生产了,只是没有和公链一个网络。

    但是测试结果准确性不能证明在它的派生链也有效,比如基于 eth 拓展的 quorum 框架,虽然都是 eth 虚拟机,但是有些兼容问题。
    zsszuh
        3
    zsszuh  
       2018-12-16 01:49:02 +08:00 via Android   ❤️ 1
    谁知道以太币怎么造的?😂
    whoami9894
        4
    whoami9894  
    OP
       2018-12-16 08:47:52 +08:00 via Android
    @liangdu

    感谢回复,确实冷门←_←,原来都没听说过 solidity。还想请问一下:

    capturetheflag 的 owner 是理解为合约的创造者==消息的发送者吗。这里需要以自己的邮箱为参数调用 capturetheflag 来获得 flag,但我调用了好像没有什么用,remix 里也没有报错信息(可能是我没看到)

    这个合约无法查看 abi(和我看别人的项目不太一样),且合约地址的 code 里有类似汇编的代码,那个是可以反编译生成完整代码的吗。题目给了一个 sol 文件就是我贴上的,还有一个合约地址,如果按您说的代码不全可能需要从操作码反编译?(或者合约没有开源)
    Hconk
        5
    Hconk  
       2018-12-16 10:00:08 +08:00 via Android   ❤️ 1
    根据代码,owner 是你在创建合约时的发送人,有些合约提供了修改 owner 的功能,这样的合约 owner 就不一定是合约的发布者了。msg.sender 是你调用这个合约时使用的地址。

    timeZone1Library 和 timeZone2Library 是另外两个合约的地址,settime 具体什么功能是业务相关的,要看另外两个合约怎么写,这里应该可以理解为 c++里面的前置声明,用于在这个合约上的调用外部的函数。
    whoami9894
        6
    whoami9894  
    OP
       2018-12-16 10:18:16 +08:00
    @Hconk

    感谢回复

    是不是在构造函数里修改了 own 地址为 msg.sender,这里的 time1 和 time2 是两个合约地址,我可以填入自己的合约代码然后 delegatecall 调用是吗(不知道理解的对不对)

    还有就是我调用 capturetheflag 不知道为什么没有写入`ropsten.etherscan.io/0x_______`的 event 中
    Hconk
        7
    Hconk  
       2018-12-16 10:35:34 +08:00 via Android
    @whoami9894 构造函数肯定只在发布合约时会调用一次,调用时的 msg.sender 就是合约创建者。

    两个合约地址也是初始化时候填写的地址,是通过 delegatecall 去调用这两个合约的 settime 方法。

    remix 编译器需要选择使用哪个网络,有本地浏览器上的 vm,还有 mainnet,或者自定义,不知道你有没有选对。你先查看你那个地址的有没有交易记录,再看交易的详情 data 数据有没有问题。
    liangdu
        8
    liangdu  
       2018-12-16 10:57:54 +08:00 via Android
    我通常用 nodejs 配合 truffle test 来测试智能合约,通过 web3 接口可以监听到合约的事件(事务被打包时抛出)。remix 没怎么用,因为当时需要做测试驱动开发,用 remix 不适合。你也可以不监听,truffle 在 test 报错的时候会列出所有合约抛出的 event

    在代码最后加上 assert(false)就可以人为制造错误了
    whoami9894
        9
    whoami9894  
    OP
       2018-12-16 11:25:13 +08:00
    @Hconk
    @liangdu

    我 Google 出了这道题的解法:是 delegatecall 函数的漏洞来恶意修改 owner,可是我在按题解测试的时候依旧死在`require (owner == msg.sender);`

    http://www.bendawang.site/2018/11/13/Zeppelin-ethernaut-writeup/#Preservation-X

    https://blog.riskivy.com/智能合约 ctf:ethernaut-writeup-part-4/
    whoami9894
        10
    whoami9894  
    OP
       2018-12-16 11:48:42 +08:00
    liangdu
        11
    liangdu  
       2018-12-16 11:56:25 +08:00 via Android
    哈啊哈,不对,account 不是你理解的邮箱地址,而且钱包地址。也就外部地址。


    你可以提供更多你的资料,比如报错信息,放在 v2ex。
    imgode
        12
    imgode  
       2018-12-16 12:05:11 +08:00 via Android
    owner 是这个合约的部署者,msg.sender 是这个方法的调用者,require 是相当于一个判断,合约的部署者和调用者一致才往下执行,否则抛出异常,一般会写一个 modifier 来修饰这个函数而不是用 require 这样
    imgode
        13
    imgode  
       2018-12-16 12:08:50 +08:00 via Android
    部署合约的时候会调用 constructor 构造函数,构造函数里写了 owner=msg.sender 所以你这个合约的拥有者也就是 owner 就是你部署合约的那个账户,在调用下面的方法的时候,同样用你部署合约那个账户调用即可,setTime 就是给一个状态变量赋值
    whoami9894
        14
    whoami9894  
    OP
       2018-12-16 12:14:07 +08:00
    @imgode

    可是我的函数依旧卡在 require 的判断

    可能我理解有误,我在 remix 里构建实例并且获得了一个地址是部署吗
    whoami9894
        15
    whoami9894  
    OP
       2018-12-16 12:18:08 +08:00
    @liangdu

    绕晕了,我的 account 地址是 remix 右上角的 0xca35b7d915458ef540ade6068dfe2f44e8fa733c 那个吗。

    好像没有友好的报错信息,我是在 remix 的 debugger 里看到 require 那一行标红了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2832 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 13:14 · PVG 21:14 · LAX 05:14 · JFK 08:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.