Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved SmartContract classes inheritance lookup used during the zkApps deployment procedure. #640

Merged
merged 15 commits into from
May 16, 2024

Conversation

shimkiv
Copy link
Member

@shimkiv shimkiv commented May 11, 2024

Closes #636


Includes dependencies and tests upgrade/update.


Description (a bit outdated after the last commit)

This PR introduces the mechanism to identify classes extending or implementing the o1js SmartContract class in a given JavaScript file that are scanned using pattern ./build/**/*.js.
The core method findIfClassExtendsOrImplementsSmartContract(entryFilePath) performs this operation.
Below is a step-by-step breakdown of how this method works, with explanations of the intermediate methods it invokes, using an example:

./build/src/SomeZkApp.js

import { someOtherLib } from 'someOtherLib';
import { SmartContract } from 'o1js';

export class TestZkApp extends SmartContract {}
export class AnotherTestZkApp extends TestZkApp {}
export class SomethingElse extends Parent {}

findIfClassExtendsOrImplementsSmartContract(entryFilePath)

This method identifies all classes in the provided file that extend or implement the SmartContract class (Note: the o1js belonging is yet to be fixed).
It is being invoked with the file path to process like this:

const result = findIfClassExtendsOrImplementsSmartContract('./build/src/SomeZkApp.js');

It returns:

[
  { "className": "TestZkApp", "filePath": "./build/scr/SomeZkApp.js" },
  { "className": "AnotherTestZkApp", "filePath": "./build/src/SomeZkApp.js" }
]

This data then used by zkapp-cli deploy method to proceed (if only 1 SC is available) or prompt user to select which SC to deploy.

Steps:

  1. Build class hierarchy: Calls buildClassHierarchy(entryFilePath) to generate a map of class names to class information.
  2. Resolve imports: Calls resolveImports(entryFilePath) to map local import names to their resolved file paths.
  3. Check inheritance: Iterates over the classes found in the class hierarchy and checks if they extend or implement SmartContract by calling checkClassInheritance().

Intermediate methods involved

  1. buildClassHierarchy(filePath):

    • Purpose: To parse the file and create a map of class declarations.
    • Reason: Essential for understanding the structure of classes within the file, including their inheritance and implemented interfaces.

    This function parses the file to build a hierarchy of class declarations.

    const classesMap = buildClassHierarchy('./build/src/SomeZkApp.js');

    Returns:

    {
      "TestZkApp": {
        "extends": "SmartContract",
        "implements": [],
        "filePath": "./build/src/SomeZkApp.js"
      },
      "AnotherTestZkApp": {
        "extends": "TestZkApp",
        "implements": [],
        "filePath": "./build/src/SomeZkApp.js"
      },
      "SomethingElse": {
        "extends": "Parent",
        "implements": [],
        "filePath": "./build/src/SomeZkApp.js"
      }
    }
  2. resolveImports(filePath):

    • Purpose: To resolve import statements to their respective file paths.
    • Reason: Necessary for identifying classes that might extend SmartContract indirectly through imports from other files.

    This function parses the file to resolve import statements to their respective file paths.

    const importMappings = resolveImports('./build/src/SomeZkApp.js');

    Returns:

    {
      "someDep": "./node_modules/someDep/index.js"
    }
  3. resolveModulePath(moduleName, basePath):

    • Purpose: To resolve the path of a module based on its name and the base path of the current file.
    • Reason: Critical for correctly resolving and locating the files referenced in import statements, especially for node modules and relative paths.
  4. checkClassInheritance(className, targetClass, classesMap, visitedClasses, importMappings):

    • Purpose: To recursively check if a given class (or its ancestors) extends or implements the target class.
    • Reason: Ensures comprehensive detection of inheritance chains, even when they span multiple files.

    This recursive function checks if a given class (or its ancestors) extends or implements the target class.

    const result = checkClassInheritance(
      "AnotherTestZkApp",
      "SmartContract",
      classesMap,
      new Set(),
      importMappings
    );

    Returns:

    true

    Steps

    1. Avoid infinite loops: Checks if the class has already been visited to prevent infinite loops.
    2. Extend class hierarchy: If the class is not found in the current hierarchy, it tries to extend the hierarchy using the resolved imports.
    3. Direct check: Checks if the class directly extends or implements the SmartContract class.
    4. Recursive check: Recursively checks the parent class and implemented interfaces.

    Other code segments

    if (!classesMap[className]) {
        let resolvedPath = importMappings[className];
        if (!resolvedPath) return false;
        
        Object.assign(classesMap, buildClassHierarchy(resolvedPath));
    }
    • Purpose:
      • This block handles cases where the class being checked (className) is not found in the current class hierarchy map (classesMap).
      • It attempts to resolve the file path of the class from the import mappings (importMappings) and then extends the class hierarchy by parsing the resolved file.
    • Reason:
      • This code ensures that even if the class hierarchy is split across multiple files, all relevant classes are considered.
      • It allows the method to dynamically build a comprehensive class hierarchy that includes classes defined across multiple files.

@shimkiv shimkiv changed the title Improved the classes SmartContract inheritance lookup used during the zkApps deployment procedure. Improved SmartContract classes inheritance lookup used during the zkApps deployment procedure. May 11, 2024
@shimkiv shimkiv marked this pull request as ready for review May 13, 2024 16:22
@shimkiv shimkiv marked this pull request as draft May 14, 2024 14:40
@shimkiv shimkiv marked this pull request as ready for review May 15, 2024 07:03
Copy link
Collaborator

@ymekuria ymekuria left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@shimkiv shimkiv merged commit 2795090 into main May 16, 2024
12 checks passed
@shimkiv shimkiv deleted the feat/smart-contract-lookup branch May 16, 2024 18:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement better SmartContract classes lookup during the deploy procedure.
2 participants