Skip to content

Add latest symlinks #1104

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

Closed
wants to merge 1 commit into from
Closed

Add latest symlinks #1104

wants to merge 1 commit into from

Conversation

frangio
Copy link

@frangio frangio commented Jan 31, 2025

closes #817

For discussion. I'd personally find this very useful.

What was wrong?

Navigating to the latest specs requires knowing the fork name. Even though this information is available in the repo, it can be slow to remember and find in the list.

How was it fixed?

A symlink called latest was added.

Cute Animal Picture

image

@SamWilsn
Copy link
Contributor

Looks like this closes #817.

Apparently you can from ethereum import latest in Python, which is interesting. Means that this would probably interact with our versioning scheme. Simplest fix would be to say that imports from latest are not guaranteed to remain stable across HARDFORK version bumps?

@SamWilsn
Copy link
Contributor

Note that if we do decide to go forward with this, we'll need to:

  • Add the file to setup.cfg.
  • Add a lint that ensures the symlink is always pointing to the latest fork.
  • Document the symlink in RELEASING.md.

@frangio
Copy link
Author

frangio commented Feb 26, 2025

  • Add a lint that ensures the symlink is always pointing to the latest fork.

What should I use as the source of truth for what is the latest fork?

@SamWilsn
Copy link
Contributor

Hardfork.discover returns an ordered list.

Let me get a vibe check from @gurukamath and @petertdavies before you put in too much work. Personally, I don't have any objections offhand.

@gurukamath
Copy link
Collaborator

gurukamath commented Feb 26, 2025

Let me get a vibe check from @gurukamath and @petertdavies before you put in too much work. Personally, I don't have any objections offhand.

With the understanding that the latest here means the most recent fork to be live on mainnet, I'm in favour of this with a lint in place.

@SamWilsn
Copy link
Contributor

SamWilsn commented Feb 26, 2025

Let's go ahead with this. If you're willing to work on it @frangio, by all means do. Otherwise, we'll get around to it.

@SamWilsn
Copy link
Contributor

Unfortunately it seems like pip/setuptools don't support symlinks. It might be possible to emulate this with a post-deploy hook, but that wouldn't show up in the repository itself, so less useful.

If we ever come back to this, here's a lint:

"""
Latest Symlink
^^^^^^^^^^^^^^

Ensures that the `latest` symlink points to the latest hardfork.
"""
from pathlib import Path
from typing import List, Sequence

from ethereum_spec_tools.forks import Hardfork
from ethereum_spec_tools.lint import Diagnostic, Lint


class LatestSymlink(Lint):
    """
    Ensures that the `latest` symlink poins to the latest hardfork.
    """

    def lint(
        self, forks: List[Hardfork], position: int
    ) -> Sequence[Diagnostic]:
        """
        Reads the path of the `latest` symlink and compares it to the latest
        hardfork.
        """
        if position != len(forks) - 1:
            return []

        fork = forks[position]
        assert fork.path is not None

        fork_path = Path(fork.path)
        symlink_path = fork_path.parent.joinpath("latest")

        # Use `readlink` instead of `resolve` because there should only ever be
        # one symlink in the chain.
        try:
            print(symlink_path)
            target_path = symlink_path.readlink()
        except FileNotFoundError:
            return [Diagnostic("The latest symlink is missing.")]

        if target_path.is_absolute():
            return [Diagnostic("The latest symlink is not relative.")]

        if len(target_path.parts) != 1:
            return [Diagnostic("The latest symlink is not relative to forks.")]

        target_path = fork_path.parent.joinpath(target_path)

        if not symlink_path.is_symlink():
            return [Diagnostic("The latest pointer is not a symlink.")]

        if target_path.is_symlink():
            return [Diagnostic("The latest symlink target is also a symlink.")]

        target_path = target_path.resolve()
        fork_path = fork_path.resolve()

        if target_path == fork_path:
            return []

        fork_path = fork_path.relative_to(fork_path.parent)
        target_path = target_path.relative_to(target_path.parent)
        return [
            Diagnostic(
                f"The latest symlink should point to `{fork_path}` "
                f"(but points to `{target_path}` instead)."
            )
        ]

@SamWilsn SamWilsn closed this May 20, 2025
@frangio
Copy link
Author

frangio commented May 20, 2025

FWIW, my motivation for this PR was to have a quick way to navigate to the latest spec in the repo, on GitHub. I still think that would be valuable in some form. It could be via symlinks (even if not supported in import paths in Python), or it could be by adding direct links in the readme.

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.

Idea: "latest" directory to always hold latest fork
3 participants