智能合约编写高级篇(一)获取区块时间

这篇具有很好参考价值的文章主要介绍了智能合约编写高级篇(一)获取区块时间。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文档从区块时间基本概念出发,介绍了中移链的区块时间接口和应用方向。适用于EOS智能合约的高级开发人员,熟悉如何获取当前区块时间、下一个区块的区块时间、时间戳的转换等。

01

概述

(一)时间戳

时间戳是标识特定事件何时发生的字符序列或编码信息。如今,该术语的用法已经扩展到指附加在数字信息上的数字日期和时间信息。例如,计算机文件包含时间戳,用于提示文件最后一次修改的时间。然而随着数字化文档的诞生,电子数据具有脆弱性、易变性、隐蔽性、载体多样性等特点,容易被复制、删除、篡改且难以被发现。因此,电子数据在实际的司法认定过程中,很难准确坚定其生成的时间以及内容的真实性、完整性。

(二)区块链时间戳

区块链时间戳系统实际就是在P2P网络上通过节点间的共识算法实现的分布式时间戳服务。它是利用时间戳实现在时间上有序的、由一个个区块组成的一根链条。每一个新区块生成时,都会被打上时间戳,最终依照区块生成时间的先后顺序相连成区块链,每个独立节点又通过P2P网络建立联系,这样就为信息数据的记录形成了一个去中心化的分布式时间戳服务系统。

(三)区块链时间戳特点

因区块链拥有以下特点,使得时间戳可以完全信任:(1)不可销毁/修改;(2)Block具有天然时间特性,时间戳是Block meta字段之一;(3)Block可以存储交易信息,交易是可以“写入”的数据;时间戳使得更改一条记录的困难程度按时间的指数倍增加,越老的记录越难修改。

02

环境依赖

  • eosio_2.1.0-1:

https://github.com/eosio/eos/releases/download/v2.1.0/eosio_2.1.0-1-ubuntu-18.04_amd64.deb

  • eosio.cdt v1.8.x:

https://github.com/EOSIO/eosio.cdt/releases/tag/v1.8.1

03

区块时间类与接口

与区块时间相关的类主要为:

  • eosio::time_point

  • eosio::time_point_sec

  • eosio::block_timestamp

其中block_timestamp为区块时间戳,time_pointUnix纪元时间戳(毫秒级精度),time_point_secUnix纪元时间戳(秒级精度)。

可以通过外部接口获取时间进行业务处理,其中current_block_time()和current_time_point()主要用于对区块时间的操作,分别返回block_timestamp实例和time_point实例。expiration()主要用于对区块内交易时间的操作,返回uint32_t整型。

(一)外部接口

1、current_block_time()

获取当前块的Unix纪元时间戳(block_timestamp实例,以微秒为单位)。

  • 调用方式

#include<eosio/time.hpp>
#include<eosio/system.hpp>
auto cur_timestamp = current_block_time();

2、current_time_point()

获取当前块的Unix纪元时间戳(time_point实例,以微秒为单位)。

  • 调用方式

#include<eosio/time.hpp>
#include<eosio/system.hpp>
auto cur_timepoint = current_time_point();

3、expiration()

获取当前交易的Unix纪元时间戳(uint32_t,以秒为单位)。

  • 调用方式

#include<eosio/transaction.hpp>
auto trx_time = eosio::expiration();

transaction_header _trx_header;

4、外部接口对比详解

current_block_time()和current_time_point()两者代表意义均为区块时间,对应于区块结构中的timestamp,区别只在于具体实例不同。(注:timestamp可以表示半秒,而block_timestamp和time_point类中提供的to_string()函数只能输出精度为秒的字符串格式时间,虽然时间戳的精度可以表示半秒)

  • current_block_time()获取当前区块时间(block_timestamp类实例),并提供相关操作函数,next()获取下一个块的区块时间(block_timestamp类实例),通过转换成time_point实例转换成整型时间戳,进行业务运算或输出时间戳。

  • current_time_point()直接获取当前区块时间的(time_point实例),可进行业务运算或输出时间戳,time_point实例可以通过block_timestamp类的构造函数转换成block_timestamp类实例。

  • expiration()获取当前action隶属交易的时间戳,对应区块结构中transaction中的expiration。

以下为区块结构(含交易):

jasmine@Jasmine:~/eosio/eos/build/bin$ ./cleos get block 110
{
  "timestamp": "2023-03-31T01:31:15.000",
  "producer": "eosio",
  "confirmed": 0,
  "previous": "0000006d5b29b623251bea57a48155377081a1b34fa3be9aa5cde21e7d50cb18",
  "transaction_mroot": "706eb8ba97278c9f2a6a5ca4c255394403a3abd60bdd6e09265101d9d0626f3c",
  "action_mroot": "357eb8fba52b02a68930c6d577dbc53523463534026c60100bf84f28b2ad42ae",
  "schedule_version": 0,
  "new_producers": null,
  "producer_signature": "SIG_K1_KgCxbksk9ttikb1WkLvaAtv9doCcjD9CAgBznTyitbfPNWfkQfPrQpW8NE2WPqmNbJx8onM23uKSmRi3X3zfH5PS2LXstu",
  "transactions": [{
      "status": "executed",
      "cpu_usage_us": 40787,
      "net_usage_words": 25,
      "trx": {
        "id": "e2205dd5cfd536ac07adde8bdf9fa341cc736a5751ec4f6aadd17e8ec6601dcf",
        "signatures": [
          "SIG_K1_KVxTaDLMu65ZrPnkrtxmZe7BrjdBbF3XztEdYNo9XkN8SJAnPF3cHoMyC5PWKUCF7UCqQgRi6etMTF3dnjooEVEe7QFA4b"
        ],
        "compression": "none",
        "packed_context_free_data": "",
        "context_free_data": [],
        "packed_trx": "003826646c009a80664500000000010000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed3232660000000000ea3055000000008440a54a01000000010002c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cf0100000001000000010002c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cf0100000000",
        "transaction": {
          "expiration": "2023-03-31T01:31:44",
          "ref_block_num": 108,
          "ref_block_prefix": 1164345498,
          "max_net_usage_words": 0,
          "max_cpu_usage_ms": 0,
          "delay_sec": 0,
          "context_free_actions": [],
          "actions": [{
              "account": "eosio",
              "name": "newaccount",
              "authorization": [{
                  "actor": "eosio",
                  "permission": "active"
                }
              ],
              "data": {
                "creator": "eosio",
                "name": "demo11",
                "owner": {
                  "threshold": 1,
                  "keys": [{
                      "key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
                      "weight": 1
                    }
                  ],
                  "accounts": [],
                  "waits": []
                },
                "active": {
                  "threshold": 1,
                  "keys": [{
                      "key": "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
                      "weight": 1
                    }
                  ],
                  "accounts": [],
                  "waits": []
                }
              },
              "hex_data": "0000000000ea3055000000008440a54a01000000010002c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cf0100000001000000010002c0ded2bc1f1305fb0faac5e6c03ee3a1924234985427b6167ca569d13df435cf01000000"
            }
          ]
        }
      }
    }
  ],
  "id": "0000006e062a01ae4fa1829b16a28dc1cb19b253c4612541590d7d25e9f0fa53",
  "block_num": 110,
  "ref_block_prefix": 2609029455
}

(二)block_timestamp类

1、block_timestamp()

构造函数

  • 源码描述

block_timestamp(const time_point& t) {
    set_time_point(t);
}
block_timestamp(const time_point_sec& t) {
    set_time_point(t);
}

2、block_interval_ms

EOS区块链中,每间隔0.5秒进行一次出块,block_interval_ms为区块间隔(500毫秒)

  • 源码描述

static constexpr int32_t block_interval_ms = 500;

3、from_iso_string()

将字符串格式时间转为block_timestamp实例(注:传入字符串格式为%Y-%m-%dT%H:%M:%S,精度为秒)

  • 源码描述

static block_timestamp from_iso_string(const std::string& date_str) {
    auto time_p = time_point::from_iso_string(date_str);
    return block_timestamp{ time_p };
}

4、next()

返回下一个块的出块时间(block_timestamp实例)

下一个块的出块时间=当前块时间+block_interval_ms

  • 源码描述

block_timestamp next() const {
    eosio::check( std::numeric_limits<uint32_t>::max() - slot >= 1, "block timestamp overflow" );
    auto result = block_timestamp(*this);
    result.slot += 1;
    return result;
}

5、to_time_point()

返回time_point实例

  • 源码描述

time_point to_time_point() const {
    return (time_point)(*this);
}

6、to_string()

返回时间字符串(注:字符串格式为%Y-%m-%dT%H:%M:%S,因精度为秒而出块间隔为500毫秒,部分区块转string有误差损失)

  • 源码描述

std::string to_string() const {
    return to_time_point().to_string();
}

7、测试用例

/*
测试block_timestamp类,由current_block_time()获取当前区块时间的block_timestamp实例,并进行如下测试:
  测试获取静态变量区块间隔时间block_interval_ms
  测试from_iso_string()验证时间转换精度
  测试next()获取下一个区块时间戳
  测试to_time_point()转换block_timestamp实例为time_point实例
  测试to_string()返回时间字符串
  测试block_timestamp重载运算符
*/
ACTION tstime::gettime(){
    block_timestamp current_timestamp = current_block_time();               //获取当前区块时间的block_timestamp实例
    
    //测试获取静态变量区块间隔时间block_interval_ms
    int32_t ms = eosio::block_timestamp::block_interval_ms;                      //current_timestamp.block_interval_ms:500(毫秒)
  
  //测试from_iso_string()验证时间转换精度
    auto my_timestamp = eosio::block_timestamp::from_iso_string("2023-03-31T01:31:15.000").to_time_point().time_since_epoch().count();     //时间戳:1680226275000000
    auto my_timestamp3 = eosio::block_timestamp::from_iso_string("2023-03-31T01:31:15.999").to_time_point().time_since_epoch().count();    //时间戳:1680226275000000(微秒) 结果相同,时间字符串的解析精度为秒
    
    //测试next()验证下一个区块的时间戳与当前区块时间戳关系
  auto next_interval = current_timestamp.next().to_time_point() - current_timestamp.to_time_point();  //500 下一个区块与当前区块的间隔时间 
    
    // 测试to_time_point()转换block_timestamp实例为time_point实例
  auto cur_timestamp_timepoint = current_timestamp.to_time_point();               //当前区块block_timestamp实例
    auto next_timestamp_timepoint = current_timestamp.next().to_time_point();       //下一个区块block_timestamp实例
    
    //测试to_string()返回时间字符串
    eosio::print("block_timestamp is:",current_timestamp.to_string(),"\t");             //返回时间字符串2023-05-05T08:13:15
    
  //测试block_timestamp实例的重载运算符    
  check(next_timestamp > current_timestamp,"next_timestamp <= current_timestamp");   
    check(next_timestamp < current_timestamp,"next_timestamp >= current_timestamp"); 
    check(next_timestamp != current_timestamp,"next_timestamp == current_timestamp");
    check(next_timestamp >= current_timestamp,"next_timestamp < current_timestamp");
}
}

(三)time_point类

1、time_point()

构造函数

  • 源码描述

explicit time_point( microseconds e = microseconds() ) :elapsed(e){}

2、elapsed

当前实例的过期时间(单位微秒)

  • 源码描述

microseconds elapsed;

3、from_iso_string()

将字符串格式时间转为time_point实例(注:传入字符串格式为%Y-%m-%dT%H:%M:%S,精度为秒)

  • 源码描述

static time_point from_iso_string(const std::string& date_str) {
    std::tm tm;
    check(strptime(date_str.c_str(), "%Y-%m-%dT%H:%M:%S", &tm), "date parsing failed");

    auto tp = std::chrono::system_clock::from_time_t( ::mktime( &tm ) );
    auto duration = std::chrono::duration_cast<std::chrono::microseconds>( tp.time_since_epoch() );
    return time_point{ microseconds{ static_cast<int64_t>(duration.count()) } };
}

4、time_since_epoch()

返回当前实例的Unix纪元时间戳(精度:微秒)

  • 源码描述

const microseconds& time_since_epoch()const { return elapsed; }

5、sec_since_epoch()

返回当前实例的Unix纪元时间戳(精度:秒)

  • 源码描述

uint32_t    sec_since_epoch()const  { return uint32_t(elapsed.count() / 1000000); }

6、to_string()

返回时间字符串(注:字符串格式为%Y-%m-%dT%H:%M:%S,因精度为秒而出块间隔为500毫秒,部分区块转string有误差损失)

  • 源码描述

std::string to_string() const {
    time_t rawtime = sec_since_epoch();

    char buf[100];
    strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", gmtime ( &rawtime ));

    return std::string{buf};
}

7、测试用例

/*
测试time_point类,current_time_point()获取当前区块时间的time_point实例,并进行如下测试:
  测试获取变量过期时间elapsed
  测试from_iso_string()验证时间转换精度
  测试time_point实例转换为block_timestamp实例
  测试sec_since_epoch()的返回时间戳精度
  测试time_since_epoch()的返回时间戳精度
  测试to_string()返回时间字符串
  测试time_point重载运算符
*/
ACTION tstime::gettime(){
    time_point block_time_point = current_time_point();                                 //获取当前区块time_point实例
    
    //测试获取变量过期时间elapsed
    auto cur_elapsed = block_time_point.elapsed.count();                                // 当前区块time_point实例时间戳 1683274397500000(微秒)
    
    //测试from_iso_string()验证时间转换精度
    auto my_time_point = eosio::time_point::from_iso_string("2023-03-31T01:31:15.000").time_since_epoch().count();//时间戳:1680226275000000(微秒) 
    auto my_time_point2 = eosio::time_point::from_iso_string("2023-03-31T01:31:15.999").time_since_epoch().count();//时间戳:1680226275000000(微秒)结果相同,时间字符串的解析精度为秒
    
    //测试time_point实例转换为block_timestamp实例
    auto blocktimestamp_trs = eosio::block_timestamp(block_time_point);                 //time_point 转block_timestamp
    
    //测试sec_since_epoch()的返回时间戳精度
    uint32_t cur_time_point_sec_since = block_time_point.sec_since_epoch();             //返回时间戳1683274397(秒)
    
    //测试time_since_epoch()的返回时间戳精度
    int64_t cur_time_point_time_since = block_time_point.time_since_epoch().count();    //返回时间戳1683274397500000(微秒)
    
    //测试to_string()返回时间字符串
    eosio::print("block_time_point is:",block_time_point.to_string(),"\t");             //返回时间字符串2023-05-05T08:13:15
    
    //测试time_point重载运算符
    eosio::time_point resadd1 = my_time_point4 + my_time_point;             
    eosio::time_point resadd2 = my_time_point4 + my_time_point.elapsed;
    eosio::time_point ressub1 = my_time_point4 - my_time_point.elapsed;
    eosio::microseconds ressub2 = my_time_point4 - my_time_point;
    check(my_time_point4 > my_time_point,"my_time_point4 <= my_time_point");
    check(my_time_point4 < my_time_point,"my_time_point4 >= my_time_point"); 
    check(my_time_point4 != my_time_point,"my_time_point4 == my_time_point");
    check(my_time_point4 >= my_time_point,"my_time_point4 < my_time_point");
}
}

(四)time_point_sec类

1、time_point_sec()

构造函数

  • 源码描述

time_point_sec():
    utc_seconds(0){}
explicit time_point_sec(uint32_t seconds )
    :utc_seconds(seconds){}
time_point_sec( const time_point& t )
    :utc_seconds( uint32_t(t.time_since_epoch().count() / 1000000ll) ){}

2、from_iso_string()

将字符串格式时间转为time_point实例(注:传入字符串格式为%Y-%m-%dT%H:%M:%S,精度为秒)

  • 源码描述

static time_point_sec from_iso_string(const std::string& date_str) {
    auto time_p = time_point::from_iso_string(date_str);
    return time_point_sec{ time_p };
}

3、to_string()

返回时间字符串(注:字符串格式为%Y-%m-%dT%H:%M:%S,精度为秒)

  • 源码描述

std::string to_string() const {
    return ((time_point)(*this)).to_string();
}

4、sec_since_epoch()

返回当前实例的Unix纪元时间戳(精度:秒)

  • 源码描述

uint32_t sec_since_epoch()const { return utc_seconds; }

5、测试用例

/*
测试time_point_sec类,由transaction_header.expiration获取当前交易的time_point_sec实例,并进行如下测试:
  测试from_iso_string()验证时间转换精度
  测试to_string()返回时间字符串
  测试sec_since_epoch()返回时间戳
*/
ACTION tstime::gettime(){
    transaction_header _trx_header;
    eosio::time_point_sec trx_time_sec = _trx_header.expiration;
    //测试from_iso_string()验证时间转换精度
    auto trx_time_secmy01 = eosio::time_point_sec::from_iso_string("2023-03-31T01:31:15.000").sec_since_epoch();//返回时间戳1680226275(秒)
    auto trx_time_secmy02 = eosio::time_point_sec::from_iso_string("2023-03-31T01:31:15.500").sec_since_epoch();//返回时间戳1680226275(秒)结果相同,时间字符串的解析精度为秒
    
    //测试to_string()返回时间字符串
    auto trx_time_str = trx_time_sec.to_string(); 
    
    //测试sec_since_epoch()返回时间戳
    auto trx_timestamp = trx_time_sec.sec_since_epoch();    // 返回当前交易时间戳16832743977(秒)
}

-END-文章来源地址https://www.toymoban.com/news/detail-584066.html

到了这里,关于智能合约编写高级篇(一)获取区块时间的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【区块链】以太坊Solidity编写一个简单的Hello World合约

    熟悉一门语言得从Hello World! 开始,因为这是最简单的一个输出形式。 我们先在contracts目录下建立一个helloworld.sol文件 进入编辑 保存退出 在migrations下新建一个部署合约的js文件:3_initial_migration.js 名字可以变动 接下来在test中使用js调用智能合约 在另一个窗口打开ganache 运行智

    2024年02月15日
    浏览(72)
  • 【区块链 | 智能合约】Ethereum源代码 - 智能合约地址生成算法

    当提交智能合约部署后,会返回智能合约的地址。智能合约地址的生成逻辑在eth.api.go的submitTransaction函数中:

    2024年02月13日
    浏览(47)
  • 区块链java开发智能合约nf(部署第一个NFT智能合约)

    手把手教你区块链java开发智能合约nft-第二篇(部署第一个NFT智能合约) 刚搞区块链开发真的是太累了,自己摸石头过河,动不动就报错,网上搜索错误,一律看不出什么问题,或者报错的信息太少,问同事同事不鸟,问领导,领导也烦,无奈,对于英文不好的我,只能被迫

    2024年02月12日
    浏览(53)
  • 2.DApp-编写和运行solidity智能合约

    题记         演示如何编写solidity智能合约,以及在remix中运行solidity代码。 准备Remix环境         在浏览器中搜索remix,找到remix官网,并打开         由于是国内网络,所以访问国外网站较慢,可以耐心等待加载完成,或者科学上网。          加载完成是这样:    编写

    2024年02月03日
    浏览(43)
  • 长安区块链:服务器时间不一致导致调用合约失败

    区块链业务调用合约失败:最终找到的原因是业务服务器和区块链部署服务器两台服务器时间不一致。 调用区块链的ID为:org.chainmaker.sdk.ChainClient@4916e52d参数为:{deptName=[B@72f87e55, shareDate=[B@20fb3bd0, contactInfo=[B@16500a50, file_name=[B@6891ba3a, dataName=[B@59aa7bab, checkDate=[B@2076fef5, checkSta

    2024年02月14日
    浏览(47)
  • 区块链与智能合约

    要想理解什么区块链,我们先来从本质上认识一下它 区块链:本质上是一个去中心化的分布式账本数据库,是指通过去中心化和去信任的方式集体维护一个可靠数据库的技术方法。 没有基础的人可能理解起来有点困难,我们来解释一下里边的名词 分布式账本数据库:了解过

    2024年03月26日
    浏览(89)
  • 区块链智能合约基础

    什么是智能合约 简单来说,智能合约是一种满足在一定条件时,就执行的程序,例如自动售货机就类似一个智能合约系统。 1.向自动售货机投入足够硬币,按下按钮 2.售货机供出商品 3.售货机回到初始状态 智能合约的工作原理 智能合约是一段程序(代码和数据的集合),可

    2024年02月13日
    浏览(42)
  • 区块链智能合约开发学习

    最近正在肝区块链知识学习,入手学习智能合约的开发,由于网上资料实在是太少了,好不容易东拼西凑完成了智能合约的开发、编译、部署、web3js调用(网页页面)和web3j调用(java调用),赶紧趁热把重点提炼出来。 先上图,是我最近学习知识点的一个概括总结,此外还包

    2023年04月18日
    浏览(40)
  • 区块链智能合约

    合同(Contract)又称契约、协议,是平等主体的自然人、法人、其他组织之间设立、变更、终止民事权利义务关系的协议。本质上讲,合同是当事双方或多方在并没有充足信任的情况下,通过文字的约定和法律的权威,对各自的权利与义务进行的约定。 制订合同的目的就在于

    2024年01月18日
    浏览(47)
  • 区块链之智能合约

    智能合约( Smart Contract)是以计算机为主要工具,将数学算法嵌入到程序中,用以证明某个事件是否符合约定条件,并保证各方在约定时间内按照约定条件达成一致,以验证和执行合同条款的计算机文本。简单来说智能合约是一个计算机程序,可以在不需要第三方介入的情况

    2024年02月07日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包