TradeTrust / tradetrust-website

https://tradetrust.io
Apache License 2.0
17 stars 32 forks source link

Enhance performance of View endorsement chain #923

Open satz07 opened 2 months ago

satz07 commented 2 months ago

Issue: View endorsement chain option while verifying document is getting timed out or resulting in RPC errors

Issue Description: When verifying a document and attempting to view the endorsement chain on the TradeTrust platform, the process often results in 'time out' or 'block range too wide' errors. This issue arises from an eth_getLogs RPC call that queries the blockchain (archive node) from the genesis block to the latest block. Due to the extensive block range, the process is resource-intensive and prone to errors.

Steps to Reproduce: Create a document on the TradeTrust platform (e.g., eBoL) at TradeTrust Document Creator. Verify the document on the TradeTrust platform at TradeTrust Verify. Once the document is verified, click on the "View endorsement chain" option. Alternatively, replicate the issue using the following command:

curl -X POST -H "Content-Type: application/json" --data '{
  "method":"eth_getLogs",
  "params":[{
    "fromBlock":"0x0",
    "toBlock":"latest",
    "address":"0xYourContractAddress",
    "topics":[
      "0xYourEventSignature",
      null,
      null,
      "0xYourDocumentHash"
    ]
  }],
  "id":59,
  "jsonrpc":"2.0"
}' <RPC_URL>

Suggested Enhancements: To optimize the process and effectively fetch the data, it is recommended to implement an events mechanism in the smart contract functions. Logging events when actions such as issuing a document, transferring ownership, or changing ownership occur will allow for more efficient data retrieval using filter log

Example Enhancement: Add events to the smart contract and log them during relevant actions. Below is an example of how to add and use events in a smart contract:

Smart Contract Example:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract DocumentManagement {
    event DocumentIssued(address indexed issuer, uint256 indexed documentId, string documentHash);
    event OwnershipTransferred(address indexed from, address indexed to, uint256 indexed documentId);

    function issueDocument(uint256 documentId, string memory documentHash) public {
        // Issue document logic...
        emit DocumentIssued(msg.sender, documentId, documentHash);
    }

    function transferOwnership(address to, uint256 documentId) public {
        // Transfer ownership logic...
        emit OwnershipTransferred(msg.sender, to, documentId);
    }
}

Query Logs with Filters:

async function getDocumentEvents(documentId) {
    const filter = {
        address: contractAddress,
        topics: [
            [documentIssuedEventSignature, ownershipTransferredEventSignature],
            null,
            ethers.utils.hexZeroPad(ethers.BigNumber.from(documentId).toHexString(), 32)
        ],
        fromBlock: "earliest",
        toBlock: "latest"
    };
    const logs = await provider.getLogs(filter);
    logs.forEach(log => {
        const parsedLog = contract.interface.parseLog(log);
        console.log(parsedLog);
    });
}

Related Pull Request: A pull request was made to make the fromBlockNumber configurable for each chain, but implementing the event mechanism described above would provide a more optimized solution: PR #921

isaackps commented 2 months ago

Hi,

Thank you for the suggestion! its a great suggestion for improvement, let me take it back to the team and analyse what we can do to the smart contract for this improvement.

👍

MinHtet-O commented 1 month ago

Hi @satz07

Thank you very much for your suggestion. So far, we have been emitting events in our smart contract and using log filters in our frontend to query the blockchain.

This piece of code is from token-registry

  function _setBeneficiary(address newBeneficiary) internal virtual {
    emit BeneficiaryTransfer(beneficiary, newBeneficiary, registry, tokenId);
    _setNominee(address(0));
    beneficiary = newBeneficiary;
  }  

And in tradetrust-website, we are using filters.

 export const fetchOwnerTransfers = async (
  titleEscrowContract: TitleEscrow,
  provider: providers.Provider
): Promise<TitleEscrowTransferEvent[]> => {
  const ownerChangeFilter = titleEscrowContract.filters.BeneficiaryTransfer(null, null);
  const ownerChangeLogs = await provider.getLogs({ ...ownerChangeFilter, fromBlock: 0 });

  const ownerChangeLogsParsed = getParsedLogs(ownerChangeLogs, titleEscrowContract);
  return ownerChangeLogsParsed.map((event) => ({
    type: "TRANSFER_BENEFICIARY",
    owner: event.args.toBeneficiary,
    blockNumber: event.blockNumber,
    transactionHash: event.transactionHash,
    transactionIndex: event.transactionIndex,
  }));
};

Based on your suggestion, do you think we need more detailed fine-grained event logging?

Feel free to adjust further if needed!