智能合约是否可以查询当前区块内的其他交易?
实现方案说明
EVM 架构的公链上,智能合约本身无法直接遍历当前正在打包区块的全部交易列表,你需要通过链下发送控制+合约状态标记的组合方案实现需求,具体逻辑如下:
核心实现步骤
- 给需要绑定的两笔交易分配唯一关联标识,比如同一个
batch_id,记第一笔交易为交易A,第二笔为交易B - 交易A执行时,先不提交核心业务数据,仅在合约中存储
batch_id对应的block.number(当前交易执行时的区块高度),同时将batch_id状态标记为待确认,要求交易A发起者锁定业务执行所需的保证金/资源 - 交易B执行时,首先校验当前
block.number是否和batch_id存储的区块高度一致:- 若一致:将
batch_id标记为已完成,正常执行两笔交易对应的核心业务逻辑,解锁交易A发起者的锁定资源 - 若不一致:直接触发
revert,后续可通过公开的作废接口将batch_id标记为已失效,交易A的锁定资源按规则原路退回/扣除,即实现交易A执行失败的需求
- 若一致:将
- 额外添加超时兜底逻辑:如果
batch_id处于待确认状态超过预设区块数(比如10个区块),任何人都可以触发作废逻辑,避免长期占用合约存储资源
注意事项
- 链下发送交易时,需要将两笔交易的gas price设置为相近数值,同时发送到节点交易池,最大化两笔交易被打包进同一个区块的概率
- 不要尝试用
blockhash做实时校验:当前正在执行的交易所在区块的哈希还未生成,EVM 内置的blockhash(uint blockNumber)方法仅能获取最近256个已确认区块的哈希,无法获取当前打包区块的哈希 - 测试方法:可以用Foundry或者Hardhat本地测试节点,通过
evm_mine相关RPC方法手动控制区块打包时机:先发送交易A、不触发区块打包,再发送交易B后手动触发一次打包,即可模拟两笔交易同区块的场景;先发送交易A、触发一次打包后再发送交易B,即可模拟不同区块的场景
// 核心校验逻辑示例 mapping(bytes32 => uint256) public batchBlock; mapping(bytes32 => bool) public batchExecuted; // 第一笔交易调用的接口 function submitFirstTx(bytes32 batchId) external payable { require(batchBlock[batchId] == 0, "Batch already exists"); batchBlock[batchId] = block.number; // 此处添加资源锁定逻辑,比如锁定msg.value对应金额 } // 第二笔交易调用的接口 function submitSecondTx(bytes32 batchId) external { require(batchBlock[batchId] == block.number, "Not in the same block"); require(!batchExecuted[batchId], "Batch already executed"); batchExecuted[batchId] = true; // 此处添加两笔交易对应的核心业务逻辑 }
内容的提问来源于stack exchange,提问作者Jay Williams
相关产品推荐
相关产品推荐

