开发
时间戳

时间戳

Rooch 的 Framework 提供了一个时间戳功能,位于 frameworks/rooch-framework/sources/timestamp.move,它保存的是 Unix 时间。UNIX 时间,或称 POSIX 时间是 UNIX 或类 UNIX 系统使用的时间表示方式:从 UTC1970 年 1 月 1 日 0 时 0 分 0 秒起至现在的总秒数,在多数 Unix 系统上 Unix 时间可以透过 date +%s 命令来检查。

该模块保存一个全局挂钟,以毫秒为单位存储当前 Unix 时间。

通过时间戳,能确切定位到 Rooch 网络的创世时间。作为 Layer2,Rooch 需要同步 Layer1 上的区块信息,则时间戳是其保持数据同步的关键因素。

Rooch 需要通过 Layer1 的区块头的时间戳来更新或者检查自身的时间戳。

在未来 Rooch 还将实现 TickTransaction,则可以通过时间的偏移量来更新自身的时间戳。

中继以太坊区块信息

目前 Rooch 已经实现了中继以太坊区块信息的功能,可以通过下面这条命令来源源不断地获取以太坊上的区块交易信息:

rooch server start --eth-rpc-url https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161

注意观察区块高度 number 之后的 timestamp

如何查看当前时间戳

在启动中继服务后,我们可以使用 rooch object --id 0x2::timestamp::Timestamp 命令来获取时间戳对象返回的一些信息,在这些返回信息中就包含了当前的时间戳。

rooch object --id 0x2::timestamp::Timestamp
 
{
  "value": "0x711ab0301fd517b135b88f57e84f254c94758998a602596be8ae7ba56a0d14b300000000000000000000000000000000000000000000000000000000000000000060f968ce8b010000",
  "value_type": "0x2::object::ObjectEntity<0x2::timestamp::Timestamp>",
  "decoded_value": {
    "abilities": 0,
    "type": "0x2::object::ObjectEntity<0x2::timestamp::Timestamp>",
    "value": {
      "flag": 0,
      "id": "0x3a7dfe7a9a5cd608810b5ebd60c7adf7316667b17ad5ae703af301b74310bcca",
      "owner": "0x0000000000000000000000000000000000000000000000000000000000000000",
      "value": {
        "abilities": 8,
        "type": "0x2::timestamp::Timestamp",
        "value": {
          "milliseconds": "1699975068000"           <== Note!
        }
      }
    }
  }
}

注意 milliseconds 这一行数据,这就是 Rooch 记录的时间戳!

因为 Rooch 的时间戳最小粒度是毫秒,如上面的输出结果 1699975068000,所以我们把最后三个零去掉即是实际上的时间戳了,即 1699975068

让时间戳向前推进

Rooch 的时间戳模块目前提供了一个改变当前时间戳的入口函数:

public entry fun fast_forward_seconds_for_local(ctx: &mut Context, timestamp_seconds: u64)

我们尝试在命令行调用一下这个函数:

rooch move run --function 0x3::timestamp::fast_forward_seconds_for_local --args u64:22222222222

再次查看时间戳:

rooch object --id 0x2::timestamp::Timestamp
 
{
  "value": "0x711ab0301fd517b135b88f57e84f254c94758998a602596be8ae7ba56a0d14b3000000000000000000000000000000000000000000000000000000000000000000d09941d2c1150000",
  "value_type": "0x2::object::ObjectEntity<0x2::timestamp::Timestamp>",
  "decoded_value": {
    "abilities": 0,
    "type": "0x2::object::ObjectEntity<0x2::timestamp::Timestamp>",
    "value": {
      "flag": 0,
      "id": "0x3a7dfe7a9a5cd608810b5ebd60c7adf7316667b17ad5ae703af301b74310bcca",
      "owner": "0x0000000000000000000000000000000000000000000000000000000000000000",
      "value": {
        "abilities": 8,
        "type": "0x2::timestamp::Timestamp",
        "value": {
          "milliseconds": "23922200386000"
        }
      }
    }
  }
}

此时,时间戳确实已经前进了非常多。但是要注意,这个特性只能在本地网络上使用,因为现实的时间不会因为我们的一条命令而改变!

这个功能也许在日后开发游戏方面的场景会应用比较多。

使用时间戳函数

在启动中继服务后,我们可以调用时间戳函数来获取当前的时间戳。

下面简单地编写了一个入口函数来演示获取时间戳的值:

module timestamp::timestamp {
    use std::debug::print;
    use moveos_std::timestamp::{Self, Timestamp};
    use moveos_std::object::Object;
    use moveos_std::object;

    entry fun get_timestamp(timestamp_obj: &Object<Timestamp>) {
        let timestamp = object::borrow(timestamp_obj);
        let now_seconds = timestamp::seconds(timestamp);
        print(&now_seconds);
    }
}

这里使用了 std::debug::print 函数,可以通过观察服务端中的输出,来确定是否准确获取到了时间戳。

因为 Rooch 的时间戳最小粒度是毫秒,所以我们还需要使用模块内提供的 seconds 函数转换一下,如此就能得到我们实际上的时间戳了。

将测试的合约部署后,我们来尝试调用这个函数,并观察终端里的输出。

启动中继服务后,执行 Shell 命令:

rooch move run --function 0x9fd886140ae373a85101d2c7a5f2eda077ca9a05c3b1c221594ff4473a702c83::timestamp::get_timestamp --args object:0x2::timestamp::Timestamp --sender-account default

可以从服务端看到 debug 消息,我们已经成功获取到时间戳的值了。