Managing Intelligent Contract Operations with the Equivalence Principle
The Equivalence Principle is a core concept in GenLayer's Intelligent Contract framework. It ensures consistency and reliability when handling non-deterministic operation results, such as responses from Large Language Models or web data retrieval, by establishing a standard for validators to agree on the correctness of these outputs. These functions give users detailed control over how the outputs are validated.
Depending on how you want the validators to work, you can choose from a few options, such as a principle that uses LLMs or one that just uses a strict comparison.
Advanced users may also choose to write their own equivalence principle
The Equivalence Principle involves multiple validators randomly selected to determine whether different outputs from non-deterministic operations can be considered equivalent. One validator acts as the leader, proposing the output, while others validate it and then return it instead of their computation.
Equivalence Principles Options
Validators work to reach a consensus on whether the result set by the leader is acceptable, which might involve direct comparison or qualitative evaluation, depending on the contract's design. If the validators do not reach a consensus due to differing data interpretations or an error in data processing, the transaction will become undetermined.
Comparative Equivalence Principle
In the Comparative Equivalence Principle, the leader and the validators perform identical tasks and then directly compare their respective results with the predefined criteria to ensure consistency and accuracy. This method uses an acceptable margin of error to handle slight variations in results between validators and is suitable for quantifiable outputs. However, computational demands and associated costs increase since multiple validators perform the same tasks as the leader.
gl.eq_principle_prompt_comparative(
your_non_deterministic_function,
"The result must not differ by more than 5%"
)
For example, if an intelligent contract is tasked with fetching the follower count of a Twitter account and the Equivalence Principle specifies that follower counts should not differ by more than 5%, validators will compare their results to the leader's result utilizing their own LLMs to ensure they fall within this margin.
Non-Comparative Equivalence Principle
In contrast, the Non-Comparative Equivalence Principle does not require validators to replicate the leader's output, which makes the validation process faster and less costly. Instead, validators assess the accuracy of the leader's result against the criteria defined in the Equivalence Principle. This method is particularly useful for qualitative outputs like text summaries.
This feature is in development. GenVM doesn't have an interface for Non-Comparative Equivalence Principle right now
Ideal Scenarios
- Complex decision-making processes that might require fetching and processing large amounts of data
- Situations where outputs from different operations need to be cross-validated against each other
- Tasks that involve sequential steps where each step might affect the outcome of the next
# { "Depends": "py-genlayer:test" }
from genlayer import *
import json
import typing
@gl.contract
class PredictionMarket:
has_resolved: bool
game_date: str
team1: str
team2: str
resolution_url: str
def __init__(self, game_date: str, team1: str, team2: str):
"""
Initializes a new instance of the prediction market with the specified game date and teams.
Args:
game_date (str): The date of the game in the format 'YYYY-MM-DD'.
team1 (str): The name of the first team.
team2 (str): The name of the second team.
Attributes:
has_resolved (bool): Indicates whether the game's resolution has been processed. Default is False.
game_date (str): The date of the game.
resolution_url (str): The URL to the game's resolution on BBC Sport.
team1 (str): The name of the first team.
team2 (str): The name of the second team.
"""
self.has_resolved = False
self.game_date = game_date
self.resolution_url = (
"https://www.bbc.com/sport/football/scores-fixtures/" + game_date
)
self.team1 = team1
self.team2 = team2
@gl.public.write
def resolve(self) -> typing.Any:
if self.has_resolved:
return "Already resolved"
def nondet() -> str:
web_data = gl.get_webpage(self.resolution_url, mode="text")
print(web_data)
task = f"""In the following web page, find the winning team in a matchup between the following teams:
Team 1: {self.team1}
Team 2: {self.team2}
Web page content:
{web_data}
End of web page data.
If it says "Kick off [time]" between the names of the two teams, it means the game hasn't started yet.
If you fail to extract the score, assume the game is not resolved yet.
Respond with the following JSON format:
{{
"score": str, // The score with numbers only, e.g, "1:2", or "-" if the game is not resolved yet
"winner": int, // The number of the winning team, 0 for draw, or -1 if the game is not yet finished
}}
It is mandatory that you respond only using the JSON format above,
nothing else. Don't include any other words or characters,
your output must be only JSON without any formatting prefix or suffix.
This result should be perfectly parsable by a JSON parser without errors.
"""
result = gl.exec_prompt(task).replace("```json", "").replace("```", "")
print(result)
return json.dumps(json.loads(result), sort_keys=True)
result_json = json.loads(gl.eq_principle_strict_eq(nondet))
if result_json["winner"] > -1:
self.has_resolved = True
self.winner = result_json["winner"]
self.score = result_json["score"]
return result_json