Alert Source Discuss
🚧 Stagnant Standards Track: Interface

EIP-2831: 交易替换消息类型

Authors Gregory Markou (@GregTheGreek)
Created 2020-07-26
Discussion Link https://ethereum-magicians.org/t/eip-2831-transaction-replacement-message-type/4448
Requires EIP-1193

概要

作为 JavaScript Ethereum Provider API (EIP-1193) 的扩展,此提案在发生交易替换时创建一个新的消息类型。

摘要

mempool 中的交易被更新的交易取代的情况下,provider 和 provider 的使用者之间的当前通信从根本上被破坏。Provider 目前无法通信交易替换,并且需要使用者逐个区块地轮询结果交易。

动机

摘自 EIP-1193

以太坊 Web 应用程序(“dapp”)生态系统中的一个常见约定是,密钥管理软件(“钱包”)通过 Web 页面中的 JavaScript 对象公开其 API。 此对象称为“Provider”。

钱包开发者已经做了许多巧妙的开发,以改善与以太坊区块链交互的整体用户体验。其中一项特定的创新是交易替换,它为用户提供了有效地取消先前发送的交易的能力。

交易替换不是一个新概念,但不幸的是,由于替换的交易几乎无法跟踪,因此给 dapp 开发者带来了主要的用户体验问题。

此 EIP 正式化了一种供 Provider 和 dapp 开发者无缝跟踪交易替换的方法。

规范

本文档中的关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL”应按照 RFC-2119 中的描述进行解释。

定义

此部分为非规范性内容。

  • Provider
    • 提供给消费者的 JavaScript 对象,通过客户端提供对以太坊的访问。
  • 钱包
    • 管理私钥、执行签名操作并充当 Provider 和客户端之间中间件的最终用户应用程序。
  • 交易替换
    • 提交一个交易,该交易:具有相同的 nonce,并且 gas 价格比用户不再希望发送的前一个交易高出 10%。这必须在原始交易包含在区块链中之前发生。

事件

这些方法 MUST 按照 Node.js EventEmitter API 实现。

必须实现以下三个事件:tx_replacementtx_speeduptx_cancel

tx_speedup 定义为用户希望调整 gasPrice 的交易替换,以便可能更快地包含区块。为了使 tx_speedup 被认为是有效的,替换交易必须包含与其取代的交易相同的以下属性:

  • Nonce
  • To
  • Value
  • Data
interface txSpeedupInfo {
  readonly oldTx: string;
  readonly newTx: string;
  readonly nonce: string;
  readonly from: string;
}

Provider.on('tx_speedup', listener: (txSpeedupInfo: txSpeedupInfo) => void): Provider;

此事件发出旧的交易哈希 (oldTx)、新的交易哈希 (newTx)、用于两个交易的 nonce (nonce) 以及交易的签名地址 (from)。

tx_cancel 定义为用户希望在先前交易被包含之前将其作废的交易替换。 为了使 tx_cancel 被认为是有效的,替换交易必须包含以下属性:

  • 与被取代的交易相同的 nonce
  • 相同的 From 和 To
  • 零 value
  • 没有 data
interface txCancelInfo {
  readonly oldTx: string;
  readonly newTx: string;
  readonly nonce: string;
  readonly from: string;
}

Provider.on('tx_cancel', listener: (txCancelInfo: txCancelInfo) => void): Provider;

此事件发出旧的交易哈希 (oldTx)、新的交易哈希 (newTx)、用于两个交易的 nonce (nonce) 以及交易的签名地址 (from)。

tx_replacement 定义为用户已使用全新的交易完全替换了先前的交易的交易替换。 替换交易必须包含以下属性:

  • 与被取代的交易相同的 nonce
interface txReplacementInfo {
  readonly oldTx: string;
  readonly newTx: string;
  readonly nonce: string;
  readonly from: string;
}

Provider.on('tx_replacement', listener: (txReplacementInfo: txReplacementInfo) => void): Provider;

此事件发出旧的交易哈希 (oldTx)、新的交易哈希 (newTx)、用于两个交易的 nonce (nonce) 以及交易的签名地址 (from)。

理由

选择该实现是为了帮助 Provider 和 dapp 开发者简化实现。 由于 ProviderMessage 已被 dapp 开发者广泛使用,这意味着实现路径就像在其现有的消息侦听器中添加一个额外的 if 子句一样简单。 这也为 dapp 提供了好处,如果 Provider 尚未实现这些事件,它不会因 undefined 而导致 dapp 崩溃,而应以原生方式实现(例如:ethereum.txCancel(...) 会因为 ethereum.txReplacement() 不是一个函数而报错)。

向后兼容性

许多 Provider 采用了 EIP-1193,因为此 EIP 扩展了相同的事件逻辑,因此不应有任何重大更改。 所有不支持新事件的 Provider 都应 I) 忽略订阅或 II) 向用户提供一些错误。

实现

安全注意事项

目前没有。

参考

版权

通过 CC0 放弃版权及相关权利。

附录 I:示例

这些示例假定为 Web 浏览器环境。

// 大多数 Provider 在页面加载时都可用作 window.ethereum。
// 这只是一种约定,而不是标准,在实践中可能并非如此。
// 请查阅 Provider 实现的文档。
const ethereum = window.ethereum;

const transactionParameters = { ... } // 填写参数

ethereum
  .request({ 
    method: 'eth_sendTransaction',
    params: [transactionParameters],
  })
  .then((txHash) => {
    ethereum.on('tx_cancel', (info) => {
      const { oldTx, newTx, nonce, from } = message.data;
      console.log(`Tx ${oldTx} with nonce ${nonce} from ${from} was cancelled, the new hash is ${newTx}`) // 交易 ${oldTx},nonce 为 ${nonce},来自 ${from} 已被取消,新的哈希是 ${newTx}
    });
    ethereum.on('tx_speedup', (info) => {
      const { oldTx, newTx, nonce, from } = message.data;
      console.log(`Tx ${oldTx} with nonce ${nonce} from ${from} was sped up, the new hash is ${newTx}`) // 交易 ${oldTx},nonce 为 ${nonce},来自 ${from} 已被加速,新的哈希是 ${newTx}
    });
    ethereum.on('tx_replacement', (info) => {
      const { oldTx, newTx, nonce, from } = message.data;
      console.log(`Tx ${oldTx} with nonce ${nonce} from ${from} was replaced, the new hash is ${newTx}`) // 交易 ${oldTx},nonce 为 ${nonce},来自 ${from} 已被替换,新的哈希是 ${newTx}
    });


    console.log(`Transaction hash ${txHash}`) // 交易哈希 ${txHash}
  })
  .catch((error) => {
    console.error(`Error sending transaction: ${error.code}: ${error.message}`); // 发送交易时出错: ${error.code}: ${error.message}
  });

Citation

Please cite this document as:

Gregory Markou (@GregTheGreek), "EIP-2831: 交易替换消息类型 [DRAFT]," Ethereum Improvement Proposals, no. 2831, July 2020. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2831.