Skip to content

qkc/types: refactor transactions to two-layer TxData - #43

Open
ping-ke wants to merge 1 commit into
qkc-3-types-04-transactionsfrom
qkc-3-types-04-transactions-refactor
Open

qkc/types: refactor transactions to two-layer TxData#43
ping-ke wants to merge 1 commit into
qkc-3-types-04-transactionsfrom
qkc-3-types-04-transactions-refactor

Conversation

@ping-ke

@ping-ke ping-ke commented Jul 28, 2026

Copy link
Copy Markdown

QKC Transaction 两层设计

1. 改什么

将 goquarkchain 的现有设计,也就是本 branch 修改前 qkc/types/transaction.go 的三层对象结构:

Transaction
└── EvmTransaction
    └── txdata

evmTx := types.NewEvmTransaction(...)
tx := &types.Transaction{TxType: types.EvmTx, EvmTx: evmTx}
tx.EvmTx.Gas() 

改成类似 geth Transaction / LegacyTx 的两层对象结构:

Transaction
└── QkcTx(实现 TxData interface)

tx := types.NewQkcTransaction(...)
tx.Gas()

TxData 只是接口约束,不是额外的数据包装层。Transaction.inner 的类型是 TxData,实际保存 *QkcTx

具体修改:

  • EvmTransaction 和内部 txdata 合并为 QkcTx,直接保存 Nonce、Gas 和签名等交易字段。
  • Transaction 通过 TxData 接口读写和编码交易数据,QkcTx 提供具体实现;新增交易类型只需实现 TxData
  • hash、size、sender cache 统一放在外层 Transaction。setter 修改交易字段时会清理相关 cache,避免后续返回修改前的 hash、size 或 sender。
  • 构造函数重命名为 NewQkcTransactionNewQkcContractCreation,并直接返回 *Transaction
  • 当前和未来都只支持每条 chain 一个 shard,因此删除不参与 RLP、Serialize、hash 或签名的 FromShardsizeToShardsize 字段、getter 和 setter。相关计算直接使用常量 1

兼容性说明:

  • QKC Serialize/Deserialize、交易 hash、签名和 minor-block Merkle leaf 的实现会随新结构做适配,但编码格式和计算结果保持不变。
  • Deserialize 根据 type byte 创建对应的 TxData 实现后解码;DecodeRLP 处理不包含 type byte 的 inner RLP,目前创建唯一支持的 QkcTx 实现。新增交易类型时可以参考 core/types/transaction.go 的扩展方式。

2. 有什么好处

  • 删除不必要的数据包装,使结构更加简单。
  • 与 geth 的 Transaction + TxData implementation 模型一致,更容易理解和 review。
  • cache 和交易修改入口集中在外层,避免字段修改后继续读取旧 cache。
  • 以后添加 geth 新交易类型,或将 QKC 交易移入 geth 的 core/types 时,由于两者结构一致、接口相似,扩展和迁移都会更简单。

外部调用的修改简单直观,大部分是删除 .EvmTx

tx.EvmTx.Gas()                 -> tx.Gas()
tx.EvmTx.SetGas(gas)           -> tx.SetGas(gas)
types.Sender(signer, tx.EvmTx) -> types.Sender(signer, tx)

新增交易类型

修改前,Transaction 直接保存每一种具体交易。新增类型需要修改 Transaction,调用方也需要根据 TxType 访问不同字段:

type Transaction struct {
    TxType uint8
    EvmTx  *EvmTransaction
    NewTx  *NewTransaction
}

newTx := NewNewTransaction(...)
tx := &Transaction{TxType: NewTxType, NewTx: newTx}

switch tx.TxType {
case EvmTx:
    tx.EvmTx.SetGas(gas)
case NewTxType:
    tx.NewTx.SetGas(gas)
}

修改后,Transaction 只保存 TxData。新类型实现 TxData,调用方继续使用外层统一接口:

type NewTx struct {
    GasLimit uint64
}

func (*NewTx) txType() uint8        { return NewTxType }
func (tx *NewTx) gas() uint64       { return tx.GasLimit }
func (tx *NewTx) setGas(gas uint64) { tx.GasLimit = gas }
// 实现其余 TxData 方法。

tx := NewTransaction(&NewTx{GasLimit: gas})
tx.SetGas(newGas)

新增类型还需要在 type factory 中增加对应的解码分支,但不需要给 Transaction 增加新字段。

3. 修改量

除了当前代码的修改,参考 goquarkchain 的实际使用场景:

  • 外部迁移合计约涉及 33 个文件、305 处引用,大部分是删除 .EvmTx 的简单机械替换。
  • NewEvmTransactionNewEvmContractCreation 约有 69 处调用,都需要分别重命名为 NewQkcTransactionNewQkcContractCreation
  • 原来额外包装 EvmTransaction 的代码可以直接删除:
// 修改前:evmTx 是 *EvmTransaction,tx 是 *Transaction
evmTx := types.NewEvmTransaction(...)
tx := &types.Transaction{TxType: types.EvmTx, EvmTx: evmTx}

// 修改后:tx 直接是 *Transaction
tx := types.NewQkcTransaction(...)

整体上,这是一次范围较广但以机械修改为主。实现和 review 时需要重点验证 Serialize/Deserialize 的交易字节、交易 hash、签名结果及 minor-block Merkle root 与修改前完全一致。

Restructure QKC transactions from the three-layer
Transaction -> EvmTransaction -> txdata model to a geth-style
two-layer Transaction -> QkcTx (implements TxData) model.

Wire bytes, transaction hash, signature results and minor-block
Merkle root are preserved for existing (v0) transactions. Caches
and setters move to the outer Transaction, and version-2 signing
is now internally consistent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant