智能合约编写高级篇(二)区块哈希介绍

本文档从区块哈希基本概念出发,详细介绍了中移链的区块哈希交易接口和应用方向。适用于EOS区块链智能合约高级开发人员,熟悉如何获取当前发生交易所在的区块号和区块哈希前缀,并通过Tapos机制验证交易的有效性。

01

概述

(一)哈希算法

哈希算法是可以将任意长度的二进制数据映射为固定长度二进制数据(哈希值)的一种算法。在这个过程中,哈希函数将输入数据通过一系列的复杂运算变换成固定长度的输出,这个值等同于存放数据的地址,这个地址里面再将输入的数据进行存储,所以哈希函数可以将互联网上的数据以固定长度字符串的形式来保存。同时,哈希函数可以用于密码学、数据完整性验证、信息指纹等领域,常见的哈希算法有MD5、SHA-1、SHA-256等。

(二)区块哈希

区块哈希是通过哈希算法对区块中的所有数据进行计算得出的固定长度的字符串。具体来说,区块哈希是指在区块链技术中,对于每一个新生产的区块,会给这个区块计算一个固定长度的哈希值,这个哈希值包含了这个区块中所有的数据,包括交易记录、上一个区块的哈希值、时间戳等,并且只要这些数据有任何一点改变,那么这个区块的哈希值就会发生变化,所以它在保证网络安全性、防止篡改和验证数据完整性方面起着非常重要的作用。

(三)区块哈希的特点

区块哈希的存在保证了区块链的数据安全性,任何篡改数据的行为都会被立即发现,同时它也具备以下特点:

唯一性:每个区块哈希值都是唯一的,即使是区块链上有极其微小的一点数据改变,也会导致哈希值的变化。这保证了数据的不可变性和唯一标识性。

不可逆性:区块哈希函数是一个单向函数,可以将任意长度的数据转换为固定长度的哈希值。对于哈希值无法进行反向计算推导恢复原始数据,这保证了数据的安全性。

不可篡改性:如果输入数据发生了任何改变,计算得到的哈希值都会发生变化。

02

环境依赖

  • eosio_2.1.0-1

  • eosio.cdt v1.8.x

03

区块哈希接口

与区块哈希相关的交易接口分别有tapos_block_num()和tapos_block_prefix(),它们用于生成区块哈希及验证交易执行的前提条件,这有助于确保交易的有效性和安全性,并提供区块链的相关信息以支持智能合约的开发。

(一)tapos_block_num()

它是一个用于获取当前交易所引用的区块号的函数,它返回一个无符号整数值,代表当前执行交易的区块高度。块高度表示当前执行的块在整个区块链上的位置,可以用于构建块摘要和验证交易。在交易处理过程中,每个块都有一个唯一的块高度。

  • 源码描述

   /***  Gets the block number used for TAPOS on the currently executing transaction.**  @ingroup transaction*  @return block number used for TAPOS on the currently executing transaction*  Example:*  @code*  int tbn = tapos_block_num();*  @endcode*/inline int tapos_block_num() {return internal_use_do_not_use::tapos_block_num();}

  • 调用方式

#include <eosio/transaction.hpp>
#include <eosio/eosio.hpp>
uint16_t current_block_num = tapos_block_num(); // 获取用于当前执行交易所在的区块号

(二)tapos_block_prefix()

它是一个用于获取当前交易所在区块哈希前缀的函数,它返回一个无符号整数值,代表当前执行交易的区块哈希前缀。区块哈希前缀是区块哈希的一部分,用于构建block summary。它通常作为一个随机数,用于增加区块哈希的难度,以保持加密的安全性。

  • 源码描述

/***  Gets the block prefix used for TAPOS on the currently executing transaction.**  @ingroup transaction*  @return block prefix used for TAPOS on the currently executing transaction*  Example:*  @code*  int tbp = tapos_block_prefix();*  @endcode*/inline int tapos_block_prefix() {return internal_use_do_not_use::tapos_block_prefix();}
  • 调用方式

#include <eosio/transaction.hpp>
#include <eosio/eosio.hpp>
uint32_t current_block_prefix = tapos_block_prefix(); // 获取用于当前执行交易所在的区块哈希前缀

(三)什么是TaPos机制?

TaPos是“交易作为权益证明”(Transaction-as-Proof-of-Stake)的缩写。TaPos是在EOS的交易处理过程中引入的一个概念,它是一种用于实现去中心化共识的机制,目的是确保交易执行的前提条件和验证交易的有效性。在去中心化的区块链网络中,由于网络可能存在延迟和分叉,交易的确认和执行顺序可能会有所不同,所以引入TaPos机制来防止在不包含引用区块的分叉上重放交易,从而增加了安全性和可靠性。下面我们来看一下EOS白皮书是如何对TaPos进行描述的。

Transaction as Proof of Stake (TaPoS)
The EOS.IO software requires every transaction to include part of the hash of a recent block header. This hash serves two purposes:
1. prevents a replay of a transaction on forks that do not include the referenced block.
//防止在不包含引用区块的分叉上重放交易。
2. signals the network that a particular user and their stake are on a specific fork.
//向网络发出信号,表明特定用户及其权益位于哪条特定分叉上。
Over time all users end up directly confirming the blockchain which makes it difficult to forge counterfeit chains as the counterfeit would not be able to migrate transactions from the legitimate chain.

(四)如何通过TaPos验证交易

通过TaPoS机制,EOS网络可以确保交易的顺序性并防止在不同块之间重放交易,所以每个交易都必须包含正确的TaPoS字段,即交易作为股权证明的一部分,在交易签名过程中,这些字段会与其他的交易信息一起打包进入交易,以便验证它们的有效性。为了让链更稳固,也让用户交易更安全,当链中每发生一笔交易时,都会验证两个字段,分别是ref_block_num和ref_block_prefix,以下是eosio.cdt中对它们的声明。

// eosio.cdt/1.8.1/include/eosiolib/contracts/eosio/transaction.hpp
class transaction_header {public:/*** Construct a new transaction_header with an expiration of now + 60 seconds.** @brief Construct a new transaction_header object initialising the transaction header expiration to now + 60 seconds*/transaction_header( time_point_sec exp = time_point_sec(current_time_point()) + 60):expiration(exp){}time_point_sec  expiration;/// the time at which a transaction expiresuint16_t        ref_block_num; /// specifies a block num in the last 2^16 blocksuint32_t        ref_block_prefix; /// specifies the lower 32 bits of the block id at get_ref_blocknumunsigned_int    max_net_usage_words = 0UL; /// number of 8 byte words this transaction can serialize into after compressionsuint8_t         max_cpu_usage_ms = 0UL; /// number of CPU usage units to bill transaction forunsigned_int    delay_sec = 0UL; /// number of seconds to delay transaction, default: 0EOSLIB_SERIALIZE( transaction_header, (expiration)(ref_block_num)(ref_block_prefix)(max_net_usage_words)(max_cpu_usage_ms)(delay_sec) )};

以下代码是在交易初始化时候验证ref_block_num和ref_block_prefix两个字段。

// eos/libraries/chain/transaction.cpp
void transaction_header::set_reference_block( const block_id_type& reference_block ) {ref_block_num    = fc::endian_reverse_u32(reference_block._hash[0]);ref_block_prefix = reference_block._hash[1];
}bool transaction_header::verify_reference_block( const block_id_type& reference_block )const {return ref_block_num    == (decltype(ref_block_num))fc::endian_reverse_u32(reference_block._hash[0]) &&ref_block_prefix == (decltype(ref_block_prefix))reference_block._hash[1];
}
// eos/libraries/chain/transaction_context.cpp
void transaction_context::init_for_input_trx_common( uint64_t initial_net_usage, bool skip_recording ){published = control.pending_block_time();is_input = true;const transaction& trx = packed_trx.get_transaction();if (!control.skip_trx_checks()) {control.validate_expiration(trx);control.validate_tapos(trx);validate_referenced_accounts( trx, enforce_whiteblacklist && control.is_producing_block() );}init( initial_net_usage );if (!skip_recording)record_transaction( packed_trx.id(), trx.expiration ); /// checks for dupes}
// eos/libraries/chain/controller.cpp
void controller::validate_tapos( const transaction& trx )const { try {const auto& tapos_block_summary = db().get<block_summary_object>((uint16_t)trx.ref_block_num);//Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expirationEOS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), invalid_ref_block_exception,"Transaction's reference block did not match. Is this transaction from a different fork?",("tapos_summary", tapos_block_summary));
} FC_CAPTURE_AND_RETHROW() }

(五)测试用例

编写智能合约测试用例,通过调用上文中介绍的tapos_block_num()和tapos_block_prefix()两个函数来获取验证交易有效性的两个字段ref_block_num和ref_block_prefix。

#include <eosio/transaction.hpp>
#include <eosio/eosio.hpp>using namespace eosio;class [[eosio::contract("test")]] test: public contract {
public:using contract::contract;[[eosio::action]]void checktapos() {uint32_t current_block_num = tapos_block_num(); // 获取当前交易执行所在的区块号uint32_t current_block_prefix = tapos_block_prefix(); // 获取当前交易执行所在的区块哈希前缀print("ref_block_num: ", current_block_num,"\t\t\t");print("ref_block_prefix: ", current_block_prefix);}
};

返回结果如下:

executed transaction: b35a59a178af7dedbbad641952146470adbe5e4d48316382afec5941fcdf2372  96 bytes  146 us
#          test <= test::checktapos             ""
>> ref_block_num: 43983             ref_block_prefix: 448306994

以下是对应区块结构transaction中的ref_block_num和ref_block_prefix。

root@VM-24-16-ubuntu:/home/ubuntu/biosboot/genesis# cleos get transaction b35a59a178af7dedbbad641952146470adbe5e4d48316382afec5941fcdf2372
{"id": "b35a59a178af7dedbbad641952146470adbe5e4d48316382afec5941fcdf2372","trx": {"receipt": {"status": "executed","cpu_usage_us": 146,"net_usage_words": 12,"trx": [1,{"compression": "none","prunable_data": {"prunable_data": [0,{"signatures": ["SIG_K1_Jzmoz3cfi8H7tA3V8zidyihS7XYv29h1bnxdoFSM7ddvRXRo7q4GTJrgPKDsvbbXMFsaFxzCZeAqwwhG2GNVdjHXiL41y1"],"packed_context_free_data": ""}]},"packed_trx": "6b6eae64cfab329fb81a0000000001000000000090b1ca0000a6d56488544301000000000090b1ca00000000a8ed32320000"}]},"trx": {"expiration": "2023-07-12T09:12:11","ref_block_num": 43983,"ref_block_prefix": 448306994,"max_net_usage_words": 0,"max_cpu_usage_ms": 0,"delay_sec": 0,"context_free_actions": [],"actions": [{"account": "test","name": "checktapos","authorization": [{"actor": "test","permission": "active"}],"data": ""}],"signatures": ["SIG_K1_Jzmoz3cfi8H7tA3V8zidyihS7XYv29h1bnxdoFSM7ddvRXRo7q4GTJrgPKDsvbbXMFsaFxzCZeAqwwhG2GNVdjHXiL41y1"],"context_free_data": []}},"block_time": "2023-07-12T09:11:41.500","block_num": 43985,"last_irreversible_block": 44144,"traces": [{"action_ordinal": 1,"creator_action_ordinal": 0,"closest_unnotified_ancestor_action_ordinal": 0,"receipt": {"receiver": "test","act_digest": "f0d16f853ef72e7be5d8c84219cdcaa75d9b13d89b59c9385aebaecc20bc34f7","global_sequence": 43996,"recv_sequence": 8,"auth_sequence": [["test",11]],"code_sequence": 2,"abi_sequence": 1},"receiver": "test","act": {"account": "test","name": "checktapos","authorization": [{"actor": "test","permission": "active"}],"data": ""},"context_free": false,"elapsed": 39,"console": "ref_block_num: 43983             ref_block_prefix: 448306994","trx_id": "b35a59a178af7dedbbad641952146470adbe5e4d48316382afec5941fcdf2372","block_num": 43985,"block_time": "2023-07-12T09:11:41.500","producer_block_id": null,"account_ram_deltas": [],"account_disk_deltas": [],"except": null,"error_code": null,"return_value_hex_data": ""}]
}

需要注意,ref_block_num表示的是交易所引用的区块的区块号码,而ref_block_prefix是这个区块的哈希前缀。在交易签名过程中,这些字段会与其他的交易信息一起打包进入交易中,以便验证这个交易是否合法。而在cleos get transaction命令所显示的交易信息中,另一个名为block_num的字段则表示最终执行该交易的区块的区块号码,此字段与交易提交时所引用的区块号码ref_block_num是不同的。因为在提交交易时,可能会发生交易被延迟,所以最终执行该交易的区块可能与该交易所引用的区块不同。

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/74751.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【大模型】更强的开源可商用的中英文大语言模型baichuan2来了,从零开始搭建

【大模型】更强的开源可商用的中英文大语言模型baichuan2来了&#xff0c;从零开始搭建 Baichuan 2 介绍技术报告github 地址 模型下载开放协议协议 测试评估通用领域测试7B 模型结果13B 模型结果 法律、医疗7B 模型结果13B 模型结果 数学、代码7B 模型结果13B 模型结果 多语言…

html 学习 之 文本标签

下面是一些常见的HTML文本标签&#xff08;&#xff0c;&#xff0c;&#xff0c;&#xff0c;和&#xff09;以及它们的作用&#xff1a; 标签 (Emphasis - 强调): 作用&#xff1a;用于在文本中表示强调或重要性。 示例&#xff1a; <p>这是一段文本&#xff0c;&l…

数据资产管理:数据目录怎么搞?

经过了站在业务视角的自上而下的数据梳理&#xff0c;以及站在IT视角的自下而上的数据盘点&#xff0c;一套“热腾腾”的数据资产清单终于新鲜出炉了。 通过数据资产盘点&#xff0c;企业终于知道他们拥有哪些数据、如何使用数据、是否安全以及数据在哪里。 然而&#xff0c;据…

微博一面:JVM预热,你的方案是啥?

说在前面 在40岁老架构师 尼恩的读者社区(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如微博、阿里、汽车之家、极兔、有赞、希音、百度、网易、滴滴的面试资格&#xff0c;遇到一几个很重要的面试题&#xff1a; JVM预热&#xff0c;你的方案是啥&#xff1f;Springb…

docker 和 podman的区别

Podman 和 Docker 都是用于容器化应用程序的工具&#xff0c;它们在很多方面非常相似&#xff0c;但也有一些关键区别&#xff1a; 1. 架构和权限&#xff1a; - Docker&#xff1a;Docker 使用守护进程&#xff08;dockerd&#xff09;来管理容器&#xff0c;它需要在操作…

TortoiseGit设置作者信息和用户名、密码存储

前言 Git 客户端每次与服务器交互&#xff0c;都需要输入密码&#xff0c;但是我们可以配置保存密码&#xff0c;只需要输入一次&#xff0c;就不再需要输入密码。 操作说明 在任意文件夹下&#xff0c;空白处&#xff0c;鼠标右键点击 在弹出菜单中按照下图点击 依次点击下…

侧边栏的文章分类、热门文章和热门文章的展示(Go 搭建 qiucode.cn 之九)

早就有言,秋码记录 虽早已不是原来的面貌,但这终究是不防碍我们使用golang来搭建它。 而又为什么是使用golang呢?并非是其他编程语言呢?想必 时候回答【我为什么要学习 Go 语言(golang)】这个问题了 已经给出了答案! 当然,当初学习golang时,不单单是为了搭建一个博客应…

【数据结构】二叉树基础入门

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

makefile之目标文件生成

目标文件:源码经过编译还没有链接那些中间文件.linux .o文件 gcc $(CFLAGS) -c xxx.c -o xx.o include Makefile.config SRC : $(wildcard *.c wildcard ./audio_module/*.c) SRC_OBJ $(patsubst %.c,%.o,$(SRC))all:$(SRC_OBJ) $(info contents $(SRC))$(info objfiles $(SR…

获取板块分类并展示

板块分类也会变动&#xff0c;偶尔看下&#xff0c;利于总体分析大盘 https:dapanyuntu.com/ 该网站含有板块信息 分析接口 搜素关键字 拷贝curl到curl解析工具&#xff0c;去掉无用的参数&#xff0c;生成requests代码 尝试nginx反代接口 server {listen 443;loca…

数据结构算法-分而治之算法

引言 在茫茫人海中找寻那个特定的身影&#xff0c;犹如在浩瀚的星海中寻找那一颗独特的星辰。小森&#xff0c;一个平凡而真实的男孩&#xff0c;此时正在人群中寻找他的朋友&#xff0c;温迪。 小森运用了一种“分而治之”的算法策略&#xff0c;将周围的人群分成两组&#…

算法通关村第十九关——动态规划是怎么回事(青铜)

算法通关村第十九关——动态规划是怎么回事&#xff08;青铜&#xff09; 前言1 什么是动态规划2 动态规划的解题步骤3 简单入门3.1 组合总和3.2 最小路径和3.3 三角形最小路径和 4 理解动态规划 前言 动态规划是一种解决复杂问题的算法思想&#xff0c;它将一个大问题分解为多…

Spring Boot 中使用 Poi-tl 渲染数据并生成 Word 文档

本文 Demo 已收录到 demo-for-all-in-java 项目中&#xff0c;欢迎大家 star 支持&#xff01;后续将持续更新&#xff01; 前言 产品经理急冲冲地走了过来。「现在需要将按这些数据生成一个 Word 报告文档&#xff0c;你来安排下」 项目中有这么一个需求&#xff0c;需要将用户…

eNSP基本命令大全

单交换机VLAN划分 进入系统视图 system 进入系统视图 system-view 退到系统视图 quit 删除vlan 20 undo vlan 20 交换机命名 sysname 显示vlan disp vlan 创建vlan(也可进入vlan 20) vlan 20 把端口1-5放入VLAN 20 中 port e1/0/1 to e1/0/5 显示vlan里的端口20 disp v…

【JavaEE】_CSS引入方式与选择器

目录 1. 基本语法格式 2. 引入方式 2.1 内部样式 2.2 内联样式 2.3 外部样式 3. 基础选择器 3.1 标签选择器 3.2 类选择器 3.3 ID选择器 4. 复合选择器 4.1 后代选择器 4.2 子选择器 4.3 并集选择器 4.4 伪类选择器 1. 基本语法格式 选择器若干属性声明 2. 引入…

【数据结构】AVL树的插入与验证

文章目录 一、基本概念1.发展背景2.性质 二、实现原理①插入操作1.平衡因子1.1平衡因子的更新1.1.1树的高度变化1.1.2树的高度不变 2. 旋转2.1左旋2.2右旋2.3右左双旋2.4 左右双旋 ②验证1.求二叉树高度2. 判断是否为AVL树 源码总结 一、基本概念 1.发展背景 普通的二叉搜索树…

el-form表单动态校验(场景: 输入框根据单选项来动态校验表单 没有选中的选项就不用校验)

el-form表单动态校验 el-form常规校验方式: // 结构部分 <el-form ref"form" :model"form" :rules"rules"><el-form-item label"活动名称: " prop"name" required><el-input v-model"form.name" /…

2023 最新 Git 分布式版本控制系统介绍和下载安装使用教程

Git 基本概述 Git 是一个开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或大或小的项目。 集中式和分布式的区别&#xff1f; 最常见的集中式版本控制系统是SVN&#xff0c;版本库是集中放在中央处理器中的&#xff0c;而干活的时候&#xff0c;用的都是自己电…

第15章_瑞萨MCU零基础入门系列教程之Common I2C总线模块

本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写&#xff0c;需要的同学可以在这里获取&#xff1a; https://item.taobao.com/item.htm?id728461040949 配套资料获取&#xff1a;https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总&#xff1a; ht…

postman和node.js的使用

一 nodejs下载 下载链接&#xff1a; nodejs官网&#xff1a; https://nodejs.org/zh-cn/download 我使用的windows .msi安装方式&#xff0c;双击一直下一步就行 当前安装完成后的版本&#xff1a;1.下载 2.安装步骤 下载完成后&#xff0c;双击安装包&#xff0c;开始安装&…