From bda2838395f91ae6e20e52d1ae2221426decc3ea Mon Sep 17 00:00:00 2001 From: Kyon <32325790+kyonRay@users.noreply.github.com> Date: Wed, 17 Apr 2024 20:22:04 +0800 Subject: [PATCH] (v3): update c sdk docs. (#1793) --- .../docs/sdk/c_sdk/assemble_transaction.md | 210 ++++++++++++++++++ 3.x/zh_CN/docs/sdk/c_sdk/dylibs.md | 46 +++- 3.x/zh_CN/docs/sdk/c_sdk/index.md | 2 + .../docs/sdk/c_sdk/transaction_data_struct.md | 205 +++++++++++++++++ 4 files changed, 462 insertions(+), 1 deletion(-) create mode 100644 3.x/zh_CN/docs/sdk/c_sdk/assemble_transaction.md create mode 100644 3.x/zh_CN/docs/sdk/c_sdk/transaction_data_struct.md diff --git a/3.x/zh_CN/docs/sdk/c_sdk/assemble_transaction.md b/3.x/zh_CN/docs/sdk/c_sdk/assemble_transaction.md new file mode 100644 index 000000000..3bb3f2edf --- /dev/null +++ b/3.x/zh_CN/docs/sdk/c_sdk/assemble_transaction.md @@ -0,0 +1,210 @@ +# 交易构造与发送 + +标签:``c-sdk`` ``组装交易`` + +---- + +```eval_rst +.. important:: + FISCO BCOS 在3.6.0版本以后开始支持V1版本的交易,在3.7.0版本以后开始支持V2交易,在使用之前请确认发送的节点版本。3.6.0版本特性请参考:`v3.6.0 <../introduction/change_log/3_6_0.html>`_ +``` + +```eval_rst +.. note:: + 交易的数据结构可以参考 `这里 <./transaction_data_struct.html>`_ +``` + +FISCO BCOS 在3.6.0版本以后开始支持V1版本的交易,在3.7.0版本以后开始支持V2交易,新增以下五个字段: + +```c++ +string value; // v1交易新增字段,原生转账金额 +string gasPrice; // v1交易新增字段,执行时gas的单价(gas/wei) +long gasLimit; // v1交易新增字段,交易执行时gas使用的上限 +string maxFeePerGas; // v1交易新增字段,EIP1559预留字段 +string maxPriorityFeePerGas; // v1交易新增字段,EIP1559预留字段 +vector extension; // v2交易新增字段,用于额外存储 +``` + +为了解决未来可能的增加交易字段的需求,C SDK支持全新的能够支持灵活拼装的交易服务,方便用户开发者灵活使用。 + +## 1. 交易结构体定义 + +在3.6.0以后增加了使用交易结构体的支持,即返回值、入参都支持使用交易结构体。结构体如下: + +```c +// 基础bytes类型 +struct bcos_sdk_c_bytes +{ + uint8_t* buffer; + uint32_t length; +}; +// v0交易data结构体 +struct bcos_sdk_c_transaction_data +{ + int32_t version; + int64_t block_limit; + char* chain_id; + char* group_id; + char* nonce; + char* to; + char* abi; + struct bcos_sdk_c_bytes* input; +}; +// v1交易data结构体 +struct bcos_sdk_c_transaction_data_v1 +{ + struct bcos_sdk_c_transaction_data base; + char* value; + char* gas_price; + int64_t gas_limit; + char* max_fee_per_gas; + char* max_priority_fee_per_gas; +}; +// v2交易data结构体 +struct bcos_sdk_c_transaction_data_v2 +{ + struct bcos_sdk_c_transaction_data_v1 base_v1; + struct bcos_sdk_c_bytes* extension; +}; +// v0交易结构体 +struct bcos_sdk_c_transaction +{ + struct bcos_sdk_c_transaction_data* transaction_data; + struct bcos_sdk_c_bytes* data_hash; + struct bcos_sdk_c_bytes* signature; + struct bcos_sdk_c_bytes* sender; + int64_t import_time; + int32_t attribute; + char* extra_data; +}; +// v1交易结构体 +struct bcos_sdk_c_transaction_v1 +{ + struct bcos_sdk_c_transaction_data_v1* transaction_data; + struct bcos_sdk_c_bytes* data_hash; + struct bcos_sdk_c_bytes* signature; + struct bcos_sdk_c_bytes* sender; + int64_t import_time; + int32_t attribute; + char* extra_data; +}; +// v2交易结构体 +struct bcos_sdk_c_transaction_v2 +{ + struct bcos_sdk_c_transaction_data_v2* transaction_data; + struct bcos_sdk_c_bytes* data_hash; + struct bcos_sdk_c_bytes* signature; + struct bcos_sdk_c_bytes* sender; + int64_t import_time; + int32_t attribute; + char* extra_data; +}; +``` + +## 2. 交易的组装过程 + +SDK需要先组装好 `TransactionData`,再组装交易数据结构为 `Transaction`,最后对交易数据结构进行编码,发到区块链节点。具体步骤如下: + +- 交易调用合约的实际参数,使用ABI/Scale编码后作为 `input` 字段; +- 传入`blockLimit`字段,一般为当前块高+600; +- 传入`nonce`字段,一般为随机16进制字符串; +- 传入其他参数,构造出 `TransactionData` 结构体对象; +- 对`TransactionData`的对象进行哈希计算; +- 使用密钥对上一步骤计算出的哈希值(字节数组)进行签名计算,得出签名; +- 传入其他参数,构造出 `Transaction` 结构体对象; +- 使用`Tars`编码对 `Transaction` 结构体对象进行编码; +- 得到最终的交易Raw data,发送到链上。 + +## 3. 交易结构体计算接口 + +下面以 `v2` 版本交易为例,以交易组装的过程为时间线,介绍交易结构体的计算接口。 + +### 3.1 构造TransactionData结构体 + +接口`bcos_sdk_create_transaction_data_struct_v2` + +- 功能: + - 创建`bcos_sdk_c_transaction_data_v2`交易结构体,该对象结构体是未签名的交易对象 +- 参数: + - `version`: 交易版本,根据使用的交易字段情况传入对应的交易版本,默认为2 + - `group_id`: 群组ID + - `chain_id`: 链ID,可以调用`bcos_sdk_get_group_chain_id`接口获取群组的链ID + - `to`: 调用的合约地址,部署合约时设置为空字符串"" + - `input`: ABI编码后的参数,bytes数组,需要传入bytes指针以及长度 + - `abi`: 合约的ABI,JSON字符串,可选参数,部署合约时可以将合约的ABI传入,默认传入空字符串"" + - `block_limit`: 区块限制,可以调用`bcos_rpc_get_block_limit`接口获取 + - `value`: 交易transfer balance的值 + - `gas_price`: 交易给定的gas price + - `gas_limit`: 交易最大使用gas 数量 + - `max_fee_per_gas`: 交易给定的EIP-1559字段 + - `max_priority_fee_per_gas`: 交易给定的EIP-1559字段 + - `extension`: 交易可额外存储的bytes类型,需要传入bytes指针以及长度 +- 返回: + - `bcos_sdk_c_transaction_data_v2`交易结构体指针 + - 失败返回`NULL`,使用`bcos_sdk_get_last_error`、 `bcos_sdk_get_last_error_msg`获取错误码和错误描述信息 +- 注意: + - `bcos_sdk_c_transaction_data_v2`交易结构体,需要调用`bcos_sdk_destroy_transaction_data_struct_v2`接口释放,以免造成内存泄露 + +### 3.2 计算TransactionData结构体Hash + +接口 `bcos_sdk_calc_transaction_data_struct_hash_v2` + +- 功能:计算交易Data对象的哈希 +- 参数: + - `crypto_type`: 哈希类型,0 为keccak256,1 为SM3 + - `bcos_sdk_c_transaction_data_v2`: transactionData指针 +- 返回:交易哈希,Hex String形式 +- 注意:计算哈希时会根据交易的版本号进行不同判断,哈希计算错误会导致交易上链检查失败,因此请正确设置交易版本号。 + +### 3.3 使用签名、交易哈希构造交易Transaction结构体 + +在使用3.2的接口计算出交易哈希之后,可以使用C-SDK的接口,或者外部签名服务计算出对交易哈希的签名。 + +**注意:FISCO BCOS的签名的构造方式为:** + +- 如果是ECDSA签名,签名的字节构造方式为 R||S||V,其中V为标准ECDSA的值,取值范围是[0,1] +- 如果是SM2签名,签名的字节构造方式为 R||S||PK,其中PK为私钥的公钥 + +接口 `bcos_sdk_create_encoded_transaction_v2` + +- 功能:使用签名、交易哈希构造出编码后的交易,可直接发送到链上 +- 参数: + - `bcos_sdk_c_transaction_data_v2` : 交易TransactionData对象指针 + - `signature` :对交易哈希的签名,Hex String格式 + - `transaction_data_hash` : 交易哈希,Hex String格式 + - `attribute`: 交易属性,待拓展,默认填0即可 + - `extra_data`: 交易额外数据,可存额外交易值,填""空字符串即可 +- 返回:编码后的交易数据结构,Hex String格式,可直接用于上链 + +接口 `bcos_sdk_encode_transaction_struct_to_hex_v2` + +- 功能:可另外构建Transaction结构体,对其进行编码,可直接发送到链上 +- 参数: + - `bcos_sdk_c_transaction_v2` : 交易Transaction对象指针 +- 返回:编码后的交易数据结构,Hex String格式,可直接用于上链 + +### 3.4 解析已编码的Transaction + +接口 `bcos_sdk_decode_transaction_struct_from_hex_v2`: + +- 功能:可解析已`Tars`编码过后的交易Hex String,构造出Transaction结构体 +- 参数:`transaction_hex_str` Tars编码后的交易结构体,Hex String +- 返回:`bcos_sdk_c_transaction_v2` :transaction对象指针 + +### 3.5 释放TransactionData结构体 + +由于`C-SDK`在构造交易结构体的时候都是使用指针进行操作。因此按照C的规范做法,每次在使用完交易结构体后应该主动调用释放结构体接口,以免内存泄漏。 + +接口 `bcos_sdk_destroy_transaction_data_struct_v2` + +- 功能:释放构造好的transactionData对象。 +- 参数:`bcos_sdk_c_transaction_data_v2` transactionData指针 +- 注意:调用完该接口后不应该再次使用该指针,也不应该多次使用同一个指针调用该接口。 + +### 3.6 释放Transaction结构体 + +接口 `bcos_sdk_destroy_transaction_struct_v2` + +- 功能:释放构造好的transaction对象。 +- 参数:`bcos_sdk_c_transaction_v2` transactionData指针 +- 注意:调用完该接口后不应该再次使用该指针,也不应该多次使用同一个指针调用该接口。 diff --git a/3.x/zh_CN/docs/sdk/c_sdk/dylibs.md b/3.x/zh_CN/docs/sdk/c_sdk/dylibs.md index 35e52dc70..8fe0f4309 100644 --- a/3.x/zh_CN/docs/sdk/c_sdk/dylibs.md +++ b/3.x/zh_CN/docs/sdk/c_sdk/dylibs.md @@ -6,6 +6,51 @@ `bcos-c-sdk`已经提供了各个平台的动态库, 用户可以直接下载使用: +## v3.7.0 + +- bcos-c-sdk.dll # windows dll + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.7.0/bcos-c-sdk.dll) +- bcos-c-sdk.lib # windows dll symbol + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.7.0/bcos-c-sdk.lib) +- libbcos-c-sdk-aarch64.so # linux arm64 + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.7.0/libbcos-c-sdk-aarch64.so) +- libbcos-c-sdk.so # linux x64 + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.7.0/libbcos-c-sdk.so) +- libbcos-c-sdk-aarch64.dylib # mac m1 + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.7.0/libbcos-c-sdk-aarch64.dylib) +- libbcos-c-sdk.dylib # mac x64 + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.7.0/libbcos-c-sdk.dylib) + +## v3.6.0 + +- bcos-c-sdk.dll # windows dll + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.6.0/bcos-c-sdk.dll) +- bcos-c-sdk.lib # windows dll symbol + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.6.0/bcos-c-sdk.lib) +- libbcos-c-sdk-aarch64.so # linux arm64 + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.6.0/libbcos-c-sdk-aarch64.so) +- libbcos-c-sdk.so # linux x64 + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.6.0/libbcos-c-sdk.so) +- libbcos-c-sdk-aarch64.dylib # mac m1 + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.6.0/libbcos-c-sdk-aarch64.dylib) +- libbcos-c-sdk.dylib # mac x64 + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.6.0/libbcos-c-sdk.dylib) + +## v3.5.0 + +- bcos-c-sdk.dll # windows dll + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.5.0/bcos-c-sdk.dll) +- bcos-c-sdk.lib # windows dll symbol + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.5.0/bcos-c-sdk.lib) +- libbcos-c-sdk-aarch64.so # linux arm64 + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.5.0/libbcos-c-sdk-aarch64.so) +- libbcos-c-sdk.so # linux x64 + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.5.0/libbcos-c-sdk.so) +- libbcos-c-sdk-aarch64.dylib # mac m1 + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.5.0/libbcos-c-sdk-aarch64.dylib) +- libbcos-c-sdk.dylib # mac x64 + - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.5.0/libbcos-c-sdk.dylib) + ## v3.4.0 - bcos-c-sdk.dll # windows dll @@ -21,7 +66,6 @@ - libbcos-c-sdk.dylib # mac x64 - [github下载](https://github.com/FISCO-BCOS/bcos-c-sdk/releases/download/v3.4.0/libbcos-c-sdk.dylib) - ## v3.3.0 - bcos-c-sdk.dll # windows dll diff --git a/3.x/zh_CN/docs/sdk/c_sdk/index.md b/3.x/zh_CN/docs/sdk/c_sdk/index.md index cb7163263..1a05d63e4 100644 --- a/3.x/zh_CN/docs/sdk/c_sdk/index.md +++ b/3.x/zh_CN/docs/sdk/c_sdk/index.md @@ -15,6 +15,8 @@ dylibs.md config.md api.md + transaction_data_struct.md + assemble_transaction.md dev.md appendix.md faq.md diff --git a/3.x/zh_CN/docs/sdk/c_sdk/transaction_data_struct.md b/3.x/zh_CN/docs/sdk/c_sdk/transaction_data_struct.md new file mode 100644 index 000000000..e344f9326 --- /dev/null +++ b/3.x/zh_CN/docs/sdk/c_sdk/transaction_data_struct.md @@ -0,0 +1,205 @@ +# 交易与回执数据结构与组装过程 + +标签:``java-sdk`` ``组装交易`` ``数据结构`` ``交易`` ``交易回执`` + +--- + +## 1. 交易数据结构解释 + +3.0的交易定义于FISCO-BCOS仓库中 `bcos-tars-protocol/bcos-tars-protocol/tars/Transaction.tars` 中定义,可见链接:[Transaction.tars](https://github.com/FISCO-BCOS/FISCO-BCOS/blob/master/bcos-tars-protocol/bcos-tars-protocol/tars/Transaction.tars)。数据结构如下所示: + +```c++ +module bcostars { + struct TransactionData { + 1 optional int version; // 交易版本号,目前已有v0,v1,v2三种交易 + 2 optional string chainID; // 链名 + 3 optional string groupID; // 群组名 + 4 optional long blockLimit; // 交易限定执行的区块高度 + 5 optional string nonce; // 交易唯一性标识 + 6 optional string to; // 交易调用的合约地址 + 7 optional vector input; // 交易调用合约的参数,经过ABI/Scale编码 + 8 optional string abi; // ABI的JSON字符串,建议在部署合约时带上ABI + 9 optional string value; // v1交易新增字段,原生转账金额 + 10 optional string gasPrice; // v1交易新增字段,执行时gas的单价(gas/wei) + 11 optional long gasLimit; // v1交易新增字段,交易执行时gas使用的上限 + 12 optional string maxFeePerGas; // v1交易新增字段,EIP1559预留字段 + 13 optional string maxPriorityFeePerGas; // v1交易新增字段,EIP1559预留字段 + 14 optional vector extension; // v2交易新增字段,用于额外存储 + }; + + struct Transaction { + 1 optional TransactionData data; // 交易基础字段 + 2 optional vector dataHash; // 交易基础字段data的哈希值 + 3 optional vector signature; // 对交易基础字段data的哈希值字节的签名 + 4 optional long importTime; // 交易到达交易池的时间 + 5 optional int attribute; // 交易属性,EVM交易为1,默认可填写0;WASM交易为2;WASM部署交易为2 || 8; + // 6 optional string source; + 7 optional vector sender; // 交易发起的EOA地址 + 8 optional string extraData; // 交易额外字段,该字段不计算哈希 + }; +}; +``` + +## 2. 交易回执数据结构解释 + +3.0的交易回执定义于FISCO-BCOS仓库中 `bcos-tars-protocol/bcos-tars-protocol/tars/TransactionReceipt.tars` 中定义,可见链接:[TransactionReceipt.tars](https://github.com/FISCO-BCOS/FISCO-BCOS/blob/master/bcos-tars-protocol/bcos-tars-protocol/tars/TransactionReceipt.tars)。数据结构如下所示: + +```c++ +module bcostars { + struct LogEntry { // 事件结构体 + 1 optional string address; // 事件合约地址 + 2 optional vector> topic; // 事件的indexed字段的topic,最多为4 + 3 optional vector data; // 事件的indexed字段以外的数值,ABI编码 + }; + + struct TransactionReceiptData { // 交易回执基础类型 + 1 require int version; // 交易回执的版本,目前已有v0,v1,v2 + 2 optional string gasUsed; // 交易使用的gas + 3 optional string contractAddress; // 交易调用的合约地址,若为部署合约交易则为新的合约地址 + 4 optional int status; // 交易执行状态,为0则成功;非0为不成功,将在output写入错误信息(Error(string) ABI编码后的值) + 5 optional vector output; // 交易执行返回值 + 6 optional vector logEntries; // 事件列表 + 7 optional long blockNumber;// 交易执行所在的块高 + 8 optional string effectiveGasPrice; // v1版本新增字段,交易执行时生效的gas单价(gas/wei) + }; + + struct TransactionReceipt { // 交易回执类型 + 1 optional TransactionReceiptData data; // 交易回执基础类型 + 2 optional vector dataHash; // 交易回执基础类型data的哈希值 + 3 optional string message; // 交易回执返回信息 + }; +}; +``` + +## 3. 交易的组装过程 + +由上所示,SDK需要先组装好 `TransactionData`,再组装交易数据结构为 `Transaction`,最后发到区块链节点。具体步骤如下: + +- 交易调用合约的实际参数,使用ABI/Scale编码后作为 `input` 字段; +- 传入`blockLimit`字段,一般为当前块高+600; +- 传入`nonce`字段,一般为随机16进制字符串; +- 传入其他参数,构造出 `TransactionData` 结构体对象; +- 对`TransactionData`的对象进行哈希计算,哈希计算算法可见第4小节; +- 使用密钥对上一步骤计算出的哈希值(字节数组)进行签名计算,得出签名; +- 传入其他参数,构造出 `Transaction` 结构体对象; +- 使用`Tars`编码对 `Transaction` 结构体对象进行编码; +- 得到最终的交易Raw data,发送到链上。 + +## 4. TransactionData哈希计算算法与示例 + +TransactionData在进行哈希计算时,是对该对象内的所有字段的字节进行拼装,最后对字节数组进行哈希计算。C++实现的示例如下: + +```c++ +int32_t version = boost::endian::native_to_big((int32_t)hashFields.version); +hasher.update(version); +hasher.update(hashFields.chainID); +hasher.update(hashFields.groupID); +int64_t blockLimit = boost::endian::native_to_big((int64_t)hashFields.blockLimit); +hasher.update(blockLimit); +hasher.update(hashFields.nonce); +hasher.update(hashFields.to); +hasher.update(hashFields.input); +hasher.update(hashFields.abi); +// if version == 1, update value, gasPrice, gasLimit, maxFeePerGas, maxPriorityFeePerGas to +// hashBuffer calculate hash +if ((uint32_t)hashFields.version >= (uint32_t)bcos::protocol::TransactionVersion::V1_VERSION) +{ + hasher.update(hashFields.value); + hasher.update(hashFields.gasPrice); + int64_t bigEndGasLimit = boost::endian::native_to_big((int64_t)hashFields.gasLimit); + hasher.update(bigEndGasLimit); + hasher.update(hashFields.maxFeePerGas); + hasher.update(hashFields.maxPriorityFeePerGas); +} +if ((uint32_t)hashFields.version >= (uint32_t)bcos::protocol::TransactionVersion::V2_VERSION) +{ + hasher.update(hashFields.extension); +} +hasher.final(out); +``` + +Java实现的示例如下: + +```java +ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); +// version +byteArrayOutputStream.write(toBytesPadded(BigInteger.valueOf(getVersion()), 4)); +// chainId +byteArrayOutputStream.write(getChainID().getBytes()); +// groupId +byteArrayOutputStream.write(getGroupID().getBytes()); +// blockLimit +byteArrayOutputStream.write(toBytesPadded(BigInteger.valueOf(getBlockLimit()), 8)); +// nonce +byteArrayOutputStream.write(Hex.decode(getNonce())); +// to +byteArrayOutputStream.write(getTo().getBytes()); +// input +byteArrayOutputStream.write(Hex.decode(getInput())); +// abi +byteArrayOutputStream.write(getAbi().getBytes()); +if (getVersion() == TransactionVersion.V1.getValue()) { + byteArrayOutputStream.write(getValue().getBytes()); + byteArrayOutputStream.write(getGasPrice().getBytes()); + byteArrayOutputStream.write(toBytesPadded(BigInteger.valueOf(getGasLimit()), 8)); + byteArrayOutputStream.write(getMaxFeePerGas().getBytes()); + byteArrayOutputStream.write(getMaxPriorityFeePerGas().getBytes()); +} +if (getVersion() == TransactionVersion.V2.getValue()) { + byteArrayOutputStream.write(getExtension()); +} +return byteArrayOutputStream.toByteArray(); +``` + +## 5. TransactionReceiptData哈希计算算法与示例 + +如同第4节所述,TransactionReceiptData的哈希计算方法也是对该对象内的所有字段的字节进行拼装,最后对字节数组进行哈希计算。C++实现的示例如下: + +```c++ +int32_t version = boost::endian::native_to_big((int32_t)hashFields.version); +hasher.update(version); +hasher.update(hashFields.gasUsed); +hasher.update(hashFields.contractAddress); +int32_t status = boost::endian::native_to_big((int32_t)hashFields.status); +hasher.update(status); +hasher.update(hashFields.output); +if(hashFields.version >= int32_t(bcos::protocol::TransactionVersion::V1_VERSION)) +{ + hasher.update(hashFields.effectiveGasPrice); +} +for (auto const& log : hashFields.logEntries) +{ + hasher.update(log.address); + for (auto const& topicItem : log.topic) + { + hasher.update(topicItem); + } + hasher.update(log.data); +} +int64_t blockNumber = boost::endian::native_to_big((int64_t)hashFields.blockNumber); +hasher.update(blockNumber); +hasher.final(out); +``` + +Java实现的示例如下: + +```java +ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); +byteArrayOutputStream.write(toBytesPadded(BigInteger.valueOf(getVersion()), 4)); +byteArrayOutputStream.write(getGasUsed().getBytes()); +byteArrayOutputStream.write(getContractAddress().getBytes()); +byteArrayOutputStream.write(toBytesPadded(BigInteger.valueOf(getStatus()), 4)); +byteArrayOutputStream.write(getOutput().getBytes()); +if (getVersion() == TransactionVersion.V1.getValue()) { + byteArrayOutputStream.write(getEffectiveGasPrice().getBytes()); +} +for (Logs logEntry : getLogEntries()) { + byteArrayOutputStream.write(logEntry.getAddress().getBytes()); + for (String topic : logEntry.getTopics()) { + byteArrayOutputStream.write(topic.getBytes()); + } + byteArrayOutputStream.write(logEntry.getData().getBytes()); +} +byteArrayOutputStream.write(toBytesPadded(getBlockNumber(), 8)); +return byteArrayOutputStream.toByteArray(); +```