package org.fisco.bcos.web3j.tx; import java.math.BigInteger; import java.util.List; import org.fisco.bcos.channel.client.Merkle; import org.fisco.bcos.channel.client.ReceiptEncoder; import org.fisco.bcos.web3j.crypto.Hash; import org.fisco.bcos.web3j.protocol.core.methods.response.MerkleProofUnit; import org.fisco.bcos.web3j.protocol.core.methods.response.Transaction; import org.fisco.bcos.web3j.protocol.core.methods.response.TransactionReceipt; import org.fisco.bcos.web3j.protocol.core.methods.response.TransactionReceiptWithProof; import org.fisco.bcos.web3j.protocol.core.methods.response.TransactionWithProof; import org.fisco.bcos.web3j.rlp.RlpEncoder; import org.fisco.bcos.web3j.rlp.RlpString; import org.fisco.bcos.web3j.utils.Numeric; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MerkleProofUtility { private static final Logger logger = LoggerFactory.getLogger(MerkleProofUtility.class); /** * Verify transaction merkle proof * * @param transactionRoot * @param transAndProof * @return */ public static boolean verifyTransaction( String transactionRoot, TransactionWithProof.TransAndProof transAndProof) { // transaction index Transaction transaction = transAndProof.getTransaction(); BigInteger index = transaction.getTransactionIndex(); String input = Numeric.toHexString(RlpEncoder.encode(RlpString.create(index))) + transaction.getHash().substring(2); String proof = Merkle.calculateMerkleRoot(transAndProof.getTxProof(), input); logger.debug( " transaction hash: {}, transaction index: {}, root: {}, proof: {}", transaction.getHash(), transaction.getTransactionIndex(), transactionRoot, proof); return proof.equals(transactionRoot); } /** * Verify transaction receipt merkle proof * * @param receiptRoot * @param receiptAndProof * @return */ public static boolean verifyTransactionReceipt( String receiptRoot, TransactionReceiptWithProof.ReceiptAndProof receiptAndProof) { TransactionReceipt transactionReceipt = receiptAndProof.getTransactionReceipt(); // transaction index byte[] byteIndex = RlpEncoder.encode(RlpString.create(transactionReceipt.getTransactionIndex())); if (!transactionReceipt.getGasUsedRaw().startsWith("0x")) { transactionReceipt.setGasUsed("0x" + transactionReceipt.getGasUsed().toString(16)); } String receiptRlp = ReceiptEncoder.encode(transactionReceipt); String rlpHash = Hash.sha3(receiptRlp); String input = Numeric.toHexString(byteIndex) + rlpHash.substring(2); String proof = Merkle.calculateMerkleRoot(receiptAndProof.getReceiptProof(), input); logger.debug( " transaction hash: {}, receipt index: {}, root: {}, proof: {}, receipt: {}", transactionReceipt.getTransactionHash(), transactionReceipt.getTransactionIndex(), receiptRoot, proof, receiptAndProof.getTransactionReceipt()); return proof.equals(receiptRoot); } /** * Verify transaction merkle proof * * @param transactionHash * @param index * @param transactionRoot * @param txProof * @return */ public static boolean verifyTransaction( String transactionHash, BigInteger index, String transactionRoot, List<MerkleProofUnit> txProof) { String input = Numeric.toHexString(RlpEncoder.encode(RlpString.create(index))) + transactionHash.substring(2); String proof = Merkle.calculateMerkleRoot(txProof, input); logger.debug( " transaction hash: {}, transaction index: {}, txProof: {}, transactionRoot: {}, proof: {}", transactionHash, index, txProof, transactionRoot, proof); return proof.equals(transactionRoot); } /** * Verify transaction receipt merkle proof * * @param receiptRoot * @param transactionReceipt * @param receiptProof * @return */ public static boolean verifyTransactionReceipt( String receiptRoot, TransactionReceipt transactionReceipt, List<MerkleProofUnit> receiptProof) { if (!transactionReceipt.getGasUsedRaw().startsWith("0x")) { transactionReceipt.setGasUsed("0x" + transactionReceipt.getGasUsed().toString(16)); } // transaction index byte[] byteIndex = RlpEncoder.encode(RlpString.create(transactionReceipt.getTransactionIndex())); String receiptRlp = ReceiptEncoder.encode(transactionReceipt); String rlpHash = Hash.sha3(receiptRlp); String input = Numeric.toHexString(byteIndex) + rlpHash.substring(2); String proof = Merkle.calculateMerkleRoot(receiptProof, input); logger.debug( " transaction hash: {}, transactionReceipt: {}, receiptProof: {}, receiptRoot: {}, proof: {}", transactionReceipt.getTransactionHash(), transactionReceipt, receiptProof, receiptRoot, proof); return proof.equals(receiptRoot); } }