tip: 250
title: Include transaction results on the chain
author: Andy <Andy.zhang@tron.network>
discussions to: https://github.com/tronprotocol/TIPs/issues/250
status: Final
type: Standards Track
category: Core
created: 2021-04-06
This TIP provides Include transaction results on the chain for java-tron.
Currently, the result of transaction execution is written in the block. But there is no signature, so it can be tampered with. The tampered block will cause other nodes to think it is a bad block. Then disconnect the node connected to it. It will cause certain damage to the network and affect the stability of the TRON network.
Put the transaction results on the chain so that they cannot be tampered with and ensure the security of the TRON network.
public Sha256Hash calcReceiptsRoot(): Calculate the Merkel root of all transaction results public Sha256Hash getReceiptsMerkleHash(): Get the hash value of each transaction result public boolean allowReceiptsMerkleRoot(): Whether to enable the function of trading results on the chain
The receiptsRoot field is added to the block header to store the Merkel root of the transaction result.
message BlockHeader {
message raw {
int64 timestamp = 1;
bytes txTrieRoot = 2;
bytes parentHash = 3;
//bytes nonce = 5;
//bytes difficulty = 6;
int64 number = 7;
int64 witness_id = 8;
bytes witness_address = 9;
int32 version = 10;
bytes accountStateRoot = 11;
bytes receiptsRoot = 12;
}
raw raw_data = 1;
bytes witness_signature = 2;
}
In the stage of generating blocks. All transactions are executed, the transaction results are calculated to generate the transaction result Merkel root (receiptsRoot), and then the receiptsRoot is written into the block header. Finally, the block is signed.
Merkel root generation method of trading results.
public Sha256Hash calcReceiptsRoot() {
List<Transaction> transactionsList = this.block.getTransactionsList();
if (CollectionUtils.isEmpty(transactionsList)) {
return Sha256Hash.ZERO_HASH;
}
ArrayList<Sha256Hash> ids = transactionsList.stream()
.map(TransactionCapsule::new)
.map(TransactionCapsule::getReceiptsMerkleHash)
.collect(Collectors.toCollection(ArrayList::new));
return MerkleTree.getInstance().createTree(ids).getRoot().getHash();
}
Get the hash value of each transaction result.
public Sha256Hash getReceiptsMerkleHash() {
if (this.transaction.getRetCount() <= 0) {
return Sha256Hash.ZERO_HASH;
}
byte[] transBytes = this.transaction.getRet(0).toByteArray();
return Sha256Hash.of(CommonParameter.getInstance().isECKeyCryptoEngine(),
transBytes);
}
When processing a block, it is necessary to verify the root of the transaction result while verifying the transaction root.
if (getDynamicPropertiesStore().allowReceiptsMerkleRoot() && !block.calcReceiptsRoot().equals(block.getReceiptsRoot())) {
throw new BadBlockException("The receipt merkle hash is not validated");
}
Due to the need to modify the protocol, a hard fork is required. By adding a proposal to open the transaction results on the chain function. Proposal id is: 50