hyperledger-cacti / cacti

Hyperledger Cacti is a new approach to the blockchain interoperability problem
https://wiki.hyperledger.org/display/cactus
Apache License 2.0
338 stars 282 forks source link

Implement/Augment Besu Interoperation Module #2489

Open VRamakrishna opened 2 years ago

VRamakrishna commented 2 years ago

Create a set of interop contracts in Solidity to support data sharing with a Besu network as one of the participating networks. These include:

  1. handleExternalRequest
  2. writeExternalState
dhinakaran2705 commented 2 years ago

One of the main tasks of handleExternalRequest is proof generation.

To obtain a signature by the validators on the contract response:

  1. Start with the Transaction Receipt Object for the transaction of interest.
  2. From the block hash present in the Transaction Receipt Object, obtain the Block Object.
  3. Obtain the receiptsRoot in the Block Object.
  4. Get the Merkle proof for the Transaction Receipt Object of interest linking it to receiptsRoot.
  5. Extract validator addresses and their signatures from extraData.
  6. Check whether the signature successfully verifies against the receiptsRoot (and the Block Object) being used for all the validator addresses of interest.

Among these, Steps 4 and 6 have to be figured out. In Step 4, we have to figure out how we get the Merkle Patricia trie corresponding to receiptsRoot? In Step 6, three things to be figured out:

a. how to obtain block hash from the Block Object? b. how to verify block hash against the validator signatures? c. identify the parts of Transaction Receipt Object to be hashed and verified against the tree node in the Merkle tree rooted at receiptsRoot.

dhinakaran2705 commented 2 years ago

@sanvenDev identified that the following are the parameters that are hashed to obtain the block hash: {parentHash, ommersHash, coinbase, stateRoot, transactionsRoot, receiptsRoot, logsBloom, difficulty, number, gasLimit, gasUsed, timestamp, extraData, mixHash, nonce, baseFee} But we still have to figure out the hashing routine on obtaining the block hash from the above parameters.

Some seemingly related links to start figuring this out:

  1. receiptRoot hash: https://github.com/hyperledger/besu/blob/main/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java#L72
  2. block header: https://github.com/hyperledger/besu/blob/21.7.0/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeader.java#L199
  3. transaction receipt object: https://github.com/hyperledger/besu/blob/bce6e09aa3e52175b988e7e2b5a77192a2d566d1/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java#L144
dhinakaran2705 commented 2 years ago

After a discussion in Hyperledger Discord channel (https://discord.com/channels/905194001349627914/938504958909747250/1003647719291764797) and a conversation internally, we realized that the implementation in Besu (and possibly also the web3 recover() function) of the validity and recovery of the validators implicitly performs the ECDSA signature verification. This resolves Question b in the comment above.

The link suggested in the above Discord chat shows how the block has is computed. So, this, in addition to @sanvenDev's finding in the above comment, resolves Question a.

We still have to figure out the answer to a part of Question c.

sandeepnRES commented 2 years ago

extraData field in block header object contains signatures of the validators (atleast 2/3rd of the total validators) on the hash of blockHeader object. During this computation of the hash, the signature field in extraData is removed.

Proof:

  1. Signatures of Validators: Array
  2. BlockHeader Object: {parentHash, ommersHash, coinbase, stateRoot, transactionsRoot, receiptsRoot, logsBloom, difficulty, number, gasLimit, gasUsed, timestamp, extraData (without signatures), mixHash, nonce, baseFee}.
  3. TransactionReceipt Object of the transaction of interest. (Is transaction receipt header object sufficient?)
  4. Merkle Proof for this TransactionReceipt object linking to receiptsRoot in block header object.

Flow of trust / reverse flow of verification: Data -> TransactionReceipt Object -(merkle proof)-> ReceiptsRoot -> BlockHeader -(hash and sign)-> Signature

sandeepnRES commented 2 years ago

Steps to obtain data:

  1. Get transaction Hash (txHash) from response of interop contract handleExternalRequest function call.
  2. Get transactionReceipt object from txHash (web3.eth.getTransactionReceipt) -> txRcpt.
  3. Get logs of txRcpt, and get the index of log whose address is interop contract. Make sure in handleExternalRequest there is only one event emitted. Else we obtain id by the event name from the response, and filter txRcpt using this id.
  4. From the logs[index], get the data by logs[index].args.data.
sandeepnRES commented 2 years ago

Steps to generate proof:

  1. Get transaction Hash (txHash), and blockHash from response of interop contract handleExternalRequest function call.
  2. Get Transaction Receipt Object from txHash.
  3. Get Block Object from blockHash.
  4. Obtain the receiptsRoot in the Block Object.
  5. Generate the Merkle-Patricia proof for the Transaction Receipt Object of interest linking it to receiptsRoot.
  6. Extract validator addresses and their signatures from extraData.
  7. Extract header fields from Block object (and transaction receipt?), and compose the proof.

We still have to figure out Step 5, which is related to Question c in the first comment.

sandeepnRES commented 2 years ago

Typescript library for merkle patricia trie: https://www.npmjs.com/package/merkle-patricia-tree

We can try this to generate merkle-patricia proof.

sandeepnRES commented 2 years ago

To explore: how to specify particular validators i.e. the verification policy specified by the destination network.

sandeepnRES commented 2 years ago

To explore: