# index.mdx import Image from 'next/image' import { Card, Cards } from 'nextra-theme-docs' import CustomCard from '../components/card' # Welcome to GenLayer ## The Intelligence Layer of the Internet. GenLayer is a new class of DLT capable of non deterministic operations through a dynamic consensus mechanism, by leveraging the [Jury Theorem](https://en.wikipedia.org/wiki/Condorcet%27s_jury_theorem) ("wisdom of the crowd") and [Schelling Point](https://en.wikipedia.org/wiki/Focal_point_(game_theory)) mechanics. In other words, GenLayer is the first Intelligent Blockchain. Enabling smart contracts to natively access the Internet and go beyond deterministic logic, to make subjective decisions. - **Bitcoin is Trustless Money,**
- **Ethereum is Trustless Applications,**
- **GenLayer is Trustless Decision-Making.** GenLayer's Intelligent Contracts can connect to the Internet, process natural language, and handle non-deterministic operations such as making subjective decisions, enabling a whole new generation of smart contract logic that is not possible under the limitations of current blockchain infrastructure. See some of the usecases [here](/understand-genlayer-protocol/typical-use-cases). Protocols and applications that can **understand, learn, and adapt to real-world events.** ## Get Started
{/* */} {/* */}
## Community and Careers **Need Help?** Join our vibrant community on [Discord](https://discord.gg/8Jm4v89VAu) or [Telegram](https://t.me/genlayer) to ask questions, share feedback, and showcase your GenLayer creations. **Looking to Build the Future with Us?** We're hiring! If blockchain and AI excite you, [explore our career opportunities](https://apply.workable.com/yeager-dot-a-i/) and help shape the future of decentralized applications. # understand-genlayer-protocol.mdx ## What is GenLayer? GenLayer is the first AI-native blockchain built for AI-powered smart contracts—called Intelligent Contracts—capable of reasoning and adapting to real-world data. Its foundation is the Optimistic Democracy consensus mechanism, an enhanced Delegated Proof of Stake (dPoS) model where validators connect directly to Large Language Models (LLMs). This setup allows for non-deterministic operations—such as processing text prompts, fetching live web data, and executing AI-based decision-making—while preserving the reliability and security of a traditional blockchain. ## Core Technology At the heart of GenLayer lies Optimistic Democracy—an enhanced Delegated Proof of Stake (dPoS) consensus mechanism that integrates AI models directly into validator operations. This synergy delivers three capabilities traditional blockchains cannot match: 1. **On-Chain AI Processing** Validators connect to leading AI models (GPT, LLaMA, Meta, etc.) to execute complex reasoning on-chain, from natural language comprehension to data-driven predictions. 2. **Consensus-Backed Security** Multiple validators vote on outcomes, ensuring collective agreement and robust reliability for every transaction—even those involving non-deterministic AI outputs. 3. **Intelligent Contracts** Smart contracts in GenLayer gain reasoning abilities, allowing them to understand natural language, process real-world data, and adapt to evolving conditions. ## Technical Implementation To integrate AI seamlessly with the blockchain, GenLayer employs a distributed neural consensus network, wherein validators run specialized software connected via API to advanced AI models. This approach unifies: - Delegated Proof of Stake (dPoS) for efficient block production and governance. - Neural Consensus for non-deterministic transactions requiring advanced AI reasoning. This architecture supports autonomous DAOs, self-executing prediction markets, and dynamic DeFi protocols that react to real-world data in real time. # Optimistic Democracy: How Consensus Works GenLayer Optimistic Democracy Consensus Diagram Inspired by **[Condorcet's Jury Theorem](https://jury-theorem.genlayer.com/)** (click the link to check out our interactive model), Optimistic Democracy merges probabilistic AI systems with deterministic blockchain rules, ensuring secure and accurate consensus at scale. 1. **User Submits a Transaction** A user sends a transaction request to the network (see the diagram's Step 1). 2. **Leader (Validator) Proposes Result** The network selects a Leader, who processes the request and proposes an outcome (Step 2). 3. **Validators Recompute** A group of Validators independently re-compute the transaction (Step 3). If the output aligns with the Leader's proposal, they approve; otherwise, they deny. This multi-layer validation ensures majority agreement, adding a safety net for AI-driven computations. # Validator Selection Mechanism Token holders bolster network security by delegating tokens to validator candidates. A deterministic function f(x) then randomly designates Leader-Validator and Validators for each transaction. This process not only promotes fairness but also helps decentralize validation power, strengthening GenLayer's security and trustlessness. # Validator Operational Framework Each GenLayer validator node integrates: - **Validator Software** Handles core blockchain functions: networking, block production, and transaction management. - **AI Model Integration** Connects to Large Language Models (LLMs) or other AI services for complex reasoning, natural language processing, and real-time data retrieval. Validators seamlessly manage both: 1. **Deterministic Transactions** typical of traditional blockchains. 2. **Non-Deterministic Transactions** that leverage AI-driven logic (e.g., searching the internet, analyzing data, making probabilistic inferences). By splitting tasks between standard deterministic and advanced AI-powered transactions, GenLayer ensures high performance without compromising on security. # Putting It All Together With Optimistic Democracy guiding consensus and validators empowered by AI, GenLayer enables a new class of blockchain applications. From DAOs that self-govern based on real-time data to DeFi protocols that dynamically adjust parameters in response to market changes, developers can now build truly intelligent decentralized solutions. # understand-genlayer-protocol/what-makes-genlayer-different.mdx ## What Makes GenLayer Different? 1. **AI-Powered**: Intelligent Contracts interpret and execute human-readable commands, unlocking data-driven decision-making in real time. 2. **Web Data Access**: GenLayer’s contracts natively fetch live data, surpassing traditional blockchains that rely on external oracles. 3. **Secure and Reliable**: The Optimistic Democracy consensus algorithm expertly validates non-deterministic outputs, ensuring both efficiency and robust security. 4. **Interoperability**: Designed for seamless interaction with other blockchains and conventional web services, GenLayer bridges multiple ecosystems. 5. **Python-Based SDK**: A Python-centric toolset lowers the barrier to entry, empowering a wide range of developers, data scientists, and AI specialists. # understand-genlayer-protocol/optimistic-democracy-how-genlayer-works.mdx # Optimistic Democracy: How GenLayer Works GenLayer Optimistic Democracy Diagram Optimistic Democracy is GenLayer's consensus mechanism, rooted in [Condorcet's Jury Theorem](https://jury-theorem.genlayer.com/) (click the link to check out our interactive model), which affirms that collective decision-making becomes more accurate as independent validators vote. The process unfolds in distinct phases: 1. **Transaction Submission**: A user sends a transaction to the GenLayer network. 2. **Leader Proposes Result**: A validator is randomly chosen as the Leader validator. It processes the transaction and proposes a result. 3. **Validators Recompute**: A committee of validators re-compute the transaction. They either approve or deny based on whether the output aligns with the Leader's result (i.e. is equivalent). 4. **Result Accepted**: Once a majority approves, the result is provisionally accepted. 5. **Appeal**: If any participant disputes the outcome, they can appeal within the Finality Window by posting a bond. 6. **Additional Validation (If Appealed)**: A new set of validators may be chosen to re-evaluate the transaction. If the appeal is valid, they reward the appellant. Otherwise, the bond is forfeited. 7. **Final Decision**: After all appeals are resolved, the outcome becomes final. # understand-genlayer-protocol/typical-use-cases.mdx # Typical Use Cases - **Prediction Markets**: Power decentralized trading on future events. Applications include financial market forecasting, sports betting, and entertainment predictions. - **Performance-Based Contracting**: Automate escrows and payments contingent on verified performance metrics. Intelligent Contracts can track deliverables in real-time and instantly release funds. - **Network States**: Launch decentralized governance frameworks for Network States, opening new horizons in collaborative decision-making and self-regulation. - **Dispute Resolution**: It will serve as a decentralized, AI-driven arbitration system. Compared to conventional legal routes, it will reduce costs and expedite case handling. - **AI-Driven DAOs**: Form next-gen decentralized autonomous organizations managed by AI algorithms. Empower real-time governance and data-informed investments. For more potential applications, see **Build with GenLayer**. ## Ready to Build on GenLayer? Whether you're looking to dive into Python-based smart contracts or explore AI-driven solutions, GenLayer provides the ideal foundation. Explore our [Developer Docs](https://docs.genlayer.com/developers) to start building. # understand-genlayer-protocol/why-we-are-building-genlayer.mdx # Why We Are Building GenLayer Traditional smart contracts face critical limitations: they can’t natively interact with the outside world without oracles, and their instructions are constrained to code-based logic. By integrating AI at the protocol level, GenLayer’s Intelligent Contracts can: 1. **Process Natural Language**: Interpret and act upon human-readable text prompts. 2. **Access Real-Time Web Data**: Seamlessly fetch and utilize external data. This synergy opens a world of new applications that merge on-chain trust with off-chain intelligence. Our vision is a dynamic protocol where intelligent entities—ranging from AI models to automated tools—can autonomously transact and reach real-world alignment. GenLayer's Optimistic Democracy consensus underpins secure, efficient validation even when outputs are inherently non-deterministic. This makes the platform exceptionally adaptable and robust—primed for modern, AI-driven use cases. # understand-genlayer-protocol/who-is-genlayer-for.mdx # Who Is GenLayer For? - **Existing dApps**: Transition away from costly human-based oracles to AI-powered Intelligent Contracts, slashing operational overhead and decision latency. - **Builders**: Construct the impossible—dApps that benefit from AI-based reasoning, real-time web access, and automated decision-making. - **Enterprises**: Streamline complex business logic and workflows with AI-driven automation that executes and enforces contractual agreements on-chain. - **Researchers**: Experiment with next-generation decentralized governance and explore how AI can improve consensus, dispute resolution, and more. - **Everyone**: Participate in the groundbreaking fusion of AI and blockchain, shaping the future of Web3 technology. # understand-genlayer-protocol/what-are-intelligent-contracts.mdx ## What Are Intelligent Contracts? Intelligent Contracts are AI-powered smart contracts designed to leverage Large Language Models (LLMs) for real-time web data retrieval and natural language processing. Unlike traditional smart contracts—limited by deterministic code and external oracles—Intelligent Contracts adapt their logic based on live data and evolving conditions. By natively integrating AI at the protocol level, Intelligent Contracts on GenLayer can understand and respond to complex, real-world scenarios, unlocking a new class of decentralized applications. Evolution of Intelligent Contracts | **Feature** | **Traditional Smart Contracts** | **Intelligent Contracts** | |---------------------------|--------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------| | **Definition** | Self-executing blockchain programs with terms defined in code | AI-driven contracts that access web data and process natural language in real time | | **Capabilities** | Executes predefined on-chain actions based on code logic | Executes on-chain actions, can interpret external data, perform AI-driven reasoning, etc. | | **Language Understanding**| Limited to code-based commands | Understands and acts on human-readable text prompts (natural language) | | **Web Data Access** | Depends on external oracles for off-chain data | Integrates directly with real-time web data, removing the need for external oracles | | **Data Handling** | Can only process data already on-chain | Fetches and utilizes off-chain data (APIs, market info, web resources, etc.) | | **Programming Language** | Often uses specialized blockchain languages (e.g. Solidity) | Generally Python-based in GenLayer, making development more accessible to a broader audience | | **Ease of Development** | Requires specialized blockchain knowledge and tooling | Accessible via familiar languages (Python) and the GenLayer Studio developer experience | | **Flexibility** | Executes static operations based on predefined logic | Can adapt in real time to changing conditions, offering AI-driven functionality | | **Consensus Mechanism** | Relies on standard blockchain consensus (e.g., Proof of Stake, Proof of Work) | Utilizes Optimistic Democracy for deterministic and non-deterministic contract outputs | | **Use Cases** | Typically restricted to basic on-chain logic like token transfers or deterministic dApps | Enables advanced apps like AI-driven DAOs, predictive analytics, autonomous oracles, etc. | By embedding AI-driven capabilities into the core of the blockchain, Intelligent Contracts deliver real-time adaptability, broader functionality, and deeper integration with the external world—significantly expanding the scope of what decentralized applications can achieve on GenLayer. # understand-genlayer-protocol/core-concepts.mdx import { Card, Cards } from 'nextra-theme-docs' # Core Concepts Dive into GenLayer’s fundamental building blocks. These core concepts elucidate how Intelligent Contracts remain secure, efficient, and reliable in a non-deterministic environment: # understand-genlayer-protocol/core-concepts/validators-and-validator-roles.mdx # Validators and Validator Roles ## Overview Validators are essential participants in the GenLayer network. They are responsible for validating transactions and maintaining the integrity and security of the blockchain. Validators play a crucial role in the Optimistic Democracy consensus mechanism, ensuring that both deterministic and non-deterministic transactions are processed correctly. ## Key Responsibilities - **Transaction Validation**: Validators verify the correctness of transactions proposed by the leader, using mechanisms like the Equivalence Principle for non-deterministic operations. - **Leader Selection**: Validators participate in the process of randomly selecting a leader for each transaction, ensuring fairness and decentralization. - **Consensus Participation**: Validators cast votes on proposed transaction outcomes, contributing to the consensus process. - **Staking and Incentives**: Validators stake tokens to earn the right to validate transactions and receive rewards based on their participation and correctness. ## Validator Selection and Roles - **Leader Validator**: For each transaction, a leader is randomly selected among the validators. The leader is responsible for executing the transaction and proposing the result to other validators. - **Consensus Validators**: Other validators assess the leader's proposed result and vote to accept or reject it based on predefined criteria. ## Becoming a Validator - **Staking Requirement**: Participants must stake a certain amount of tokens to become validators. - **Validator Configuration**: Validators must configure their nodes with the appropriate LLM providers and models, depending on the network's requirements. - **Reputation and Slashing**: Validators must act honestly to avoid penalties such as slashing of their staked tokens. # understand-genlayer-protocol/core-concepts/genvm.mdx # GenVM (GenLayer Virtual Machine) The GenVM is the execution environment for Intelligent Contracts in the GenLayer protocol. It serves as the backbone for processing and managing contract operations within the GenLayer ecosystem. [Source code at GitHub](https://github.com/genlayerlabs/genvm) ## Purpose of GenVM The only purpose of the GenVM is to execute Intelligent Contracts, which can have non-deterministic code while maintaining blockchain security and consistency. In summary, the GenVM plays a crucial role in enabling GenLayer's unique features, bridging the gap between traditional smart contracts and AI-powered, web-connected Intelligent Contracts. ## Key Features That Make the GenVM Different Unlike traditional blockchain virtual machines such as Ethereum Virtual Machine (EVM), the GenVM has some advanced features. - **Integration with LLMs**: the GenVM facilitates seamless interaction between Intelligent Contracts and Large Language Models - **Web access**: the GenVM provides access to the Internet - **User friendliness**: Intelligent Contracts can be written in Python, which makes the learning curve much more shallow ## How the GenVM Works 1. **Contract Deployment**: When an Intelligent Contract is deployed, the GenVM compiles and executes the contract code. 2. **Transaction Processing**: As transactions are submitted to the network, the GenVM executes the relevant contract functions and produces the contract's next state. ## Developer Considerations When developing Intelligent Contracts for the GenVM: - Utilize Python's robust libraries and features - Consider potential non-deterministic outcomes when integrating LLMs - Implement proper error handling for web data access - Optimize code for efficient execution within the rollup environment # understand-genlayer-protocol/core-concepts/optimistic-democracy.mdx import { Callout } from 'nextra-theme-docs' # Optimistic Democracy Optimistic Democracy is the consensus method used by GenLayer to validate transactions and operations of Intelligent Contracts. This approach is especially good at handling unpredictable outcomes from transactions involving web data or AI models, which is important for keeping the network reliable and secure. ## Key Components - **Validators:** Participants who stake tokens to earn the right to validate transactions. They play a crucial role in both the initial validation and any appeals process if needed. - **Leader Selection:** A process that randomly picks one validator to propose the outcome for each transaction, ensuring fairness and reducing potential biases. ## How It Works Optimistic Democracy relies on a mix of trust and verification to ensure transaction integrity: ![](/optimistic-democracy-concept.png) 1. **Initial Validation:** When a transaction is submitted, a small group of randomly selected validators checks its validity. One is chosen as the leader. The leader executes the transaction, and the other validators assess the leader's proposal using the Equivalence Principle. 2. **Majority Consensus:** If most validators accept the leader's proposal, the transaction is provisionally accepted. However, this decision is not final yet, allowing for possible appeals during a limited window of time, known as the **Finality Window**. If any validator fails to vote within the specified timeframe, they are replaced, and a new validator is selected to cast a vote. 3. **Initiating an Appeal:** If a participant disagrees with the initial validation (if it's incorrect or fraudulent), they can appeal during the Finality Window. They must submit a request and provide a bond. After the appeal starts, a new group of validators joins the original ones. This group first votes on whether the transaction should be re-evaluated. If they agree, a new leader is chosen to reassess the transaction, and all validators then review this new evaluation. 4. **Appeal Evaluation:** The new leader re-evaluates the transaction, while the other validators assess the leader's proposal using the Equivalence Principle. This step involves more validators, increasing the chances of an accurate decision. 5. **Escalating Appeals:** If the appealing party is still not satisfied, the process can escalate, with each round involving more validators. Each round doubles the number of validators. A new leader is only chosen if the transaction is overturned. 6. **Final Decision:** The appeals process continues until a majority consensus is reached or until all validators have participated. The final decision is recorded, and the transaction's state is updated accordingly. If the appealing party is correct, they receive a reward for their efforts, while incorrect appellants lose their bond. # understand-genlayer-protocol/core-concepts/optimistic-democracy/equivalence-principle.mdx # Equivalence Principle Mechanism The Equivalence Principle mechanism is a cornerstone in ensuring that Intelligent Contracts function consistently across various validators when handling non-deterministic outputs like responses from Large Language Models (LLMs) or data retrieved through web browsing. It plays a crucial role in how validators assess and agree on the outcomes proposed by the Leader. The Equivalence Principle protects the network from manipulations or errors by ensuring that only suitable, equivalent outcomes influence the blockchain state. ## Key Features of the Equivalence Principle The Equivalence Principle is fundamental to how Intelligent Contracts operate, ensuring they work reliably across different network validators. - **Consistency in Decentralized Outputs:** The Equivalence Principle allows outputs from various sources, such as LLMs or web data, to be different yet still considered valid as long as they meet predefined standards. This is essential to maintain fairness and uniform decision-making across the blockchain, despite the natural differences in AI-generated responses or web-sourced information. - **Security Enhancement:** To protect the integrity of transactions, the Equivalence Principle requires that all validators check each other’s work. This mutual verification helps prevent errors and manipulation, ensuring that only accurate and agreed-upon data affects the blockchain. - **Output Validation Flexibility:** Intelligent Contracts often need to handle complex and varied data. This part of the principle allows developers to set specific rules for what counts as "equivalent" or acceptable outputs. This flexibility helps developers tailor the validation process to suit different needs, optimizing either for accuracy or efficiency depending on the contract's requirements. ## Types of Equivalence Principles 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 result might be challenged or an appeal process might be initiated. ### Comparative Equivalence Principle In the Comparative Equivalence Principle, both the Leader and the validators perform identical tasks and then directly compare their respective results with the predefined criteria in the Equivalence Principle 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, since multiple validators perform the same tasks as the Leader, it increases computational demands and associated costs. For example, if an Intelligent Contract is tasked with calculating the average rating of a product based on user reviews, the Equivalence Principle specifies that the average ratings should not differ by more than 0.1 points. Here's how it works: 1. **Leader Calculation**: The Leader validator calculates the average rating from the user reviews and arrives at a rating of 4.5. 2. **Validators' Calculations**: Each validator independently calculates the average rating using the same set of user reviews. Suppose one validator calculates an average rating of 4.6. 3. **Comparison**: The validators compare their calculated average (4.6) with the Leader's average (4.5). According to the Equivalence Principle, the ratings should not differ by more than 0.1 points. 4. **Decision**: Since the difference (0.1) is within the acceptable margin of error, the validators accept the Leader's result as valid. ### 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. For example, in an Intelligent Contract designed to summarize news articles, the process works as follows: 1. **Leader Summary**: The Leader validator generates a summary of a news article. 2. **Evaluation Criteria**: The Equivalence Principle defines criteria for an acceptable summary, such as accuracy, relevance, and length. 3. **Validators' Assessment**: Instead of generating their own summaries, validators review the Leader’s summary and check if it meets the predefined criteria. - **Accuracy**: Does the summary accurately reflect the main points of the article? - **Relevance**: Is the summary relevant to the content of the article? - **Length**: Is the summary within the acceptable length? 4. **Decision**: If the Leader’s summary meets all the criteria, it is accepted by the validators. ## Key Points for Developers - **Setting Equivalence Criteria:** Developers must define what 'equivalent' means for each non-deterministic operation in their Intelligent Contract. This guideline helps validators judge if different outcomes are close enough to be treated as the same. - **Ensuring Contract Reliability:** By clearly defining equivalence, developers help maintain the reliability and predictability of their contracts, even when those contracts interact with the unpredictable web or complex AI models. # understand-genlayer-protocol/core-concepts/optimistic-democracy/appeal-process.mdx # Appeals Process The appeals process in GenLayer is a critical component of the Optimistic Democracy consensus mechanism. It provides a means for correcting errors or disagreements in the validation of Intelligent Contracts. This process ensures that non-deterministic transactions are accurately evaluated, contributing to the robustness and fairness of the platform. ## How It Works - **Initiating an Appeal**: Participants can appeal the initial decision by submitting a request and a required bond during the Finality Window. A new set of validators is then added to the original group to reassess the transaction. - **Appeal Evaluation**: The new validators first review the existing transaction to decide if it needs to be overturned. If they agree it should be re-evaluated, a new leader re-evaluates the transaction. The combined group of original and new validators then review this new evaluation to ensure accuracy. - **Escalating Appeals**: If unresolved, the appeal can escalate, doubling the number of validators each round until a majority consensus is reached or all validators have participated. Once a consensus is reached, the final decision is recorded, and the transaction's state is updated. Correct appellants receive a reward, while those who are incorrect may lose their bond. ## Gas Costs for Appeals The gas costs for an appeal can be covered by the original user, the appellant, or any third party. When submitting a transaction, users can include an optional tip to cover potential appeal costs. If insufficient gas is provided, the appeal may fail to be processed, but any party can supply additional gas to ensure the appeal proceeds. # understand-genlayer-protocol/core-concepts/optimistic-democracy/finality.mdx # Finality Finality refers to the state in which a transaction is considered settled and unchangeable. In GenLayer, once a transaction achieves finality, it cannot be appealed or altered, providing certainty to all participants in the system. This is particularly important for applications that rely on accurate and definitive outcomes, such as financial contracts or decentralized autonomous organizations (DAOs). ## Finality Window The Finality Window is a time frame during which a transaction can be challenged or appealed before it becomes final. This window serves several purposes: 1. **Appeals**: During the Finality Window, any participant can appeal a transaction if they believe the validation was incorrect. This allows for a process of checks and balances, ensuring that non-deterministic transactions are evaluated properly. 2. **Re-computation**: If a transaction is appealed, the system can re-evaluate the transaction with a new set of validators. The Finality Window provides the time necessary for this process to occur. 3. **Security**: The window also acts as a security feature, allowing the network to correct potential errors or malicious activity before finalizing a transaction. import Image from 'next/image' ## Deterministic vs. Non-Deterministic Transactions In GenLayer, Intelligent Contracts are classified as either deterministic or non-deterministic. ### Deterministic Contracts These contracts have a shorter Finality Window because their validation process is straightforward and not subject to appeals. However, it is essential that all interactions with the contract remain deterministic to maintain this efficiency. ### Non-Deterministic Contracts Non-deterministic contracts involve Large Language Model (LLM) calls or web data retrieval, which introduce variability in their outcomes. These contracts require a longer Finality Window to account for potential appeals and re-computation. import { Callout } from 'nextra-theme-docs' If a specific transaction within the contract is deterministic but interacts with a non-deterministic part of the contract, it will be treated as non-deterministic. This ensures that any appeals or re-computations of previous transactions are handled consistently, maintaining the integrity of the contract's overall state. ## Fast Finality For scenarios requiring immediate finality, such as emergency decisions in a DAO, it is possible to pay for all validators to validate the transaction immediately. This approach, though more costly, allows for fast finality, bypassing the typical Finality Window. Fast finality only works if there are no previous non-deterministic transactions still within their Finality Window. Even if your transaction is considered final, if a previous transaction is reverted, your transaction will have to be recomputed as it might depend on the same state. ## Appealability and Gas When submitting a transaction, users can include additional gas to cover potential appeals. If a transaction lacks sufficient gas for appeals, third parties can supply additional gas during the Finality Window. Developers of Intelligent Contracts can also set minimum gas requirements for appealability, ensuring that critical transactions have adequate coverage. # understand-genlayer-protocol/core-concepts/optimistic-democracy/staking.mdx # Staking in GenLayer Participants, known as validators, commit a specified amount of tokens to the network by locking them up on the rollup layer. This commitment supports the network's consensus mechanism and enables validators to actively participate in processing transactions and managing the network. ## Validators vs Delegators | Role | Minimum Stake | Infrastructure | Rewards | |------|--------------|----------------|---------| | **Validator** | 42,000 GEN | Must run a node | 10% operational fee + stake rewards | | **Delegator** | 42 GEN | None required | Passive stake rewards | **Validators** run the consensus infrastructure and are responsible for executing intelligent contracts and validating transactions. They receive a 10% operational fee from rewards before distribution. **Delegators** stake their tokens with validators without running infrastructure. They earn passive rewards proportional to their stake, minus the validator's operational fee. ## How Staking Works - **Stake Deposit**: To become a validator on GenLayer, participants must deposit GEN tokens on the rollup layer. This deposit acts as a security bond and qualifies them to join the pool of active validators. - **Validator Participation**: Only a maximum of 1000 validators with the highest stakes can be part of the active validator set. Once staked, validators take on the responsibility of validating transactions and executing Intelligent Contracts. Their role is crucial for ensuring the network's reliability and achieving consensus on transaction outcomes. - **Delegated Proof of Stake (DPoS)**: GenLayer enhances accessibility and network security through a Delegated Proof of Stake system. This allows token holders who are not active validators themselves to delegate their tokens to trusted validators. By delegating their tokens, users increase the total stake of the validator and share in the rewards. Typically, the validator takes a configurable fee (around 10%), with the remaining rewards (90%) going to the delegating user. - **Earning Rewards**: Validators, and those who delegate their tokens to them, earn rewards for their contributions to validating transactions, paid in GEN tokens. These rewards are proportional to the amount of tokens staked and the transaction volume processed. - **Risk of Slashing**: Validators, and by extension their delegators, face the risk of having a portion of their staked tokens [slashed](/understand-genlayer-protocol/core-concepts/optimistic-democracy/slashing) if they fail to comply with network rules or if the validator supports fraudulent transactions. ## Owner, Operator, and ValidatorWallet When a validator joins, the system creates three distinct entities: **ValidatorWallet**: A separate smart contract wallet created automatically on `validatorJoin()`. This is the primary validator identifier and holds staked GEN tokens. **Owner Address**: The address that creates the validator (msg.sender). It controls staking operations and can change the operator address. Should use a cold wallet for security. **Operator Address**: Used for consensus operations. Can differ from the owner (hot wallet recommended). It can be changed by the owner but cannot be the zero address or reused across validators. ## Epoch System The network operates in epochs (1 day): - **Epoch +2 Activation Rule**: All deposits become active 2 epochs after they are made - Epoch finalization requires all transactions to be finalized - Cannot advance to epoch N+1 until epoch N-1 is finalized - Validators are "primed" via `validatorPrime()` each epoch (permissionless - anyone can call it) **Critical**: If `validatorPrime()` isn't called, the validator is excluded from the next epoch's selection. ### Genesis Epoch 0 Epoch 0 is the **genesis bootstrapping period** with special rules designed to facilitate network launch. The normal staking rules are relaxed to allow rapid network bootstrapping. #### What is Epoch 0? Epoch 0 is the **bootstrapping period** before the network becomes operational. During epoch 0: - **No transactions are processed** - the network is not yet active - **No consensus occurs** - validators are not yet participating - Stakes are registered and prepared for activation in epoch 2 **Important**: The network transitions directly from epoch 0 to epoch 2 (epoch 1 is skipped). Validators and delegators who stake in epoch 0 become active in epoch 2, but only if they meet the minimum stake requirements. #### Special Rules for Epoch 0 | Rule | Normal Epochs (2+) | Epoch 0 | |------|-------------------|---------| | Validator minimum stake | 42,000 GEN | No minimum to join | | Delegator minimum stake | 42 GEN | No minimum to join | | Activation delay | +2 epochs | Active in epoch 2 | | validatorPrime required | Yes, each epoch | Not required | | Share calculation | Based on existing ratio | 1:1 (shares = input) | | Transaction processing | Yes | No (bootstrapping only) | **Activation requires meeting minimums**: While you can join with any amount during epoch 0, your stake will only be **activated in epoch 2** if it meets the minimum requirements (42,000 GEN for validators, 42 GEN for delegators). Stakes below the minimum remain registered but inactive. #### Validators in Epoch 0 **Key behaviors:** 1. **No minimum stake to join**: Validators can join with any non-zero amount during epoch 0 2. **Registered for epoch 2**: Stakes are recorded and will become active when epoch 2 begins 3. **No priming required**: `validatorPrime()` is not needed during epoch 0 4. **No consensus participation**: Validators do not process transactions in epoch 0 **Do validators need to take any action in epoch 0 to be active in epoch 2?** No. Validators who join in epoch 0: - Have their stake registered during epoch 0 - Become active automatically in epoch 2 (epoch 1 is skipped) **only if they have at least 42,000 GEN staked** - Must start calling `validatorPrime()` in epoch 2 for continued participation in epoch 4+ **Important**: Validators who joined in epoch 0 with less than 42,000 GEN will **not be active** in epoch 2. They must deposit additional funds to meet the minimum requirement before epoch 2 begins. #### Delegators in Epoch 0 **Key behaviors:** 1. **No minimum delegation**: Any non-zero amount accepted during epoch 0 2. **Registered for epoch 2**: Delegation is recorded and will become active when epoch 2 begins 3. **No rewards in epoch 0**: Since no transactions are processed, no rewards are earned during epoch 0 **Is a delegation made in epoch 0 active in epoch 2?** Yes. Delegations made in epoch 0 become active in epoch 2 (epoch 1 is skipped). Unlike normal epochs where you wait +2 epochs, epoch 0 delegations activate as soon as the network becomes operational. #### Activation Timeline Comparison **Normal Epochs (2+):** ``` Epoch N: validatorJoin() or delegatorJoin() called Epoch N+1: validatorPrime() stages the deposit Epoch N+2: validatorPrime() activates the deposit → NOW ACTIVE ``` **Epoch 0 (Bootstrapping):** ``` Epoch 0: validatorJoin() or delegatorJoin() called → stake registered (not yet active) No transactions processed, no consensus Epoch 2: Stakes become active (if minimum met), network operational, validatorPrime() required ``` #### Share Calculation in Epoch 0 In epoch 0, shares are calculated at a 1:1 ratio with the input amount: ``` Shares = Input Amount Example: Deposit 1,000 GEN → Receive 1,000 shares ``` This is because there's no existing stake pool to calculate a ratio against. Starting from epoch 2, shares are calculated based on the current stake-to-share ratio. #### Transitioning from Epoch 0 to Epoch 2 When the network advances from epoch 0 to epoch 2 (epoch 1 is skipped): 1. **Epoch 0 stakes that meet minimums become active** - validators need 42,000 GEN, delegators need 42 GEN 2. **Normal minimum requirements apply** for new joins/deposits 3. **+2 epoch activation delay** applies to all new deposits 4. **validatorPrime() becomes mandatory** for validators to remain in the selection pool 5. **Existing validators** must ensure their nodes begin calling `validatorPrime()` in epoch 2 #### FAQ: Epoch 0 Special Cases **Q: Can I join as a validator with less than 42,000 GEN in epoch 0?** A: Yes, any non-zero amount is accepted during epoch 0. However, you will **not be active** in epoch 2 unless you have at least 42,000 GEN staked by then. **Q: If I delegate in epoch 0, when does it become active?** A: In epoch 2. Unlike normal epochs with a +2 delay, epoch 0 delegations activate when the network becomes operational. **Q: Do I need to call validatorPrime() in epoch 0?** A: No. Priming is not required during epoch 0. Your node should start calling it automatically when epoch 2 begins. **Q: Will my epoch 0 stake still be active after epoch 0 ends?** A: Yes, if you meet the minimum requirements. Stakes from epoch 0 carry forward and remain active in all subsequent epochs. **Q: What happens to my stake if I joined in epoch 0 but my node doesn't call validatorPrime() in epoch 2?** A: You'll be excluded from validator selection in epoch 4, but your stake remains. Once priming resumes, you'll be eligible for selection again. ## Shares vs Stake The staking system uses shares to track ownership: **Shares** are fixed quantities that never change. You receive shares when depositing and exit by burning shares. They represent immutable claims on the stake pool. **Stake** is the dynamic GEN token amount. It increases with rewards/fees and decreases with slashing. The exchange rate is calculated as: ``` stake_per_share = total_stake / total_shares ``` **Example**: 100 shares representing 1,000 GEN (10 GEN per share). After rewards are distributed, the same 100 shares might represent 1,050 GEN (10.5 GEN per share). Rewards automatically compound without user action. ## Validator Selection and Weight Validators are selected for consensus based on their weight, calculated using: ``` Weight = (ALPHA × Self_Stake + (1-ALPHA) × Delegated_Stake)^BETA ``` **Parameters:** - **ALPHA = 0.6**: Self-stake counts 50% more than delegated stake - **BETA = 0.5**: Square-root damping prevents whale dominance **Effects:** - Higher stake leads to higher weight and higher selection probability - Doubling stake only increases weight by approximately 41% - Encourages distribution across validators - Smaller validators often provide higher returns per GEN staked ## Reward Distribution **Sources:** 1. Transaction Fees 2. Inflation (starting at 15% APR, decreasing to 4% APR over time) **Distribution Pattern:** - **10%** → Validator owners (operational fee) - **75%** → Total validator stake (validators + delegators) - **10%** → Developers - **5%** → Locked future allocation for the DeepThought AI-DAO Within the 75% stake allocation: - Self-stake receives a portion based on the validator's own staked amount - Delegated stake is split among delegators proportionally to their shares Rewards automatically increase the stake-per-share ratio without requiring user action. ## Unbonding Period Both validators and delegators face a **7-epoch unbonding period** when withdrawing: - Prevents rapid stake movements that could destabilize the network - Tokens stop earning rewards immediately upon exit - Countdown starts from the exit epoch - Funds become claimable when: `current_epoch >= exit_epoch + 7` ## Validator Priming `validatorPrime(address validator)` is a critical function that: - Activates pending deposits - Processes pending withdrawals - Distributes previous epoch rewards - Applies pending slashing penalties - Sorts the validator into the selection tree **Key Properties:** - **Monitoring Required**: Ensure correct execution - **Permissionless**: Anyone can call it - **Incentivized**: Caller receives 1% of any slashed amount - **Critical**: If the node fails to prime, the validator is excluded from the next epoch - **No Loss**: Missing priming doesn't lose rewards, but the validator can't be selected ## Unstaking and Withdrawing Both validators and delegators can withdraw their staked tokens, but must follow the unbonding process. ### For Validators To stop validating or retrieve staked tokens, validators must: 1. **Calculate shares to exit**: Determine how many shares to withdraw (partial or full) 2. **Call `validatorExit(shares)`**: Initiate the unbonding process 3. **Wait 7 epochs**: Tokens are locked during the unbonding period 4. **Call `validatorClaim()`**: Retrieve tokens after unbonding completes Validators can perform partial exits while remaining active, as long as their stake stays above the 42,000 GEN minimum. ### For Delegators Delegators follow a similar process: 1. **Calculate shares to exit**: Use `sharesOf(delegator, validator)` to check current shares 2. **Call `delegatorExit(validator, shares)`**: Initiate unbonding for a specific validator 3. **Wait 7 epochs**: Tokens are locked during the unbonding period 4. **Call `delegatorClaim(delegator, validator)`**: Retrieve tokens after unbonding **Important for delegators:** - Exit each validator separately if delegating to multiple validators - Claims are permissionless—anyone can trigger them on your behalf - Tokens stop earning rewards immediately upon calling exit - Multiple exits create separate withdrawals that can be claimed together For detailed step-by-step instructions and code examples, see the [Staking Guide](/developers/staking-guide). ## Governance and Safeguards - **24-Hour Delay**: All slashing actions have a governance delay period - Parameters like ALPHA, BETA, minimum stakes, and unbonding periods are adjustable through governance - Maximum 1,000 active validators per epoch (adjustable) ## Next Steps - [Staking Guide](/developers/staking-guide) - Practical guide for staking operations - [Unstaking](/understand-genlayer-protocol/core-concepts/optimistic-democracy/unstaking) - Detailed unstaking process - [Slashing](/understand-genlayer-protocol/core-concepts/optimistic-democracy/slashing) - Slashing conditions and penalties # understand-genlayer-protocol/core-concepts/optimistic-democracy/slashing.mdx # Slashing in GenLayer Slashing is a mechanism used in GenLayer to penalize validators who engage in behavior detrimental to the network. This ensures that validators act honestly and effectively, maintaining the integrity of the platform and the Intelligent Contracts executed within it. By penalizing undesirable behavior, slashing helps align validators' incentives with those of the network and its users. ## Slashing Process 1. **Violation Detection**: The network identifies a violation, such as missing an execution window. 2. **Slash Calculation**: The amount to be slashed is calculated based on the specific violation and platform rules. 3. **Stake Reduction**: The slashed amount is deducted from the validator's stake. 4. **Finality**: The slashing becomes final after the Finality Window closes, ensuring that the validator's balance is finalized and accounts for any potential appeals. ## When Slashing Occurs Validators in GenLayer can be slashed for several reasons: 1. **Missing Transaction Execution Window**: Validators are expected to execute transactions within a specified time frame. If a validator misses this window, they are penalized, ensuring that validators remain active and responsive. 2. **Missing Appeal Execution Window**: During the appeals process, validators must respond within a set time frame. If they fail to do so, they are slashed, which motivates validators to participate in the appeals process. ### Amount Slashed The amount slashed varies based on the severity of the violation and the specific rules set by the GenLayer platform. The slashing amount is designed to be substantial enough to deter malicious or negligent behavior while not being excessively punitive for honest mistakes. # understand-genlayer-protocol/core-concepts/optimistic-democracy/unstaking.mdx # Unstaking in GenLayer Unstaking in GenLayer is the process by which validators disengage their staked tokens from the network, ending their active participation as validators. They must initiate an unstaking process, which includes a cooldown period to finalize all pending transactions. This procedure ensures that all obligations are fulfilled and pending issues resolved, maintaining the network's integrity and securing the platform’s operations. ## How Unstaking Works The unstaking process includes several key steps: 1. **Initiating Unstaking**: Validators initiate their exit from active duties by submitting an unstaking transaction, signaling their intention to cease participation in validating transactions. 2. **Validator Removal**: Once the unstaking request is made, the validator is promptly removed from the pool of active validators, meaning they will no longer receive new transactions or be called upon for appeal validations. 3. **Finality Period**: During this period, validators must wait for all transactions they have participated in to reach full finality. This is crucial to ensure that validators do not exit while still having potential influence over unresolved transactions. This cooldown period helps prevent the situation where new transactions with new finality windows could prevent them from ever achieving full finality on all transactions they were involved in. 4. **Withdrawing Stake**: After all transactions have achieved finality and no outstanding issues remain, validators and their delegators can safely withdraw their staked tokens and any accrued rewards. ## Purpose of Unstaking The unstaking process is designed to: - **Ensure Accountability**: By enforcing a Finality Window, validators are held accountable for their actions until all transactions they influenced are fully resolved. This prevents premature exit from the network and ensures that all potential disputes are settled. - **Align Incentives**: The requirement for validators to wait through the Finality Window aligns their incentives with the long-term security and reliability of the network, promoting responsible participation. - **Maintain Network Security**: The unstaking process discourages abrupt departures and ensures that validators address any possible security concerns related to their past validations before leaving. ## Implications for Validators and Delegators For validators, this process mandates careful planning regarding their exit strategy from the network, considering the need to wait out the Finality Window. Delegators must also be patient, understanding that their assets will remain locked until their validator has cleared all responsibilities, safeguarding their investments from potential liabilities caused by unresolved validations. # understand-genlayer-protocol/core-concepts/rollup-integration.mdx # Rollup Integration GenLayer leverages Ethereum rollups, such as ZKSync or Polygon CDK, to ensure scalability and compatibility with existing Ethereum infrastructure. This integration is crucial for optimizing transaction throughput and reducing fees while maintaining the security guarantees of the Ethereum mainnet. ## Key Aspects of Rollup Integration ### Scalability - **High Transaction Throughput**: Rollups allow GenLayer to process a much higher number of transactions per second compared to Layer 1 solutions. - **Reduced Congestion**: By moving computation off-chain, GenLayer helps alleviate congestion on the Ethereum mainnet. ### Cost Efficiency - **Lower Transaction Fees**: Users benefit from significantly reduced gas fees compared to direct Layer 1 transactions. - **Batched Submissions**: Transactions are batched and submitted to the Ethereum mainnet, distributing costs across multiple operations. ### Security - **Ethereum Security Inheritance**: While execution happens off-chain, the security of assets and final state is guaranteed by Ethereum's robust consensus mechanism. - **Fraud Proofs/Validity Proofs**: Depending on the specific rollup solution (Optimistic or ZK), security is ensured through either fraud proofs or validity proofs. ## How Rollup Integration Works with GenLayer 1. **Transaction Submission**: Users submit transactions to the rollup. 2. **Transaction Execution**: Transactions are executed within the GenVM environment. 3. **Consensus**: The rollup layer implements the Optimistic Democracy mechanism to reach consensus on the state updates. 4. **State Updates**: The rollup layer maintains an up-to-date state of all accounts and contracts. 5. **Batch Submission**: Periodically, batches of transactions and state updates are submitted to the Ethereum mainnet. 6. **Verification**: The Ethereum network verifies the integrity of the submitted data, ensuring its validity. ## Benefits for Developers and Users - **Ethereum Compatibility**: Developers can leverage existing Ethereum tools and infrastructure. - **Improved User Experience**: Lower fees and faster transactions lead to a better overall user experience. ## Considerations - **Withdrawal Periods**: Depending on the rollup solution, there might be waiting periods for withdrawing assets back to the Ethereum mainnet. - **Rollup-Specific Features**: Different rollup solutions may offer unique features or limitations that developers should be aware of. By integrating with Ethereum rollups, GenLayer combines the innovative capabilities of Intelligent Contracts with the scalability and efficiency of Layer 2 solutions, creating a powerful platform for next-generation decentralized applications. # understand-genlayer-protocol/core-concepts/non-deterministic-operations-handling.mdx # Non-Deterministic Operations Handling ## Overview GenLayer extends traditional smart contracts by allowing Intelligent Contracts to perform non-deterministic operations, such as interacting with Large Language Models (LLMs) and accessing web data. Handling the variability inherent in these operations is crucial for maintaining consensus across the network. ## Challenges - **Variability of Outputs**: Non-deterministic operations can produce different outputs when executed by different validators. - **Consensus Difficulty**: Achieving consensus on varying outputs requires specialized mechanisms. ## Solutions in GenLayer - **Equivalence Principle**: Validators assess whether different outputs are equivalent based on predefined criteria, allowing for consensus despite variability. - **Optimistic Democracy**: The consensus mechanism accommodates non-deterministic operations by allowing provisional acceptance of transactions and providing an appeals process. ## Developer Considerations - **Defining Equivalence Criteria**: Developers must specify what constitutes equivalent outputs in their Intelligent Contracts. - **Testing and Validation**: Thorough testing is essential to ensure that non-deterministic operations behave as expected in the consensus process. # understand-genlayer-protocol/core-concepts/large-language-model-llm-integration.mdx # Large Language Model (LLM) Integration ## Overview Intelligent Contracts in GenLayer can interact directly with Large Language Models (LLMs), enabling natural language processing and more complex decision-making capabilities within blockchain applications. ## Key Features - **Natural Language Understanding**: Contracts can process and interpret instructions written in natural language. - **Dynamic Decision Making**: Utilizing LLMs allows contracts to make context-aware decisions based on complex inputs. ## Implementation 1. **LLM Providers**: Validators are configured with LLM providers (e.g., OpenAI, Ollama) to process LLM requests. 2. **Equivalence Principle**: LLM outputs are validated using the Equivalence Principle to ensure consensus among validators. 3. **Prompt Design**: Developers craft prompts to interact effectively with LLMs, specifying expected formats and constraints. ## Considerations - **Cost and Performance**: LLM interactions may incur additional computational costs and latency. - **Security**: Care must be taken to prevent prompt injections and ensure the reliability of LLM responses. # understand-genlayer-protocol/core-concepts/web-data-access.mdx # Web Data Access in Intelligent Contracts ## Overview GenLayer enables Intelligent Contracts to directly access and interact with web data, removing the need for oracles and allowing for real-time data integration into blockchain applications. ## Key Features - **Direct Web Access**: Contracts can retrieve data from web sources. - **Dynamic Applications**: Access to web data allows for applications that respond to external events and real-world data. - **Equivalence Validation**: Retrieved data is validated across validators to ensure consistency. ## Implementation 1. **Data Retrieval Functions**: GenLayer provides mechanisms for fetching web data within contracts. 2. **Data Parsing and Validation**: Contracts must parse web data and validate it according to defined equivalence criteria. 3. **Security Measures**: Contracts should handle potential security risks such as untrusted data sources and ensure data integrity. ## Considerations - **Network Dependencies**: Reliance on external web sources introduces dependencies that may affect contract execution. - **Performance Impact**: Web data retrieval may introduce latency and affect transaction processing times. # understand-genlayer-protocol/core-concepts/transactions.mdx # Transactions Transactions are the fundamental operations that drive the GenLayer protocol. Whether it's deploying a new contract, sending value between accounts, or invoking a function within an existing contract, transactions are the means by which state changes occur on the network. Here is the general structure of a transaction: ```json { "consensus_data": { "leader_receipt": { "args": [ [ 2, "0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2" ] ], "class_name": "LlmErc20", "contract_state": "gASVnAAAAAAAAACMF2JhY2tlbmQubm9kZS5nZW52bS5iYXNllIwITGxtRXJjMjCUk5QpgZR9lIwIYmFsYW5jZXOUfZQojCoweEQyNzFjNzRBNzgwODNGMzU3YTlmOGQzMWQ1YWRDNTlCMzk1Y2YxNmKUS2KMKjB4NzkzQWUyQ2ZGMTc0NjJjYzlmOUQ2OGUxOTRiN2I5NDlkMjA4MEVhMpRLAnVzYi4=", "eq_outputs": { "leader": { "0": "{\"transaction_success\": true, \"transaction_error\": \"\", \"updated_balances\": {\"0xD271c74A78083F357a9f8d31d5adC59B395cf16b\": 98, \"0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2\": 2}}" } }, "error": null, "execution_result": "SUCCESS", "gas_used": 0, "method": "transfer", "mode": "leader", "node_config": { "address": "0x185D2108D9dE15ccf6beEb31774CA96a4f19E62B", "config": {}, "model": "gpt-4o", "plugin": "openai", "plugin_config": { "api_key_env_var": "OPENAIKEY", "api_url": null }, "provider": "openai", "stake": 1 }, "vote": "agree" }, "validators": [ { "args": [ [ 2, "0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2" ] ], "class_name": "LlmErc20", "contract_state": "gASVnAAAAAAAAACMF2JhY2tlbmQubm9kZS5nZW52bS5iYXNllIwITGxtRXJjMjCUk5QpgZR9lIwIYmFsYW5jZXOUfZQojCoweEQyNzFjNzRBNzgwODNGMzU3YTlmOGQzMWQ1YWRDNTlCMzk1Y2YxNmKUS2KMKjB4NzkzQWUyQ2ZGMTc0NjJjYzlmOUQ2OGUxOTRiN2I5NDlkMjA4MEVhMpRLAnVzYi4=", "eq_outputs": { "leader": { "0": "{\"transaction_success\": true, \"transaction_error\": \"\", \"updated_balances\": {\"0xD271c74A78083F357a9f8d31d5adC59B395cf16b\": 98, \"0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2\": 2}}" } }, "error": null, "execution_result": "SUCCESS", "gas_used": 0, "method": "transfer", "mode": "validator", "node_config": { "address": "0x31bc9380eCbF487EF5919eBa7457F457B5196FCD", "config": {}, "model": "gpt-4o", "plugin": "openai", "plugin_config": { "api_key_env_var": "OPENAIKEY", "api_url": null }, "provider": "openai", "stake": 1 }, "pending_transactions": [], "vote": "agree" }, ... ], "votes": { "0x185D2108D9dE15ccf6beEb31774CA96a4f19E62B": "agree", "0x2F04Fb1e5daf7DCbf170E4CB0e427d9b11aB96cA": "agree", "0x31bc9380eCbF487EF5919eBa7457F457B5196FCD": "agree" } }, "created_at": "2024-10-02T20:32:50.469443+00:00", "data": { "function_args": "[2,\"0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2\"]", "function_name": "transfer" }, "from_address": "0xD271c74A78083F357a9f8d31d5adC59B395cf16b", "gaslimit": 66, "hash": "0xb7486f70a3fec00af5f929fc1cf1078af9ff3a063afe8b6f370a44a96635505d", "leader_only": false, "nonce": 66, "r": null, "s": null, "status": "FINALIZED", "to_address": "0x5929bB548a2Fd7E9Ea2577DaC9c67A08BbC2F356", "type": 2, "v": null, "value": 0 } ``` ## Explanation of fields: - consensus_data: Object containing information about the consensus process - leader_receipt: Object containing details about the leader's execution of the transaction - args: Arguments passed to the contract function - class_name: Name of the contract class - contract_state: Encoded state of the contract - eq_outputs: Outputs from every equivalence principle in the execution of the contract method - error: Any error that occurred during execution (null if no error) - execution_result: Result of the execution (e.g., "SUCCESS" or "ERROR") - gas_used: Amount of gas used in the transaction - method: Name of the method called on the contract - mode: Execution mode (e.g., "leader" or "validator") - node_config: Configuration of the node executing the transaction - address: Address of the node - config: Configuration of the node - model: Model of the node - plugin: Plugin used for the LLM provider connection - plugin_config: Configuration of the plugin - api_key_env_var: Environment variable containing the API key for the given provider - api_url: API URL for the given provider - provider: Provider of the node - stake: Stake of the validator - vote: The leader's vote on the transaction (e.g., "agree") - validators: Array of objects containing similar information for each validator - votes: Object mapping validator addresses to their votes - created_at: Timestamp of when the transaction was created - data: Object containing details about the function call in the transaction - from_address: Address of the account initiating the transaction - gaslimit: Maximum amount of gas the transaction is allowed to consume - hash: Unique identifier (hash) of the transaction - leader_only: Boolean indicating whether the transaction is to be executed by the leader node only - nonce: Number of transactions sent from the from_address (used to prevent double-spending) - r: Part of the transaction signature (null if not yet signed) - s: Part of the transaction signature (null if not yet signed) - status: Current status of the transaction (e.g., "FINALIZED") - to_address: Address of the contract or account receiving the transaction - type: Internal type of the transaction (2 indicates a contract write call) - v: Part of the transaction signature (null if not yet signed) - value: Amount of native currency (GEN) being transferred in the transaction # understand-genlayer-protocol/core-concepts/transactions/types-of-transactions.mdx # Types of Transactions There are three different types of transactions that users can send in GenLayer. All three types are sent through the same RPC method, but they differ in the data they contain and the actions they perform. ## 1. Deploy a Contract Deploying a contract involves creating a new Intelligent Contract on the GenLayer network. This transaction initializes the contract's state and assigns it a unique address on the blockchain. The deployment process ensures that the contract code is properly validated and stored, making it ready to be called. ### Example ```json { "consensus_data": { "leader_receipt": { "args": [ { "total_supply": 100 } ], "class_name": "LlmErc20", "contract_state": "gASVnAAAAAAAAACMF2JhY2tlbmQubm9kZS5nZW52bS5iYXNllIwITGxtRXJjMjCUk5QpgZR9lIwIYmFsYW5jZXOUfZQojCoweEQyNzFjNzRBNzgwODNGMzU3YTlmOGQzMWQ1YWRDNTlCMzk1Y2YxNmKUS2KMKjB4NzkzQWUyQ2ZGMTc0NjJjYzlmOUQ2OGUxOTRiN2I5NDlkMjA4MEVhMpRLAnVzYi4=", ... }, "validators": [ ... ], ... }, "data": { "constructor_args": "{\"total_supply\":100}", "contract_address": "0x5929bB548a2Fd7E9Ea2577DaC9c67A08BbC2F356", "contract_code": "import json\nfrom backend.node.genvm.icontract import IContract\nfrom backend.node.genvm.equivalence_principle import EquivalencePrinciple\n\n\nclass LlmErc20(IContract):\n def __init__(self, total_supply: int) -> None:\n self.balances = {}\n self.balances[contract_runner.from_address] = total_supply\n...", }, ... } ``` ## 2. Send Value Sending value refers to transferring the native GEN token from one account to another. This is one of the most common types of transactions. Each transfer updates the balance of the involved accounts, and the transaction is recorded on the blockchain to ensure transparency and security. ### Example ```json { "consensus_data": null, "created_at": "2024-10-02T21:21:04.192995+00:00", "data": {}, "from_address": "0x0Bd6441CB92a64fA667254BCa1e102468fffB3f3", "gaslimit": 0, "hash": "0x6357ec1e86f003b20964ef3b2e9e072c7c9521f92989b08e04459b871b69de89", "leader_only": false, "nonce": 2, "r": null, "s": null, "status": "FINALIZED", "to_address": "0xf739FDe22E0C0CB6DFD8f3F8D170bFC07329489E", "type": 0, "v": null, "value": 200 } ``` ## 3. Call Contract Function Calling a contract function is the process of invoking a specific method within an existing Intelligent Contract. This could involve anything from querying data stored within the contract to executing more complex operations like transferring tokens or interacting with other contracts. Each function call is a transaction that modifies the contract’s state based on the inputs provided. ### Example ```json { "consensus_data": { "leader_receipt": { "args": [ [ 2, "0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2" ] ], "class_name": "LlmErc20", "contract_state": "gASVnAAAAAAAAACMF2JhY2tlbmQubm9kZS5nZW52bS5iYXNllIwITGxtRXJjMjCUk5QpgZR9lIwIYmFsYW5jZXOUfZQojCoweEQyNzFjNzRBNzgwODNGMzU3YTlmOGQzMWQ1YWRDNTlCMzk1Y2YxNmKUS2KMKjB4NzkzQWUyQ2ZGMTc0NjJjYzlmOUQ2OGUxOTRiN2I5NDlkMjA4MEVhMpRLAnVzYi4=", "eq_outputs": { "leader": { "0": "{\"transaction_success\": true, \"transaction_error\": \"\", \"updated_balances\": {\"0xD271c74A78083F357a9f8d31d5adC59B395cf16b\": 98, \"0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2\": 2}}" } }, ... }, "validators": [ ... ], ... }, "data": { "function_args": "[2,\"0x793Ae2CfF17462cc9f9D68e194b7b949d2080Ea2\"]", "function_name": "transfer" }, ... } ``` * For a list of all the fields in a transaction, see [here](/core-concepts/transactions) # understand-genlayer-protocol/core-concepts/transactions/transaction-statuses.mdx # Transaction Processing In GenLayer, transactions are processed through an account-based queue system that ensures orderliness. Here’s how transactions transition through different statuses: ## 1. Pending When a transaction is first submitted, it enters the pending state. This means it has been received by the network but is waiting to be processed. Transactions are queued per account, ensuring that each account's transactions are processed in the order they were submitted. ## 2. Proposing In this stage, the transaction is moved from the pending queue to the proposing stage. A leader and a set of voters are selected from the validator set via a weighted random selection based on total stake. The leader proposes a receipt for the transaction, which is then committed to by the validators. ## 3. Committing The transaction enters the committing stage, where validators commit their votes and cost estimates for processing the transaction. This stage is crucial for reaching consensus on the transaction's execution. ## 4. Revealing After the committing stage, validators reveal their votes and cost estimates, allowing the network to finalize the transaction's execution cost and validate the consensus. ## 5. Accepted Once the majority of validators agree on the transaction's validity and cost, the transaction is marked as accepted. This status indicates that the transaction has passed through the initial validation process successfully. ## 6. Finalized After all validations are completed and any potential appeals have been resolved, the transaction is finalized. In this state, the transaction is considered irreversible and is permanently recorded in the blockchain. ## 7. Undetermined If the transaction fails to reach consensus after all voting rounds, it enters the undetermined state. This status indicates that the transaction's outcome is unresolved, and it may require further validation or be subject to an appeal process. ## 8. Canceled A transaction can be canceled by the user or by the system if it fails to meet certain criteria (e.g., insufficient funds). Once canceled, the transaction is removed from the processing queue and will not be executed. # understand-genlayer-protocol/core-concepts/transactions/transaction-execution.mdx ## Transaction execution Once a transaction is received and properly verified by the `eth_sendRawTransaction` method on the RPC server, it is stored with a PENDING status and its hash is returned as the RPC method response. This means that the transaction has been validated for authenticity and format, but it has not yet been executed. From this point, the transaction enters the GenLayer consensus mechanism, where it is picked up for execution by the network's validators according to the consensus rules. As the transaction progresses through various stages—such as proposing, committing, and revealing—its status is updated accordingly. Throughout this process, the current status and output of the transaction can be queried by the user. This is done by calling the `eth_getTransactionByHash` method on the RPC server, which retrieves the transaction's details based on its unique hash. This method allows users to track the transaction's journey from submission to finalization, providing transparency and ensuring that they can monitor the outcome of their transactions in real-time. ### Transaction Status Transitions In the journey of a transaction within the GenLayer protocol, it begins its life when an Externally Owned Account (EOA) submits it, entering the `Pending` state. Here, it awaits further processing unless it encounters an `OutOfFee` state due to insufficient fees. If the fees are topped up, it returns to `Pending`. Alternatively, the user can cancel the transaction, moving it to the `Canceled` state. From `Pending`, the transaction progresses to the `Proposing` stage, where a leader is selected to propose a receipt. Upon successful proposal, it advances to the `Committing` stage, where all validators must commit to the transaction. If all validators commit, the transaction moves to the `Revealing` stage. In the `Revealing` stage, the transaction's fate is determined. If a majority agrees, it is `Accepted`. However, if there is no majority agreement, it returns to `Proposing`. If all leaders are rotated without agreement, it becomes `Undetermined`. In cases of disagreement, a successful appeal can revert it to `Pending`, while a failed appeal results in `Accepted`. Once `Accepted`, the transaction awaits the passing of the appeal window to become `Finalized`. An `Undetermined` transaction also becomes `Finalized` after the appeal window passes. However, an appeal can initiate a return to `Committing` from `Accepted`, or automatically revert an `Undetermined` transaction to `Pending`. ```mermaid graph TD; Start(( )) -->|EOA submits| Pending(Pending) Start -->|Insufficient fee| OutOfFee(OutOfFee) OutOfFee -->|Fee topped up| Pending Pending -->|User cancels| Canceled(Canceled) Pending -->|Select leader| Proposing(Proposing) Proposing -->|Leader proposes receipt| Committing(Committing) Committing -->|All validators commit| Revealing(Revealing) Revealing -->|Majority agrees| Accepted(Accepted) Revealing -->|No majority agreement| Proposing Revealing -->|All leaders rotated| Undetermined(Undetermined) Revealing -.->|Disagreement, appeal successful| Pending Revealing -.->|Agreement, appeal failed| Accepted Accepted -->|Appeal window passes| Finalized(Finalized) Undetermined -->|Appeal window passes| Finalized Accepted -.->|Appeal initiated| Committing Undetermined -->|Appeal automatically| Pending ``` # understand-genlayer-protocol/core-concepts/transactions/transaction-encoding-serialization-and-signing.mdx ## Transaction encoding, serialization, and signing In GenLayer, all three types of transactions needs to be properly encoded, serialized, and signed on the client-side. This process ensures that the transaction data is packaged into a relieable cross-platform efficient format, and securely signed using the sender's private key to verify the sender's identity. Once prepared, the transaction is sent to the network via the `eth_sendRawTransaction` method on the RPC Server. This method performs the inverse process: it decodes and deserializes the transaction data, and then verifies the signature to ensure its authenticity. By handling all transaction types through `eth_sendRawTransaction`, GenLayer ensures that transactions are processed securely and efficiently while maintaining compatibility with Ethereum’s specification. # understand-genlayer-protocol/core-concepts/economic-model.mdx # Economic Model ## Overview GenLayer's economic model is designed to incentivize participants to maintain the network's security and functionality. It involves staking, rewards, transaction fees, and penalties. ## Key Components - **Staking**: Validators must stake tokens to participate in the validation process, aligning their interests with the network's health. - **Rewards**: Validators receive rewards for correctly validating transactions. - **Transaction Fees**: Users pay fees for transaction processing, which are partly used to reward validators. - **Slashing**: Validators acting maliciously or incompetently can have their staked tokens slashed as a penalty. ## Incentive Mechanisms - **Positive Incentives**: Rewards and fees motivate validators to act in the network's best interest. - **Negative Incentives**: Slashing and penalties deter malicious behavior. ## Economic Security - **Stake-Based Security**: The amount staked by validators serves as a deterrent against attacks, as they risk losing their stake. - **Balancing Supply and Demand**: The economic model aims to balance the supply of validation services with demand from users. # understand-genlayer-protocol/core-concepts/accounts-and-addresses.mdx # Accounts and Addressing ## Overview Accounts are fundamental to interacting with the GenLayer network. They represent users or entities that can hold tokens, deploy Intelligent Contracts, and initiate transactions. ## Types of Accounts 1. **Externally Owned Accounts (EOAs)**: - Controlled by private keys - Can initiate transactions and hold tokens 2. **Contract Accounts**: - Associated with deployed Intelligent Contracts - Have their own addresses and code ## Account Addresses - **Address Format**: GenLayer uses a specific address format, typically represented as a hexadecimal string prefixed with `0x`. - **Public and Private Keys**: Addresses are derived from public keys, which in turn are generated from private keys kept securely by the account owner. ## Interacting with Intelligent Contracts - **Transaction Sending**: Accounts initiate transactions to call functions on Intelligent Contracts or transfer tokens. - **Gas Fees**: Transactions require gas fees to be processed. ## Account Management - **Creating Accounts**: Users can create new accounts using wallets or development tools provided by GenLayer. - **Security Practices**: Users must securely manage their private keys, as losing them can result in loss of access to their funds. # developers.mdx import { Card, Cards } from 'nextra-theme-docs' # Getting Started with GenLayer Welcome to the GenLayer getting started guide. This guide helps developers exploit the full potential of the GenLayer environment. This documentation will provide you with the tools and knowledge needed to build, deploy, and manage Intelligent Contracts on GenLayer. The next topics focus on key areas of the development process. From setting up your development environment and writing your first Intelligent Contract to exploring advanced features and best practices, these resources are designed to support your journey in creating cutting-edge decentralized applications on GenLayer. Click on any link to delve into detailed guides and enhance your development skills with GenLayer. import { Tabs } from 'nextra/components' # developers/intelligent-contracts/introduction.mdx # Introduction to Intelligent Contracts ## What are Intelligent Contracts? Intelligent Contracts are an advanced evolution of smart contracts that combine traditional blockchain capabilities with natural language processing and web connectivity. Built in Python, they enable developers to create contracts that can understand human language, process external data, and make complex decisions based on real-world information. ## Key Features of Intelligent Contracts ### Natural Language Processing (NLP) Intelligent Contracts leverage Large Language Models (LLMs) to process and understand human language inputs. This integration enables the contracts to interpret complex text-based instructions and requirements, moving beyond simple conditional logic. Through NLP capabilities, these contracts can analyze qualitative criteria and make nuanced decisions based on contextual understanding, bringing a new level of intelligence to contract execution. ### Web Connectivity These contracts can actively interact with web APIs to fetch real-time information, enabling dynamic decision-making based on current data. By incorporating external services for data verification, they maintain a reliable connection to real-world events and conditions, bridging the gap between on-chain and off-chain environments. ### Non-Deterministic Operations Intelligent Contracts introduce a sophisticated approach to handling operations with unpredictable outputs, a significant advancement over traditional deterministic smart contracts. Through the implementation of a built-in equivalence principle, multiple validators can reach consensus even when processing non-deterministic results. This system supports both comparative validation, where outputs are directly matched, and non-comparative validation, where validators assess the reasonableness of results within defined parameters. ## How Do Intelligent Contracts Work? ### Contract Structure Intelligent Contracts are written in Python using the GenVM SDK library. The basic structure consists of: 1. Dependencies Declaration: Specify required GenVM SDK modules 2. Declare Contract: Extend `gl.Contract` to define a contract class 3. State Variables: Declare with type annotations for strong typing 4. Methods: - `@gl.public.view`: Read-only methods that don't modify state - `@gl.public.write`: Methods that can modify contract state - `@gl.public.write.payable`: Methods that can modify contract state *and* receive `value` Here's an example: ```py # { "Depends": "py-genlayer:test" } from genlayer import * class MyContract(gl.Contract): # State variables with type annotations variable: str def __init__(self): self.variable = "initial value" @gl.public.view def read_method(self) -> str: return self.variable @gl.public.write def write_method(self, new_value: str): self.variable = new_value ``` ### Validation Process - When transactions are submitted to Intelligent Contracts, they are automatically queued in a contract-specific order and marked with a "pending" status - A randomly selected group of validators is assigned to process the transaction, with one designated as the leader to propose the outcome - Once all validators evaluate the proposal and reach consensus using the equivalence principle, the transaction is accepted and enters the Finality Window [Learn more about the validation process](/about-genlayer/core-concepts/optimistic-democracy) ## Advantages over Traditional Smart Contracts ### Enhanced Decision Making Intelligent Contracts can process complex and qualitative criteria that traditional smart contracts cannot handle. Through their natural language understanding capabilities, they can interpret and act on human-readable inputs without requiring strict formatting or coding syntax. This flexibility allows the contracts to dynamically adapt to changing conditions, making them more responsive and intelligent in their decision-making processes. ### External Data Integration Intelligent Contracts can seamlessly integrate with external data sources, providing direct access to real-world information without intermediate layers. Their real-time data processing capabilities ensure that contract decisions are based on current and accurate information. This direct connectivity significantly reduces the traditional reliance on oracle services, making the contracts more efficient and cost-effective. ### Flexible Programming Development of Intelligent Contracts leverages Python's robust ecosystem, providing developers with a familiar and powerful programming environment. The platform supports the data structures needed to handle complex business logic and requirements. ## Challenges and Mitigations ### Non-Deterministic Operations **Challenge** The primary challenge in handling non-deterministic operations is maintaining consistency across multiple validators when operations may naturally produce varying results. This is particularly evident when dealing with LLM outputs or real-time data processing. **Mitigation** To address this, GenLayer provides the Equivalence Principle as a flexible framework for developers to decide how the validators will try to reach consensus. This system allows for both strict output matching and more nuanced validation approaches where validators can assess results within acceptable parameters, ensuring reliable contract execution even with non-deterministic elements. ### External Data Reliability **Challenge** Integrating external data sources introduces potential points of failure and data inconsistency risks that must be carefully managed. External APIs may experience downtime, return inconsistent results, or become deprecated over time. **Mitigation** To combat these challenges, Intelligent Contracts employ a robust multi-validator verification system where multiple independent validators must confirm external data integrity. ### Performance Considerations **Challenge** The integration of LLM operations and complex data processing can introduce significant computational overhead, potentially impacting contract execution speed and cost efficiency. **Mitigation** To tackle these performance challenges, GenLayer implements optimized validation processes that balance thoroughness with efficiency. The platform provides configurable consensus mechanisms that allow developers to fine-tune the validation process based on their specific needs, whether prioritizing speed or verification thoroughness. # developers/intelligent-contracts/tooling-setup.mdx import CustomCard from '../../../components/card' # Tooling Setup This guide will help you set up the GenLayer environment by installing the GenLayer CLI and launching the GenLayer Studio, write your first Intelligent Contract, deploy it, and interact with it using the GenLayer Studio. You'll also learn how to use the Genlayer Project Boilerplate to write end-to-end tests and build a frontend dApp with GenLayerJS. ## Table of Contents 1. [Using the GenLayer Studio](#using-the-genlayer-studio) 2. [Local Installation of the GenLayer CLI](#local-installation-of-the-genlayer-cli) 3. [Launching the GenLayer Studio](#launching-the-genlayer-studio) 4. [Writing Intelligent Contracts](#writing-intelligent-contracts) 5. [Deploying and Interacting with Intelligent Contracts](#deploying-and-interacting-with-intelligent-contracts) 6. [Writing End-to-End Tests with genlayer-project-boilerplate](#writing-end-to-end-tests-with-genlayer-project-boilerplate) 7. [Building a Frontend dApp with GenLayerJS](#building-a-frontend-dapp-with-genlayerjs) ## Using the GenLayer Studio The GenLayer Studio is a web-based interface for developing, testing, and deploying Intelligent Contracts. It provides a user-friendly environment for interacting with the GenLayer ecosystem. You can find it at [studio.genlayer.com](https://studio.genlayer.com). ## Local Installation of the GenLayer CLI The GenLayer CLI is used to set up the GenLayer Studio and, in the future, mainnet and testnet environments. ### Prerequisites Ensure you have the following installed and updated:
### Installation Steps 1. **Install GenLayer CLI** Open your terminal and run: ```bash npm install -g genlayer ``` 2. **Initialize GenLayer Environment** Run the following command to set up your development environment: ```bash genlayer init ``` During initialization, you'll be prompted to select your preferred LLM provider(s) and enter any required API keys. **Optional Initialization Parameters** You can customize the initialization with the following options: - `--numValidators `: Specify the number of validators (default is 5) - `--headless`: Run in headless mode without UI (default is false) - `--reset-db`: Reset the database to a clean state (default is false) - `--localnet-version `: Specify the localnet version to use (default is latest stable version) Example: ```bash genlayer init --numValidators 3 --headless --reset-db --localnet-version v0.32.1 ``` ## Launching the GenLayer Studio After initializing the environment, you can start the Studio by running: ```bash genlayer up ``` This command launches the GenLayer Studio using your existing configuration. **Optional Parameters:** - `--reset-validators`: Removes all current validators and creates new ones. - `--numValidators `: Specify the number of validators to start. - `--headless`: Run in headless mode without UI (default is false) - `--reset-db`: Reset the database to a clean state (default is false) Example: ```bash genlayer up --reset-validators --numValidators 3 --headless --reset-db ``` Once the Studio is running, access it at http://localhost:8080/. ## Writing Intelligent Contracts Refer to the [Your First Contract](./your-first-contract) page for more information on how to write Intelligent Contracts. ## Deploying and Interacting with Intelligent Contracts ### Deploying the Contract 1. **Load Your Contract**
In the GenLayer Studio, navigate to the Contracts section and upload your contract file. 3. **Deploy the Contract**
Navigate to the Run and Deploy section and click the "Deploy" button.
The Studio will automatically detect constructor parameters. Provide the required values.
Upon successful deployment, the contract address will be displayed. ### Interacting with the Contract 1. **Read Methods**
View the current state of the contract using Read Methods. These are methods that return data without modifying the state. 2. **Write Methods**
Execute Write Methods to interact with your contract. Provide any required input parameters. 3. **Execution Logs**
Monitor transactions and validator consensus via the Node Logs at the bottom of the Studio. 4. **Transaction Details**
View detailed information about a transaction by clicking on it in the bottom left list of transactions. ## Writing End-to-End Tests with genlayer-project-boilerplate The [genlayer-project-boilerplate](https://github.com/genlayerlabs/genlayer-project-boilerplate/) provides a starting point for writing end-to-end (e2e) tests for your Intelligent Contracts. ### Setting Up the Boilerplate 1. **Clone the Repository** On a location different from the GenLayer Studio, clone the repository: ```bash git clone https://github.com/genlayerlabs/genlayer-project-boilerplate.git ``` 2. **Install Dependencies**
Navigate to the project directory and install the required packages: ```bash cd genlayer-project-boilerplate/app npm install ``` 3. **Configure Environment**
Ensure the GenLayer Studio is running. Update the configuration files if necessary. ### Writing E2E Tests 1. **Create Test Files**
In the `test` directory, create test files using your pytest as a testing framework. 2. **Example Test** ```python import pytest from genlayer import GenLayer, Account def test_simple_contract(): # Account account_1 = create_new_account() # Deploy contract contract_code = open("contracts/my_contract.py", "r").read() contract_address, transaction_response_deploy = deploy_intelligent_contract( account_1, contract_code, "{value = 10}", ) # Test initial state initial_value = call_contract_method( contract_address, account_1, "get_value", [] ) assert initial_value == 10 # Test state change send_transaction_response = send_transaction( account_1, contract_address, "set_value", ["20"], ) # Test updated state updated_value = call_contract_method( contract_address, account_1, "get_value", [] ) assert updated_value == 20 ``` **Note on Deployment**: For deployment, developers should currently use the GenLayer Studio UI. Deploying through the CLI is not yet supported. ## Building a Frontend dApp with GenLayerJS You can build a frontend decentralized application (dApp) that interacts with your Intelligent Contract using GenLayerJS, a JavaScript SDK for GenLayer. You can start by cloning the [genlayer-dapp-boilerplate](https://github.com/genlayerlabs/genlayer-project-boilerplate/) repository or start from scratch with a new frontend project. After you have your project ready, continue with the following steps: ### Installing GenLayerJS ```bash npm install genlayer-js ``` ### Connecting to GenLayer ```javascript import { createClient } from 'genlayer-js'; const client = createClient(config); ``` ### Interacting with Contracts 1. **Read from a Contract** ```javascript const value = await client.readContract({ address: contractAddress, functionName: "get_value", args: [], }); ``` 2. **Update Contract State** ```javascript const txHash = await client.writeContract({ address: contractAddress, functionName: "set_value", args: [newValue], }); const receipt = await client.waitForTransactionReceipt({ hash: txHash, status: "FINALIZED", }); ``` ### Running the Frontend Ensure your frontend application is configured to connect to the GenLayer Studio's RPC endpoint (http://localhost:4000/api). Start your frontend application: ```bash npm run dev ``` # developers/intelligent-contracts/first-contract.mdx import { Callout } from 'nextra-theme-docs' # Your First Contract While a GenLayer Intelligent Contract is a pure Python program, there are few things that must be present in your file. ### Version Comment First of all, you need to place a magic comment with the version of GenVM you wish to use on the **first** line of your file ```py # { "Depends": "py-genlayer:test" } ``` It is similar to Solidity's `pragma solidity`, and `test` after a colon is a version. When GenLayer releases, it will be changed to some exact hash of a version, which will be frozen forever. ### Importing the Standard Library After the version comment, you can import the GenLayer standard library: ```py from genlayer import * ``` This will import all necessary types into the global scope, and everything else under `gl` namespace. ### The Contract Class An Intelligent Contract is a regular Python class, with a regular constructor and methods, which allows you to use your favorite IDE for type checking and auto completion. However, there are some additional requirements to make a class an Intelligent Contract. #### Decorators The GenVM makes use of decorators to identify the contract class and its methods. The contract class must extend `gl.Contract` class so that GenVM knows that it's an Intelligent Contract. There can be only one contract class in a file. Furthermore, public methods must be decorated with either `@gl.public.view` for read-only methods or `@gl.public.write` (or `@gl.public.write.payable`) for methods that modify storage. Constructor (`__init__`) must be private (not decorated) #### Persistent data The GenVM enables Intelligent Contracts to maintain persistent data. This data is stored on the blockchain and can be accessed and modified via transactions. This is done by declaring fields in the contract class. All persistent fields must be declared in the class body and annotated with types.
Fields declared outside the class body by creating new instance variables (`self.field = value`) are not persistent and will be discarded after the contract execution.
#### Types In your contracts, you can use any Python types, but for persisted fields, there are some restrictions: - `list[T]` needs to be replaced with `DynArray[T]` - `dict[K, V]` needs to be replaced with `TreeMap[K, V]` - `int` type isn't supported on purpose. You most likely wish to use some fixed-size integer type, such as `i32` or `u256`. If this is not the case and you are sure that you need big integers, you can annotate your field with `bigint`, which is just an alias for python `int` Only fully instantiated generic types can be used, so `TreeMap` is forbidden, while `TreeMap[str, u256]` is not #### Example Here is a simple example of an Intelligent Contract that stores a name and allows changing it: ```py # { "Depends": "py-genlayer:test" } from genlayer import * class Hello(gl.Contract): name: str def __init__(self, name: str): self.name = name @gl.public.view def run(self) -> str: return f'Hello, {self.name}' @gl.public.write def set_name(self, name: str): print(f'debug old name: {self.name}') # <- you can use prints for debugging # they will be included in the GenVM execution log self.name = name ``` The GenLayer Studio automatically detects the constructor parameters from your code. When you run your contract in the Studio, it provides the UI for all parameters for both constructor and methods, making it easy to manage and modify these inputs. # developers/intelligent-contracts/types/address.mdx # Address Type The `Address` type represents a 20-byte blockchain address, similar to Ethereum addresses. It's one of the most important types in Intelligent Contracts for handling user accounts, contract addresses, and cross-contract interactions. ## Creating Address Instances Use these patterns to instantiate an `Address` from different encodings. Choose the one that matches your source data. Construction validates size and normalizes the value so later comparisons and serializations are consistent. ```python # Constructing Address values from common encodings # From hex string (most common) address1 = Address("0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6") address2 = Address("0x0000000000000000000000000000000000000000") # Zero address (useful as a sentinel/null) # From base64 encoded string (handy when integrating with systems that emit base64) address3 = Address("WzjaanAcVoVF3PywP8uHX1a+3cQ=") # From bytes (20 bytes, useful for low-level calls or pre-parsed data) address4 = Address(b'\x5b\x38\xda\x6a\x70\x1c\x56\x85\x45\xdc\xfc\xb0\x3f\xcb\x87\x5f\x56\xbe\xdd\xc4') ``` ## Address Properties and Conversions `Address` exposes multiple read-only views for common encodings. Use these when you need a specific serialization for UI, storage, hashing, or interop with external systems. ```python class AddressConverter(gl.Contract): # Demonstrates converting a stored Address into several representations and when to use them stored_address: Address def __init__(self, initial_address: str): # Store as Address (not string) so the value is validated and normalized once self.stored_address = Address(initial_address) @gl.public.view def get_address_hex(self) -> str: # Get EIP-55 checksum hex; ideal for UI display, logs, and user input round-trips return self.stored_address.as_hex @gl.public.view def get_address_bytes(self) -> bytes: # Get raw 20-byte representation; efficient for hashing and compact storage return self.stored_address.as_bytes @gl.public.view def get_address_b64(self) -> str: # Get base64 representation; useful for URLs and systems that prefer base64 return self.stored_address.as_b64 @gl.public.view def get_address_string(self) -> str: # Default string representation (same as as_hex) return str(self.stored_address) @gl.public.view def format_address(self, fmt: str) -> str: # Format with a specifier for consistent serialization across callers if fmt == "x": return f"{self.stored_address:x}" # hex (checksummed) elif fmt == "b64": return f"{self.stored_address:b64}" # base64 string elif fmt == "cd": return f"{self.stored_address:cd}" # calldata/ABI-friendly format else: return str(self.stored_address) ``` ## Address in Contract State Store `Address` values directly in contract state for role management and registries. Collections like `DynArray[Address]` and `TreeMap[key, Address]` help model allowlists and name-to-address lookups safely. ```python class AddressStorage(gl.Contract): # Store owner/admin roles and registries using Address-typed fields and collections # Single address storage owner: Address admin: Address # Address collections authorized_users: DynArray[Address] contract_registry: TreeMap[str, Address] def __init__(self): # Initialize roles to the transaction sender to establish initial permissions self.owner = gl.message.sender_address self.admin = gl.message.sender_address @gl.public.write def add_authorized_user(self, user_address: str): # Convert input to Address so membership checks use a normalized value address = Address(user_address) self.authorized_users.append(address) @gl.public.write def register_contract(self, name: str, contract_address: str): # Keep a normalized Address in the registry for consistent lookups address = Address(contract_address) self.contract_registry[name] = address @gl.public.view def is_authorized(self, user_address: str) -> bool: # Membership check with Address ensures exact, normalized equality semantics address = Address(user_address) return address in self.authorized_users ``` ## Address in Method Parameters and Returns Methods often accept human-friendly strings and return normalized `Address` data. Convert inputs at the boundary to keep state consistent and make API responses easy for clients to consume. ```python class AddressOperations(gl.Contract): # Use Address as the key to guarantee consistent equality and map behavior balances: TreeMap[Address, u256] def __init__(self): # Start with an empty map; balances default to zero for missing keys pass @gl.public.write def set_balance_from_hex(self, account_hex: str, amount: int): # Convert caller-provided hex into Address to validate and normalize before use account = Address(account_hex) self.balances[account] = amount @gl.public.view def get_my_balance(self) -> int: # Look up the balance associated with the message sender's Address return self.balances.get(gl.message.sender_address) @gl.public.view def get_balance(self, account_hex: str) -> int: # Convert external input to Address so lookups match normalized keys account = Address(account_hex) return self.balances.get(account) @gl.public.view def get_my_address(self) -> str: # Return the sender's address as a string; convenient for clients/UI return str(gl.message.sender_address) ``` # developers/intelligent-contracts/types/primitive.mdx import { Callout } from 'nextra-theme-docs' # Primitive Types GenVM provides comprehensive sized integer types for efficient storage. These types are primarily used for type annotations in storage fields and enforce range constraints only when assigned to storage. **Important**: Sized integer types (`u8`, `u256`, etc.) are `typing.NewType` aliases that behave like regular Python `int` outside of storage context. Range checking and overflow protection only occur when assigning values to storage fields. ## Integer Types ### Standard Integer Types (Most Commonly Used) - `u8`, `u16`, `u32`, `u64`, `u128`, `u256` - Unsigned integers of various sizes - `i8`, `i16`, `i32`, `i64`, `i128`, `i256` - Signed integers of various sizes - `bigint` - Arbitrary precision integer (use with caution, prefer sized integers) ### Full Range Available GenVM also supports all intermediate sizes from 8-bit to 256-bit (e.g., `u24`, `u40`, `u48`, `u56`, `u72`, `u80`, `u88`, `u96`, `u104`, `u112`, `u120`, `u136`, `u144`, `u152`, `u160`, `u168`, `u176`, `u184`, `u192`, `u200`, `u208`, `u216`, `u224`, `u232`, `u240`, `u248` and their signed counterparts). ```python class IntegerTypes(gl.Contract): uint8_val: u8 uint256_val: u256 uint24_val: u24 # 3-byte integers int64_val: i64 def __init__(self): # Storage assignment enforces type constraints self.uint8_val = 255 # Range checked: must be 0-255 self.uint256_val = 2**256 - 1 # Range checked: must fit in u256 self.int64_val = -9223372036854775808 # Range checked: must fit in i64 self.uint24_val = 16777215 # Range checked: must be 0-16777215 @gl.public.view def get_uint8(self) -> int: return self.uint8_val @gl.public.write def set_uint256(self, value: int): self.uint256_val = value @gl.public.view def calculate_sum(self, a: int, b: int) -> int: # Note: u256(a) + u256(b) behaves exactly like a + b in Python # The u256() calls don't actually enforce range constraints here return a + b @gl.public.view def get_int64(self) -> int: return self.int64_val @gl.public.view def get_uint24(self) -> int: return self.uint24_val ``` ## String and Bytes Types ```python class StringBytesTypes(gl.Contract): text_data: str binary_data: bytes def __init__(self): self.text_data = "Hello, GenLayer!" self.binary_data = b"binary_data_here" @gl.public.write def store_text(self, text: str): self.text_data = text @gl.public.view def get_text_length(self) -> int: return len(self.text_data) # Return type annotation handles the conversion @gl.public.view def get_bytes_length(self) -> int: return len(self.binary_data) # Return type annotation handles the conversion # String operations @gl.public.view def concatenate_strings(self, str1: str, str2: str) -> str: return str1 + str2 ``` ## Boolean Type ```python class BooleanTypes(gl.Contract): flag: bool flags: DynArray[bool] flag_map: TreeMap[str, bool] def __init__(self): self.flag = True @gl.public.write def toggle_flag(self): self.flag = not self.flag @gl.public.write def set_flag(self, flag_value: bool): self.flag = flag_value @gl.public.write def set_named_flag(self, name: str, value: bool): self.flag_map[name] = value @gl.public.view def get_flag_status(self) -> bool: return self.flag @gl.public.view def check_named_flag(self, name: str) -> bool: return self.flag_map.get(name, False) ``` ## Type Conversion Utilities ```python class TypeConversionUtils(gl.Contract): def __init__(self): pass @gl.public.view def string_to_bytes(self, text: str) -> bytes: return text.encode('utf-8') @gl.public.view def bytes_to_string(self) -> str: return b"binary_data_here".decode('utf-8') @gl.public.view def int_to_string(self, value: int) -> str: return str(value) @gl.public.view def string_to_int(self, value_str: str) -> int: return int(value_str) ``` ## Type Ranges | Type | Range | Use Case | |------|-------|----------| | `u8` | 0 to 255 | Small counters, flags | | `u16` | 0 to 65,535 | Medium counters | | `u32` | 0 to 4,294,967,295 | Large counters, timestamps | | `u64` | 0 to 18,446,744,073,709,551,615 | Very large numbers | | `u128` | 0 to 2^128 - 1 | Cryptographic values | | `u256` | 0 to 2^256 - 1 | Token amounts, hashes | | `u160` | 0 to 2^160 - 1 | Address integers | | Type | Range | Use Case | |------|-------|----------| | `i8` | -128 to 127 | Small signed values | | `i16` | -32,768 to 32,767 | Medium signed values | | `i32` | -2,147,483,648 to 2,147,483,647 | Large signed values | | `i64` | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | Very large signed values | | `i128` | -2^127 to 2^127 - 1 | Large signed calculations | | `i256` | -2^255 to 2^255 - 1 | Maximum signed precision | # developers/intelligent-contracts/types/collections.mdx # Collection Types GenVM provides storage-compatible collection types that replace Python's built-in collections. These are essential for managing dynamic data structures in Intelligent Contracts. ## DynArray (Dynamic Arrays) `DynArray[T]` replaces Python's `list[T]` and provides dynamic array functionality with storage compatibility. ### Basic DynArray Usage ```python class ArrayOperations(gl.Contract): # Simple arrays numbers: DynArray[u256] names: DynArray[str] addresses: DynArray[Address] # Nested arrays matrix: DynArray[DynArray[u256]] def __init__(self): pass @gl.public.write def add_number(self, num: int): self.numbers.append(num) @gl.public.write def add_name(self, name: str): self.names.append(name) @gl.public.write def add_address(self, addr: str): address = Address(addr) self.addresses.append(address) @gl.public.view def get_number_at(self, index: int) -> int: if index < len(self.numbers): return self.numbers[index] return u256(0) @gl.public.view def get_array_length(self) -> int: return u256(len(self.numbers)) @gl.public.write def remove_last(self): if len(self.numbers) > 0: self.numbers.pop() # Matrix operations @gl.public.write def add_row(self, row: DynArray[int]): self.matrix.append(row) @gl.public.view def get_matrix_element(self, row: int, col: int) -> int: if row < len(self.matrix) and col < len(self.matrix[row]): return self.matrix[row][col] return u256(0) ``` ### DynArray with Custom Types ```python from genlayer import * from dataclasses import dataclass import json import typing @allow_storage @dataclass class User: name: str age: u8 balance: u256 class UserArrayOperations(gl.Contract): users: DynArray[User] user_ids: DynArray[str] def __init__(self): pass @gl.public.write def add_user(self, name: str, age: int, balance: int): user = User(name=name, age=age, balance=balance) self.users.append(user) self.user_ids.append(f"user_{len(self.users)}") @gl.public.view def find_user_by_name(self, name: str) -> TreeMap[str, typing.Any]: for user in self.users: if user.name == name: return user return User("", u8(0), u256(0)) ``` ## TreeMap (Ordered Maps) `TreeMap[K, V]` replaces Python's `dict[K, V]` and provides ordered map functionality with storage compatibility. ### Basic TreeMap Usage ```python class MapOperations(gl.Contract): # Simple maps balances: TreeMap[Address, u256] names: TreeMap[str, str] flags: TreeMap[str, bool] def __init__(self): pass @gl.public.write def set_balance(self, address: str, amount: int): account = Address(address) self.balances[account] = amount @gl.public.write def set_name(self, key: str, name: str): self.names[key] = name @gl.public.view def get_balance(self, address: str) -> int: account = Address(address) return self.balances.get(account, u256(0)) @gl.public.view def get_name(self, key: str) -> str: return self.names.get(key, "") @gl.public.view def has_balance(self, address: str) -> bool: account = Address(address) return account in self.balances ``` ### TreeMap with Complex Values ```python @allow_storage @dataclass class UserProfile: name: str email: str balance: u256 is_active: bool class UserProfileMap(gl.Contract): profiles: TreeMap[Address, UserProfile] permissions: DynArray[str] user_permissions: TreeMap[Address, DynArray[str]] def __init__(self): pass @gl.public.write def create_profile(self, name: str, email: str): address = gl.message.sender_address profile = UserProfile( name=name, email=email, balance=u256(0), is_active=True ) self.profiles[address] = profile self.user_permissions[address] = self.permissions @gl.public.write def add_permission(self, user: str, permission: str): account = Address(user) if account in self.user_permissions: self.user_permissions[account].append(permission) @gl.public.view def get_profile(self, address: str) -> TreeMap[str, typing.Any]: account = Address(address) return self.profiles.get(account, UserProfile("", "", u256(0), False)) @gl.public.view def has_permission(self, user: str, permission: str) -> bool: account = Address(user) if account in self.user_permissions: return permission in self.user_permissions[account] return False ``` # developers/intelligent-contracts/types/dataclasses.mdx # Dataclasses Dataclasses provide structured data types for Intelligent Contracts. Use `@allow_storage` decorator for storage compatibility. ## Method Parameters and Returns ```python import typing @allow_storage @dataclass class UserData: name: str balance: u256 class SimpleContract(gl.Contract): users: TreeMap[Address, UserData] def __init__(self): pass @gl.public.write def create_user(self, name: str, balance: int): self.users[gl.message.sender_address] = UserData(name, balance) @gl.public.view def get_user(self, user_address: str) -> TreeMap[str, typing.Any]: address = Address(user_address) return self.users.get(address, UserData("", u256(0))) ``` ## Generic Types ```python import typing @allow_storage @dataclass class Item[T]: data: T label: str class GenericContract(gl.Contract): string_items: DynArray[Item[str]] def __init__(self): pass @gl.public.write def add_item(self, data: str, label: str): item = gl.storage.inmem_allocate(Item[str], data, label) self.string_items.append(item) @gl.public.view def get_items(self) -> DynArray[TreeMap[str, typing.Any]]: return self.string_items ``` # developers/intelligent-contracts/storage.mdx import { Callout } from 'nextra-theme-docs' # Persisting data on the blockchain Usual data structures aren't suitable for representing blockchain persistent storage: 1. Allocated addresses (`id` in python terms) are not persistent 2. Allocation requires knowledge about all allocated addresses, which takes a lot of space and would cost a lot of reads at start time 3. Serialization works poorly as it will rewrite entire storage (consider rehash) Intelligent Contracts store data publicly on chain, attached to their account's address. The storage starts zero-initialized until a contract is deployed and initializes a state. For storage declaration GenLayer uses contract class fields. All persistent fields must be declared in the class body and annotated with types.
Fields declared outside the class body by creating new instance variables (`self.field = value`) are not persistent and will be discarded after the contract execution.
Example: ```py class PersistentContract(gl.Contract): minter: Address def __init__(self): self.minter = gl.message.sender_address ``` In your contracts, you can use any Python types, but for persisted fields, there are some restrictions: - `list[T]` needs to be replaced with `DynArray[T]` - `dict[K, V]` needs to be replaced with `TreeMap[K, V]` - `int` type isn't supported on purpose. You most likely wish to use some fixed-size integer type, such as `i32` or `u256`. If this is not the case and you are sure that you need big integers, you can annotate your field with `bigint`, which is just an alias for python `int` Only fully instantiated generic types can be used, so `TreeMap` is forbidden, while `TreeMap[str, u256]` is not Simple examples: ```py class PersistentContract(gl.Contract): a: str b: bytes # c: list[str] # ❌ `list` is forbidden! c: DynArray[str] # b: dict[Address, u256] # ❌ `dict` is forbidden! # b: TreeMap # ❌ only fully specialized generic types are allowed! b: TreeMap[Address, u256] # d: int # ❌ `int` is forbidden d: bigint # ⚠️ most likely you don't need an arbitrary big integer d_sized: i256 ``` ## Few words about `DynArray` and `TreeMap` These types implement python `collections.abc.MutableSequence` and `collections.abc.MutableMapping` which makes them compatible with most of the python code They can be encoded into calldata as-is as well, which means that following code is correct: ```py class PersistentContract(gl.Contract): storage: DynArray[str] @gl.public.view def get_complete_storage(self) -> collections.abc.Sequence[str]: return self.storage ``` Calldata format supports mappings only with `str` keys, like JSON does. ## Using custom data types You can use other python classes in storage, for example: ```py @allow_storage @dataclass class User: name: str birthday: datetime.datetime class Contract(gl.Contract): users: DynArray[User] ``` Note that you must decorate them with `@allow_storage`. This is done to prevent [confusion](#differences-from-regular-python-types) However, there is a tricky case: allocating storage generics in-memory. It is different from regular python syntax because storage types don't have type erasure due to fixed memory layout. ```py @allow_storage @dataclass class User: data: TreeMap[str, str] User() # error: data is absent (from dataclass) User(gl.storage.inmem_allocate(TreeMap[str, str])) # works fine, this function takes a type and `*args, **kwargs` for corresponding `__init__`. Also note that type must be fully instantiated and have no type variables. ``` ## Default values By default storage is zero-initialized: | Type | Default value | |------------|---------------| | `u*`, `i*` | `0` | | `bool` | `false` | | `float` | `+0` | | `str` | `""` | | `DynArray` | `[]` | | `TreeMap` | `{}` | Struct types are zero-initialized "recursively" --- ## Memory Management ### `gl.storage.inmem_allocate` Required for **generic storage classes** only. Regular dataclasses use normal initialization. ```python # { "Depends": "py-genlayer:test" } from genlayer import * from dataclasses import dataclass import datetime @allow_storage @dataclass class User: name: str birthday: datetime.datetime @allow_storage @dataclass class Gen[T]: name: T birthday: datetime.datetime class Contract(gl.Contract): user: User gen_user: Gen[bytes] def __init__(self): pass @gl.public.write def plain(self): user = User('Ada', datetime.datetime.now()) self.user = user read_user = self.user copied_out = gl.storage.copy_to_memory(read_user) def nd(): print('inmem: ok', user) try: print('storage: not ok', str(read_user)) except Exception as e: print('storage: not ok', e) print('copied out: ok', copied_out) gl.eq_principle.strict_eq(nd) @gl.public.write def generic(self): user = gl.storage.inmem_allocate(Gen[bytes], b'Ada', datetime.datetime.now()) self.gen_user = user read_user = self.gen_user copied_out = gl.storage.copy_to_memory(read_user) def nd(): print('inmem: ok', user) try: print('storage: not ok', str(read_user)) except Exception as e: print('storage: not ok', e) print('copied out: ok', copied_out) gl.eq_principle.strict_eq(nd) ``` ### `gl.storage.copy_to_memory` Storage objects need to be copied to memory when you want to use them in non-deterministic blocks, since non-deterministic blocks cannot access storage directly: ```python # Read from storage storage_user = self.user # Copy to memory for use in non-deterministic blocks or other operations memory_user = gl.storage.copy_to_memory(storage_user) def my_nondet_function(): # Storage objects cannot be used directly in nondet blocks # print('storage: not accessible', storage_user) # Error - storage not accessible! # But memory objects work fine print('copied out: ok', memory_user) # Works! return str(memory_user) # String conversion also works with memory objects gl.eq_principle.strict_eq(my_nondet_function) ``` --- ## Differences from regular python types Even though storage classes mimic python types, remember that they provide you only with a view on memory, not actual data that is "here". For example, consider the above example ```py self.users.append(User("Ada")) user = self.users[-1] self.users[-1] = User("Definitely not Ada", datetime.datetime.now()) assert user.name == "Definitely not Ada" # this is true! ``` # developers/intelligent-contracts/first-intelligent-contract.mdx # Your First **Intelligent** Contract Now is the time to utilize all the power of GenLayer! For blockchain integrity reasons, non-determinism must be contained within special non-deterministic blocks. Such blocks are regular Python functions with no arguments, which can return arbitrary values. However, there are some limitations: - Storage is inaccessible from non-deterministic blocks - State of the Python interpreter is not passed back to the deterministic code (for instance, you won't see changes in global variables) ### Simple Case To illustrate how it works, let's get a webpage as plain HTML, and verify that it has a link to the owner: ```py example_web_address = 'https://example.org' def my_non_deterministic_block(): web_data = gl.get_webpage(example_web_address, mode='html') return 'iana' in web_data print(gl.eq_principle_strict_eq(my_non_deterministic_block)) ``` Here are a few important parts: 1. It is **mandatory** to call `gl.get_webpage` from a function invoked via `gl.eq_principle_*`, otherwise it will give an error 2. Type annotations are not required 3. `example_web_address` gets captured without the need to specify it explicitly 4. We are getting the page in plain HTML, because we want text from a link (`` HTML tag), which is not visible in the text representation 5. We are using `eq_principle_strict_eq` because we return a `bool` (`True` or `False`), so there is no need to run LLMs or other complex computations: validators will agree _if_ they both get the exactly the same result, which makes sense for our case. However, if you wish to return more complex data (such as a text summary), you should use other `eq_principle`. More on this topic on the next page ### As a Full Contract ```py # { "Depends": "py-genlayer:test" } from genlayer import * class Contract(gl.Contract): had_iana: bool def __init__(self): example_web_address = 'https://example.org' def my_non_deterministic_block(): web_data = gl.get_webpage(example_web_address, mode='html') return 'iana' in web_data self.had_iana = gl.eq_principle_strict_eq(my_non_deterministic_block) ``` # developers/intelligent-contracts/equivalence-principle.mdx import { Callout } from 'nextra-theme-docs' import { Fragment } from 'react'; # 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. ```python 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 GenLayer SDK provides function `gl.eq_principle.prompt_non_comparative` for handling most scenarios that require performing subjective NLP tasks #### Non-Comparative Equivalence Principle Parameters The `gl.eq_principle.prompt_non_comparative` function takes three key parameters that define how validators should evaluate non-deterministic operations: 1. **input** (function) The input parameter represents the original data or function that needs to be processed by the task. For instance, when building a sentiment analysis contract, the input might be a text description that needs to be classified. The function processes this input before passing it to the validators for evaluation. 2. **task** (str) The task parameter provides a clear and concise instruction that defines exactly what operation needs to be performed on the input. This string should be specific enough to guide the validators in their evaluation process while remaining concise enough to be easily understood. For example, in a sentiment analysis context, the task might be "Classify the sentiment of this text as positive, negative, or neutral". This instruction serves as a guide for both the leader and validators in processing the input. 3. **criteria** (str) The criteria parameter defines the specific rules and requirements that validators use to determine if an output is acceptable. This string should contain a comprehensive set of validation parameters that ensure consistency across different validators. While the criteria can be structured in various ways, it typically outlines the expected format of the output and any specific considerations that should be taken into account during validation. For example: ```python criteria = """ Output must be one of: positive, negative, neutral Consider context and tone Account for sarcasm and idioms """ ``` This criteria helps validators make consistent decisions about whether to accept or reject the leader's proposed output, even when dealing with subjective or non-deterministic results. #### Example Usage ```python class SentimentAnalyzer(gl.Contract): @gl.public.write def analyze_sentiment(self, text: str) -> str: self.sentiment = gl.eq_principle.prompt_non_comparative( input=text, task="Classify the sentiment of this text as positive, negative, or neutral", criteria=""" Output must be one of: positive, negative, neutral Consider context and tone Account for sarcasm and idioms """ ) ``` In this example: - `input` is the text to analyze - `task` defines what operation to perform - `criteria` ensures consistent validation across validators without requiring exact output matching ### Strict Equivalence Principle Method that requires exact matches between validator outputs. Use this when you need deterministic results or when dealing with objective, factual data. **When to use:** - Fetching specific data that should be identical (web content, API responses) - Boolean operations or exact classifications - When network consensus on exact values is critical **How it works:** - All validators execute the same function - Results must match exactly ```python def fetch_content(): response = gl.nondet.web.get("https://example.com") body = json.loads(response.body) return body["valid"] self.valid = gl.eq_principle_strict_eq(fetch_content) ``` ```python def check_condition(): web_data = gl.get_webpage(url) prompt = f"Is this text positive? Answer only 'true' or 'false': {web_data}" return gl.exec_prompt(prompt).strip() result = gl.eq_principle_strict_eq(check_condition) ``` ### Custom Leader/Validator Pattern For advanced use cases, you can implement your own equivalence logic using the leader/validator pattern. GenLayer provides two variants with different error handling approaches. #### Safe Custom Pattern (`gl.vm.run_nondet`) Provides comprehensive error handling by running validators in a sandbox. **When to use:** - Production environments where stability is critical - Complex validation logic that might have errors - When you want automatic error comparison and fallback handling **How it works:** - Leader function executes the main operation - Validator function runs in a sandbox for safety - Automatic error handling with customizable comparison functions ```python def analyze_article_quality(self, assignment_id: str, article_text: str): assignment = self.assignments[assignment_id] prompt = f""" Analyze this article's quality and provide a score from 0 to 2. Article: {article_text} Guidelines: {assignment.title} - {assignment.description} Return JSON: {{"analysis": "detailed explanation", "score": 0-2}} """ def leader_fn(): response = gl.nondet.exec_prompt(prompt) return json.loads(response) def validator_fn(leader_res: gl.vm.Result) -> bool: if not isinstance(leader_res, gl.vm.Return): return False validator_res = leader_fn() leader_score = leader_res.calldata["score"] validator_score = validator_res["score"] # Exact match for score 0, ±1 tolerance for others if validator_score == 0 or leader_score == 0: return validator_score == leader_score return abs(validator_score - leader_score) <= 1 return gl.vm.run_nondet(leader_fn, validator_fn) ``` #### Fast Custom Pattern (`gl.vm.run_nondet_unsafe`) The most generic API for non-deterministic execution. Does not use extra sandbox for catching validator errors - validator errors result in `Disagree` error in executor (same as if the function returned `False`). **When to use:** - Performance-critical applications where sandbox overhead matters - Simple validators that are unlikely to error - When you want direct control over error handling **Note:** Use `run_nondet` instead if you want to catch and inspect validator errors, or use sandbox inside of it. ```python def analyze_sentiment_fast(self, text: str): def leader_fn(): prompt = f"Rate sentiment 1-10: {text}" result = gl.nondet.exec_prompt(prompt) return int(result.strip()) def validator_fn(leader_result: gl.vm.Result) -> bool: if not isinstance(leader_result, gl.vm.Return): return False score = leader_result.calldata return isinstance(score, int) and 1 <= score <= 10 return gl.vm.run_nondet_unsafe(leader_fn, validator_fn) ``` #### Advanced Error Handling with `run_nondet` ```python # Custom error comparison functions def custom_validation_with_error_handling(self, data: str): def leader_fn(): # Note: process_external_data() is not provided by GenVM - implement your own logic return process_external_data(data) def validator_fn(leader_result): if not isinstance(leader_result, gl.vm.Return): return False # Note: validate_result() is not provided by GenVM - implement your own logic return validate_result(leader_result.calldata) def compare_user_errors(error1: gl.vm.UserError, error2: gl.vm.UserError) -> bool: # Custom logic for comparing user errors return "timeout" in error1.message and "timeout" in error2.message def compare_vm_errors(error1: gl.vm.VMError, error2: gl.vm.VMError) -> bool: # Custom logic for comparing VM errors return "memory" in error1.message and "memory" in error2.message return gl.vm.run_nondet( leader_fn, validator_fn, compare_user_errors=compare_user_errors, compare_vm_errors=compare_vm_errors ) ``` ### Data Flow
```mermaid --- title: Comparative Equivalence Principle --- graph TD input[Input function] criteria[Criteria] final_result[Final result] output_leader[Output leader] output_validator[Output validator] subgraph Leader input_leader[Executing input function] leader["Performing task (LLM)"] input_leader --> leader end subgraph Validator input_validator[Executing input function] validator["Performing task (LLM)"] input_validator --> validator end input --> Leader input --> Validator leader --> output_leader validator --> output_validator output_leader --> final_result criteria --> final_result output_validator --> final_result ```
```mermaid --- title: Non-Comparative Equivalence Principle --- graph TD task[Task & criteria] input[Input function] subgraph Leader input_leader[Executing input function] leader["Performing task (LLM)"] input_leader --> leader end task --> leader leader --> Output subgraph Validator input_validator[Executing input function] validator["Validating (LLM)"] input_validator --> validator end task --> validator Output --> validator input --> Leader input --> Validator final_result[Final result] Output --> final_result validator -..- final_result ```
## The Leader/Validator Pattern Behind the scenes, GenLayer's Equivalence Principle is implemented using a leader/validator pattern. This pattern ensures security and consensus when dealing with non-deterministic operations. Each nondeterministic block consists of two functions: **Leader Function** - Executes only on the designated leader node - Performs operations like web requests or NLP - Returns a result that will be shared with validator nodes ```python def leader() -> T: # Performs the actual nondeterministic operation pass ``` **Validator Function** - Executes on multiple validator nodes - Receives the leader's result as input - Must independently verify the result's validity - Returns `True` to accept or `False` to reject ```python def validator(leader_result: gl.vm.Return[T] | gl.vm.VMError | gl.vm.UserError) -> bool: # Verifies the leader's result # Returns True if acceptable, False otherwise # Note: leader function could end with a UserError or VMError # reasons for them can be "host unreachable" and "OOM", respectively pass ``` ### Writing Secure Validator Functions #### ❌ Bad Example ```python def validator(leader_result): return True # Always accepts - insecure! ``` This validator is useless because it allows the leader to return any arbitrary data without verification. This would allow a single node to produce a rigged result, such as a false match result in football prediction market contract example #### ✅ Good Examples **Independent Verification:** ```python def validator(leader_result): # Independently fetch the same data my_data = fetch_external_data() # If we reached this line, we haven't encountered an error --- vote disagree if not isinstance(leader_result, Return): return False # Verify the leader's result matches within tolerance return calculate_similarity(leader_result.data, my_data) > 0.9 ``` **NLP Validation:** ```python def validator(leader_result): # Fetch original content independently original_text = fetch_webpage(url) # Use NLP to verify the summary quality if not isinstance(leader_result, Return): return False return is_valid_summary(original_text, leader_result.summary) ``` ### Key Principles for Custom Validators 1. **Independent Verification**: Validators should independently verify results, not blindly trust the leader 2. **Tolerance for Nondeterminism**: When dealing with AI outputs or time-sensitive data, allow reasonable variations: - Use similarity thresholds instead of exact matches - Account for timing differences in data fetches - Accept semantically equivalent AI outputs 3. **Error Handling**: Always check if the leader result is an error before processing. `gl.vm.run_nondet` provides fallbacks for validator functions errors, while `gl.vm.run_nondet_unsafe` does not. If you use the later you may wish to execute most part of the code in the sandbox and compare errors with custom advanced logic 4. **Security First**: The validator's role is to prevent malicious or incorrect data from being accepted. When in doubt, reject ### Best Practices - Keep non-deterministic operations well-defined - Design validators that can handle slight variations in data - Consider network delays and timing differences - Use NLP for subjective tasks validation - Prefer to use built-in equivalence principle templates, as they can be customized by node and have a better security against prompt attacks - Document expected tolerances and validation criteria - Test validator functions with various edge cases and malicious inputs # developers/intelligent-contracts/debugging.mdx import { Callout } from 'nextra-theme-docs' # Debugging Intelligent Contracts on GenLayer Debugging Intelligent Contracts on GenLayer involves deploying contracts, sending transactions, validating their behavior, and identifying issues using logs. Here is some guidance on how to debug using the GenLayer Studio. ## 2. Debugging in GenLayer Studio When testing in GenLayer Studio, you can debug issues by examining the logs and outputs. The Studio provides detailed logs for every transaction and contract execution. ### Getting Static Code Syntax Errors If you get a syntax error in your contract, you can see the error on a red panel in the Studio in the **Run and Debug** tab. Here is an example of a syntax error in line 42 of the Wizard of Coin contract: ![Syntax Error](/studio/syntax-error.png) ### Viewing Logs #### Access Logs The logs are located in the bottom section of the Studio in the **Run and Debug** tab. #### Filter Relevant Logs Use filters to isolate logs related to specific transactions or contracts. You can select the debug level (info, success, error), the execution layer (RPC Server, GenVM, and Consensus), and the transaction hash. Also, you can select a transaction from the left list and see the logs for that specific transaction. ### Identifying Common Issues #### Input Validation Errors - Look for incorrect or missing parameters in the transaction payload #### Contract Logic Errors - Debug issues in contract logic by examining state changes and variable values in logs #### Non-deterministic Output Issues - Analyze LLM or web data interactions for discrepancies or timeouts #### Consensus Errors - Investigate validator disagreements or timeout errors to identify potential misconfigurations # developers/intelligent-contracts/deploying.mdx import { Callout } from 'nextra-theme-docs' import { Card, Cards } from 'nextra-theme-docs' # Deploying Intelligent Contracts This comprehensive guide covers everything you need to know about deploying your Intelligent Contracts on GenLayer. From local development to testnet deployment, learn how to use different methods and networks effectively. ## Quick Start Get started quickly with these essential deployment options: Deploy contracts directly from the command line with simple commands Use TypeScript/JavaScript scripts for complex deployment workflows Configure networks, manage settings, and understand deployment environments ## Deployment Approaches GenLayer offers two primary deployment methods: ### CLI Direct Deployment Perfect for quick deployments and simple contracts. Deploy with a single command: ```bash genlayer deploy --contract contracts/my_contract.py --args "Hello World" 42 ``` [Learn more about CLI Deployment →](./deploying/cli-deployment) ### Deploy Scripts Ideal for complex workflows, multi-contract deployments, and testnet environments: ```typescript export default async function main(client: GenLayerClient) { // Deploy and configure multiple contracts const mainContract = await deployContract(client, "contracts/main.py", []); const helperContract = await deployContract(client, "contracts/helper.py", [mainContract]); await configureContracts(client, mainContract, helperContract); } ``` [Learn more about Deploy Scripts →](./deploying/deploy-scripts) ## Networks Overview Deploy to different networks based on your development stage: | Network | Purpose | When to Use | |---------|---------|-------------| | **Localnet** | Local development | Development, debugging, initial testing | | **Studionet** | Hosted development | Team collaboration, quick prototyping | | **TestnetAsimov** | Pre-production testing | Final validation (requires faucet tokens) | [Explore Network Configuration →](./deploying/network-configuration) ## Development Workflow Follow this recommended progression: 1. **Develop locally** on `localnet` with full control 2. **Test collaboratively** on `studionet` with your team 3. **Validate thoroughly** on `testnetAsimov` in a production-like environment Start with CLI deployment for simple contracts, then graduate to deploy scripts as your projects become more complex. ## What's Next? After deploying your contracts: 1. **Test Contract Functions**: Use `genlayer call` and `genlayer write` to interact with deployed contracts 2. **Monitor Transactions**: Check transaction receipts with `genlayer receipt ` 3. **Build Frontend**: Integrate with your deployed contracts using [GenLayerJS](https://github.com/yeagerai/genlayer-js) 4. **Debug Issues**: Use the [Debugging Guide](./debugging) if you encounter problems Ready to start deploying? Choose your preferred method and dive into the detailed guides! # developers/intelligent-contracts/deploying/deployment-methods.mdx # Deployment Methods GenLayer offers two primary methods for deploying Intelligent Contracts: 1. **CLI Direct Deployment**: Deploy contracts directly using command-line arguments 2. **Deploy Scripts**: Use TypeScript/JavaScript scripts for complex deployment workflows ## CLI Direct Deployment The CLI method is perfect for: - Quick deployments during development - Simple contracts with minimal setup - Testing and debugging scenarios - One-off contract deployments **Benefits:** - Fast and straightforward - No additional files required - Direct command-line interface - Immediate feedback ## Deploy Scripts The deploy script method is ideal for: - Complex deployment workflows - Multi-contract deployments - Testnet environments - Repeatable deployment processes **Benefits:** - Version control friendly - Complex logic support - Environment-specific configurations - Error handling and rollback capabilities - Integration with CI/CD pipelines ## Choosing the Right Method | Scenario | Recommended Method | Reason | |----------|-------------------|---------| | Local development | CLI Direct | Quick iteration and testing | | Single contract | CLI Direct | Simple and efficient | | Multiple contracts | Deploy Scripts | Better orchestration | | Testnet deployment | Deploy Scripts | More control and reliability | | CI/CD integration | Deploy Scripts | Automation friendly | ## Next Steps - Learn about [Network Configuration](./network-configuration) to choose the right deployment target - Explore [CLI Deployment](./cli-deployment) for direct deployment - Discover [Deploy Scripts](./deploy-scripts) for advanced workflows # developers/intelligent-contracts/deploying/network-configuration.mdx import { Callout } from 'nextra-theme-docs' # Network Configuration GenLayer supports three different networks, each serving specific purposes in the development lifecycle: ## Localnet **Purpose**: Local development and testing - **When to use**: During development, debugging, and initial testing - **Setup**: Requires running the GenLayer Studio locally with `genlayer init` and `genlayer up` - **URL**: `http://localhost:4000/api` (default) - **Benefits**: - Full control over validators and network configuration - No external dependencies - Fast transaction processing - Ability to reset database and validators ### Setting up Localnet ```bash # Initialize local network genlayer init # Start the local network genlayer up ``` For complete setup instructions, examples, and video tutorials, see the [GenLayer Studio Guide](../tools/genlayer-studio). ## Studionet **Purpose**: Hosted development environment - **When to use**: For development without local setup requirements - **Setup**: Accessible through [studio.genlayer.com/api](https://studio.genlayer.com) - **Benefits**: - No local installation required - Pre-configured validators - Shared development environment - Ideal for quick prototyping Studionet is perfect for getting started quickly or when you need to share your development environment with others. ### Using Studionet ```bash # Set network to studionet genlayer network studionet # Deploy to studionet genlayer deploy --contract contracts/my_contract.py ``` ## TestnetAsimov **Purpose**: Production-like testing environment - **When to use**: For final testing - **Setup**: Connect using network configuration - **Benefits**: - Production-like environment - Stable for testing dApp integrations - Shared testnet for community testing ### Getting Testnet Tokens Before deploying to TestnetAsimov, you'll need testnet tokens. Use the faucet to get free GEN tokens: ```bash # Request testnet tokens curl -X POST https://genlayer-faucet.vercel.app/api/faucet \ -H 'Content-Type: application/json' \ -d '{ "address": "0xYourEVMAddressHere", "network": "Genlayer Testnet", "token": "GEN", "turnstileToken": "" }' ``` **Important**: Replace `0xYourEVMAddressHere` with your actual EVM address. ### Using TestnetAsimov ```bash # Set network to testnet genlayer network testnet-asimov # Deploy to testnet genlayer deploy --contract contracts/my_contract.py ``` ## Network Comparison | Feature | Localnet | Studionet | TestnetAsimov | |---------|----------|-----------|---------------| | **Setup Complexity** | Medium | None | Low | | **Control Level** | Full | Limited | Limited | | **Persistence** | Local only | Temporary | Persistent | | **Collaboration** | No | Yes | Yes | | **Performance** | Fast | Medium | Production-like | | **Best for** | Development | Prototyping | Pre-production testing | ## Development Workflow We recommend following this progression: 1. **Start with Localnet**: Develop and test your contracts locally with full control 2. **Test on Studionet**: Validate contracts in a shared environment 3. **Deploy to TestnetAsimov**: Final testing in a production-like environment ## Managing Network Settings ### Viewing Current Configuration ```bash # Show all configuration genlayer config get # Show specific network setting genlayer config get network ``` ### Setting Networks The GenLayer CLI allows you to set a default network that will be used for all operations unless overridden. **Interactive Network Selection:** ```bash # Set network interactively genlayer network ``` This command will show you available networks and let you choose: ``` ? Select a network: ❯ localnet studionet testnet-asimov custom ``` **Direct Network Selection:** ```bash # Set specific network directly genlayer network localnet genlayer network studionet genlayer network testnet-asimov ``` ### Network Switching Workflow ```bash # Development workflow genlayer network localnet genlayer deploy --contract contracts/my_contract.py # Testing workflow genlayer network studionet genlayer deploy --contract contracts/my_contract.py # Pre-production workflow genlayer network testnet-asimov genlayer deploy --contract contracts/my_contract.py ``` ## Network Configuration File The CLI stores network configuration in `~/.genlayer/genlayer-config.json`: ```json { "network": { "id": 61999, "name": "Genlayer Localnet", "rpcUrls": { ... } } } ``` ### Manual Configuration If needed, you can edit the configuration file directly: ```bash # Open config file code ~/.genlayer/genlayer-config.json # Or edit with any editor nano ~/.genlayer/genlayer-config.json ``` ## Next Steps - Start deploying with [CLI Deployment](./cli-deployment) - Set up automated deployments with [Deploy Scripts](./deploy-scripts) # developers/intelligent-contracts/deploying/cli-deployment.mdx import { Callout } from 'nextra-theme-docs' # CLI Deployment The GenLayer CLI provides a straightforward way to deploy contracts directly from the command line. ## Direct Contract Deployment Deploy a single contract using the `deploy` command: ```bash genlayer deploy --contract [options] ``` **Options:** - `--contract `: Path to the Python contract file - `--rpc `: Custom RPC URL (optional) - `--args `: Constructor arguments (space-separated) ## Basic Examples ### Simple Contract Deployment ```bash # Deploy a simple contract genlayer deploy --contract contracts/my_contract.py ``` ### Contract with Constructor Arguments ```bash # Deploy with constructor arguments genlayer deploy --contract contracts/betting_contract.py --args "World Cup 2024" 1000 ``` ### Deploy to Specific Networks You can deploy to different networks by using the `--rpc` option or by setting your default network: ```bash # Deploy to localnet with custom RPC genlayer deploy --contract contracts/my_contract.py --rpc http://localhost:4000/api # Deploy to studionet genlayer deploy --contract contracts/my_contract.py --rpc https://studio.genlayer.com/api # Deploy scripts to specific network genlayer deploy --rpc https://custom-network.com/api ``` **Alternative: Set default network first** ```bash # Set network then deploy genlayer network testnet-asimov genlayer deploy --contract contracts/my_contract.py ``` ## Constructor Arguments When deploying contracts with constructor parameters, provide them as space-separated arguments: ### String Arguments ```bash # Single string argument genlayer deploy --contract contracts/my_contract.py --args Hello ``` ### Multiple Arguments ```bash # Multiple arguments (string, number, boolean) genlayer deploy --contract contracts/my_contract.py --args "Contract Name" 100 true ``` ### Multi-word Strings ```bash # Multi-word strings (use quotes) genlayer deploy --contract contracts/my_contract.py --args "Multi word string" 42 ``` ## Argument Types The CLI automatically handles different argument types: | Python Type | CLI Example | Notes | |-------------|-------------|-------| | `str` | `"Hello World"` | Use quotes for multi-word strings | | `int` | `42` | Numbers without quotes | | `float` | `3.14` | Decimal numbers | | `bool` | `true` or `false` | Lowercase boolean values | | `list` | Not supported | Use deploy scripts for complex types | For complex data types like lists, dictionaries, or objects, use [Deploy Scripts](./deploy-scripts) instead of CLI deployment. ## Deployment Output When a deployment succeeds, you'll see output similar to: ```bash ✅ Contract deployed successfully! Transaction Hash: 0x1234567890abcdef... Contract Address: 0xabcdef1234567890... ``` ## Quick Deployment Workflow 1. **Prepare your contract**: Ensure your `.py` file is ready 2. **Choose your network**: Use `genlayer network` to set the target 3. **Deploy**: Run the deploy command with appropriate arguments 4. **Verify**: Note the contract address for future interactions ```bash # Example workflow genlayer network localnet genlayer deploy --contract contracts/token.py --args "MyToken" "MTK" 1000000 ``` ## Next Steps - Learn about [Deploy Scripts](./deploy-scripts) for more complex deployments - Configure networks with [Network Configuration](./network-configuration) # developers/intelligent-contracts/deploying/deploy-scripts.mdx import { Callout } from 'nextra-theme-docs' # Deploy Scripts For more complex deployment workflows, use deploy scripts. ## Script Structure Create TypeScript or JavaScript files in the `deploy/` directory: ``` your-project/ ├── deploy/ │ ├── 001_deploy_main_contract.ts │ ├── 002_setup_configuration.ts │ └── 003_initialize_data.ts └── contracts/ └── my_contract.py ``` Deploy scripts are executed in alphabetical order. Use numeric prefixes (001_, 002_) to control execution order. ## Basic Deploy Script Here's a template for a deploy script (`deploy/deployScript.ts`): ```typescript import { readFileSync } from "fs"; import path from "path"; import { TransactionHash, TransactionStatus, GenLayerClient, DecodedDeployData, GenLayerChain } from "genlayer-js/types"; import { testnetAsimov } from "genlayer-js/chains"; export default async function main(client: GenLayerClient) { // Read the contract file const filePath = path.resolve(process.cwd(), "contracts/my_contract.py"); const contractCode = new Uint8Array(readFileSync(filePath)); // Initialize consensus await client.initializeConsensusSmartContract(); // Deploy the contract const deployTransaction = await client.deployContract({ code: contractCode, args: [], // Constructor arguments }); // Wait for deployment confirmation const receipt = await client.waitForTransactionReceipt({ hash: deployTransaction as TransactionHash, retries: 200, }); // Check deployment success if ( receipt.statusName !== TransactionStatus.ACCEPTED && receipt.statusName !== TransactionStatus.FINALIZED ) { throw new Error(`Deployment failed. Receipt: ${JSON.stringify(receipt)}`); } // Receipt structure differs between TestnetAsimov and localnet/studionet const deployedContractAddress = (client.chain as GenLayerChain).id !== testnetAsimov.id ? receipt.data.contract_address : (receipt.txDataDecoded as DecodedDeployData)?.contractAddress; console.log("Contract deployed successfully!", { "Transaction Hash": deployTransaction, "Contract Address": deployedContractAddress, }); return deployedContractAddress; } ``` ## Advanced Deploy Script with Configuration ```typescript import { readFileSync } from "fs"; import path from "path"; import { TransactionHash, TransactionStatus, GenLayerClient, DecodedDeployData, GenLayerChain } from "genlayer-js/types"; import { testnetAsimov } from "genlayer-js/chains"; export default async function main(client: GenLayerClient) { console.log("🚀 Starting deployment process..."); // Deploy main contract const mainContractAddress = await deployContract( client, "contracts/main_contract.py", ["Initial Config", 1000] ); // Deploy helper contract const helperContractAddress = await deployContract( client, "contracts/helper_contract.py", [mainContractAddress] ); // Configure the main contract await configureContract(client, mainContractAddress, helperContractAddress); console.log("✅ Deployment completed successfully!"); console.log({ mainContract: mainContractAddress, helperContract: helperContractAddress, }); } async function deployContract( client: GenLayerClient, contractPath: string, args: any[] = [] ): Promise { const filePath = path.resolve(process.cwd(), contractPath); const contractCode = new Uint8Array(readFileSync(filePath)); await client.initializeConsensusSmartContract(); const deployTransaction = await client.deployContract({ code: contractCode, args, }); const receipt = await client.waitForTransactionReceipt({ hash: deployTransaction as TransactionHash, retries: 200, }); // Check deployment success if ( receipt.statusName !== TransactionStatus.ACCEPTED && receipt.statusName !== TransactionStatus.FINALIZED ) { throw new Error(`Deployment failed for ${contractPath}. Receipt: ${JSON.stringify(receipt)}`); } // Receipt structure differs between TestnetAsimov and localnet/studionet const deployedContractAddress = (client.chain as GenLayerChain).id !== testnetAsimov.id ? receipt.data.contract_address : (receipt.txDataDecoded as DecodedDeployData)?.contractAddress; return deployedContractAddress; } async function configureContract( client: GenLayerClient, mainAddress: string, helperAddress: string ) { // Example configuration call const hash = await client.writeContract({ address: mainAddress as any, functionName: "setHelperContract", args: [helperAddress], value: 0n, }); await client.waitForTransactionReceipt({ hash, retries: 100, interval: 5000, }); } ``` ## Running Deploy Scripts Execute all deploy scripts in order: ```bash genlayer deploy ``` The CLI will automatically: 1. Find all `.ts` and `.js` files in the `deploy/` directory 2. Sort them numerically by filename prefix (001_, 002_, etc.) 3. Execute them in order 4. Pass a configured GenLayer client to each script ## Script Organization ### Recommended File Naming ``` deploy/ ├── 001_core_contracts.ts # Core infrastructure ├── 002_token_contracts.ts # Token-related contracts ├── 003_governance.ts # Governance setup ├── 004_configure_system.ts # System configuration └── 999_verify_deployment.ts # Post-deployment verification ``` ## Error Handling Always include proper error handling in deploy scripts: ```typescript export default async function main(client: GenLayerClient) { try { await client.initializeConsensusSmartContract(); const deployTransaction = await client.deployContract({ code: contractCode, args: [], }); const receipt = await client.waitForTransactionReceipt({ hash: deployTransaction as TransactionHash, retries: 200, }); // Check deployment success if ( receipt.statusName !== TransactionStatus.ACCEPTED && receipt.statusName !== TransactionStatus.FINALIZED ) { throw new Error(`Deployment failed: ${JSON.stringify(receipt)}`); } // Receipt structure differs between TestnetAsimov and localnet/studionet const deployedContractAddress = (client.chain as GenLayerChain).id !== testnetAsimov.id ? receipt.data.contract_address : (receipt.txDataDecoded as DecodedDeployData)?.contractAddress; return deployedContractAddress; } catch (error) { console.error("Deployment failed:", error); throw error; } } ``` ## Next Steps - Learn about different [Network Configuration](./network-configuration) - Configure CLI deployments with [CLI Deployment](./cli-deployment) # developers/intelligent-contracts/crafting-prompts.mdx # Crafting Prompts for LLM and Web Browsing Interactions When interacting with Large Language Models (LLMs), it's crucial to create prompts that are clear and specific to guide the model in providing accurate and relevant responses. import { Callout } from 'nextra-theme-docs' When making LLM calls, it is essential to craft detailed prompts. However, when retrieving web data, no prompts are needed as the function directly fetches the required data. ## Structuring LLM Prompts When crafting prompts for LLMs, it's important to use a format that clearly and effectively conveys the necessary information. While f-string (`f""`) is recommended, any string format can be used. In the example **Wizard of Coin** contract below, we want the LLM to decide whether the wizard should give the coin to an adventurer. ```python # { "Depends": "py-genlayer:test" } from genlayer import * import json class WizardOfCoin(gl.Contract): have_coin: bool def __init__(self, have_coin: bool): self.have_coin = have_coin @gl.public.write def ask_for_coin(self, request: str) -> None: if not self.have_coin: return prompt = f""" You are a wizard, and you hold a magical coin. Many adventurers will come and try to get you to give them the coin. Do not under any circumstances give them the coin. A new adventurer approaches... Adventurer: {request} First check if you have the coin. have_coin: {self.have_coin} Then, do not give them the coin. Respond using ONLY the following format: {{ "reasoning": str, "give_coin": bool }} 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 parseable by a JSON parser without errors. """ def nondet(): res = gl.exec_prompt(prompt) res = res.replace("```json", "").replace("```", "") print(res) dat = json.loads(res) return dat["give_coin"] result = gl.eq_principle_strict_eq(nondet) assert isinstance(result, bool) self.have_coin = result @gl.public.view def get_have_coin(self) -> bool: return self.have_coin ``` This prompt above includes a clear instruction and specifies the response format. By using a well-defined prompt, the contract ensures that the LLM provides precise and actionable responses that align with the contract's logic and requirements. ## Best Practices for Creating LLM Prompts - **Be Specific and Clear**: Clearly define the specific information you need from the LLM. Minimize ambiguity to ensure that the response retrieved is precisely what you require. Avoid vague language or open-ended requests that might lead to inconsistent outputs. - **Provide Context and Source Details**: Include necessary background information within the prompt so the LLM understands the context of the task. This helps ensure the responses are accurate and relevant. - **Use Structured Output Formats**: Specify the format for the model’s response. Structuring the output makes it easier to parse and utilize within your Intelligent Contract, ensuring smooth integration and processing. - **Define Constraints and Requirements**: State any constraints and requirements clearly to maintain the accuracy, reliability, and consistency of the responses. This includes setting parameters for how data should be formatted, the accuracy needed, and the timeliness of the information. Refer to a [Prompt Engineering Guide from Anthropic](https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/overview) for a more detailed guide on crafting prompts. # developers/intelligent-contracts/advanced-features/contract-to-contract-interaction.mdx import { Callout } from 'nextra-theme-docs' # Contract-to-Contract Interaction Contract-to-Contract Interaction in GenLayer allows developers to create more complex and modular Intelligent Contracts by enabling communication between them. This feature is crucial for building scalable and composable decentralized applications, allowing contracts to read from and write to other contracts. Please note that this feature is in progress and will be subject to changes in the near future. ## Features of Contract-to-Contract Interaction The Contract-to-Contract Interaction provides several powerful capabilities: #### 1. Cross-Contract Reads Contracts can read data from other contracts, allowing for the sharing of state and information across different parts of your application. #### 2. Cross-Contract Writes Contracts can initiate state changes in other contracts, enabling complex multi-step operations that span multiple contracts. #### 3. Modular Design By separating concerns into different contracts, developers can create more maintainable and upgradable systems. #### 4. Composability Contracts can be designed to work together, creating more powerful and flexible applications by combining different functionalities. ## Methods for Contract-to-Contract Interaction #### 1. Reading from Another Contract To read data from another contract, create an instance of the `Contract` class and call its methods: ```python filename="token_interaction" copy token_contract = gl.ContractAt(self.token_contract_address) balance = token_contract.view().get_balance_of(account_address) ``` #### 2. Writing to Another Contract To initiate a state change in another contract, call a method that modifies its state: ```python filename="token_interaction" copy token_contract = gl.ContractAt(self.token_contract_address) success = token_contract.emit().transfer(to_address, amount) ``` #### 3. Handling Multiple Contract Interactions For more complex scenarios involving multiple contracts: ```python filename="multi_contract_interaction" copy class MultiContractInteraction(gl.Contract): token_contract: Address storage_contract: Address def __init__(self, token_contract: str, storage_contract: str): self.token_contract = Address(token_contract) self.storage_contract = Address(storage_contract) @gl.public.write def complex_operation(self, account: str, amount: int, data: str) -> bool: token = gl.ContractAt(self.token_contract) storage = gl.ContractAt(self.storage_contract) # Read from token contract balance = token.view().get_balance_of(account) if balance >= amount: # Write to token contract token.emit().transfer(self.address, amount) # Write to storage contract storage.emit().store_data(account, data) return True return False ``` ## How to Use Contract-to-Contract Interaction in Your Contracts As GenLayer calldata is dynamically typed users can send whatever they want to a contract, or use statically typed interface to facilitate type checking and autocompletion Exact parameters of `.view()` and `.emit()` are subject to change ### Dynamically typed approach ```py address = Address("0x03FB09251eC05ee9Ca36c98644070B89111D4b3F") result = gl.ContractAt(address).view().method_name(1, '234') gl.ContractAt(address).emit().method_name(1, '234') # ^ write methods do not return anything! ``` ### Statically typed approach ```py @gl.contract_interface class GenLayerContractIface: class View: def method_name(self, a: int, b: str): ... class Write: pass ### in your contract method ### address = Address("0x03FB09251eC05ee9Ca36c98644070B89111D4b3F") result = GenLayerContractIface(address).view().method_name(1, '234') ``` ## Interacting with Ghost Contracts Eth contracts have statically typed calldata format, which means that only statically typed approach with interfaces is applicable This is not supported in the Studio right now ```py @gl.ghost_contract class GhostContractIface: class View: def method_name(self, param: str, /) -> tuple[u32, str]: ... class Write: def bar(self, param: str, /): ... ### in your contract method ### address = Address("0x03FB09251eC05ee9Ca36c98644070B89111D4b3F") i, s = GhostContractIface(address).view().method_name('234') ``` ## Best Practices for Contract-to-Contract Interaction 1. **Security**: Always validate inputs and check permissions before allowing cross-contract interactions. 2. **Error Handling**: Implement proper error handling for cases where called contracts might revert or throw exceptions. 3. **Upgradability**: Consider using upgradable patterns if you need to change contract interactions in the future. 4. **Testing**: Thoroughly test all contract interactions, including edge cases and potential vulnerabilities. # developers/intelligent-contracts/advanced-features/working-with-balances.mdx # Working With Balances ## Core concepts Each contract has a `balance` property: both derivatives of `gl.Contract` and `gl.ContractAt` All transactions and messages (both internal and external) can have attached `value`: `ContractAt(...).emit(value=100).my_method()` To get `value` from the incoming message users can read `gl.message.value` There is a special method to call a "nameless" transfer: `ContractAt(...).emit_transfer(value=100)`. You can receive such transfers by overriding `__receive__(self)` method. There are few simple rules: 1. If your method expects a `value`, annotate it with `@gl.public.write.payable` instead of just `write` 2. Emitting transaction to a non-payable method with non-zero value is an error 3. If transaction outcome is not *success*, attached value is sent back ## Code example ```python filename="working_with_balances" copy class TokenForwarder(gl.Contract): vault_contract: Address def __init__(self, vault_contract: str): self.vault_contract = Address(vault_contract) @gl.public.write.payable def forward(self) -> None: vault = gl.ContractAt(self.vault_contract) amount = gl.message.value vault.emit_transfer(value=amount) @gl.public.write.payable def donate_twice(self) -> bool: vault = gl.ContractAt(self.vault_contract) amount = gl.message.value if self.balance < amount: return False vault.emit(value=amount*2).save(self.address) return True ``` ## Special methods There are two special methods allowed in each contract **definition**: ```python class Contract(gl.Contract): @gl.public.write # .payable? def __handle_undefined_method__( self, method_name: str, args: list[typing.Any], kwargs: dict[str, typing.Any] ): """ Method that is called for undefined method calls, must be either ``@gl.public.write`` or ``@gl.public.write.payable`` """ ... @gl.public.write.payable def __receive__(self): """ Method that is called for no-method transfers, must be ``@gl.public.write.payable`` """ ... ``` Below is a diagram that shows how GenVM decides which method to pick, in case any regular method did not match: ```mermaid graph TD unhandled_message>unhandled message] ---> has_value[has value?] has_value -->|yes| has_method_name[has method name?] has_method_name -->|yes| fallback_defined1[__handle_undefined_method__ is defined?] has_method_name -->|no| receive_defined[is __receive__ defined?] receive_defined -->|no| fallback_defined1[is __handle_undefined_method__ defined?] receive_defined -->|yes| receive{{call __receive__}} fallback_defined1 -->|yes| fallback_is_payable[is __handle_undefined_method__ payable?] fallback_defined1 -->|no| error3{{error}} fallback_is_payable -->|yes| fallback1{{call __handle_undefined_method__}} fallback_is_payable -->|no| error1{{error}} has_value -->|no| fallback_defined fallback_defined -->|yes| fallback2{{call __handle_undefined_method__}} fallback_defined -->|no| error2{{error}} ``` # developers/intelligent-contracts/advanced-features/vector-store.mdx # Vector Store The Vector Store feature in GenLayer allows developers to enhance their Intelligent Contracts by efficiently storing, retrieving, and calculating similarities between texts using vector embeddings. This feature is particularly useful for tasks that require natural language processing (NLP), such as creating context-aware applications or indexing text data for semantic search. ## Key Features of Vector Store The Vector Store provides several powerful features for managing text data: #### 1. Text Embedding Storage You can store text data as vector embeddings, which are mathematical representations of the text, allowing for efficient similarity comparisons. Each stored text is associated with a vector and metadata. #### 2. Similarity Calculation The Vector Store allows you to calculate the similarity between a given text and stored vectors using cosine similarity. This is useful for finding the most semantically similar texts, enabling applications like recommendation systems or text-based search. #### 3. Metadata Management Along with the text and vectors, you can store additional metadata (any data type) associated with each text entry. This allows developers to link additional information (e.g., IDs or tags) to the text for retrieval. #### 4. CRUD Operations The Vector Store provides standard CRUD (Create, Read, Update, Delete) operations, allowing developers to add, update, retrieve, and delete text and vector entries efficiently. ## How to Use Vector Store in Your Contracts To use the Vector Store in your Intelligent Contracts, you will interact with its methods to add and retrieve text data, calculate similarities, and manage vector storage. Below are the details of how to use this feature. #### Importing Vector Store First, import the VectorStore class from the standard library in your contract: ```python from backend.node.genvm.std.vector_store import VectorStore ``` #### Creating a Contract with Vector Store Here’s an example of a contract using the Vector Store for indexing and searching text logs: ```python # { # "Seq": [ # { "Depends": "py-lib-genlayermodelwrappers:test" }, # { "Depends": "py-genlayer:test" } # ] # } from genlayer import * import genlayermodelwrappers import numpy as np from dataclasses import dataclass @dataclass class StoreValue: log_id: u256 text: str # contract class class LogIndexer(gl.Contract): vector_store: VecDB[np.float32, typing.Literal[384], StoreValue] def __init__(self): pass def get_embedding_generator(self): return genlayermodelwrappers.SentenceTransformer("all-MiniLM-L6-v2") def get_embedding( self, txt: str ) -> np.ndarray[tuple[typing.Literal[384]], np.dtypes.Float32DType]: return self.get_embedding_generator()(txt) @gl.public.view def get_closest_vector(self, text: str) -> dict | None: emb = self.get_embedding(text) result = list(self.vector_store.knn(emb, 1)) if len(result) == 0: return None result = result[0] return { "vector": list(str(x) for x in result.key), "similarity": str(1 - result.distance), "id": result.value.log_id, "text": result.value.text, } @gl.public.write def add_log(self, log: str, log_id: int) -> None: emb = self.get_embedding(log) self.vector_store.insert(emb, StoreValue(text=log, log_id=u256(log_id))) @gl.public.write def update_log(self, log_id: int, log: str) -> None: emb = self.get_embedding(log) for elem in self.vector_store.knn(emb, 2): if elem.value.text == log: elem.value.log_id = u256(log_id) @gl.public.write def remove_log(self, id: int) -> None: for el in self.vector_store: if el.value.log_id == id: el.remove() ``` # developers/intelligent-contracts/advanced-features/error-handling.mdx import { Callout } from 'nextra-theme-docs' # Error handling Sometimes contracts can produce errors. There are two kinds of GenVM errors: 1. unrecoverable errors - `exit(x)` where $x \neq 0$ (if $x = 0$ then return is considered to be `None`) - unhandled `Exception`, which will result in `exit(1)` 2. rollbacks - `raise Rollback("message")` --- raises regular Python exception that can be caught, if it escapes your contract, then it will call the later - `gl.rollback_immediate("message")` --- immediately terminates current sub-vm without unwinding the stack, which is more cost-efficient, but can't be caught in the current sub-vm Built-in `gl.eq_principle_*` functions family will `raise Rollback(sub_vm_message)` in case non-deterministic block agreed on a rollback. Which means that deterministic block can catch and inspect such error from a non-deterministic block and act on it. Note that rollback message is compared for **strict** equality, which means that you should not include stacktrace there, but rather use some descriptive error codes. Difference between rollbacks and unrecoverable errors is that unrecoverable errors can't be handled by user code and their "message" contains only short description provided by the GenVM. However, there are two exceptions of when a contract can observe unrecoverable errors: 1. If leaders non-deterministic block produced an error. It is discouraged to do that and indicates that some unexpected (by contract) corner case was reached 2. You can get one out of `gl.advanced.sandbox` method ```python filename="catching_a_rollback" copy # { "Depends": "py-genlayer:test" } from genlayer import * class Contract(gl.Contract): @gl.public.write def main(self): def run(): raise gl.Rollback('my message') try: gl.eq_principle_strict_eq(run) except Rollback as r: print(r.msg) # will print `my message` ``` # developers/intelligent-contracts/security-and-best-practices/prompt-injection.mdx # Prompt Injection Intelligent Contracts exclusively interact with public data, reducing certain types of risks such as data leakage. However, ensuring the integrity of these contracts still requires careful management of inputs and outputs. ## Understanding Prompt Injection Prompt injection involves manipulating the prompts fed to AI models to produce unintended outcomes. In GenLayer, this risk is primarily associated with how inputs are structured and how outputs are managed within Intelligent Contracts. ## Strategies for Mitigating Prompt Injection To safeguard against prompt injection in GenLayer, you need to implement these key strategies: - **Restrict Inputs**: Limit user inputs to the minimum necessary information. This reduces the chances of malicious data entering the system. Construct prompts within the contract code as much as possible, rather than allowing free-form user inputs which could be manipulated. - **Restrict Outputs**: Define and enforce strict parameters on what outputs are permissible from the AI models. This helps prevent the model from generating outputs that could trigger unintended actions within the contract. - **Simplify and Secure Contract Logic**: Ensure that the logic within Intelligent Contracts is clear and robust against manipulation. Errors in contract logic can be exploited just as easily as manipulated inputs. - **Human-in-the-Loop**: For critical operations or decisions, consider implementing a human review step before actions are finalized. This adds an additional layer of scrutiny and can catch issues that automated systems might miss. These measures are essential for maintaining the security and reduce the risk of prompt injections # developers/intelligent-contracts/examples/storage.mdx # Storage Contract The Storage contract sets up a simple scenario to store and retrieve a string value. This contract demonstrates basic data storage and retrieval functionality within a blockchain environment. ```python # { "Depends": "py-genlayer:test" } from genlayer import * # contract class class Storage(gl.Contract): storage: str # constructor def __init__(self, initial_storage: str): self.storage = initial_storage # read methods must be annotated with view @gl.public.view def get_storage(self) -> str: return self.storage # write method @gl.public.write def update_storage(self, new_storage: str) -> None: self.storage = new_storage ``` ## Code Explanation - **Initialization**: The `Storage` class initializes the contract with an `initial_storage` value. This value is stored in the `self.storage` attribute. - **Read Method**: The `get_storage()` method is a read-only function that returns the current value stored in `self.storage`. - **Write Method**: The `update_storage(new_storage)` method allows updating the stored value with a new string. ## Deploying the Contract To deploy the Storage contract, you need to initialize the contract state correctly. This setup will determine the initial value stored in the contract. 1. **Set Initial Storage**: Provide the initial storage value. The `initial_storage` constructor parameter is detected from the code. For example, you might set `initial_storage` to "Hello, World!". 2. **Deploy the Contract**: Once the initial storage is set, deploy the contract to make it ready for interaction. ## Checking the Contract State After deploying the contract, its address is displayed and you can check its state in the **Read Methods** section. Use the `get_storage()` function to see the current value stored in the contract. ## Executing Transactions To interact with the deployed contract, go to the **Write Methods** section. Here, you can call the `update_storage` method to change the stored value. This triggers the contract's logic to update the storage with the new value. ## Analyzing the Contract's Behavior When the `update_storage` method is executed: - The contract updates the `self.storage` attribute with the new value provided. - You can then use the `get_storage()` method to verify that the value has been updated. ## Handling Different Scenarios - **Initial State**: When the contract is first deployed, the `get_storage()` method will return the initial value set during deployment. - **After Update**: After calling `update_storage`, the `get_storage()` method will return the newly set value. - **Multiple Updates**: You can update the storage multiple times, and each time the most recent value will be stored and returned by `get_storage()`. You can view the logs to see detailed information about the contract interaction, including the values being stored and retrieved. This Storage contract provides a simple example of how data can be stored and retrieved on a blockchain, demonstrating basic state management within a smart contract. # developers/intelligent-contracts/examples/user-storage.mdx # UserStorage Contract The UserStorage contract sets up a scenario to store and retrieve string values associated with different user accounts. This contract demonstrates basic per-user data storage and retrieval functionality within a blockchain environment. ```python # { "Depends": "py-genlayer:test" } from genlayer import * class UserStorage(gl.Contract): storage: TreeMap[Address, str] # constructor def __init__(self): pass # read methods must be annotated @gl.public.view def get_complete_storage(self) -> dict[str, str]: return {k.as_hex: v for k, v in self.storage.items()} @gl.public.view def get_account_storage(self, account_address: str) -> str: return self.storage[Address(account_address)] @gl.public.write def update_storage(self, new_storage: str) -> None: self.storage[gl.message.sender_address] = new_storage ``` ## Code Explanation - **Initialization**: The `UserStorage` class initializes the contract with an empty dictionary `self.storage` to store user-specific data. - **Read Methods**: - `get_complete_storage()` returns the entire storage dictionary, containing all user data. - `get_account_storage(account_address)` returns the stored value for a specific user account. - **Write Method**: `update_storage(new_storage)` allows updating the stored value for the user who called the contract (identified by `contract_runner.from_address`). ## Deploying the Contract To deploy the UserStorage contract, you don't need to provide any initial parameters: 1. **Deploy the Contract**: Simply deploy the contract to make it ready for interaction. ## Checking the Contract State After deploying the contract, its address is displayed and you can check its state in the **Read Methods** section. - Use `get_complete_storage()` to see all stored user data. - Use `get_account_storage(account_address)` to see the data for a specific user account. ## Executing Transactions To interact with the deployed contract, go to the **Write Methods** section. Here, you can call the `update_storage` method to change the stored value for the calling user. This triggers the contract's logic to update the storage with the new value. ## Analyzing the Contract's Behavior When the `update_storage` method is executed: - The contract updates the `self.storage` dictionary, associating the new value with the address of the user who called the function (`contract_runner.from_address`). - You can then use the `get_account_storage()` or `get_complete_storage()` methods to verify that the value has been updated for the specific user. ## Handling Different Scenarios - **Initial State**: When the contract is first deployed, the storage is empty. `get_complete_storage()` will return an empty dictionary. - **First Update for a User**: When a user first calls `update_storage`, a new entry is created in the storage dictionary for that user's address. - **Subsequent Updates**: If a user calls `update_storage` again, their existing entry in the storage is updated with the new value. - **Multiple Users**: Different users can store and retrieve their own values independently. - **Accessing Non-existent Data**: If `get_account_storage()` is called with an address that hasn't stored any data yet, it will raise a `KeyError`. You can view the logs to see detailed information about the contract interaction, including the values being stored and retrieved for different user accounts. This UserStorage contract provides a simple example of how user-specific data can be stored and retrieved on a blockchain, demonstrating basic multi-user state management within a smart contract. # developers/intelligent-contracts/examples/llm-hello-world.mdx # LlmHelloWorld Contract The LlmHelloWorld contract demonstrates a simple example of integrating AI capabilities within an intelligent contract. This contract shows how to use the [comparative equivalence principle](/developers/intelligent-contracts/equivalence-principle#comparative-equivalence-principle) to call an LLM and store the response in the contract state. ```python # { "Depends": "py-genlayer:test" } from genlayer import * import typing class LlmHelloWorld(gl.Contract): message: str def __init__(self): self.message = "" @gl.public.write def set_message(self) -> typing.Any: def get_message() -> str: task = "There is no context, I just want you to answer with a string equal to 'yes'" result = gl.exec_prompt(task) print(result) return result self.message = gl.eq_principle_strict_eq(get_message) @gl.public.view def get_message(self) -> str: return self.message ``` ## Code Explanation - **Initialization**: The `LlmHelloWorld` class initializes with an empty string in the `message` variable. - **Write Method**: - `set_message()` uses AI functionality to generate and store a message. - It contains an inner function `get_message()` that prompts an AI model with a simple task. - Uses `gl.eq_principle_strict_eq()` to ensure deterministic AI responses across the network. - **Read Method**: - `get_message()` returns the stored message. ## Key Components 1. **AI Integration**: The contract uses `gl.exec_prompt()` to interact with an AI model. 2. **Deterministic Execution**: `gl.eq_principle_strict_eq()` ensures that all nodes in the network arrive at the same exact result. 3. **State Management**: The contract maintains a single string state variable that stores the AI response. ## Deploying the Contract To deploy the LlmHelloWorld contract: 1. **Deploy the Contract**: No initial parameters are needed for deployment. 2. The contract will initialize with an empty message. ## Checking the Contract State After deployment, you can: - Use `get_message()` to view the currently stored message. - Initially, this will return an empty string. ## Executing Transactions To interact with the deployed contract: 1. Call `set_message()` to trigger the AI interaction. 2. The function will: - Execute the AI prompt requesting a "yes" response - Store the result using the equivalence principle - Print the result to the logs ## Understanding AI Integration This contract demonstrates several important concepts: - **AI Prompting**: Shows how to formulate simple prompts for AI models within smart contracts. - **Deterministic AI**: Uses the equivalence principle to ensure all nodes reach consensus on AI outputs. - **State Updates**: Demonstrates how AI-generated content can be stored in blockchain state. ## Handling Different Scenarios - **Initial State**: The message starts empty. - **After set_message()**: The message will contain "yes" (the AI's response). - **Multiple Calls**: Each call to `set_message()` will update the stored message. - **Network Consensus**: All nodes will agree on the same message due to the equivalence principle. ## Important Notes 1. This is a minimal example to demonstrate AI-blockchain integration. 2. The AI prompt is intentionally simple for demonstration purposes. 3. The equivalence principle ensures that the AI response is consistent across all network nodes. You can monitor the contract's behavior through transaction logs, which will show the AI responses and state updates as they occur. # developers/intelligent-contracts/examples/llm-hello-world-non-comparative.mdx # LlmHelloWorldNonComparative Contract The LlmHelloWorldNonComparative contract demonstrates a simple example of integrating AI capabilities within an intelligent contract without requiring that all the validators execute the full task. They just need to evaluate the leader's response against the specified criteria. This is done by using the [non-comparative equivalence principle](/developers/intelligent-contracts/equivalence-principle#non-comparative-equivalence-principle). ```python # { "Depends": "py-genlayer:test" } from genlayer import * import typing class LlmHelloWorldNonComparative(gl.Contract): message: str def __init__(self): self.message = "" @gl.public.write def set_message(self) -> typing.Any: self.message = gl.eq_principle_prompt_non_comparative( lambda: "There is no context, I just want you to answer with truthy value in python (for example: 'yes', 'True', 1)", task="Answer with truthy value in python (for example: 'yes', 'True', 1)", criteria="Answer should be a truthy value in python" ) @gl.public.view def get_message(self) -> str: return self.message ``` ## Code Explanation - **Initialization**: The `LlmHelloWorldNonComparative` class initializes with an empty string in the `message` variable. - **Write Method**: - `set_message()` uses AI functionality to generate and store a message. - Uses `gl.eq_principle_prompt_non_comparative()` with three parameters: - A lambda function providing the prompt - A task description - Validation criteria for the response - **Read Method**: - `get_message()` returns the stored message. ## Key Components 1. **AI Integration**: The contract uses non-comparative equivalence principle to interact with an AI model. 2. **Deterministic Execution**: `gl.eq_principle_prompt_non_comparative()` ensures that all nodes in the network accept responses that meet the specified criteria. 3. **State Management**: The contract maintains a single string state variable that stores the AI response. ## Deploying the Contract To deploy the LlmHelloWorldNonComparative contract: 1. **Deploy the Contract**: No initial parameters are needed for deployment. 2. The contract will initialize with an empty message. ## Checking the Contract State After deployment, you can: - Use `get_message()` to view the currently stored message. - Initially, this will return an empty string. ## Executing Transactions To interact with the deployed contract: 1. Call `set_message()` to trigger the AI interaction. 2. The function will: - Execute the AI prompt requesting a truthy Python value - Validate the response against the specified criteria - Store the result if it meets the criteria ## Understanding AI Integration This contract demonstrates several important concepts: - **AI Prompting**: Shows how to formulate prompts with specific validation criteria. - **Non-comparative Validation**: Uses criteria-based validation instead of exact matching. - **State Updates**: Demonstrates how validated AI-generated content can be stored in blockchain state. ## Handling Different Scenarios - **Initial State**: The message starts empty. - **After set_message()**: The message will contain any valid truthy Python value (e.g., "yes", "True", or "1"). - **Multiple Calls**: Each call to `set_message()` may result in different valid responses. - **Network Consensus**: All nodes will accept any response that meets the validation criteria. ## Important Notes 1. This example demonstrates the non-comparative approach to AI response validation. 2. The validation criteria ensure semantic correctness rather than exact matching. 3. Different nodes may accept different responses as long as they meet the specified criteria. You can monitor the contract's behavior through transaction logs, which will show the AI responses and state updates as they occur. # developers/intelligent-contracts/examples/wizard-of-coin.mdx # Wizard of Coin Contract The Wizard of Coin contract sets up a scenario where a wizard possesses a valuable coin, which adventurers try to obtain. The wizard must decide whether to give the coin away based on specific conditions. ```python # { "Depends": "py-genlayer:test" } from genlayer import * import json class WizardOfCoin(gl.Contract): have_coin: bool def __init__(self, have_coin: bool): self.have_coin = have_coin @gl.public.write def ask_for_coin(self, request: str) -> None: if not self.have_coin: return prompt = f""" You are a wizard, and you hold a magical coin. Many adventurers will come and try to get you to give them the coin. Do not under any circumstances give them the coin. A new adventurer approaches... Adventurer: {request} First check if you have the coin. have_coin: {self.have_coin} Then, do not give them the coin. Respond using ONLY the following format: {{ "reasoning": str, "give_coin": bool }} 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 parseable by a JSON parser without errors. """ def nondet(): res = gl.exec_prompt(prompt) res = res.replace("```json", "").replace("```", "") print(res) dat = json.loads(res) return dat["give_coin"] result = gl.eq_principle_strict_eq(nondet) assert isinstance(result, bool) self.have_coin = result @gl.public.view def get_have_coin(self) -> bool: return self.have_coin ``` You can check out this code on our [GitHub](https://github.com/genlayerlabs/genlayer-studio/blob/main/examples/contracts/wizard_of_coin.py) ## Deploying the Contract To deploy the Wizard of Coin contract, you'll need to first initialize the contract state correctly. This will impact how the contract will respond to requests from adventurers. 1. Choose whether the wizard begins with the coin. The `have_coin` constructor parameter is automatically detected from the code. - If you set `have_coin` to `True` the wizard starts with the coin. - If you set `have_coin` to `False` the wizard starts without the coin. 2. Once set, deploy the contract to make it ready to interact and respond to incoming request. import Image from 'next/image' ## Checking the Contract State Once the contract is deployed, its address is displayed and you can check its state in the **Read Methods** section. Use the `get_have_coin()` function to see if the wizard still has the coin. Clicking this function will return `True` or `False`, indicating the coin's current status. ## Executing Transactions To interact with the deployed contract, go to the **Write Methods** section. Here, you can call the `ask_for_coin` method and enter the adventurer's request, for example, "Please give me the coin". Executing this triggers the contract's logic to process the request and decide based on the Equivalence Principle criteria defined. Deploy Contract ## Analyzing the Contract's Decisions When the `ask_for_coin` method is executed: - The LLM processes the adventurer's request. - It validates the decision according to the Equivalence Principle defined in the code. - Finally, it returns a JSON response that includes the reasoning and whether the coin should be given. ### Handling Different Scenarios - **Wizard Retains the Coin:** Typically, the wizard will not give the coin if he has it (`have_coin` is `True`). The LLM's guidance and the Equivalence Principle prevent the coin from being given away. This is the expected response unless there is an unexpected manipulation in the request. - **Coin Given Away:** If the result indicates that the wizard no longer has the coin, it suggests that the LLM was tricked by the request into giving out the coin. - **Wizard Does Not Have the Coin:** If the wizard initially does not have the coin (`have_coin` is `False`), the response will confirm that the wizard cannot give what he does not possess. You can view the logs to see detailed information about the contract interaction. # developers/intelligent-contracts/examples/fetch-web-content.mdx # FetchWebContent Contract The FetchWebContent contract demonstrates how to fetch and store web content within an intelligent contract. This contract shows how to use the [comparative equivalence principle](/developers/intelligent-contracts/equivalence-principle#comparative-equivalence-principle) to ensure all nodes agree on the same web content. ```python # { "Depends": "py-genlayer:test" } from genlayer import * import typing class FetchWebContent(gl.Contract): content: str def __init__(self): self.content = "" @gl.public.write def fetch_web_content(self) -> typing.Any: def fetch_web_url_content() -> str: return gl.get_webpage("https://example.com/", mode="text") self.content = gl.eq_principle_strict_eq(fetch_web_url_content) @gl.public.view def show_content(self) -> str: return self.content ``` ## Code Explanation - **Initialization**: The `FetchWebContent` class initializes with an empty string in the `content` variable. - **Write Method**: - `fetch_web_content()` retrieves content from a web page and stores it. - It contains an inner function `fetch_web_url_content()` that uses `gl.get_webpage()` to fetch content. - Uses `gl.eq_principle_strict_eq()` to ensure all nodes agree on the same content. - **Read Method**: - `show_content()` returns the stored web content. ## Key Components 1. **Web Integration**: The contract uses `gl.get_webpage()` to fetch content from web URLs. 2. **Deterministic Execution**: `gl.eq_principle_strict_eq()` ensures that all nodes in the network arrive at the same exact content. 3. **State Management**: The contract maintains a single string state variable that stores the web content. ## Deploying the Contract To deploy the FetchWebContent contract: 1. **Deploy the Contract**: No initial parameters are needed for deployment. 2. The contract will initialize with an empty content string. ## Checking the Contract State After deployment, you can: - Use `show_content()` to view the currently stored web content. - Initially, this will return an empty string. ## Executing Transactions To interact with the deployed contract: 1. Call `fetch_web_content()` to trigger the web content fetch. 2. The function will: - Fetch the content from example.com - Store the result using the equivalence principle - Make the content available through `show_content()` ## Understanding Web Content Integration This contract demonstrates several important concepts: - **Web Fetching**: Shows how to safely retrieve content from web sources. - **Deterministic Results**: Uses the equivalence principle to ensure all nodes reach consensus on web content. - **State Updates**: Demonstrates how web content can be stored in blockchain state. ## Handling Different Scenarios - **Initial State**: The content starts empty. - **After fetch_web_content()**: The content will contain the text from example.com. - **Multiple Calls**: Each call to `fetch_web_content()` will update the stored content. - **Network Consensus**: All nodes will agree on the same content due to the equivalence principle. ## Important Notes 1. This example uses example.com as a stable demonstration URL. 2. Web content should be relatively stable to ensure consensus. 3. The equivalence principle ensures that all nodes store identical content. 4. The `mode="text"` parameter ensures only text content is retrieved. ## Security Considerations 1. Only fetch content from trusted and stable sources. 2. Be aware that web content can change over time. 3. Consider implementing content validation before storage. 4. Use appropriate error handling for network issues. You can monitor the contract's behavior through transaction logs, which will show the fetched content and state updates as they occur. ## HTML Mode for Web Content The `gl.get_webpage()` function supports different modes for retrieving web content. While `mode="text"` returns the plain text content, `mode="html"` allows you to retrieve the complete HTML `` of the webpage. Here's an example of using HTML mode: ```python class FetchHTMLContent(gl.Contract): html_content: str def __init__(self): self.html_content = "" @gl.public.write def fetch_html_content(self) -> typing.Any: def fetch_web_url_html() -> str: return gl.get_webpage("https://example.com/", mode="html") self.html_content = gl.eq_principle_strict_eq(fetch_web_url_html) @gl.public.view def show_html_content(self) -> str: return self.html_content ``` ### Key Differences with HTML Mode: - **Complete Structure**: Returns the full HTML document including tags, attributes, and DOM structure - **Use Cases**: - Parsing specific HTML elements or attributes - Extracting links, images, or other structured content - Analyzing webpage structure and metadata - **Data Size**: HTML content is typically larger than text mode as it includes markup - **Processing**: May require additional HTML parsing to extract specific elements ### When to Use HTML Mode: 1. When you need to extract information from specific HTML elements 3. When analyzing page structure or links 4. If you need to process structured data like tables or forms This addition provides users with a clear understanding of the HTML mode option and its specific use cases, complementing the existing text mode example. # developers/intelligent-contracts/examples/fetch-github-profile.mdx # FetchGitHubProfile Contract The FetchGitHubProfile contract demonstrates how to fetch and store GitHub profile content within an intelligent contract. This contract shows how to use the [comparative equivalence principle](/developers/intelligent-contracts/equivalence-principle#comparative-equivalence-principle) to ensure all nodes agree on the same profile content. ```python # { "Depends": "py-genlayer:test" } from genlayer import * import typing class FetchGitHubProfile(gl.Contract): github_profile: str def __init__(self): self.github_profile = "" @gl.public.write def fetch_github_profile(self, github_handle: str) -> typing.Any: github_profile_url = "https://github.com/"+github_handle def fetch_github_profile_page_content() -> str: return gl.get_webpage(github_profile_url, mode="text") self.github_profile = gl.eq_principle_strict_eq(fetch_github_profile_page_content) @gl.public.view def show_github_profile(self) -> str: return self.github_profile ``` ## Code Explanation - **Initialization**: The `FetchGitHubProfile` class initializes with an empty string in the `github_profile` variable. - **Write Method**: - `fetch_github_profile(github_handle)` takes a GitHub username and retrieves their profile content. - Constructs the profile URL using the provided handle. - Uses `gl.eq_principle_strict_eq()` to ensure all nodes agree on the same profile content. - **Read Method**: - `show_github_profile()` returns the stored profile content. ## Key Components 1. **GitHub Integration**: The contract uses `gl.get_webpage()` to fetch content from GitHub profiles. 2. **Deterministic Execution**: `gl.eq_principle_strict_eq()` ensures that all nodes in the network arrive at the same exact content. 3. **State Management**: The contract maintains a single string state variable that stores the profile content. ## Deploying the Contract To deploy the FetchGitHubProfile contract: 1. **Deploy the Contract**: No initial parameters are needed for deployment. 2. The contract will initialize with an empty profile string. ## Checking the Contract State After deployment, you can: - Use `show_github_profile()` to view the currently stored profile content. - Initially, this will return an empty string. ## Executing Transactions To interact with the deployed contract: 1. Call `fetch_github_profile(github_handle)` with a GitHub username. 2. The function will: - Construct the GitHub profile URL - Fetch the profile content - Store the result using the equivalence principle - Make the content available through `show_github_profile()` ## Understanding GitHub Integration This contract demonstrates several important concepts: - **Dynamic URLs**: Shows how to construct URLs based on input parameters. - **Web Fetching**: Demonstrates safe retrieval of content from GitHub. - **Deterministic Results**: Uses the equivalence principle to ensure all nodes reach consensus on profile content. - **State Updates**: Shows how external web content can be stored in blockchain state. ## Handling Different Scenarios - **Initial State**: The profile content starts empty. - **Valid GitHub Handle**: The content will contain the text from the GitHub profile page. - **Invalid Handle**: May result in a 404 page content or error. - **Network Consensus**: All nodes will agree on the same content due to the equivalence principle. ## Important Notes 1. This example fetches public GitHub profile pages only. 2. Profile content may change over time. 3. The equivalence principle ensures that all nodes store identical content. 4. The `mode="text"` parameter ensures only text content is retrieved. ## Security Considerations 1. Be aware that GitHub profiles are dynamic and can change. 2. Consider implementing rate limiting to respect GitHub's terms of service. 3. Handle potential errors for non-existent profiles. 4. Be mindful of GitHub's robots.txt and usage policies. You can monitor the contract's behavior through transaction logs, which will show the fetched profile content and state updates as they occur. # developers/intelligent-contracts/examples/github-profile-projects.mdx # GitHubProfilesRepositories Contract The GitHubProfilesRepositories contract demonstrates how to fetch GitHub profile data, analyze repository counts, and store profiles of high-contributing developers. This contract shows how to use the [comparative equivalence principle](/developers/intelligent-contracts/equivalence-principle#comparative-equivalence-principle) along with pattern matching to process web content. ```python # { "Depends": "py-genlayer:test" } from genlayer import * import typing import re class GitHubProfilesRepositories(gl.Contract): github_profiles: DynArray[str] def __init__(self): pass @gl.public.write def store_high_contributors_github_profile(self, github_handle: str) -> typing.Any: github_profile_url = "https://github.com/"+github_handle def fetch_github_profile_repositories() -> int: profile_web_page = gl.get_webpage(github_profile_url, mode="text") # Regular expression to find the number between "Repositories" and "Projects" pattern = r"Repositories\s+(\d+)\s+Projects" # Search for the pattern match = re.search(pattern, profile_web_page) # Extract the number if found if match: return int(match.group(1)) # Group 1 contains the captured number else: return 0 repositories = gl.eq_principle_strict_eq(fetch_github_profile_repositories) if repositories > 25: self.github_profiles.append(github_handle) @gl.public.view def show_github_profiles(self) -> str: return [profile for profile in self.github_profiles] ``` ## Code Explanation - **Initialization**: The `GitHubProfilesRepositories` class initializes with an empty dynamic array to store the GitHub handles of the high-contributing developers. - **Write Method**: - `store_high_contributors_github_profile(github_handle)` analyzes a GitHub profile's repository count. - Uses regular expressions to extract the repository count from the profile page. - Stores profiles with more than 25 repositories. - **Read Method**: - `show_github_profiles()` returns the list of stored high-contributor profiles. ## Key Components 1. **GitHub Integration**: Uses `gl.get_webpage()` to fetch profile content. 2. **Pattern Matching**: Employs regular expressions to extract repository counts. 3. **Deterministic Execution**: Uses `gl.eq_principle_strict_eq()` to ensure network consensus. 4. **Conditional Storage**: Only stores profiles meeting specific criteria. ## Deploying the Contract To deploy the GitHubProfilesRepositories contract: 1. **Deploy the Contract**: No initial parameters are needed for deployment. 2. The contract will initialize with an empty profiles array. ## Checking the Contract State After deployment, you can: - Use `show_github_profiles()` to view the list of stored high-contributor profiles. - Initially, this will return an empty list. ## Executing Transactions To interact with the deployed contract: 1. Call `store_high_contributors_github_profile(github_handle)` with a GitHub username. 2. The function will: - Fetch the profile page content - Extract the repository count - Store the handle if repositories > 25 - Make the profile list available through `show_github_profiles()` ## Understanding Data Processing This contract demonstrates several important concepts: - **Web Scraping**: Shows how to extract specific data from web pages. - **Regular Expressions**: Demonstrates pattern matching in web content. - **Conditional Logic**: Implements criteria-based storage decisions. - **Dynamic Arrays**: Shows how to maintain a growing list of data. ## Handling Different Scenarios - **Initial State**: The profiles list starts empty. - **High Contributors**: Profiles with >25 repositories are added to the list. - **Low Contributors**: Profiles with ≤25 repositories are not stored. - **Invalid Profiles**: Returns 0 repositories and doesn't store the profile. ## Important Notes 1. This example focuses on public GitHub profiles only. 2. Repository counts may change over time. 3. The regular expression pattern assumes specific GitHub page structure. 4. The threshold of 25 repositories is arbitrary and can be adjusted. ## Security Considerations 1. Be aware that GitHub's page structure might change. 2. Consider implementing error handling for malformed profiles. 3. Respect GitHub's rate limits and terms of service. 4. Validate input GitHub handles before processing. ## Performance Optimization 1. The contract only stores handles, not full profile content. 2. Regular expression pattern is optimized for specific data extraction. 3. Conditional storage prevents unnecessary state bloat. 4. Dynamic array allows for efficient list management. You can monitor the contract's behavior through transaction logs, which will show the repository counts and profile additions as they occur. # developers/intelligent-contracts/examples/github-profile-summary.mdx # GitHubProfilesSummaries Contract The GitHubProfilesSummaries contract demonstrates how to fetch GitHub profile data and generate AI-powered summaries of user profiles. This contract shows how to combine web scraping with AI analysis using both [comparative](/developers/intelligent-contracts/equivalence-principle#comparative-equivalence-principle) and [non-comparative](/developers/intelligent-contracts/equivalence-principle#non-comparative-equivalence-principle) equivalence principles. ```python # { "Depends": "py-genlayer:test" } from genlayer import * import typing import re class GitHubProfilesSummaries(gl.Contract): github_profiles: TreeMap[str, str] def __init__(self): pass @gl.public.write def store_github_profile_summary(self, github_handle: str) -> typing.Any: current_profile_summary = self.github_profiles.get(github_handle, None) if not current_profile_summary is None: raise Exception("profile summary already generated") github_profile_url = "https://github.com/"+github_handle def fetch_github_profile_summaries() -> str: return gl.get_webpage(github_profile_url, mode="text") profile_content = gl.eq_principle_strict_eq(fetch_github_profile_summaries) task = """Given the web page content of a github profile in HTML format, generate a comprehensive summary of the profile mentioning the key meta attributes and the GitHub contribution most important metrics""" criteria = """The summary provided should include different metrics and a summary of a GitHub profile""" profile_summary = ( gl.eq_principle_prompt_non_comparative( lambda: profile_content, task=task, criteria=criteria, ) ) self.github_profiles[github_handle] = profile_summary @gl.public.view def show_github_profile_summaries(self) -> str: return {profile: summary for profile, summary in self.github_profiles.items()} ``` ## Code Explanation - **Initialization**: The `GitHubProfilesSummaries` class initializes with an empty TreeMap to store GitHub handles and their corresponding summaries. - **Write Method**: - `store_github_profile_summary(github_handle)` generates an AI summary of a GitHub profile. - Checks if a summary already exists for the handle. - Uses both strict and non-comparative equivalence principles for different parts of the process. - **Read Method**: - `show_github_profile_summaries()` returns a dictionary mapping GitHub handles to their summaries. ## Key Components 1. **Data Storage**: Uses `TreeMap` for efficient key-value storage of profile summaries. 2. **Web Fetching**: Uses `gl.get_webpage()` with strict equivalence for deterministic content retrieval. 3. **AI Analysis**: Uses non-comparative equivalence for generating profile summaries. 4. **Duplicate Prevention**: Includes checks to prevent regenerating existing summaries. ## Deploying the Contract To deploy the GitHubProfilesSummaries contract: 1. **Deploy the Contract**: No initial parameters are needed for deployment. 2. The contract will initialize with an empty TreeMap. ## Checking the Contract State After deployment, you can: - Use `show_github_profile_summaries()` to view all stored profile summaries. - Initially, this will return an empty dictionary. ## Executing Transactions To interact with the deployed contract: 1. Call `store_github_profile_summary(github_handle)` with a GitHub username. 2. The function will: - Check for existing summary - Fetch the profile content - Generate an AI summary - Store the result in the TreeMap ## Understanding AI Integration This contract demonstrates several important concepts: - **Dual Equivalence Principles**: Uses both comparative and non-comparative approaches. - **Error Handling**: Implements checks for duplicate processing. - **Structured Storage**: Maintains an organized mapping of profiles to summaries. ## Handling Different Scenarios - **Initial State**: The TreeMap starts empty. - **New Profile**: Generates and stores a new summary. - **Existing Profile**: Raises an exception to prevent duplicate processing. - **Invalid Profile**: Web content fetch would fail for non-existent profiles. ## Important Notes 1. Summaries are generated once and cached. 2. The AI task is focused on extracting key metrics and attributes. 3. Profile content is fetched deterministically using strict equivalence. 4. Summary generation allows for semantic variation while maintaining quality. ## Security Considerations 1. Validate GitHub handles before processing. 2. Handle web content fetch failures gracefully. 3. Consider implementing rate limiting. 4. Be mindful of storage space for summaries. ## Performance Optimization 1. Uses TreeMap for efficient key-value lookups. 2. Prevents redundant summary generation. 4. Stores only processed summaries, not raw HTML. You can monitor the contract's behavior through transaction logs, which will show the profile fetches and summary generations as they occur. # developers/intelligent-contracts/examples/prediction.mdx # Prediction Market Contract The Prediction Market contract sets up a scenario to determine the outcome of a football game between two teams. The contract uses the Equivalence Principle to ensure accurate and consistent decision-making based on the game's resolution data. ```python filename="PredictionMarket" copy # { "Depends": "py-genlayer:test" } from genlayer import * import json import typing class PredictionMarket(gl.Contract): 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 ``` You can check out this code on our [GitHub](https://github.com/genlayerlabs/genlayer-studio/blob/main/examples/contracts/football_prediction_market.py) ## Deploying the Contract To deploy the Prediction Market contract, you'll need to initialize the contract state correctly. This will impact how the contract will respond to the game's resolution. 1. Provide the game date and the names of the two teams. The `game_date`, `team1`, and `team2` constructor parameters are automatically detected from the code. For example, you might set `game_date` to "2024-06-05", `team1` to "Brazil", and `team2` to "Jamaica". 2. Once the game details are set, deploy the contract to make it ready to interact and resolve the game results. import Image from 'next/image' ## Checking the Contract State Once the contract is deployed, its address is displayed as well as the **Read Methods** section. In this case, there are no Read Methods defined. ## Executing Transactions To interact with the deployed contract, go to the **Write Methods** section. Here, you can call the `resolve` method to process the game's result. This triggers the contract's logic to retrieve the game's data and determine the outcome based on the Equivalence Principle criteria defined. Execute Transactions ## Analyzing the Contract's Decisions When the `resolve` method is executed: - The LLM retrieves the game data from the specified URL. - It validates the game's outcome according to the Equivalence Principle defined in the code. - Finally, it returns a JSON response that includes the game's score and the winner. ### Handling Different Scenarios - If the game has started but not finished, the JSON response will indicate the game is not resolved yet. - If the game has finished, the JSON response will include the final score and the winning team. - If the game hasn't started, the JSON response will indicate this status. You can view the logs to see detailed information about the contract interaction. # developers/intelligent-contracts/examples/vector-store-log-indexer.mdx # LogIndexer Contract The LogIndexer contract demonstrates how to use the Vector Store database (VecDB) provided by the GenVM SDK. This contract shows how to store, retrieve, update, and remove text logs using vector embeddings for similarity-based searches. ```python # { # "Seq": [ # { "Depends": "py-lib-genlayermodelwrappers:test" }, # { "Depends": "py-genlayer:test" } # ] # } from genlayer import * import genlayermodelwrappers import numpy as np from dataclasses import dataclass import typing @dataclass class StoreValue: log_id: u256 text: str # contract class class LogIndexer(gl.Contract): vector_store: VecDB[np.float32, typing.Literal[384], StoreValue] def __init__(self): pass def get_embedding_generator(self): return genlayermodelwrappers.SentenceTransformer("all-MiniLM-L6-v2") def get_embedding( self, txt: str ) -> np.ndarray[tuple[typing.Literal[384]], np.dtypes.Float32DType]: return self.get_embedding_generator()(txt) @gl.public.view def get_closest_vector(self, text: str) -> dict | None: emb = self.get_embedding(text) result = list(self.vector_store.knn(emb, 1)) if len(result) == 0: return None result = result[0] return { "vector": list(str(x) for x in result.key), "similarity": str(1 - result.distance), "id": result.value.log_id, "text": result.value.text, } @gl.public.write def add_log(self, log: str, log_id: int) -> None: emb = self.get_embedding(log) self.vector_store.insert(emb, StoreValue(text=log, log_id=u256(log_id))) @gl.public.write def update_log(self, log_id: int, log: str) -> None: emb = self.get_embedding(log) for elem in self.vector_store.knn(emb, 2): if elem.value.text == log: elem.value.log_id = u256(log_id) @gl.public.write def remove_log(self, id: int) -> None: for el in self.vector_store: if el.value.log_id == id: el.remove() ``` ## Code Explanation - **Data Structure**: Uses `StoreValue` dataclass to store log ID and text. - **Vector Store**: Initializes a VecDB with 384-dimensional float32 vectors. - **Embedding Generation**: Uses the SentenceTransformer model for text embedding. - **Methods**: - `get_closest_vector()`: Finds the most similar log entry. - `add_log()`: Adds a new log with its embedding. - `update_log()`: Updates an existing log entry. - `remove_log()`: Removes a log by its ID. ## Key Components 1. **Vector Database**: Uses VecDB for efficient similarity-based searches. 2. **Embedding Model**: Utilizes SentenceTransformer for text vectorization. 3. **CRUD Operations**: Implements Create, Read, Update, Delete functionality. 4. **Similarity Search**: Supports k-nearest neighbors (KNN) queries. ## Deploying the Contract To deploy the LogIndexer contract: 1. **Deploy the Contract**: No initial parameters are needed. 2. The contract will initialize with an empty vector store. ## Checking the Contract State After deployment, you can: - Use `get_closest_vector()` to find similar logs. - Query will return None if no logs are stored. ## Executing Transactions The contract supports several operations: 1. **Adding Logs**: - Call `add_log(log, log_id)` with text and ID. - Creates embedding and stores in VecDB. 2. **Finding Similar Logs**: - Use `get_closest_vector(text)` to find matches. - Returns vector, similarity score, ID, and text. 3. **Updating Logs**: - Call `update_log(log_id, log)` to modify entries. - Updates based on text similarity. 4. **Removing Logs**: - Use `remove_log(id)` to delete entries. - Removes based on log ID. ## Understanding Vector Storage This contract demonstrates several important concepts: - **Vector Embeddings**: Converts text to numerical vectors. - **Similarity Search**: Uses vector distance for finding related content. - **Persistent Storage**: Maintains vector database state. - **Efficient Querying**: Supports fast nearest neighbor searches. ## Handling Different Scenarios - **Empty Database**: Returns None for searches. - **Adding New Logs**: Creates new vector embeddings. - **Updating Logs**: Modifies existing entries. - **Removing Logs**: Deletes entries by ID. ## Important Notes 1. This is a demonstration of VecDB features. 2. Uses a specific embedding dimension (384). 3. Similarity is based on vector distance. 4. Supports basic CRUD operations. ## Performance Considerations 1. Embedding generation may be computationally intensive. 2. KNN searches scale with database size. 3. Vector dimension affects storage requirements. 4. Consider batch operations for efficiency. ## Technical Details 1. Uses 384-dimensional float32 vectors. 2. Implements the all-MiniLM-L6-v2 model. 3. Stores both vector embeddings and metadata. 4. Supports exact and approximate nearest neighbor search. You can monitor the contract's behavior through transaction logs, which will show vector operations and search results as they occur. # developers/intelligent-contracts/tools/genlayer-cli.mdx # GenLayer CLI The GenLayer CLI is a command-line interface designed to streamline the setup and local execution of the GenLayer Studio. It automates the process of downloading and launching the Studio, allowing developers to start simulating and testing locally with minimal effort. ## Features - **Easy Initialization**: Quickly set up the GenLayer Studio with a single command. - **Automated Downloads**: Automatically downloads all necessary components required to run the Studio. - **Developer-Friendly**: Simplifies local development and testing workflows. - **Extensible**: Plans for additional commands to enhance interaction with the Studio. ## How it's Built The GenLayer CLI is a Command Line Interface tool built using **Node.js** and **TypeScript**. It's designed to automate the setup and management of the GenLayer Studio, simplifying the process for developers. ### Technologies Used - **Node.js**: A JavaScript runtime environment that allows the execution of JavaScript code on the server side. - **TypeScript**: A statically typed superset of JavaScript that compiles to plain JavaScript, enhancing code reliability and maintainability. - **ESBuild**: A fast JavaScript bundler and minifier used for building the CLI efficiently. - **Jest**: A JavaScript testing framework utilized for writing and running tests. ### Project Structure The source code for the GenLayer CLI is organized as follows: - `src/`: Contains the main TypeScript source files. - `tests/`: Includes all the test files written using Jest. - `dist/`: The compiled JavaScript files ready for execution. ## Requirements Before using the GenLayer CLI, ensure your system meets the following requirements: - **Node.js**: Version 14.x or higher is required. - **npm**: Comes bundled with Node.js, used for managing packages. - **Git**: Required if cloning the repository directly from GitHub. - **Operating System**: Compatible with macOS, Linux, and Windows. ## Installation To install the GenLayer CLI globally using npm, ensure you have Node.js installed, then run: ```bash npm install -g genlayer ``` ## Usage After installation, you can use the following command to start the Studio: ```bash genlayer init ``` This command will download the necessary components and start the Studio. Once initialized, you can execute further commands (to be implemented) to interact with the Studio. ## General Format of Commands The GenLayer CLI commands follow a consistent syntax pattern: ```bash genlayer [options] ``` - ``: The primary action you want the CLI to perform (e.g., `init`, `up`). - `[options]`: Optional flags that alter the behavior of the command. ### Example To initialize the GenLayer Studio with specific parameters: ```bash genlayer init --numValidators 10 --branch develop ``` ## Testing The GenLayer CLI uses Jest with ts-jest for testing TypeScript files. To run tests: ```bash npm run test ``` ## Further Development Additional commands are planned to enhance interaction with the GenLayer Studio. Stay tuned for updates. ## Repository You can find the GenLayer CLI repository on GitHub: [GenLayer CLI Repository](https://github.com/genlayerlabs/genlayer-cli) ## Full Reference The full reference for the GenLayer CLI is available in the [GenLayer CLI Reference](/references/genlayer-cli). ## GenLayer FAQ The GenLayer FAQ is a collection of useful questions and answers about the project. If you have a question that isn't answered here, please let us know on our [Discord](https://discord.gg/8Jm4v89VAu) .
How do I set up the GenLayer Development Environment? To quickly set up the GenLayer Development Environment, run the commands below: ``` $ npm install -g genlayer $ genlayer init ``` For more detailed setup instructions, please refer to the [Getting Started page](/getting-started)
Where can I find the GenLayer Studio? The GenLayer Studio is available at [studio.genlayer.com](https://studio.genlayer.com).
How do I deploy an Intelligent Contract? - Go to [studio.genlayer.com](https://studio.genlayer.com) or use the [GenLayer CLI](/getting-started#installation-of-the-genlayer-cli) to start the GenLayer Studio locally. - Write your contract in Python using the [Intelligent Contract SDK](/core-concepts/intelligent-contracts). - Follow the guide [here](/genlayer-stack/genlayer-studio/execute-transaction) to interact with the Studio and deploy your Intelligent Contract.
What is the GenLayer CLI used for? The GenLayer CLI is used for setting up the GenLayer Studio and, in the future, will support mainnet and testnet environments.
# developers/intelligent-contracts/tools/genlayer-studio.mdx import { Card, Cards, Callout, Bleed } from 'nextra-theme-docs' # GenLayer Studio This Studio is an interactive sandbox designed for developers to explore the potential of GenLayer's Intelligent Contracts. It replicates the GenLayer network's execution environment and consensus algorithm, but offers a controlled and local environment to test different ideas and behaviors. ### What you can do with the GenLayer Studio: - **Experiment with AI smart contracts:** Intelligent Contracts leverage LLMs, such as GPT-4 or Llama3, to understand natural language and be capable of complex decision making. - **Access the Web Natively:** GenLayer is the first platform where smart contracts don’t need oracles to access the Internet. - **Code in Python:** Develop in a familiar, developer-friendly language, where memory and string management are not a big headache. ### Explore the Studio Here is a video introduction to help you get started with the GenLayer Studio:
### Intelligent Contract SDK Learn how to write your own Intelligent Contracts at [Intelligent Contracts](/build-with-genlayer/intelligent-contracts) # developers/intelligent-contracts/tools/genlayer-studio/loading-contract.mdx # Load Your Contract To start using the GenLayer Studio, you need to load your Intelligent Contract into the Studio. This involves navigating the Studio interface, selecting your contract file, and preparing it for deployment and execution. ## Access your Intelligent Contracts 1. On the left sidebar, click on the **Contracts** icon. This is where you can see the list of your Intelligent Contracts. There are pre-loaded example contracts for you to try out. import Image from 'next/image' Navigate Contract 2. To add a new contract, click on the **+** button labeled **New Contract** to create a new contract file in the Studio. Add a New Contract 3. Click on the **Add From File** button to select and upload your Intelligent Contract file from your local machine. Add From File 4. Once your contract is uploaded, you will see it listed under **Your Contracts**. ## Run Your Intelligent Contract 1. Click on the contract file to open it in the editor pane. This allows you to review and edit the code if necessary before running it. Open the Contract 2. Once you have your contract file open, you have two options to run and debug your contract: - Click the **Run and Debug** button on the left sidebar. - Click the **play icon** at the top right of the editor pane. Run and Debug Now that you have loaded your Intelligent Contract into the GenLayer Studio, you can proceed to set constructor parameters and deploy it. # developers/intelligent-contracts/tools/genlayer-studio/deploying-contract.mdx # Deploy Contracts Once you have loaded your Intelligent Contract into the GenLayer Studio, the next step is to set the constructor parameters and deploy it. The constructor parameters are essential inputs that initialize the state of your contract. ## Setting Constructor Parameters 1. After loading your Intelligent Contract, you will see the **Constructor Inputs** section on the left-hand pane. The constructor parameters are [automatically detected from your code if defined properly](#detecting-constructor-parameters). 2. If you need to manually adjust your constructor parameters, you can write them in JSON format by clicking on the **JSON** button. import Image from 'next/image' ## Detecting Constructor Parameters The GenLayer Studio automatically detects the constructor parameters from your code. It analyzes your `__init__` method to identify the parameters and their types. This automatic detection ensures that you have the correct inputs for initializing your contract. It’s important to have clear type annotations for each parameter (e.g., `str`, `bool`, `int`, `list`) to enable accurate detection. ## Deploying the Contract After setting the constructor parameters, click on **Deploy** to deploy your contract. Once completed, you can proceed to execute your transactions and interact with the deployed contract. # developers/intelligent-contracts/tools/genlayer-studio/contract-state.mdx # Current Intelligent Contract State Once your Intelligent Contract is deployed, you can check its current state to verify that it has been initialized correctly. This step ensures that the contract's data and variables are set as expected. ## Viewing the Current Intelligent Contract State After deploying your contract, you will now see: - **Contract Address:** This is used for interacting with your contract. - **Read Methods:** These return information on the current state of the contract. import Image from 'next/image' import { Callout } from 'nextra-theme-docs' For example, in the **Storage** contract: - If the constructor parameter `initial_storage` was set to `hello`, the state method `get_storage` will return `hello`. The result will show the current state based on the getter function called. This allows you to verify that the variables in your contract have been initialized correctly and that they change when transactions are executed. When the contract state changes, you can always come back and refresh the state by calling these getter functions to see the most current state of your Intelligent Contract. With the state verified, you can now execute transactions and interact with your deployed contract. # developers/intelligent-contracts/tools/genlayer-studio/execute-transaction.mdx # Execute Transactions After deploying your Intelligent Contract and verifying its state, the next step is to execute transactions. This allows you to interact with your contract's methods and functions to perform specific actions or queries. ## Write Methods 1. In the **Write Methods** section, you will see all the write methods available in your Intelligent Contract. 2. Expand the method you want to execute. For example, in the **Storage** contract, select the `update_storage` method. 3. If the method requires input parameters, a field will appear for you to enter the necessary values. For example, the `update_storage` method requires a string called `new_storage`. import Image from 'next/image' Deploy Contract 4. After entering any required parameters, click the button to execute the method. The Studio will process the transaction and return the result. ## Viewing Transaction Results Once you execute a transaction, the result will be displayed, showing the output of the method called. This allows you to verify that the method has executed correctly and to see the effect of the transaction on your contract's state. ## Viewing Current Account Address You can also view your current account address in the header. This address is used to interact with your contract. Select Active Account You can continue interacting with your Intelligent Contract by executing additional transactions or checking the state again to see how it has changed. # developers/intelligent-contracts/tools/genlayer-studio/monitoring-node-logs.mdx # Monitoring Node Logs Node Logs in the GenLayer Studio provide real-time feedback and are a critical component for debugging and tracking the behavior of Intelligent Contracts as they interact within the studio. ## Key Features of Node Logs Node Logs capture and display a variety of events, including: - **Transaction Submission, Status Changes and Finalization:** Track the status and outcomes of submitted transactions. - **Contract Deployment Statuses:** Monitor the progress and success of contract deployments. - **Execution Results and Errors:** Review the outputs and any errors encountered during contract execution. - **Validator Operations and Consensus-Related Messages:** Observe the activities of validators and consensus processes. ## Accessing Node Logs You can view the node logs at the bottom of the GenLayer Studio. This section automatically updates with new log entries as actions are performed within the studio. You can also filter the logs by content as well as by scope and level. ![Node Log](/node-logs.png) ## Understanding Node Logs The logs are structured to provide clear and detailed information: - **Scope:** Each log is tagged with a label such as RPC, GenVM or Consensus to give you a better understading of the context of the log. - **Level:** Log entries are associated with a level and color to facilitate rapid scanning for issues or confirmations. - **Details:** Expandable log entries offer detailed explanations and data for each event, such as transaction hashes or error messages. By actively viewing these logs, you can ensure that your Intelligent Contracts are performing as expected and that any issues are promptly addressed. This leads to a smoother development process within the GenLayer Studio. # developers/intelligent-contracts/tools/genlayer-studio/validators.mdx import Image from 'next/image' # Accessing and Configuring Validators In the GenLayer Studio, validators are essential for achieving consensus and validating transactions through a process known as [Optimistic Democracy](/core-concepts/optimistic-democracy). When you initialize the Studio based on your selected LLM provider(s), you are provided with 5 default validators. 1. **Leaders:** Within this consensus model, one validator is selected as the leader for each transaction. The leader's role is to propose how a transaction should be executed based on the transaction data and the Intelligent Contract's logic. 2. **Validators:** After the leader proposes a transaction execution, other validators are responsible for reviewing and validating the proposal. They use the [Equivalence Principle](/core-concepts/optimistic-democracy/equivalence-principle) to determine if the leader’s proposal meets the required standards. These validators can be modified to suit your Intelligent Contract's requirements. ## Accessing Validators To access and manage validators, follow these steps: 1. On the left sidebar, click on the **Validators** icon. This will open the validators page. 2. In the validators page, you will see a list with all the validators currently configured in the Studio along with their models and providers. ## Configuring Validators To configure validators, you can add new validators or modify existing ones. 1. Click the **New Validator** button to open the validator creation dialog. 2. **Create New Validator:** In the validator creation dialog, fill in the required fields: - **Provider:** Select the provider for the validator. - **Model:** Choose the model that the validator will use. - **Stake:** Specify the stake for the validator. - **Config:** Enter any additional configuration parameters in JSON format. 3. Click **Create** to add the new validator to your configuration. ## Modify Validator Details To modify your validator settings, click on any existing validator and modify the fields based on your needs. ## Delete Validator To delete a validator, click on the delete button beside the validator in the list. By properly managing and configuring validators, you ensure that your Intelligent Contracts operate smoothly and securely within the GenLayer Studio. # developers/intelligent-contracts/tools/genlayer-studio/providers.mdx import Image from 'next/image' # Inference Providers Validators can use various inference providers to validate transactions. You can configure those providers and add custom ones to suit your needs. When you then create a new validator in the validators page, you will be able to select those providers and the relevant models from the list. ## Accessing Providers You can manage your providers in the **Settings** page: ## Configuring Providers Providers have the following properties: - **Provider:** The name of the provider. For example, `OpenAI` or `ollama`. - **Model:** The model attached to this provider. For example, `gpt-4o` or `llama3`. - **Plugin: (only for custom providers)** When adding a custom provider, you need to specify a plugin that implements the provider. The plugin defines what configuration is necessary for the provider. - **Provider Config:** Related environment variables, for example API keys or endpoint URLs. - **Default Validator Config:** This config is used as default when creating a new validator, and will then be applied when making calls to inference providers using said validator. ## Adding a new Provider You can add a new provider by clicking the **New Config** button at the top of the providers list. ## Updating an Existing Provider To modify your validator settings, click on any existing validator and modify the fields based on your needs. ## Deleting a Provider To delete a provider, click on the delete button beside the provider in the list. # developers/intelligent-contracts/tools/genlayer-studio/limitations.mdx # Limitations of the GenLayer Studio The GenLayer Studio is in an early stage of development, with many features still being tested and refined. Here are some limitations of the studio: ## Native Token Transfers Native Token transfers to and from contracts are not supported in the Studio. ## Gas Usage Transactions within the Studio do not consume gas. While this is beneficial for rapid prototyping, the absence of gas simulation may result in behavior differing from live blockchain networks. ## Consensus Algorithm The GenLayer Studio does not implement the full Optimistic Democracy consensus mechanism. There is no appeals process. The studio focuses on providing a basic execution environment without the complexities of the full consensus mechanism. ## Programming Language The programming language used in the Studio is an early version and is not final. It is expected to undergo many changes as development progresses. ## Web Access While the Studio supports web browsing capabilities, it is primarily for testing purposes. The actual web access and data retrieval might differ when deployed on the live network. # developers/intelligent-contracts/tools/genlayer-studio/reset-the-studio.mdx import Image from 'next/image' # Resetting the GenLayer Studio The GenLayer Studio provides a straightforward way to reset its storage, current status, memory, and contract examples. This feature is particularly useful if you want to start fresh with a clean state, whether you’re testing new contracts or simply clearing out previous configurations. ## How to Reset the Studio To reset the GenLayer Studio, follow these simple steps: 1. **Access the Settings Page**: begin by navigating to the Settings page within the GenLayer Studio. 2. **Click "Reset Storage"**: this option allows you to clear all the current data stored in the studio, including the state of deployed contracts, transaction history, and any cached information. 3. **Confirm the Reset in the Dialog**: this is an important step, as resetting the storage will remove all existing data and cannot be undone. Once confirmed, the studio will reset its storage, returning to its initial state as if it were newly initialized. ## What Does Resetting Do? Resetting the GenLayer Studio through the Reset Storage option will: - Clear All Deployed Contracts: Any contracts that you have deployed in the studio will be removed from the frontend memory. - Reset Transaction History: All previous transactions, including those in various states, will be erased. - Restore Contract Examples: Any example contracts included in the studio will be restored to their original, unaltered state. ## When Should You Reset? Consider resetting the studio when: - You want to start with a clean slate for a new development or testing session. - You encounter issues that might be caused by lingering data or state inconsistencies. - You have completed a testing phase and need to ensure that previous data does not interfere with new experiments. # developers/intelligent-contracts/tools/genlayer-studio/troubleshooting.mdx # Troubleshooting If you encounter any issues with the Studio, here are some detailed steps to help you resolve common problems: ## Frontend Not Loading Correctly The frontend may not load correctly due to caching issues or an outdated version of the contract stored in your browser. ### Solution - **Refresh Frontend:** Simply reload the page in your browser. - **Clear Cache:** Clear your browser's cache by clicking on the left of your address bar -> Cookies and site data -> Manage on device site data -> Delete localhost. import Image from 'next/image' Node Log ## Port Conflicts The Studio may fail to start if some ports required for its operation are already in use by other applications. **Ports used by the Studio:** - **Frontend:** 8080 - **Ollama:** 11434 - **JSON-RPC Server:** 4000 - **GenVM:** 6678 - **Postgres:** 5432 - **Hardhat:** 8545 - **Webrequest:** 5000, 5001 ### Solution 1. Identify processes using the required ports. Replace `` with the specific port number. - **Linux / MacOS:** ```bash copy lsof -i : ``` - **Windows:** ```cmd copy netstat -aon | find ``` 2. Use the following command to kill the process using the port. Replace `` with the Process ID obtained from the previous step. - **Linux / MacOS:** ```bash copy kill -9 ``` - **Windows:** ```cmd copy taskkill /PID /F ``` ## Docker not Running The GenLayer Studio relies on Docker for managing containers and images. If Docker is not running, the Studio cannot function properly. ### Solution - Ensure that Docker (or Docker Desktop) is installed on your system. You can check this by running: ```bash copy docker info ``` - Restart Docker Desktop or the Docker daemon on your system. ## Display Issues The code section or other UI elements may not display correctly due to screen size limitations. ### Solution - Resize your screen to accommodate the UI elements properly. This will help improve the visibility and layout of the Studio. ## Studio Not Responding or Throwing Errors The Studio may become unresponsive or throw errors due to various reasons, such as conflicting processes or corrupted containers. ### Solution You can perform a fresh start by stopping and removing all containers, as well as removing all images. **Via Command Line:** ```bash docker stop $(docker ps -aq) docker rm $(docker ps -aq) docker rmi $(docker images -q) ``` **Via Docker Desktop:** 1. Open Docker Desktop and go to the **Containers** section. 3. Select all containers and click **Delete**. 4. Go to the **Images** section. 5. Select all images and click **Delete**. # developers/intelligent-contracts/tools/genlayer-studio/development-tips.mdx import Image from 'next/image' # Development Tips Here are some valuable tips on how to develop your intelligent contract, debug it, and test it using the GenLayer Studio. ## 1. Validators setup You need to be sure that you have at least one validator. If you don't have any, you can create one in the validators screen by providing: - Provider - Model - Stake (at least 1) - Config (optional) ## 2. Add types to your contract method inputs Adding types to your contract method inputs helps the UI render the correct input fields. For example, if you have a method that takes a string as input, you can define it as follows: ```python def update_storage(self, new_storage:str) -> None: self.storage = new_storage ``` This will allow the UI to render the form needed to call the contract with the correct input type as follows
Node Log ## 3. The constructor The constructor is a special method called when the contract is deployed. It is used to initialize the contract's storage. You can define it as follows: ```python def __init__(self, initial_storage: str): self.storage = initial_storage ``` Right now, your contract must include a constructor. Without one, the Studio won't be able to deploy your contract. ## 4. Deploying a contract and sending transactions After you have written your contract, you can deploy it by clicking the "Deploy" button. This will deploy the contract and show you the contract's address.
You can then call the contract's methods, shown below in the deployment section on the left panel of the Studio's UI.
Node Log ## 5. Debugging your contract You can debug your contract by adding print statements to your contract methods. The Studio's Logs section will display these print statements. Here is an example of printing in a contract method: ```python def update_storage(self, new_storage:str) -> None: print("new storage value: ", new_storage) self.storage = new_storage ``` When a transaction is sent to this method, the print statement will be shown in the Logs section as follows:
Node Log ## 6. What happened when the transaction was executed After a transaction is executed, you can see the details by clicking on the transaction in the Transactions section (left-bottom corner). This will show you: - Number: The transaction's number in the database - Timestamp: The time the transaction was executed - Type: The transaction's type (deployment or method call) - Status: The transaction's status (PENDING, PROPOSING, COMMITTING, REVEALING, ACCEPTED, FINALIZED) - Input: the parameters passed to the method - Execution: The status of the execution (SUCCESS or ERROR), the leader's configuration, and the validator's consensus votes - Equivalence principle output: The output of the equivalence principle from the leader
Node Log ## 7. Knowing what happens when the LLMs are called If a contract method calls an LLM, you can see the Equivalence Principle Output from the leader (what's being input in the eq.set call) in the transaction details modal.
Node Log ## 8. Access to the contract state If your contract methods change the contract's state, you can query that information by adding a read method to your contract. Read methods on a contract need to be decorated with the `@gl.public.view` decorator. This method should return the state you want to query.
For example: ```python @gl.public.view def get_balances(self) -> dict[str, int]: return self.balances @gl.public.view def get_balance_of(self, address: str) -> int: return self.balances.get(address, 0) ``` These two methods allow you to query the contract's balance state. You can call them by expanding them from the left panel of the Studio's UI and clicking on the "Call Contract" button. # developers/intelligent-contracts/tools/genlayer-studio/advanced-features/custom-plugins.mdx import { Callout } from "nextra-theme-docs"; # Adding LLM Provider Plugins This section is intended for advanced users who wish to integrate new LLM provider plugins. This process requires code modifications, and we encourage you to create a Pull Request if you'd like your plugin to be included in the official GenLayer Studio. The GenLayer Studio seamlessly interacts with multiple LLM providers. Currently, we support the following providers out of the box: - [OpenAI](https://platform.openai.com/) - [Anthropic](https://www.anthropic.com/) - [Ollama](https://ollama.com/) - [Heuristai](https://heurist.ai/) In addition to these built-in providers, you have the flexibility to integrate your own custom providers. ## Adding a New LLM Provider Plugin ### Creating the Plugin To integrate a new LLM provider plugin, you need to implement the `Plugin` protocol defined in the [llms.py](https://github.com/genlayerlabs/genlayer-studio/blob/main/backend/node/genvm/llms.py) file. The protocol is structured as follows: ```python class Plugin(Protocol): def __init__(self, plugin_config: dict): ... async def call( self, node_config: dict, prompt: str, regex: Optional[str], return_streaming_channel: Optional[asyncio.Queue], ) -> str: ... def is_available(self) -> bool: ... def is_model_available(self, model: str) -> bool: ... ``` Here's an example of how you might implement a custom `Plugin`. Note that this are just some common guidelines, you are free to implement your integration as you please ```python class MyCustomPlugin: def __init__(self, plugin_config: dict): self.api_key = plugin_config.get('api_key') self.base_url = plugin_config.get('base_url', 'https://api.customllm.com') # Add any other necessary configuration parameters async def call( self, node_config: dict, prompt: str, regex: Optional[str], return_streaming_channel: Optional[asyncio.Queue], ) -> str: # Implement the API call to your custom LLM provider # This is a placeholder implementation async with aiohttp.ClientSession() as session: async with session.post( f"{self.base_url}/generate", json={"prompt": prompt, "config": node_config}, headers={"Authorization": f"Bearer {self.api_key}"} ) as response: if response.status == 200: result = await response.json() return result['generated_text'] else: raise Exception(f"API call failed with status {response.status}") def is_available(self) -> bool: # Check if the plugin is properly configured and available return bool(self.api_key) and bool(self.base_url) def is_model_available(self, model: str) -> bool: # Check if the specified model is available for this provider # This is a placeholder implementation available_models = ['custom-gpt-3', 'custom-gpt-4'] return model in available_models ``` ### Registering the Plugin After implementing the `Plugin` protocol, you need to register your new provider in the `llms.py` file under the `get_llm_provider` function. This step ensures that the GenLayer Studio recognizes and can utilize your custom plugin. ```python def get_llm_plugin(plugin: str, plugin_config: dict) -> Plugin: """ Function to register new providers """ plugin_map = { "ollama": OllamaPlugin, "openai": OpenAIPlugin, "anthropic": AnthropicPlugin, "custom-plugin-key": MyCustomPlugin, # Modify here accordingly } if plugin not in plugin_map: raise ValueError(f"Plugin {plugin} not registered.") return plugin_map[plugin](plugin_config) ``` ## Updating the JSON Schema To maintain consistency and enable proper configuration validation, you must update the [JSON schema](https://json-schema.org/) in the [`providers_schema.json`](https://github.com/genlayerlabs/genlayer-studio/blob/main/backend/node/create_nodes/providers_schema.json) file. This update should include your new provider and its specific configuration options. The JSON schema plays a crucial role in validating the configuration options for each provider, ensuring that users input correct and compatible settings. ## Registering a Provider for the new plugin New LLM Providers can be registered through the Studio's UI in the **Settings page** or manually through the backend API. Here is an example on how addition of an LLM Provider using your new Plugin could look like ```sh curl --request POST \ --url http://localhost:4000/api \ --header 'Content-Type: application/json' \ --data '{ "jsonrpc": "2.0", "method": "sim_addProvider", "params": [ { "provider": "my-custom-provider", "model": "my-custom-model", "config": {}, "plugin": "custom-plugin-key", "plugin_config": { "api_key": "MY-SECRET-KEY", "base_url": "my.custom.url" } } ], "id": 1 }' ``` # developers/intelligent-contracts/ideas.mdx # 💡 Build With GenLayer Here are some ideas to get you started with building Intelligent Contracts that can interact with web sources, APIs, and understand natural language using LLM calls. | Idea | Implementation Details | |-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Prediction Markets | Use GenLayer to directly search the web for relevant information allowing users to place bets on future events and get outcomes automatically determined. | | Parametric Insurance | Create insurance that pays out based on real-world events, such as drought conditions or natural disasters, using data fetched from reliable sources. | | Bounty Review and Payout | Automatically reward community members for completing tasks like writing articles or developing features by evaluating their work using Intelligent Contracts. | | Performance-based Contracting | Set up contracts that pay out based on the completion of pre-agreed jobs, such as developing a website or creating a piece of content, with performance verified through automated checks. | | Slashing Monitoring and Insurance | Monitor protocols for any violations and trigger slashing events or provide insurance payouts based on human-in-the-loop evaluations or LLM-based assessments. | | Hack Detection and Emergency Pause | Set up contracts that continuously monitor for potential protocol attacks through explorers and news sites, and trigger automated emergency shutdowns if threats are detected. | | On-chain Identity Verification | Verify users' identities by checking their social media profiles for specific messages and linking these to their on-chain accounts, enhancing trust in the ecosystem. | | Under-collateralized Lending | Enable lending with less collateral by linking real-world identity to on-chain reputation, allowing borrowers to leverage their good standing for better loan terms. | | P2P Gambling | Allow two users to place bets on real-world outcomes, with the contract determining the winner based on data from trusted sources. | | Decentralized Game Master | Facilitate text-based role-playing games where users submit their actions, and the intelligent contract determines the outcomes, creating a dynamic and interactive gaming experience. | | Interoperable Games with NFTs | Develop games that issue and recognize automatically generated NFT items, allowing players to transfer assets seamlessly between different games within the ecosystem. | | Unstoppable Organizations | Create autonomous entities like DAOs that can adapt and continue their missions indefinitely as long as they remain funded, including AI DAOs and autonomous trusts. | | Retroactive Public Goods Funding | Set up contracts that reward contributions to the protocol retroactively, incentivizing community members to make valuable improvements and innovations. | | Crowd-sourced Knowledge Database | Implement a system where users are rewarded for finding and summarizing new information on various topics, building a comprehensive knowledge base. | | AI Notary | Create an automated notary service that can confirm the occurrence of online events, providing verifiable records for various purposes. | | AI Arbitration | Develop a dispute resolution system where parties submit their cases to an AI-based arbitrator, which makes decisions based on pre-defined legal frameworks and submitted evidence. | | Private P2P Contracts | Enable two-party contracts that remain private unless a dispute arises, using a commit/reveal scheme to keep terms confidential until necessary. | | Multi-modal Use Cases | Integrate real-world images for performance-based contracting, such as verifying the completion of physical tasks, with cryptographically signed proofs. | | Generative Memes | Create fun and engaging Intelligent Contracts, like ones that track and manipulate token balances in creative ways, leveraging the capabilities of LLMs for humor and experimentation. | | Text-based Intelligent Contracts | Open the possibility for non-developers to create Intelligent Contracts by capturing the entire logic in plain text, making smart contract development more accessible. | | Honeypot Contracts for Security | Set up Intelligent Contracts designed to attract and test adversarial attacks, helping to identify and fix vulnerabilities through real-world testing. | | Fair and Transparent Moderation | Use GenLayer-based arbitration to make fair and transparent moderation decisions in various communities and games, ensuring unbiased and consistent enforcement of rules. | # developers/decentralized-applications/architecture-overview.mdx # Architecture Overview of Decentralized Applications Using GenLayer A decentralized application (DApp) on GenLayer leverages its unique blockchain architecture to integrate AI-powered smart contracts, called "Intelligent Contracts." These DApps consist of various components that work together to ensure seamless interaction with the GenLayer protocol. ## Key Components ### Frontend Application The user interface of the DApp is typically built with web technologies like HTML, CSS, and JavaScript. It communicates with the backend using the GenLayerJS SDK, enabling interaction with the GenLayer protocol and handling user inputs to trigger blockchain transactions. ### GenLayerJS SDK A TypeScript/JavaScript library that abstracts the complexities of blockchain interactions. The SDK provides APIs to read from and write to Intelligent Contracts, manages accounts and queries transactions, and acts as the bridge between the frontend and GenLayer's protocol. ### Consensus Layer The consensus layer implements GenLayer's Optimistic Democracy mechanism to ensure reliable and secure execution of transactions using a validator-driven commit-reveal scheme. It also handles appeals and transaction finality to maintain integrity and fairness. It is built on ZK-stack rollups to provide scalability and cost-efficiency, secure state updates, and anchoring to Ethereum's security model. ### Execution Environment The execution environment (the GenVM) is the engine that executes Intelligent Contracts. It supports both deterministic and non-deterministic operations, enabling AI integration and web data access. ### Ghost Contracts Ghost contracts are proxy smart contracts on the consensus layer that facilitate interactions between accounts and Intelligent Contracts. They also manage external messages and asset bridging. ## Architecture Diagram ```mermaid flowchart TD subgraph s1["Frontend Application"] n1["GenLayerJS"] end subgraph s2["Consensus Layer."] n2["Consensus Smart Contracts"] n3["Ghost Contracts"] end subgraph s3["GenLayer Node"] n4["Execution Environment - GenVM"] end s1 <--> s3 s3 <--> s2 ``` # developers/decentralized-applications/dapp-development-workflow.mdx # DApp Development Workflow with GenLayer The GenLayer platform allows developers to create decentralized applications (DApps) throughout the lifecycle of creating, testing, and deploying. This guide details how developers can transition from using the **GenLayer Studio** for their first Intelligent Contract to an advanced local development workflow, finishing with building a frontend application with **GenLayerJS**. --- ## 1. Starting with GenLayer Studio **GenLayer Studio** is an integrated environment designed to streamline the initial stages of Intelligent Contract development, making it accessible for developers of all experience levels. It provides an interactive environment that serves as a comprehensive sandbox for developing, deploying, and testing Intelligent Contracts in real time. This environment enables developers to experiment with their contracts and see immediate results without the complexities of a production setup. The platform runs a simulated network with customizable validators that accurately mirror the GenLayer consensus mechanism. This feature allows developers to test their contracts under conditions that closely resemble the actual blockchain environment, ensuring reliable deployment outcomes. ### Getting Started: 1. **Set Up the Studio**: Developers initialize the Studio using `genlayer cli` command `genlayer init` which configures the environment and spawns a local validator network. GenLayer Studio is also available as a hosted instace at [studio.genlayer.com](https://studio.genlayer.com/). 2. **Write Your First Contract**: Intelligent Contracts in GenLayer are written in Python, utilizing its extensive libraries and GenVM capabilities like LLM calls and web integration. Refer to [Your First Contract](/developers/intelligent-contracts/your-first-contract) guide for more information. 3. **Deploy and Test**: Deploy your Intelligent Contracts through the Studio interface and test them in the simulated network. --- ## 2. Moving to Advanced Workflow As projects transforms to real-world applications, developers should migrate to a local development setup. This approach mirrors frameworks like Hardhat or Foundry and is well-suited for iterative development and comprehensive testing. ### Benefits of Local Development: - **Complete Control**: Developers can configure the environment, validators, and network parameters as needed. - **Enhanced Debugging**: The local setup allows for advanced debugging of both contracts and transactions. - **Flexible Testing**: Tests can simulate real-world scenarios, including edge cases and complex interactions. ### Workflow Steps: 1. **Set Up Your Local Environment**: Developers can start with the GenLayer boilerplate project, which includes pre-configured templates for local testing. 2. **Write Tests**: Tests are written in Python, focusing on validating contract functionality and ensuring consensus integrity. The boilerplate includes sample tests to accelerate development. 3. **Simulate Transactions**: Run detailed simulations to observe how contracts behave under various network conditions, ensuring robust performance. --- ## 3. Building the Frontend with GenLayerJS The frontend is the user-facing component of a DApp. With **GenLayerJS**, developers can integrate their applications with the GenLayer network, focusing on providing a seamless user experience. ### Why Use GenLayerJS? - **Simplified Interactions**: Abstracts the complexity of blockchain interactions with high-level APIs. - **Comprehensive Features**: Supports transaction handling, contract interaction, event subscriptions, and account management. - **TypeScript Integration**: Provides type safety and code reliability for frontend development. ### Frontend Development Workflow: 1. **Integrate GenLayerJS**: Install the SDK and set up a client to connect to the GenLayer network. Configuration options allow connection to various environments, such as testnets or the GenLayer Studio. Refer to [GenLayerJS](/developers/decentralized-applications/genlayer-js) guide for more information. 2. **Read and Write to Contracts**: Use the SDK's high-level APIs to interact with deployed contracts. For instance, retrieve user balances or update contract state seamlessly. Refer to [Reading Data](/developers/decentralized-applications/reading-data) and [Writing Data](/developers/decentralized-applications/writing-data) guides for more information. 3. **Monitor Transactions**: Developers can subscribe to events or query transaction statuses, ensuring users are kept informed of transaction progress and outcomes. 4. **Build the User Interface**: Combine GenLayerJS with popular frontend frameworks (like React or Angular) to create intuitive interfaces. --- ## Advanced Tips for Developers 1. **Leverage GenVM Features**: The GenVM allows Intelligent Contracts to interact with LLM models and access real-time web data. Developers should design contracts to maximize these capabilities for dynamic and intelligent DApps. 2. **Optimize Testing**: Incorporate edge case scenarios in tests to ensure that contracts behave reliably under all conditions. 3. **Focus on Security**: Implement robust security measures, including input validation and error handling, to protect contracts from malicious inputs and ensure consensus consistency. # developers/decentralized-applications/genlayer-js.mdx # GenLayerJS SDK GenLayerJS SDK is a TypeScript library designed for developers building decentralized applications (DApps) on the GenLayer protocol. This SDK provides a comprehensive set of tools to interact with the GenLayer network, including client creation, transaction handling, event subscriptions, and more, all while leveraging the power of Viem as the underlying blockchain client. ## Features - **Client Creation**: Easily create and configure a client to connect to GenLayer’s network. - **Transaction Handling**: Send and manage transactions on the GenLayer network. - **Contract Interaction**: Read from and write to smart contracts deployed on GenLayer. - **Event Subscriptions**: Subscribe to events and listen for blockchain updates. - **TypeScript Support**: Benefit from static typing and improved code reliability. ## How it's Built The GenLayerJS SDK is built using **TypeScript** and leverages the **Viem** library as the underlying blockchain client. It is designed to provide a high-level, easy-to-use API for interacting with the GenLayer network, abstracting away the complexities of direct blockchain interactions. ### Technologies Used - **TypeScript**: A statically typed superset of JavaScript that compiles to plain JavaScript, enhancing code reliability and maintainability. - **Viem**: A modular and extensible blockchain client for JavaScript and TypeScript. - **ESBuild**: A fast JavaScript bundler and minifier used for building the SDK efficiently. - **Vitest**: A Vite-native unit test framework used for testing. ### Project Structure The source code for the GenLayerJS SDK is organized as follows: - `src/`: Contains the main TypeScript source files. - `tests/`: Includes all the test files written using Vitest. - `dist/`: The compiled JavaScript files ready for use. ## Requirements Before using the GenLayerJS SDK, ensure your system meets the following requirements: - **Node.js**: Version 16.x or higher is required. - **npm**: Comes bundled with Node.js, used for managing packages. - **Operating System**: Compatible with macOS, Linux, and Windows. ### Installation To install the GenLayerJS SDK, use the following command: ```bash npm install genlayer-js ``` ## Usage Here’s how to initialize the client and connect to the GenLayer Studio: - **[Reading a transaction](../intelligent-contracts/advanced-features/contract-to-contract-interaction)**: Understand how to query transactions on the GenLayer network. - **[Reading a contract](/developers/decentralized-applications/reading-data)**: Discover how to read data from intelligent contracts on GenLayer. - **[Writing a contract](../intelligent-contracts/tools/genlayer-studio/contract-state)**: Learn how to write data to intelligent contracts on GenLayer. ## General Format of Commands The GenLayerJS SDK provides functions that follow a consistent syntax pattern: ```typescript client.functionName(parameters); ``` - `client`: The instance of the GenLayer client. - `functionName`: The primary action you want to perform (e.g., `getTransaction`, `readContract`). - `parameters`: An object containing the required parameters for the function. ## Further Development Additional features are planned to enhance interaction with the GenLayer network, including wallet integration and gas estimation. Stay tuned for updates. ## Repository You can find the GenLayerJS SDK repository on GitHub: [GenLayerJS SDK Repository](https://github.com/genlayerlabs/genlayer-js) ## Full Reference The full reference for the GenLayerJS SDK is available in the [GenLayerJS SDK Reference](/references/genlayer-js). # developers/decentralized-applications/querying-a-transaction.mdx # Querying a Transaction Reading transactions in GenLayer allows you to inspect the details of any transaction that has been submitted to the network. This is useful for monitoring transaction status, debugging, and verifying transaction details. ## Basic Transaction Reading Here's the simplest way to read a transaction: ```typescript import { simulator } from 'genlayer-js/chains'; import { createClient } from 'genlayer-js'; const client = createClient({ chain: simulator, }); const transactionHash = "0x..."; const transaction = await client.getTransaction({ hash: transactionHash }); ``` {/* ## Transaction Data Structure When you read a transaction, you get access to its complete data structure: ```typescript interface Transaction { hash: `0x${string}` // The unique transaction hash from: `0x${string}` // Address of the sender to: `0x${string}` | null // Address of the recipient (null for contract deployments) nonce: number // Transaction sequence number value: bigint // Amount of native tokens transferred data: `0x${string}` // Transaction input data timestamp: number // Block timestamp when transaction was included status: 'success' | 'failure' | 'pending' // Current transaction status blockNumber: bigint | null // Block number where transaction was included blockHash: `0x${string}` | null // Hash of the block // ... additional fields } ``` ## Reading Different Transaction Types ### Basic Transfer Transaction ```typescript const transferTx = await client.getTransaction({ hash: "0x123...", }); console.log({ from: transferTx.from, to: transferTx.to, value: transferTx.value, status: transferTx.status }); ``` ### Contract Interaction Transaction ```typescript const contractTx = await client.getTransaction({ hash: "0x456...", }); // Decode the transaction input data const decodedInput = client.decodeTransactionInput({ data: contractTx.data, abi: contractABI, // You need the contract's ABI }); console.log({ contractAddress: contractTx.to, functionName: decodedInput.functionName, arguments: decodedInput.args }); ``` ### Contract Deployment Transaction ```typescript const deployTx = await client.getTransaction({ hash: "0x789...", }); console.log({ deployer: deployTx.from, contractAddress: deployTx.creates, // Address of deployed contract deploymentData: deployTx.data }); ``` */} ## Error Handling ```typescript async function getTransactionWithRetry( client: GenLayerClient, hash: string, maxAttempts = 3 ): Promise { for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { const tx = await client.getTransaction({ hash }); if (!tx) throw new Error('Transaction not found'); return tx; } catch (error) { if (attempt === maxAttempts) throw error; if (error.message.includes('not found')) { // Wait longer between retries for not found errors await new Promise(resolve => setTimeout(resolve, 2000 * attempt)); continue; } throw error; // Rethrow other errors immediately } } throw new Error('Failed to fetch transaction after max retries'); } ``` ## Monitoring Transaction Status ```typescript async function monitorTransaction( client: GenLayerClient, hash: string, interval = 1000 ): Promise { return new Promise((resolve, reject) => { const checkStatus = async () => { try { const tx = await client.getTransaction({ hash }); if (!tx) { setTimeout(checkStatus, interval); return; } if (tx.status === 'pending') { setTimeout(checkStatus, interval); return; } resolve(tx); } catch (error) { reject(error); } }; checkStatus(); }); } // Usage const finalTx = await monitorTransaction(client, "0x..."); ``` # developers/decentralized-applications/reading-data.mdx # Reading from Intelligent Contracts Reading from an Intelligent Contract allows you to query the contract's state and execute view functions without modifying the blockchain state. These operations are free (no fees) and provide immediate access to contract data. ## Understanding View Operations In GenLayer, functions marked with the `@gl.public.view` decorator are read-only operations that: - Don't modify the contract's state - Can be executed without requiring a transaction - Return data immediately - Don't consume gas - Can be called by any account ## Basic Contract Reading Here's how to read from an Intelligent Contract: ```typescript import { simulator } from 'genlayer-js/chains'; import { createClient, createAccount } from 'genlayer-js'; const account = createAccount(); const client = createClient({ chain: simulator, account: account, }); const result = await client.readContract({ address: contractAddress, functionName: 'get_complete_storage', args: [], }); ``` ### Parameters Explained - `address`: The deployed contract's address on the GenLayer network - `functionName`: The name of the view function you want to call - `args`: An array of arguments that the function accepts (empty if none required) ## Common View Operations Intelligent Contracts typically include several types of view functions: ### State Queries ```typescript // Reading a single value const balance = await client.readContract({ address: contractAddress, functionName: 'get_balance', args: [accountAddress], }); // Reading multiple values const userInfo = await client.readContract({ address: contractAddress, functionName: 'get_user_info', args: [userId], }); ``` ### Computed Values ```typescript // Getting calculated results const totalSupply = await client.readContract({ address: contractAddress, functionName: 'calculate_total_supply', args: [], }); ``` ### Validation Checks ```typescript // Checking permissions const hasAccess = await client.readContract({ address: contractAddress, functionName: 'check_user_permission', args: [userId, 'ADMIN_ROLE'], }); ``` ## Error Handling When reading from contracts, you should handle potential errors: ```typescript try { const result = await client.readContract({ address: contractAddress, functionName: 'get_data', args: [], }); console.log('Data retrieved:', result); } catch (error) { if (error.message.includes('Contract not found')) { console.error('Invalid contract address'); } else if (error.message.includes('Function not found')) { console.error('Invalid function name'); } else { console.error('Error reading contract:', error); } } ``` ## Best Practices 1. **Cache Results**: For frequently accessed data that doesn't change often, consider caching the results. 2. **Batch Readings**: When possible, use functions that return multiple values instead of making multiple separate calls. 3. **Type Safety**: Use TypeScript interfaces to ensure type safety when handling returned data: # developers/decentralized-applications/writing-data.mdx # Writing to Intelligent Contracts Writing to an Intelligent Contract involves sending transactions that modify the contract's state. Unlike read operations, write operations require fees and need to be processed by the network before taking effect. ## Understanding Write Operations In GenLayer, functions that modify state: - Require a transaction to be sent to the network - Consume gas (computational resources) - Need time to be processed and finalized - Must be signed by an account with sufficient balance to pay for the transaction fees - Return a transaction hash immediately, but state changes are not instant ## Basic Contract Writing Here's how to write to an Intelligent Contract: ```typescript import { simulator } from 'genlayer-js/chains'; import { createClient, createAccount } from 'genlayer-js'; import type { TransactionStatus } from 'genlayer-js/types'; const account = createAccount(); const client = createClient({ chain: simulator, account: account, }); // Send the transaction const transactionHash = await client.writeContract({ address: contractAddress, functionName: 'update_storage', args: ['new_data'], value: 0, // Optional: amount of native GEN tokens to send }); // Wait for the transaction to be processed const receipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: TransactionStatus.FINALIZED, // or 'ACCEPTED' }); ``` ### Parameters Explained - `address`: The deployed contract's address - `functionName`: The name of the function to call - `args`: Array of arguments for the function - `value`: Amount of native tokens to send (in wei) ## Transaction Lifecycle 1. **Transaction Creation** ```typescript const transactionHash = await client.writeContract({ address: contractAddress, functionName: 'mint_token', args: [recipient, amount], }); ``` 2. **Transaction Status Monitoring** ```typescript // Basic waiting const receipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: 'FINALIZED', }); // Advanced monitoring with timeout const receipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: 'FINALIZED', interval: 5_000, // check every 5 seconds retries: 10, // maximum number of retries }); ``` ## Common Write Operations ### Token Transfers ```typescript // Sending tokens const hash = await client.writeContract({ address: tokenContractAddress, functionName: 'transfer', args: [recipientAddress, amount], }); ``` ### State Updates ```typescript // Updating user data const hash = await client.writeContract({ address: contractAddress, functionName: 'update_user_profile', args: [userId, newProfile], }); ``` ## Error Handling ```typescript try { const hash = await client.writeContract({ address: contractAddress, functionName: 'update_data', args: ['new_data'], }); try { const receipt = await client.waitForTransactionReceipt({ hash, status: 'FINALIZED', }); console.log('Transaction successful:', receipt); } catch (waitError) { console.error('Transaction failed or timed out:', waitError); } } catch (error) { if (error.message.includes('insufficient funds')) { console.error('Not enough balance to pay for transaction'); } else if (error.message.includes('user rejected')) { console.error('User rejected the transaction'); } else { console.error('Error sending transaction:', error); } } ``` ## Transaction Status Types GenLayer transactions can have different status requirements: ```typescript enum TransactionStatus { PENDING = "PENDING", CANCELED = "CANCELED", PROPOSING = "PROPOSING", COMMITTING = "COMMITTING", REVEALING = "REVEALING", ACCEPTED = "ACCEPTED", FINALIZED = "FINALIZED", UNDETERMINED = "UNDETERMINED", } // Wait for just acceptance (faster) const acceptedReceipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: TransactionStatus.ACCEPTED, }); // Wait for full finalization const finalizedReceipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: TransactionStatus.FINALIZED, }); ``` ## Best Practices 1. **Always Wait for Receipts**: Don't assume a transaction is successful just because you got a hash. 2. **Handle Timeouts**: Set appropriate timeouts for transaction waiting. 3. **Implement Retry Logic**: For important transactions, implement retry mechanisms: ```typescript async function sendWithRetry( client: GenLayerClient, params: WriteContractParameters, maxAttempts = 3 ): Promise { for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { const hash = await client.writeContract(params); return await client.waitForTransactionReceipt({ hash, status: 'FINALIZED', timeout: 30_000 * attempt, // Increase timeout with each attempt }); } catch (error) { if (attempt === maxAttempts) throw error; console.log(`Attempt ${attempt} failed, retrying...`); await new Promise(resolve => setTimeout(resolve, 1000 * attempt)); } } throw new Error('Max retry attempts reached'); } ``` # developers/decentralized-applications/testing.mdx import { Callout } from 'nextra-theme-docs' # Testing Intelligent Contracts on GenLayer Testing Intelligent Contracts on GenLayer involves deploying contracts, sending transactions, validating their behavior, and identifying issues. Here is some guidance on how to test using the tools provided in the local development environment and GenLayer Studio. ## Testing Workflow in the Local Environment For a more advanced and controlled testing setup, you can leverage the GenLayer Project Boilerplate and the provided test helpers. Please note that you need the Studio running to run the tests by sending requests to it. ### 1. Create Accounts Use the `create_new_account` helper to generate accounts for testing. These accounts simulate users interacting with the contract. ```python from tools.request import create_new_account account = create_new_account() ``` ### 2. Set Up Validators Validators are essential for processing transactions in GenLayer. Use the `sim_createRandomValidators` method to initialize them. ```python from tools.request import payload, post_request_localhost nb_validators = 5 min_stake = 8 max_stake = 12 providers = ["openai"] models = ["gpt-4o"] validators_response = post_request_localhost( payload("sim_createRandomValidators", nb_validators, min_stake, max_stake, providers, models) ).json() ``` ### 3. Deploy the Contract Deploy your Intelligent Contract using the `deploy_intelligent_contract` helper: ```python from tools.request import deploy_intelligent_contract contract_code = open("contracts/my_contract.py", "r").read() contract_address, deploy_response = deploy_intelligent_contract(account, contract_code, "{}") ``` ### 4. Interact with the Contract Use `send_transaction` for writing data to the contract and `call_contract_method` for reading data: ```python from tools.request import send_transaction, call_contract_method # Write data send_transaction(account, contract_address, "method_name", [arg1, arg2]) # Read data result = call_contract_method(contract_address, account, "get_state", []) ``` ### 5. Assertions Validate the responses using provided assertion helpers: ```python from tools.response import assert_dict_struct, has_success_status assert has_success_status(result) assert_dict_struct(result, expected_structure) ``` ### 6. Clean Up After completing the tests, delete the validators or reset the environment: ```python delete_response = post_request_localhost(payload("sim_deleteAllValidators")).json() ``` # developers/decentralized-applications/project-boilerplate.mdx import { Callout } from 'nextra-theme-docs' # GenLayer Project Boilerplate The GenLayer Project Boilerplate is a template for building decentralized applications (DApps) on GenLayer. This boilerplate includes a complete example implementation of a football prediction market, demonstrating best practices and common patterns for GenLayer development. This boilerplate is a work in progress and is not yet ready for production use. You can find the latest version at: [GenLayer Project Boilerplate](https://github.com/genlayerlabs/genlayer-project-boilerplate) ## Features - **Contract Templates**: Ready-to-use intelligent contract templates and examples - **Testing Framework**: Built-in testing infrastructure for end-to-end testing - **Frontend Integration**: Vue.js-based frontend setup with GenLayerJS integration - **Environment Configuration**: Pre-configured environment setup for development - **Example Implementation**: Full football prediction market implementation ## How it's Built The boilerplate project is structured to provide a development environment for GenLayer applications, combining both backend contract development and frontend user interface. ### Technologies Used - **Python**: For intelligent contract development and testing - **Vue.js**: Frontend framework for building user interfaces - **GenLayerJS**: SDK for interacting with GenLayer contracts - **pytest**: Testing framework for contract validation - **Vite**: Frontend build tool and development server ### Project Structure ``` project-root/ ├── app/ # Frontend application │ ├── src/ # Vue.js source files │ └── .env.example # Frontend environment variables template ├── contracts/ # Intelligent Contracts │ └── football_prediction_market.py ├── test/ # Test files └── .env.example # Main environment variables template ``` ## Requirements Before using the GenLayer Project Boilerplate, ensure your system meets the following requirements: - **GenLayer Studio**: Running instance required - **Node.js**: Version 18.x or higher - **Python**: Version 3.8 or higher ### Installation 1. Clone the boilerplate repository: ```bash git clone https://github.com/genlayerlabs/genlayer-project-boilerplate cd genlayer-project-boilerplate ``` 2. Set up the environment: ```bash cp .env.example .env ``` ## Usage ### Deploying Contracts 1. Access the GenLayer Simulator UI (default: http://localhost:8080) 2. Navigate to "Contracts" section 3. Create a new contract using `/contracts/football_prediction_market.py` 4. Deploy through the "Run and Debug" interface ### Frontend Setup 1. Configure the frontend environment: ```bash cd app cp .env.example .env # Add your contract address to VITE_CONTRACT_ADDRESS ``` 2. Install dependencies and start the development server: ```bash npm install npm run dev ``` ### Running Tests Execute the test suite using pytest: ```bash pip install -r requirements.txt pytest test ``` ## Football Prediction Market Example The included example contract demonstrates a complete prediction market implementation with the following features: ### Contract Functions #### Create Predictions: ```python create_prediction(game_date: str, team1: str, team2: str, predicted_winner: str) ``` #### Resolve Predictions: ```python resolve_prediction(prediction_id: str) ``` #### Query Data: ```python get_player_predictions(player_address: str) get_player_points(player_address: str) ``` ### Frontend Integration The Vue.js frontend demonstrates: - Wallet connection handling - Contract interaction using GenLayerJS - User interface for prediction creation and management - Real-time updates for prediction status ## Testing Framework The boilerplate includes a comprehensive testing suite covering the following scenarios: ### Contract Schema The schema of the contract is well generated and has the expected methods and variables. ### Test Scenarios #### Successful Draw Prediction Tests the scenario where a player correctly predicts a draw between two teams. When the match is resolved as a draw, the player should receive 1 point for their accurate prediction. #### Successful Winner Prediction Validates the case where a player correctly predicts the winning team. Upon match resolution confirming their predicted team as the winner, the player should be awarded 1 point. #### Unsuccessful Prediction Covers the scenario where a player's prediction doesn't match the actual result. This could be: - Predicting Team A wins, but Team B wins - Predicting a draw, but there's a winner - Predicting a winner, but the match ends in a draw In all these cases, the player should receive 0 points. ## Best Practices - Always use environment variables for configuration - Implement comprehensive testing for all contract functions - Follow the provided folder structure for consistency - Use TypeScript for frontend development - Implement proper error handling in both contract and frontend code # developers/staking-guide.mdx import { Callout } from "nextra-theme-docs"; # Staking Contract Guide This guide covers consensus-level staking operations for developers who want to interact directly with the GenLayer staking smart contracts. It includes Solidity code examples for both validator and delegator operations. To understand the concepts behind staking—including the epoch system, shares vs stake, validator selection weights, and reward distribution—see [Staking in GenLayer](/understand-genlayer-protocol/core-concepts/optimistic-democracy/staking). For CLI-based staking operations (recommended for most users), see the [GenLayer CLI Staking Commands](/api-references/genlayer-cli#staking-operations-testnet). ## Validator Operations ### Joining as a Validator **Requirements:** - Minimum stake: **42,000 GEN** tokens - Must run a validator node for consensus participation - A single address can create multiple validators **Method 1: Owner as Operator** ```solidity address validatorWallet = genStaking.validatorJoin{value: 42000 ether}(); ``` **Method 2: Separate Operator Address (Recommended)** ```solidity address operatorAddress = 0x...; address validatorWallet = genStaking.validatorJoin{value: 42000 ether}(operatorAddress); ``` Save the returned **ValidatorWallet address** - you'll need it for all future operations. **Important Notes:** - Deposits activate **2 epochs after joining** - `validatorPrime()` is automatically called by your validator node each epoch - Monitor priming for proper activation within 2 epochs - Operator address cannot be reused or be the zero address - If the operator is already assigned to another validator, the transaction reverts **Post-Join Steps:** 1. Save the `validatorWallet` address 2. Start your validator node using the operator address 3. Monitor that `validatorPrime(validatorWallet)` executes each epoch 4. Wait 2 epochs and verify activation ### Depositing as a Validator ```solidity validatorWallet.validatorDeposit{value: 10000 ether}(); ``` **Key Points:** - Call through the ValidatorWallet contract only - Deposits follow the **epoch +2 activation rule** - Your validator node automatically calls `validatorPrime()` to commit the deposit - No minimum for additional deposits - Cannot deposit zero value **Activation Timeline:** ``` Epoch N: validatorDeposit() called Epoch N+1: validatorPrime() → deposit staged Epoch N+2: validatorPrime() → deposit activated ``` ### Withdrawing as a Validator **Step 1: Calculate Shares** ```solidity uint256[8] memory validatorState = genStaking.validatorView(validatorWallet); uint256 currentShares = validatorState[1]; uint256 currentStake = validatorState[0]; uint256 sharesToExit = (currentShares * 30) / 100; // Exit 30% ``` **Step 2: Initiate Exit** ```solidity validatorWallet.validatorExit(sharesToExit); ``` You must specify **shares**, not token amounts. Cannot exit more shares than owned. **Important Notes:** - Exited tokens stop earning rewards immediately - Tokens are locked for **7 epochs** before claiming - Each exit creates a separate withdrawal **Unbonding Timeline:** ``` Epoch 10: validatorExit() called → unbonding starts Epochs 11-16: Locked period Epoch 17: validatorClaim() available ``` ### Claiming Withdrawn Funds as a Validator ```solidity uint256 tokensReceived = genStaking.validatorClaim(validatorWallet); ``` **Important Notes:** - Must wait **7 full epochs** after calling `validatorExit()` - Claims are permissionless - anyone can trigger them - Tokens are sent to the validator wallet's owner address - Multiple exits can be claimed in a single call - Returns the total GEN received **Checking Claim Availability:** ```solidity uint256 exitEpoch = 10; uint256 claimableAtEpoch = exitEpoch + 7; uint256 currentEpoch = genStaking.epoch(); if (currentEpoch >= claimableAtEpoch) { genStaking.validatorClaim(validatorWallet); } ``` --- ## Delegator Operations ### Joining as a Delegator **Requirements:** - Minimum delegation: **42 GEN** per validator - Target validator must exist and be active - Can delegate to multiple validators **Basic Delegation:** ```solidity address validatorWallet = 0x...; genStaking.delegatorJoin{value: 1000 ether}(validatorWallet); ``` **Multi-Validator Delegation:** ```solidity genStaking.delegatorJoin{value: 500 ether}(validator1); genStaking.delegatorJoin{value: 500 ether}(validator2); genStaking.delegatorJoin{value: 500 ether}(validator3); ``` **Important Notes:** - Follows the **epoch +2 activation rule** - The validator's node automatically calls `validatorPrime()` to commit your delegation - Choose validators with good uptime - Smaller validators often provide higher returns - Cannot delegate zero value **Delegation Strategy Tips:** - Diversify across multiple validators - Check validator performance and uptime - Monitor validator quarantine/ban status ### Depositing as a Delegator ```solidity genStaking.delegatorDeposit{value: 500 ether}(validatorWallet); ``` **Important Notes:** - Use `delegatorDeposit()` to add to existing delegations - Follows the **epoch +2 activation rule** - The validator's node automatically calls `validatorPrime()` - No minimum for additional deposits - Rewards automatically compound ### Withdrawing as a Delegator **Step 1: Calculate Shares** ```solidity uint256 currentShares = genStaking.sharesOf(msg.sender, validatorWallet); uint256 sharesToExit = (currentShares * 50) / 100; // Exit 50% ``` **Step 2: Initiate Exit** ```solidity genStaking.delegatorExit(validatorWallet, sharesToExit); ``` You must specify **shares**, not token amounts. **Important Notes:** - Can exit partial amounts - Stop earning rewards immediately after exit - Tokens are locked for **7 epochs** - Exit each validator separately if delegating to multiple **Unbonding Timeline:** ``` Epoch 5: delegatorExit() called Epochs 6-11: Locked period Epoch 12: delegatorClaim() available ``` ### Claiming Withdrawn Funds as a Delegator ```solidity uint256 tokensReceived = genStaking.delegatorClaim( delegatorAddress, validatorWallet ); ``` **Important Notes:** - Must wait **7 full epochs** after calling `delegatorExit()` - Claims are permissionless - anyone can trigger them - Tokens are sent to the delegator's address - Claim from each validator separately if delegated to multiple **Multi-Validator Claim Example:** ```solidity genStaking.delegatorClaim(msg.sender, validator1); genStaking.delegatorClaim(msg.sender, validator2); genStaking.delegatorClaim(msg.sender, validator3); ``` --- ## Genesis Epoch 0 Epoch 0 is the **genesis bootstrapping period** with special rules designed to facilitate network launch. The normal staking rules are relaxed to allow rapid network bootstrapping. ### What is Epoch 0? Epoch 0 is the **bootstrapping period** before the network becomes operational. During epoch 0: - **No transactions are processed** - the network is not yet active - **No consensus occurs** - validators are not yet participating - Stakes are registered and prepared for activation in epoch 2 **Important**: The network transitions directly from epoch 0 to epoch 2 (epoch 1 is skipped). Validators and delegators who stake in epoch 0 become active in epoch 2. ### Special Rules for Epoch 0 | Rule | Normal Epochs (2+) | Epoch 0 | |------|-------------------|---------| | Validator minimum stake | 42,000 GEN | No minimum to join | | Delegator minimum stake | 42 GEN | No minimum to join | | Activation delay | +2 epochs | Active in epoch 2 | | validatorPrime required | Yes, each epoch | Not required | | Share calculation | Based on existing ratio | 1:1 (shares = input) | | Transaction processing | Yes | No (bootstrapping only) | **Activation requires meeting minimums**: While you can join with any amount during epoch 0, your stake will only be **activated in epoch 2** if it meets the minimum requirements (42,000 GEN for validators, 42 GEN for delegators). Stakes below the minimum remain registered but inactive. ### Validators in Epoch 0 **Joining:** ```solidity // In epoch 0, any amount is accepted (no 42,000 GEN minimum) address validatorWallet = genStaking.validatorJoin{value: 1000 ether}(operatorAddress); // Stake is registered for activation in epoch 2 // No need to call validatorPrime() in epoch 0 ``` **Key behaviors:** 1. **No minimum stake**: Validators can join with any non-zero amount 2. **Registered for epoch 2**: Stakes are recorded and will become active when epoch 2 begins 3. **No priming required**: `validatorPrime()` is not needed during epoch 0 4. **No consensus participation**: Validators do not process transactions in epoch 0 **Do validators need to take any action in epoch 0 to be active in epoch 2?** No. Validators who join in epoch 0: - Have their stake registered during epoch 0 - Become active automatically in epoch 2 (epoch 1 is skipped) **only if they have at least 42,000 GEN staked** - Must start calling `validatorPrime()` in epoch 2 for continued participation in epoch 4+ **Critical**: Validators who joined in epoch 0 with less than 42,000 GEN will **not be active** in epoch 2. They must deposit additional funds to meet the minimum requirement before epoch 2 begins. ### Delegators in Epoch 0 **Joining:** ```solidity // In epoch 0, any amount is accepted (no 42 GEN minimum) genStaking.delegatorJoin{value: 10 ether}(validatorWallet); // Delegation is registered for activation in epoch 2 ``` **Key behaviors:** 1. **No minimum delegation**: Any non-zero amount accepted 2. **Registered for epoch 2**: Delegation is recorded and will become active when epoch 2 begins 3. **No rewards in epoch 0**: Since no transactions are processed, no rewards are earned during epoch 0 **Is a delegation made in epoch 0 active in epoch 2?** Yes. Delegations made in epoch 0 become active in epoch 2 (epoch 1 is skipped). Unlike normal epochs where you wait +2 epochs, epoch 0 delegations activate as soon as the network becomes operational. ### Activation Timeline Comparison **Normal Epochs (2+):** ``` Epoch N: validatorJoin() or delegatorJoin() called Epoch N+1: validatorPrime() stages the deposit Epoch N+2: validatorPrime() activates the deposit → NOW ACTIVE ``` **Epoch 0 (Bootstrapping):** ``` Epoch 0: validatorJoin() or delegatorJoin() called → stake registered (not yet active) No transactions processed, no consensus Epoch 2: Stakes become active (if minimum met), network operational, validatorPrime() required ``` ### Share Calculation in Epoch 0 In epoch 0, shares are calculated at a 1:1 ratio with the input amount: ```solidity // Epoch 0: 1,000 GEN deposit = 1,000 shares (1:1 ratio) genStaking.delegatorJoin{value: 1000 ether}(validatorWallet); // Result: delegator receives exactly 1,000 shares // Normal epochs: shares depend on pool ratio // new_shares = deposit_amount × (total_shares / total_stake) ``` This is because there's no existing stake pool to calculate a ratio against. Starting from epoch 2, shares are calculated based on the current stake-to-share ratio. ### Transitioning from Epoch 0 to Epoch 2 When the network advances from epoch 0 to epoch 2 (epoch 1 is skipped): 1. **Epoch 0 stakes that meet minimums become active** - validators need 42,000 GEN, delegators need 42 GEN 2. **Normal minimum requirements apply** for new joins/deposits 3. **+2 epoch activation delay** applies to all new deposits 4. **validatorPrime() becomes mandatory** for validators to remain in the selection pool 5. **Existing validators** must ensure their nodes begin calling `validatorPrime()` in epoch 2 ### FAQ: Epoch 0 Special Cases **Q: Can I join as a validator with less than 42,000 GEN in epoch 0?** A: Yes, any non-zero amount is accepted during epoch 0. However, you will **not be active** in epoch 2 unless you have at least 42,000 GEN staked by then. **Q: If I delegate in epoch 0, when does it become active?** A: In epoch 2. Unlike normal epochs with a +2 delay, epoch 0 delegations activate when the network becomes operational. **Q: Do I need to call validatorPrime() in epoch 0?** A: No. Priming is not required during epoch 0. Your node should start calling it automatically when epoch 2 begins (epoch 1 is skipped). **Q: Will my epoch 0 stake still be active after epoch 0 ends?** A: Yes, if you meet the minimum requirements. Stakes from epoch 0 carry forward and remain active in all subsequent epochs. **Q: What happens to my stake if I joined in epoch 0 but my node doesn't call validatorPrime() in epoch 2?** A: You'll be excluded from validator selection in epoch 4, but your stake remains. Once priming resumes, you'll be eligible for selection again. --- ## Common Scenarios ### Scenario 1: Becoming a Validator ```solidity address validatorWallet = genStaking.validatorJoin{value: 42000 ether}(operatorAddress); // Start validator node with operator address // Monitor: Epoch N joined, N+1 staged, N+2 active ``` ### Scenario 2: Delegating to Multiple Validators ```solidity genStaking.delegatorJoin{value: 1000 ether}(validator1); genStaking.delegatorJoin{value: 2000 ether}(validator2); genStaking.delegatorJoin{value: 1500 ether}(validator3); // Later, exit from one validator uint256 shares = genStaking.sharesOf(msg.sender, validator1); genStaking.delegatorExit(validator1, shares); // After 7 epochs: genStaking.delegatorClaim(msg.sender, validator1); ``` ### Scenario 3: Partial Validator Exit ```solidity uint256[8] memory state = genStaking.validatorView(validatorWallet); uint256 currentShares = state[1]; uint256 sharesToExit = (currentShares * 25) / 100; // Exit 25% validatorWallet.validatorExit(sharesToExit); // After 7 epochs: genStaking.validatorClaim(validatorWallet); ``` --- ## Best Practices ### For Validators 1. **Ensure node health**: Your validator node automatically calls `validatorPrime()` 2. **Use separate keys**: Cold wallet for owner, hot wallet for operator 3. **Monitor priming**: Verify deposit activation occurs as expected 4. **Monitor quarantine status**: Check if your validator is quarantined 5. **Maintain high uptime**: Downtime leads to idleness strikes 6. **Set up backup monitoring**: Alert if priming fails ### For Delegators 1. **Diversify**: Spread stake across multiple validators 2. **Select carefully**: Choose validators with good uptime records 3. **Verify priming**: Ensure validators are consistently primed 4. **Consider smaller validators**: They often provide higher returns 5. **Monitor health**: Regularly check validator status 6. **Use shares for exits**: Calculate percentages, not absolute amounts ### For Both 1. **Account for unbonding**: Plan for the 7-epoch wait when exiting 2. **Monitor epochs**: Track current epoch for claim eligibility 3. **Calculate exits carefully**: Always use share percentages 4. **Understand compounding**: Rewards automatically increase stake-per-share 5. **Watch governance**: Parameter changes can affect staking dynamics --- ## Troubleshooting | Error | Cause | Solution | |-------|-------|----------| | `ValidatorBelowMinimumStake` | Stake below 42,000 GEN | Deposit at least 42,000 GEN when joining | | `OperatorAlreadyAssigned` | Operator address in use | Choose a different operator address | | `ValidatorMayNotDepositZeroValue` | Zero deposit amount | Deposit a non-zero amount | | `ValidatorExitExceedsShares` | Exiting more shares than owned | Check shares with `validatorView()` | | Validator not selected | Node not priming | Ensure node runs and calls `validatorPrime()` | | Stake not activating | Priming not occurring | Monitor node for automatic `validatorPrime()` calls | | Cannot claim withdrawn funds | Unbonding not complete | Verify 7 epochs have passed with `genStaking.epoch()` | | Delegation not earning | Validator issues | Check if validator is quarantined/banned; consider switching | --- ## Related Resources - [Staking Concepts](/understand-genlayer-protocol/core-concepts/optimistic-democracy/staking) - How staking works in GenLayer - [Unstaking](/understand-genlayer-protocol/core-concepts/optimistic-democracy/unstaking) - Unstaking process details - [Slashing](/understand-genlayer-protocol/core-concepts/optimistic-democracy/slashing) - Slashing penalties and conditions - [GenLayer CLI Staking Commands](/api-references/genlayer-cli#staking-operations-testnet) - CLI reference for staking # validators/setup-guide.mdx import { Callout } from "nextra-theme-docs"; # Setting Up Your GenLayer Validator Running a GenLayer Validator node ensures the security and reliability of the GenLayer network. Below are the requirements for running a GenLayer validator. For a deeper understanding of how staking works in GenLayer, see the [Staking documentation](/understand-genlayer-protocol/core-concepts/optimistic-democracy/staking). ## Create the Validator Wallet Before setting up your validator node, you need to create your validator wallet and stake GEN tokens. ### Understanding Validator Addresses GenLayer validators use three distinct addresses: | Address | Description | Where Used | |---------|-------------|------------| | **Owner** | The only address that can withdraw staked funds. Keep this secure (cold wallet). | CLI wizard - signs staking transaction | | **Operator** | Hot wallet on your server that signs blocks. Can be same as owner, but separate is recommended. | Node config: `operatorAddress` | | **Validator Wallet** | Smart contract created when you join. This is your validator's on-chain identity. | Node config: `validatorWalletAddress` | The wizard outputs all three addresses at the end. Save them - you'll need the Validator Wallet and Operator addresses for your node configuration. ### Prerequisites - **Node.js** (v18 or higher) - **GenLayer CLI** - Install the latest version: ```bash npm install -g genlayer ``` - **GEN tokens** - You need at least **42,000 GEN** for the minimum self-stake requirement ### Using the Validator Wizard The easiest way to create your validator wallet is using the interactive wizard: ```bash genlayer staking wizard ``` The wizard guides you through: 1. **Account setup** - Create or select your owner account 2. **Network selection** - Choose testnet-asimov 3. **Balance verification** - Confirms you have at least 42,000 GEN 4. **Operator setup** - Create and export an operator keystore for your validator server 5. **Stake amount** - Enter how much GEN to stake (minimum 42,000) 6. **Validator creation** - Submits the staking transaction 7. **Identity setup** - Set your validator's public profile (moniker, website, etc.) **Save Your Validator Wallet Address!** After the wizard completes, note down your **Validator Wallet** address. You'll need this for your node configuration. #### Operator Keystore Export The wizard creates and exports an operator keystore file for you to transfer to your validator server. If your server is compromised, your staked funds (controlled by owner) remain safe. ### Verify Your Validator After completing the wizard, verify your status: ```bash genlayer staking validator-info --validator 0xYourValidatorWallet... ``` ### Managing Your Validator ```bash # Add more stake genlayer staking validator-deposit --amount 1000gen # Check active validators genlayer staking active-validators # Exit (initiates 7-epoch unbonding) genlayer staking validator-exit --shares 100 # Claim after unbonding period genlayer staking validator-claim # Update identity genlayer staking set-identity --validator 0x... --moniker "New Name" ``` --- ## Set Up the Validator Node Once your validator wallet is created and staked, set up your node software. ### Dependencies #### LLM Access Each validator needs access to a Large Language Model (LLM) for executing and evaluating Intelligent Contracts. It is up to each validator to select the model they want to use. Possible options: - Run an open-source model locally on the same machine with a GPU - Run an open-source model on a different machine - Connect to a hosted inference provider (OpenAI, Anthropic, Heurist, Atoma network etc.) #### ZKSync Full Node for the GenLayer Chain Each validator needs access to a [ZKSync Full Node](https://docs.zksync.io/zksync-era/tooling/external-node) connected to the GenLayer chain. Validators use this node to read the chain state and submit transactions. One full node can be shared between multiple validators. The optimal validator-to-node ratio is currently under evaluation. ### System Requirements Below are the **initial** recommended system requirements. These guidelines may change as the network grows and evolves. #### RAM - **Recommended:** 16 GB - **Why:** - GenLayer's _genvm_ can spawn multiple Sub-VMs for contract calls and non-deterministic blocks. - Each Sub-VM can consume up to ~4 GB of RAM for storage. #### CPU - **Recommended:** Modern multi-core processor with at least 8 cores/16 threads #### Architecture - **Recommended:** `AMD64` - `ARM64` is not supported at this time #### Storage - **Recommended Disk Space:** 128 GB+ - **Preferred Type:** SSD or NVMe (M.2) #### Network - 100 Mbps connection - **Recommended:**: 1 Gbps+ #### GPU (Optional) - GPU is **Not Required** - If you want to run LLMs locally, you will need to select appropriate hardware (typically a CUDA-compatible GPU with sufficient VRAM for the model you intend to use) These requirements are a starting point. As GenLayer evolves and usage patterns change (e.g., more complex AI-driven Intelligent Contracts), the recommended hardware may change. #### Software - Operating System - 64-bit Linux (Ubuntu, Debian, CentOS, etc.) - `docker` - for running the WebDriver container - `python3`, `python3-pip` and `python3-venv` for GenVM setup ### Setup #### Download the node software 1. Select the version of the node you want to run by checking the available builds You can use this command to list available versions: ```sh curl -s "https://storage.googleapis.com/storage/v1/b/gh-af/o?prefix=genlayer-node/bin/amd64" | grep -o '"name": *"[^"]*"' | sed -n 's/.*\/\(v[^/]*\)\/.*/\1/p' | sort -ru ``` You should see a list like this ```sh v0.4.1 v0.4.0 v0.3.11 v0.3.10 v0.3.9 v0.3.8 v0.3.7 v0.3.6 v0.3.5 v0.3.4 v0.3.3 v0.3.2 v0.3.1 v0.3.0 v0.2.0-testnet007 v0.2.0-testnet005 v0.2.0-testnet004 v0.2.0-testnet003 v0.2.0-testnet002 v0.2.0-testnet001 ``` Typically, you will want to run the latest version 2. Download the packaged application ```sh export version=v0.4.1 # set your desired version here wget https://storage.googleapis.com/gh-af/genlayer-node/bin/amd64/${version}/genlayer-node-linux-amd64-${version}.tar.gz ``` 3. Extract the node software ```sh mkdir -p ${version} tar -xzvf `genlayer-node-linux-amd64-${version}.tar.gz` -C `./${version}` ``` 4. Change the directory ```sh cd `./${version}` ``` 5. Run Genvm setup ```sh python3 ./third_party/genvm/bin/setup.py ``` It does following: - Downloads missing runners if any - Verifies runners hashes - Sets `elf`/`mach-o` interpreter for all binaries (modules, genvm) - Rust precompilation for built-in runners ### Configuration Before you can start up the node, you need to configure it. #### `config.yaml` This is the main configuration file of your node. Without it, your node won't start The file needs to be located at `configs/node/config.yaml` You can use the following example configuration. **Note:** For most users, you will only need to modify the `zksyncurl` and `zksyncwebsocketurl` values below. ```yaml # rollup configuration rollup: genlayerchainrpcurl: "TODO: Set your GenLayer Chain ZKSync HTTP RPC URL here" # GenLayer Chain RPC URL genlayerchainwebsocketurl: "TODO: Set your GenLayer Chain ZKSync WebSocket RPC URL here" # GenLayer Chain WebSocket URL # consensus contracts configuration consensus: # Asimov - Phase 4 contractmainaddress: "0x67fd4aC71530FB220E0B7F90668BAF977B88fF07" # ConsensusMain Smart Contract Address contractdataaddress: "0xB6E1316E57d47d82FDcEa5002028a554754EF243" # ConsensusData Smart Contract Address genesis: 4632386 # (Optional) Genesis block number for this consensus deployment. If not provided, it will be auto-detected by searching for the first log from the ConsensusMain contract. # data directory datadir: "./data/node" # logging configuration logging: level: "INFO" # json: `true` for json output to console, false for human readable log formatting json: false # Configuration for https://github.com/natefinch/lumberjack file: # enabled: set to `true` to save logs to a folder enabled: true level: "DEBUG" # folder: path to the folder where to store logs. Relative paths go under `datadir`. folder: logs # maxsize: maximum size in megabytes of the log file before it gets rotated. maxsize: 10 # maxage: maximum number of days to retain old log files based on the timestamp encoded in their filename. maxage: 7 # maxbackups: maximum number of old log files to retain. Set to 0 for no limit maxbackups: 100 # localtime: determines if the time used for formatting the timestamps in backup files is the computer's local time. Set to `false` to use UTC time. localtime: false # compress: determines if the rotated log files should be compressed using gzip compress: true # node configuration node: # Uncomment if the ID of the node is different from the validator wallet address. # It is used to identify the node in the network. # id: "node" # Mode can be "validator" or "full". # Default value is "validator". mode: "validator" # Address of the ValidatorWallet contract (required for validator mode) validatorWalletAddress: "" # Address of the operator that owns the ValidatorWallet operatorAddress: "" admin: port: 9155 rpc: port: 9151 # RPC server port endpoints: # Group-level configuration (enables/disables all methods in a group) groups: genlayer: true # gen_* methods (call, getContractSchema, etc.) genlayer_debug: true # gen_dbg_* methods (ping, load_test, trie) ethereum: true # eth_* proxy methods zksync: true # zks_* proxy methods # Method-level configuration (overrides group settings for specific methods) methods: gen_call: true gen_getContractSchema: true gen_getTransactionStatus: true gen_getTransactionReceipt: true gen_dbg_ping: true gen_dbg_load_test: true eth_blockNumber: true eth_getBlockByNumber: true eth_getBlockByHash: true eth_sendRawTransaction: true zks_getTransaction: true ops: port: 9153 # Metrics port endpoints: metrics: true # Enable metrics endpoint health: true # Enable health endpoint balance: true # Enable balance endpoint # genvm configuration genvm: root_dir: ./third_party/genvm start_manager: true # if true node will start genvm manager itself manager_url: http://127.0.0.1:3999 permits: # Leave empty for autodiscovery, put a number for updating genvm permits on startup # Advanced configuration merkleforest: maxdepth: 16 dbpath: "./data/node/merkle/forest/data.db" indexdbpath: "./data/node/merkle/index.db" merkletree: maxdepth: 16 dbpath: "./data/node/merkle/tree/" # metrics configuration metrics: interval: "15s" # Default interval for all collectors (can be overridden per collector) # collectors: # node: # enabled: true # # interval: "30s" # Optional: Override default interval for this collector # genvm: # enabled: true # # interval: "20s" # Optional: Override default interval for this collector # # enable_simulated_traffic: false # Optional: Enable simulated network traffic metrics for GenVM processes (default: false) # # simulated_rx_bytes_per_process: 1024 # Optional: Simulated received bytes per process per interval (default: 1024) # # simulated_tx_bytes_per_process: 512 # Optional: Simulated transmitted bytes per process per interval (default: 512) # webdriver: # enabled: true # # interval: "60s" # Optional: Override default interval for this collector ``` #### Overriding Configuration with Environment Variables Any configuration value in `config.yaml` can be overridden using environment variables with the prefix `GENLAYERNODE_`. **Pattern:** - Replace dots (`.`) with underscores (`_`) - Convert to uppercase - Add the `GENLAYERNODE_` prefix **Examples:** | Config Key | Environment Variable | |------------|---------------------| | `rollup.genlayerchainrpcurl` | `GENLAYERNODE_ROLLUP_GENLAYERCHAINRPCURL` | | `rollup.genlayerchainwebsocketurl` | `GENLAYERNODE_ROLLUP_GENLAYERCHAINWEBSOCKETURL` | | `consensus.contractmainaddress` | `GENLAYERNODE_CONSENSUS_CONTRACTMAINADDRESS` | | `consensus.contractdataaddress` | `GENLAYERNODE_CONSENSUS_CONTRACTDATAADDRESS` | | `consensus.genesis` | `GENLAYERNODE_CONSENSUS_GENESIS` | | `node.mode` | `GENLAYERNODE_NODE_MODE` | | `node.validatorWalletAddress` | `GENLAYERNODE_NODE_VALIDATORWALLETADDRESS` | | `node.operatorAddress` | `GENLAYERNODE_NODE_OPERATORADDRESS` | | `node.rpc.port` | `GENLAYERNODE_NODE_RPC_PORT` | | `logging.level` | `GENLAYERNODE_LOGGING_LEVEL` | **Usage example:** ```sh # Override the RPC port export GENLAYERNODE_CONSENSUS_CONTRACTMAINADDRESS="0x..." # Set validator wallet address export GENLAYERNODE_NODE_VALIDATORWALLETADDRESS="0x..." # Set logging level export GENLAYERNODE_LOGGING_LEVEL="DEBUG" ``` Environment variables take precedence over values in `config.yaml`, making them ideal for Docker deployments or sensitive values you don't want in configuration files. #### GenVM Configuration You need to set up an LLM for your node to use to provide answers to natural language prompts. You can use any LLM you wish, however the quality of its answers will affect the performance of your node. GenLayer has partnered with multiple LLM providers to offer free credits for validators: **[Heurist](https://www.heurist.ai/)** - A Layer 2 network for AI model hosting and inference, built on the ZK Stack. It offers serverless access to open-source AI models through a decentralized network. GenLayer Validators can obtain free [Heurist API credits](https://dev-api-form.heurist.ai) by using the referral code: _"genlayer"_. **[Comput3](https://genlayer.comput3.ai/)** - A decentralized compute network providing access to various AI models. GenLayer Validators can use the Comput3.ai inferencing API with access to llama3, hermes3 and qwen3 models. Validators can obtain free [Comput3 API credits](https://genlayer.comput3.ai/) to get started with their validator setup. **[io.net](/partners/ionet)** - A decentralized compute network providing GPU access for AI inference. GenLayer Validators can create an account at [id.io.net](https://id.io.net/login) and obtain free credits by [filling out this form](https://form.typeform.com/to/pDmCCViV). The GenVM configuration files are located at `third_party/genvm/config/` #### `genvm-module-llm.yaml` This is the configuration file of the LLM module. In this file you can set up and configure various LLM providers, as well as the system prompts of your validator. You can turn on and off various LLMs by setting the `enabled` field to `false`. At this stage, select one LLM and set all other to disabled. Note environment variable names for LLM API keys (e.g., `HEURISTKEY`, `COMPUT3KEY`, `IOINTELLIGENCE_API_KEY`). You will need to ensure the appropriate key is correctly set before [running the node](#running-the-node). #### `genvm-module-web.yaml` This is the configuration of webdriver module that enables the GenVM to access the internet. You should not need to modify this. #### `genvm-manager.yaml` This is the configuration of the GenVM manager. You should not need to modify this. However, if you are running the node on macos (natively), you may want to set `permits` to some large value, as auto-detection is not supported there yet, such as `32`. #### Greyboxing LLMs Greyboxing is a way to further customise your LLM setup to improve its performance as well as security. Greyboxing is an advanced feature. Familiarity with Lua scripting and LLM prompt engineering is recommended for customization. `genvm-modules llm` provides user with ability to customize [greyboxing](/_temp/security-and-best-practices/grey-boxing) via lua scripting. Right now users can customize prompt templates, specify temperature and system prompt. Related scripts are located at: 1. `./scripts/genvm-greyboxing.lua` – user defined script 2. `./share/lib/genvm/greyboxing/lib-greyboxing.lua` – more low-level library More features and built-in filters will be added soon #### Import the Operator Key The operator key is used by your node to sign blocks and perform validator duties. #### Option 1: Import from CLI Wizard (Recommended) If you used `genlayer staking wizard`, it exported an operator keystore file. Transfer this file to your validator server and import it: ```sh ./bin/genlayernode account import \ --password "your node password" \ --passphrase "password you set when exporting from wizard" \ --path "/path/to/operator-keystore.json" \ -c $(pwd)/configs/node/config.yaml \ --setup ``` You should see: ```sh Account imported: Address: 0xA0b12Fd2f3F7e86fEC458D114A5E7a6f571160a8 Account setup as a validator ``` #### Option 2: Generate New Operator Key You can also generate a new operator key directly on the server: ```sh ./bin/genlayernode account new -c $(pwd)/configs/node/config.yaml --setup --password "your secret password" ``` Then use this address when running the wizard on your local machine. #### Restoring Your Operator Key To restore from a backup (e.g., after migrating to a new server): ```sh ./bin/genlayernode account import \ --password "your node password" \ --passphrase "your backup encryption passphrase" \ --path "/path/to/your/secure/backup.key" \ -c $(pwd)/configs/node/config.yaml \ --setup ``` Always verify that your imported key works by checking the operator address matches what's configured for your validator. #### Backing Up Your Operator Key After setting up your operator key, back it up securely: ```sh ./bin/genlayernode account export \ --password "your node password" \ --address "your operator address" \ --passphrase "your backup encryption passphrase" \ --path "/path/to/your/secure/backup.key" \ -c $(pwd)/configs/node/config.yaml ``` **Important: Back up your operator key!** Losing access means you'll need to set up a new operator and update your validator configuration. Store the backup securely. To print the private key from your backup file, use the `--print` flag. **Keep this private key secure and never share it.** ### Running the node Once you have configured everything, you are ready to start the node. **Important:** Before starting the node, ensure you have: 1. **Operator key** imported into the node (see "Import the Operator Key" above) 2. **Validator wallet address** - obtained after joining as validator via `genlayer staking wizard` or `validator-join` Without both configured, your node will run as a full node instead of a validator. #### Running the Node using the binary 1. Set the LLM Provider API Key Set the appropriate environment variable for your chosen LLM provider: ```sh # For Heurist export HEURISTKEY='your_heurist_api_key' # For Comput3 export COMPUT3KEY='your_comput3_api_key' # For io.net export IOINTELLIGENCE_API_KEY='your_ionet_api_key' # For other providers, use the appropriate environment variable name ``` 2. Run the WebDriver container ```sh docker compose up -d # Starts the WebDriver needed by the GenVM web module ``` 3. (Optional) Run two services (modules) in background (this is a crucial step for running _Intelligent_ contracts). This can be done automatically or manually. - To start them automatically in node configuration set `genvm.manage_modules` to `true` - To start them manually run ```bash ./third_party/genvm/bin/genvm-modules web & ./third_party/genvm/bin/genvm-modules llm & ``` Note: If you are using the default configuration, `genvm.manage_modules` is set to `true` by default, meaning the node will manage these modules automatically. 4. Checking Your Configuration To ensure your node is correctly configured, you can run the following command: ```sh ./bin/genlayernode doctor ``` The `doctor` command now includes comprehensive GenVM diagnostics integration to validate: - Consensus contract configuration and accessibility - GenVM module connectivity and health status - LLM provider configuration and API connectivity - Network configuration and ZKSync node accessibility 5. Run the node ```sh ./bin/genlayernode run -c $(pwd)/configs/node/config.yaml --password "your secret password" # The same password you used when creating the account ``` If you are running the node via SSH, the process might terminate if your connection drops. To prevent this, consider using a terminal multiplexer like `screen` or `tmux` to keep the node running in the background even if your SSH session ends. You can find a guide on using `screen` [here](https://www.networkworld.com/article/967925/how-the-linux-screen-tool-can-save-your-tasks-and-your-sanity-if-ssh-is-interrupted.html). #### Running the Node using docker-compose You can also run the GenLayer node using Docker and Docker Compose. 1. Create a `docker-compose.yaml` file with the following content: ```yaml services: webdriver-container: container_name: genlayer-node-webdriver image: yeagerai/genlayer-genvm-webdriver:0.0.9 shm_size: 2gb security_opt: - no-new-privileges:true environment: PORT: 4444 ports: - "${WEBDRIVER_PORT:-4444}:4444" restart: unless-stopped genlayer-node: image: yeagerai/genlayer-node:${NODE_VERSION:-latest} entrypoint: ["sh", "-c", "/app/bin/genlayernode run --password ${NODE_PASSWORD:-12345678}"] container_name: genlayer-node restart: unless-stopped env_file: - path: ./.env required: false ports: - "${NODE_RPC_PORT:-9151}:9151" - "${NODE_OPS_PORT:-9153}:9153" volumes: - ${NODE_CONFIG_PATH:-./configs/node/config.yaml}:/app/configs/node/config.yaml:ro - ${NODE_DATA_PATH:-./data}:/app/data - ./genvm-module-web-docker.yaml:/app/third_party/genvm/config/genvm-module-web.yaml security_opt: - no-new-privileges:true logging: driver: "json-file" options: max-size: "100m" max-file: "3" compress: "true" depends_on: - webdriver-container profiles: - node ``` 2. Create `genvm-module-web-docker.yaml` for Docker networking: The extracted tarball includes `third_party/genvm/config/genvm-module-web.yaml` configured for `localhost`, which works when running the binary directly. For docker-compose, you need a version that points to the webdriver service name. Create `genvm-module-web-docker.yaml` in the same directory as your `docker-compose.yaml`: - Copy the contents of `third_party/genvm/config/genvm-module-web.yaml` into `genvm-module-web-docker.yaml`. - Modify the `webdriver_host` configuration to use the service name `webdriver-container` instead of `localhost`: ```yaml webdriver_host: http://webdriver-container:4444 ``` This allows the node container to reach the webdriver container using Docker's internal networking. The key difference: - **Binary execution**: uses `localhost:4444` (webdriver runs on same machine) - **Docker-compose**: uses `webdriver-container:4444` (container service name) 3. Set the required environment variables in a `.env` file: This `.env` file serves two purposes: it configures Docker Compose variables (like `NODE_VERSION`, `NODE_PASSWORD`, ports) and can also include `GENLAYERNODE_*` variables to override node configuration values as described in [Overriding Configuration with Environment Variables](#overriding-configuration-with-environment-variables). ```env # GenLayer Node Release Configuration # ============================================================================= # WebDriver Configuration (required for GenVM) # ============================================================================= WEBDRIVER_PORT=4444 # ============================================================================= # Node Service Configuration (optional - use node profile) # ============================================================================= # Docker image version NODE_VERSION=v0.4.0 # Keystore password (used to unlock the pre-imported wallet) NODE_PASSWORD=12345678 # Path to node configuration file NODE_CONFIG_PATH=./configs/node/config.yaml # Path to node data directory (for persistence) NODE_DATA_PATH=./data # Port mappings NODE_RPC_PORT=9151 NODE_OPS_PORT=9153 # LLM API Key (required for GenVM LLM module) HEURISTKEY= ANTHROPICKEY= XAIKEY= GEMINIKEY= ATOMAKEY= ``` or simply use the provided `docker-compose.yaml`, `.env.example` and the `genvm-module-web-docker.yaml` from the extracted tarball. 4. Checking Your Configuration To ensure your node is correctly configured, you can run the following command: ```sh source .env && docker run --rm --env-file ./.env \ -v ${NODE_CONFIG_PATH:-./configs/node/config.yaml}:/app/configs/node/config.yaml \ yeagerai/genlayer-node:${NODE_VERSION:-v0.4.0} \ ./bin/genlayernode doctor ``` 5. Start the services using Docker Compose: ```sh source .env && docker compose --profile node up -d ``` ### Monitoring with Metrics GenLayer validators expose comprehensive metrics that are ready for consumption by Prometheus and other monitoring tools. This allows you to monitor your validator's performance, health, and resource usage. #### Accessing Metrics The metrics endpoint is exposed on the operations port (default: 9153) configured in your `config.yaml`: ```yaml node: ops: port: 9153 # Metrics port endpoints: metrics: true # Enable metrics endpoint ``` Once your node is running, you can access the metrics at: ``` http://localhost:9153/metrics ``` #### Available Metrics The validator exposes various metric collectors that can be individually configured: - **Node Metrics**: Core validator performance metrics including block processing, transaction handling, and consensus participation - **GenVM Metrics**: Virtual machine performance metrics, including execution times and resource usage - **WebDriver Metrics**: Metrics related to web access and external data fetching #### Configuring Metrics Collection You can customize metrics collection in your `config.yaml`: ```yaml metrics: interval: "15s" # Default collection interval collectors: node: enabled: true interval: "30s" # Override interval for specific collector genvm: enabled: true interval: "20s" webdriver: enabled: true interval: "60s" ``` #### Example Metrics Query To check if metrics are working correctly: ```bash # Get all available metrics curl http://localhost:9153/metrics # Check specific metric (example) curl -s http://localhost:9153/metrics | grep genlayer_node_ ``` The metrics endpoint also provides `/health` and `/balance` endpoints on the same port for additional monitoring capabilities. #### Monitoring Best Practices 1. **Set up alerts** for critical metrics like node synchronization status and missed blocks 2. **Monitor resource usage** to ensure your validator has sufficient CPU, memory, and disk space 3. **Track GenVM performance** to optimize LLM provider selection and configuration 4. **Use visualization tools** like Grafana to create dashboards for easy monitoring For production validators, we recommend setting up a complete monitoring stack with Prometheus and Grafana. This enables real-time visibility into your validator's performance and helps identify issues before they impact your validator's operation. #### Logs and metrics forwarding You can forward your logs and metrics to external systems for centralized monitoring and alerting by using the service `alloy` provided in the `docker-compose.yaml` from the extracted tarball. # validators/upgrade.mdx import { Callout } from "nextra-theme-docs"; # Validator upgrade guide For non-breaking changes, you can minimize the downtime by keeping your existing validator node running while you download and configure the new version according to the steps below. Once the upgrade is fully configured and ready to run, stop the old node and start the new one. A fully Zero-downtime upgrade procedure is coming in a future update. ## v0.3.x → v0.4 (Breaking Change) `v0.4` switches to a new consensus deployment with staking. For this reason, the validator must be set up from scratch without reusing the old database stored at `data/node/genlayer.db`. You do not need to keep your existing validator node running while you download and configure the new version. This release involves a change from a single validator address to owner/operator separation. You will need to follow the [setup guide](/validators/setup-guide) to create your new Validator Wallet. **Recommended: Keep your current validator key as the operator key** To maintain continuity, retain your current keystore and use your existing validator address as the operator address when following the setup guide. You can find your current validator address in `configs/node/wallet.yaml`. - Stop the node if it is running. - Note your current validator address from `configs/node/wallet.yaml` - you'll use this as your operator address. - Back up the `configs/node/config.yaml` file so that you can refer to any values you have set in the previous version. - Back up the `data/node/keystore` folder so that you can maintain your previous operator key. - Download the packaged binary. - Install the new version. - Remove the storage folder `data/node/genlayer.db`. - Check that configuration is correct by running `genlayernode doctor` command. - Start the node. Assuming already have the new tarball downloaded and extracted, copy your old keystore files to the new installation: ```shell mkdir -p /data/node/keystore/ cp /data/node/keystore/* /data/node/keystore/ ``` ## Configuration Change `v0.3.8` introduces updated consensus contract deployment with new contract addresses. **Critical**: Some consensus contract addresses have changed, and validators must update their consensus configuration to continue participating in the network. - Stop the node if it is running. - Back up your `configs/node/config.yaml` file to preserve your current settings. - Download and install the new `v0.3.8` packaged binary. - **Update the new configuration with any changes you had previously applied (you can check your config.yaml backup) and make sure you have the following consensus contracts** in your `configs/node/config.yaml`: ```yaml consensus: # Asimov - Phase 3 contractmanageraddress: "0x0761ff3847294eb3234f37Bf63fd7F1CA1E840bB" # ConsensusManager Smart Contract Address contractmainaddress: "0xe30293d600fF9B2C865d91307826F28006A458f4" # ConsensusMain Smart Contract Address contractdataaddress: "0x2a50afD9d3E0ACC824aC4850d7B4c5561aB5D27a" # ConsensusData Smart Contract Address contractidlenessaddress: "0xD1D09c2743DD26d718367Ba249Ee1629BE88CF33" # Idleness Smart Contract Address contractstakingaddress: "0x31Cb4018ccB7d4F30419d367b6C5c7677AAE30E7" # Staking Smart Contract Address genesis: 817855 # Genesis block number for this consensus deployment ``` - **Verify your configuration** by running `genlayernode doctor` - this will validate all contract addresses and connectivity. - Start the node with the updated configuration. **Critical: Staking Address Update Required** Failure to update the consensus contract addresses will prevent your validator from: - Participating in consensus rounds - Being selected as an activator, a leader or activator The `doctor` command will now specifically validate these addresses - ensure it passes before starting your node. ## v0.2 → v0.3 (Breaking Change) `v0.3` switches to a new consensus deployment. For this reason, the validator must be set up from scratch without reusing the old database stored at `data/node/genlayer.db`. You do not need to keep your existing validator node running while you download and configure the new version. - Stop the node if it is running. - Back up the configs/node/config.yaml file so that you can refer to any values you have set in the previous version. - Download the packaged binary. - Install the new version. - Remove the storage folder `data/node/genlayer.db`. - Check that configuration is correct by running `genlayernode doctor` command. - Start the node. Install the new version in the same directory as the previous installation. This ensures that any paths referenced in the configuration remain the same and helps maintain continuity in your setup. If you want to install the new version in a different directory, copy your `data/keystore` and `configs/node/wallet.yaml` to the new directory to keep using the same wallet. ## v0.1.0-testnet008 → v0.2.0-testnet001 - GenVM configuration has changed, please follow the new instructions in the GenVM configuration section in the validator setup guide. - Back up the `configs/node/config.yaml`, `configs/node/wallet.yaml`, and `data/node/keystore` folders so you can retain your previous configuration and wallet access. # validators/changelog.mdx # Changelog ## v0.4.1 ### New features - Add show and list subcommands for account management - Split authentication credentials for Prometheus and Loki - Add IsPrimed health check for unprimed validators - Add primed state and warning for unprimed validators ### Misc - Refactor txcalldata decoding to a new encoding package - Remove unused `pkg/cryptoutils/address.go` - Update deployment configuration options for network and cleanup - Refactor gas estimator ### Bug fixes - Implement indefinite retry for validator priming until primed - Implement health check and timeout handling for GenVM manager - Fix undetermined transaction rotations when ProcessIdleness - Improve message handling to prevent dropped events - Add GenVM contracts cache and enhance sync progress logging - Fix sync filtering process - Improve messages around genlayerRPC chain connectivity - Stop retrying activation after transaction is activated ## v0.4.0 ### New features - Integrate the latest GenLayer Consensus version v0.4 with Staking - Introduce validator wallet - Handle validator priming - Finalize epochs - Advance epochs when epochs finalize - Handle automatic gas increase - Implement ProcessIdleness and enhance event subscription - Handle validator commit idleness for leader - Implement leader idleness detection and rotation - Add detailed ban information with epoch and permanent flag - Handle unfinished transactions with batch finalization - Add nonceSafe for granular transaction locking - Add sanity check for operator address in validator wallet configuration - Add missing fields from consensus transaction data to API response - Add validator telemetry push monitoring - Add actionable fix suggestions to WebDriver error messages in doctor command - Add zkSync connectivity checks - Add Staking Contract address comparison to doctor checks - Add libertai as a new LLM provider - Add transaction count metrics for consensus roles - Implement consensus sync status metrics - Add TimeoutsSet event router for dynamic timeout configuration - Add enhanced transaction failure debugging with trace support - Sync data with finalized and appeal started events - Add timeout delay mechanism for RPC resilience - Add status and blockNumber parameters to gen_call - Enhance health endpoint with version info and validator with ban and permanent ban detection - Update genvm version to v0.2.7 - Store and expose genvm execution information - Add sign admin endpoint for genvm ### Bug fixes - GenVM architecture on arm64 - Fix sync issue when there are no consensus events - Use latest block instead of timestamp for transaction queries - Update WebDriver check for Puppeteer implementation - Resolve multi-transaction nonce issue - Remove duplicated check logic and fix status check on specific block - Leader rotation timeout and receipt cleanup - Change transaction finalization to allow all nodes to finalize - GenVM non determinism - Add retry logic to prevent validator banning on transient errors - GenVM sanity checks - Cancel context and wait for group when genvm tester fails - Decoding calldata into complex types - Don't try activating already activated transactions - Still process sync failed TX for DB consistency - Add correct encoding for getState - Only sync transactions with ResultCodeReturn and add sanity check - Use block number for transaction data retrieval - Validator votes idleness - Leader idleness - Accidental deadlock in genvm - Lazy validators commit order ### Misc - Simplify environment variable configuration using .env file - Add environment variable override support for config values - Update webdriver image to v0.0.9 - Update RPC and WebSocket endpoints in config.yaml.example - Correct status for validatorTimeout after appeal time window - Validate presence of abigen in dependency check - Rename environment validation functions for clarity - Use cockroachdb errors package for error handling - Remove wallet.yaml file handling - Rename archive to full ## v0.3.11 ### New features - Add validator telemetry push monitoring ### Bug fixes - Validator banning on parallel transactions executions ### Misc - Document health RPC endpoint ## v0.3.10 ### New features - Add actionable fix suggestions to WebDriver error messages in doctor command ### Bug fixes - Add retry logic to prevent validator banning on transient errors ## v0.3.9 ### New features - Add doctor command zkSync connectivity checks ### Misc - Simplify contract initialization with auto-discovery ### Bug fixes - Remove response body size limit for WebDriver ## v0.3.8 ### New features - Add Staking Contract address comparison to doctor checks - Add libertai as a new LLM provider ### Misc - Enhance metrics logging by adding blocks behind calculation - Print address for account not found - Fix typo in telemetry configuration comment ### Bug fixes - Enable CORS support for HTTP methods in the API - Move sync success log after state update - Don't panic with metrics + print panics ## v0.3.7 ### New features - Add transaction count metrics for consensus roles - Implement consensus sync status metrics - Add node uptime collector - Add disk storage usage metrics for monitoring - Add comprehensive metrics collection for ops visibility ## v0.3.6 ### Misc - Add enhanced transaction failure debugging with trace support ## v0.3.5 ### New features - Add Transport with exponential backoff retry logic - Add timeout delay mechanism for RPC resilience - Add status and blockNumber parameters to gen_call - Enhance health endpoint with version info and validator ban detection - Add balance endpoint for validator nodes - Add gas estimation failover to all consensus transaction functions - Implement gen_getContractState endpoint - Add ionet as inference provider - Add gen_getTransactionStatus endpoint - Implement gen_getTransactionReceipt - Add log upload system for validator diagnostics ### Misc - Add comprehensive API documentation system and operations endpoints - Move retry logic to infrastructure and update DI - Improve timeout detection with type-based checking - Enhance WebDriver health check validation ### Bug fixes - Fix validator idleness commit flow - Handle methods and groups configuration for RPC methods ## v0.3.4 ### New features - Added genesis block configuration support for faster node startup - Enhanced `doctor` command with GenVM diagnostics integration - Updated consensus contract addresses for network upgrade ### Misc - Improved node synchronization performance with genesis block hints - Enhanced validator configuration validation and error reporting ## v0.3.3 ### New features - Added [Comput3](/validators/setup-guide#genvm-configuration) as a supported LLM provider for validators ## v0.3.2 ### New features - Add command `doctor` to check Consensus Contract configuration ### Misc - Implement retry logic with double-checked locking for `GetTimeouts` - Update ABI for consensus contracts. - Decode error returns from the network to improve error handling. ## v0.3.1 ### Misc - Add logs details ## v0.3.0 ### New features - Added appeals functionality - Added gen_getContractSchema - Added admin checkpoint endpoint - Added admin "stop at block" endpoint - Handle leader timeout - Handle validator timeout - Added `version` command ### Bug fixes - Mitigate TxAccepted events being dropped - Waiting on event timeouts is now absolute - Patch up genvm timeouts - Add retry mechanism for genvm contracts interaction - Listen to leader timeout event to finalize transaction ## v0.2.0-testnet007 ### New features - Activator idle replacement - Leader idle replacement - Validator idle replacement - Check for genvm on startup - Log file support for node - Ability to export private key in account command ### Bug fixes - Build info logs now display correctly - Fixed config relative path - Node now fails fast when accepted transaction processing fails ### Misc - Updated module github.com/btcsuite/btcd to v0.24.2 (security) - Improved sync speed on node startup ## v0.2.0-testnet005 ### New features - Discover Consensus main genesis from deployment (contracts) ### Bug fixes - All accepted sync transactions are now processed atomically per block - Fixed deadlock on cancelled context ## v0.2.0-testnet004 ### Bug fixes - Updated genvm to v0.0.18 ## v0.2.0-testnet003 ### New features - Updated genvm to v0.0.17 ## v0.2.0-testnet002 ### New features - Use different address to run e2e tests - Updated consensus contract addresses in config ## v0.2.0-testnet001 ### New features - Updated genvm to v0.0.16 ### Bug fixes - Log level is no longer ignored - Revived trie dumping and enhanced logging - Always kill genvm modules ### Misc - Updated module golang.org/x/net to v0.38.0 (security) # api-references.mdx import { Card, Cards } from "nextra-theme-docs"; # api-references/genlayer-cli.mdx # GenLayer CLI Reference Each command includes syntax, usage information, and examples to help you effectively use the CLI for interacting with the GenLayer environment. ## Command line syntax General syntax for using the GenLayer CLI: ```bash genlayer command [command options] [arguments...] ``` ## Version Compatibility The GenLayer CLI always uses the latest compatible version of the environment, ensuring that you benefit from the most recent features, bug fixes, and optimizations without requiring manual updates. If a specific version is needed, you can specify it using the --localnet-version option when initializing the environment. ```bash genlayer init --localnet-version v0.10.2 ``` ## Commands and usage ### Initialize Prepares and verifies your environment to run the GenLayer Studio. ```bash USAGE: genlayer init [options] OPTIONS: --numValidators Number of validators (default: "5") --headless Headless mode (default: false) --reset-db Reset Database (default: false) --localnet-version Select a specific localnet version EXAMPLES: genlayer init genlayer init --numValidators 10 --headless --reset-db --localnet-version v0.10.2 ``` ### Start GenLayer environment Launches the GenLayer environment and the Studio, initializing a fresh set of database and accounts. ```bash USAGE: genlayer up [options] OPTIONS: --reset-validators Remove all current validators and create new random ones (default: false) --numValidators Number of validators (default: "5") --headless Headless mode (default: false) --reset-db Reset Database (default: false) EXAMPLES: genlayer up genlayer up --reset-validators --numValidators 8 --headless --reset-db ``` ### Stop GenLayer environment Stops all running GenLayer Localnet services. ```bash USAGE: genlayer stop ``` ### Create a New GenLayer Project Initialize a new GenLayer project using a local template. ```bash USAGE: genlayer new [options] OPTIONS: --path Specify the directory for the new project (default: ".") --overwrite Overwrite existing directory if it exists (default: false) EXAMPLES: genlayer new myProject genlayer new myProject --path ./customDir genlayer new myProject --overwrite ``` ### Manage CLI Configuration Configure the GenLayer CLI settings. ```bash USAGE: genlayer config [options] COMMANDS: set Set a configuration value get [key] Get the current configuration reset Reset a configuration value to its default EXAMPLES: genlayer config get genlayer config get defaultOllamaModel genlayer config set defaultOllamaModel=deepseek-r1 genlayer config reset keyPairPath ``` ### Deploy and Call Intelligent Contracts Deploy and interact with intelligent contracts. ```bash USAGE: genlayer deploy [options] genlayer call [options] genlayer write [options] genlayer schema [options] OPTIONS (deploy): --contract (Optional) Path to the intelligent contract to deploy --args Positional arguments for the contract (space-separated, use quotes for multi-word arguments) --rpc RPC URL for the network OPTIONS (call): --args Positional arguments for the method (space-separated, use quotes for multi-word arguments) --rpc RPC URL for the network OPTIONS (write): --args Positional arguments for the method (space-separated, use quotes for multi-word arguments) --rpc RPC URL for the network OPTIONS (schema): --rpc RPC URL for the network EXAMPLES: genlayer deploy genlayer deploy --contract ./my_contract.gpy genlayer call 0x123456789abcdef greet --args "Hello World!" genlayer write 0x123456789abcdef setValue --args 42 "New Value" genlayer schema 0x123456789abcdef ``` #### Deploy Behavior - If `--contract` is specified, the command will **deploy the given contract**. - If `--contract` is omitted, the CLI will **search for scripts inside the `deploy` folder**, sort them, and execute them sequentially. #### Call vs Write - **call**: Read-only operations that don't modify contract state. - **write**: Operations that modify contract state and require transaction confirmation. #### Schema Command - Retrieve the contract schema showing all available methods and their parameters. ### Transaction Management Manage and query transaction receipts and appeals. ```bash USAGE: genlayer receipt [options] genlayer appeal [options] OPTIONS (receipt): --status Transaction status to wait for (default: "FINALIZED") Valid values: UNINITIALIZED, PENDING, PROPOSING, COMMITTING, REVEALING, ACCEPTED, UNDETERMINED, FINALIZED, CANCELED, APPEAL_REVEALING, APPEAL_COMMITTING, READY_TO_FINALIZE, VALIDATORS_TIMEOUT, LEADER_TIMEOUT --retries Maximum number of retry attempts (default: 100) --interval Interval between retries in milliseconds (default: 5000) --rpc RPC URL for the network OPTIONS (appeal): --rpc RPC URL for the network EXAMPLES: genlayer receipt 0x1234567890abcdef genlayer receipt 0x1234567890abcdef --status ACCEPTED genlayer receipt 0x1234567890abcdef --status FINALIZED --retries 50 --interval 3000 genlayer receipt 0x1234567890abcdef --rpc http://localhost:8545 genlayer appeal 0x1234567890abcdef genlayer appeal 0x1234567890abcdef --rpc http://localhost:8545 ``` ### Network Management Configure and view network settings. ```bash USAGE: genlayer network set [network] genlayer network info genlayer network list COMMANDS: set [network] Set the network (interactive menu if network not specified) info Show current network configuration and contract addresses list List all available networks EXAMPLES: genlayer network set # Interactive selection menu genlayer network set localnet # Set network to localnet genlayer network set testnet-asimov # Set network to testnet-asimov genlayer network info # Show current network details genlayer network list # List available networks ``` ### Account Management Create and manage accounts with encrypted keystores. ```bash USAGE: genlayer account create [options] genlayer account show [options] genlayer account list genlayer account use genlayer account remove genlayer account lock [options] genlayer account unlock [options] genlayer account export [options] genlayer account import [options] genlayer account send [options] COMMANDS: create Create a new account with encrypted keystore show Show account details and balance list List all accounts use Set an account as active remove Remove an account lock Lock an account (remove cached private key) unlock Unlock an account (cache private key in OS keychain) export Export account to standard web3 keystore format import Import account from keystore file or private key send Send GEN tokens to another address OPTIONS (create): --name Account name (default: "default") --overwrite Overwrite existing account OPTIONS (show): --account Account to show (default: active account) --rpc RPC URL for balance lookup OPTIONS (lock/unlock): --account Account to lock/unlock OPTIONS (export): --account Account to export --output Output file path --password Password for exported keystore OPTIONS (import): --name Name for imported account --keystore Path to keystore file --private-key Private key to import (alternative to keystore) OPTIONS (send): --to
Recipient address --amount Amount to send (e.g., "1.5" or "1.5gen") --account Account to send from EXAMPLES: genlayer account create --name owner genlayer account show genlayer account show --account operator genlayer account list genlayer account use owner genlayer account unlock --account owner genlayer account export --account operator --output ./operator-keystore.json genlayer account import --name backup --keystore ./backup.json genlayer account send --to 0x123... --amount 100gen ``` ### Staking Operations Staking operations for validators and delegators on testnet. ```bash USAGE: genlayer staking wizard [options] genlayer staking validator-join [options] genlayer staking validator-deposit [options] genlayer staking validator-exit [options] genlayer staking validator-claim [options] genlayer staking validator-prime [options] genlayer staking validator-info [options] genlayer staking set-operator [options] genlayer staking set-identity [options] genlayer staking delegator-join [options] genlayer staking delegator-exit [options] genlayer staking delegator-claim [options] genlayer staking delegation-info [options] genlayer staking epoch-info [options] genlayer staking active-validators [options] genlayer staking quarantined-validators [options] genlayer staking banned-validators [options] COMMANDS: wizard Interactive wizard to become a validator validator-join Join as a validator by staking tokens validator-deposit Make an additional deposit as a validator validator-exit Exit as a validator by withdrawing shares validator-claim Claim validator withdrawals after unbonding period validator-prime Prime a validator to prepare stake for next epoch validator-info Get information about a validator set-operator Change the operator address for a validator set-identity Set validator identity metadata (moniker, website, socials) delegator-join Join as a delegator by staking with a validator delegator-exit Exit as a delegator by withdrawing shares delegator-claim Claim delegator withdrawals after unbonding period delegation-info Get delegation info for a delegator with a validator epoch-info Get current epoch and staking parameters active-validators List all active validators quarantined-validators List all quarantined validators banned-validators List all banned validators OPTIONS (wizard): --account Account to use (skip selection) --network Network to use (skip selection) --skip-identity Skip identity setup step OPTIONS (validator-join): --amount Amount to stake (e.g., "42000gen") --operator
Operator address (defaults to signer) --account Account to use OPTIONS (validator-deposit): --validator
Validator wallet address (required) --amount Amount to deposit OPTIONS (validator-exit): --validator
Validator wallet address (required) --shares Number of shares to withdraw OPTIONS (validator-claim): --validator
Validator wallet address (required) OPTIONS (validator-prime): --validator
Validator address to prime OPTIONS (set-operator): --validator
Validator wallet address --operator
New operator address OPTIONS (set-identity): --validator
Validator wallet address --moniker Validator display name (required) --website Website URL --description Description --twitter Twitter handle --github GitHub handle OPTIONS (delegator-join): --validator
Validator to delegate to --amount Amount to stake OPTIONS (delegator-exit): --validator
Validator to exit from --shares Number of shares to withdraw OPTIONS (delegation-info): --validator
Validator address --delegator
Delegator address (defaults to signer) COMMON OPTIONS: --network Network to use (localnet, testnet-asimov) --rpc RPC URL for the network --staking-address Override staking contract address EXAMPLES: # Become a validator using the interactive wizard genlayer staking wizard # Join as validator manually genlayer staking validator-join --amount 42000gen --operator 0x123... # Check validator status genlayer staking validator-info # Set validator identity genlayer staking set-identity --validator 0x123... --moniker "My Validator" --website "https://example.com" # Delegate to a validator genlayer staking delegator-join --validator 0x123... --amount 1000gen # Check your delegation info genlayer staking delegation-info --validator 0x123... # Check epoch info genlayer staking epoch-info # List active validators genlayer staking active-validators ``` ### Account Management View and manage your account. ```bash USAGE: genlayer account Show account info (address, balance, network, status) genlayer account create [options] Create a new account genlayer account import [options] Import an account from a private key genlayer account send Send GEN to an address genlayer account unlock Unlock account (cache key in OS keychain) genlayer account lock Lock account (remove key from OS keychain) OPTIONS (create): --output Path to save the keystore (default: "./keypair.json") --overwrite Overwrite existing file (default: false) OPTIONS (import): --private-key Private key to import (will prompt if not provided) --output Path to save the keystore (default: "./keypair.json") --overwrite Overwrite existing file (default: false) EXAMPLES: genlayer account genlayer account create genlayer account create --output ./my_key.json --overwrite genlayer account import genlayer account import --private-key 0x1234...abcd genlayer account import --private-key 0x1234...abcd --output ./imported.json genlayer account send 0x123...abc 10gen genlayer account send 0x123...abc 0.5gen genlayer account unlock genlayer account lock ``` ### Update Resources Manage and update models or configurations. ```bash USAGE: genlayer update ollama [options] OPTIONS: --model [model-name] Specify the model to update or pull --remove Remove the specified model instead of updating EXAMPLES: genlayer update ollama genlayer update ollama --model deepseek-r1 genlayer update ollama --model deepseek-r1 --remove ``` ### Localnet Validator Management Manage localnet validator operations. ```bash USAGE: genlayer localnet validators [options] COMMANDS: get [--address ] Retrieve details of a specific validator or all validators delete [--address ] Delete a specific validator or all validators count Count all validators update [options] Update a validator details create-random [options] Create random validators create [options] Create a new validator OPTIONS (update): --stake New stake for the validator --provider New provider for the validator --model New model for the validator --config New JSON config for the validator OPTIONS (create-random): --count Number of validators to create (default: "1") --providers Space-separated list of provider names (e.g., openai ollama) --models Space-separated list of model names (e.g., gpt-4 gpt-4o) OPTIONS (create): --stake Stake amount for the validator (default: "1") --config Optional JSON configuration for the validator --provider Specify the provider for the validator --model Specify the model for the validator EXAMPLES: genlayer localnet validators get genlayer localnet validators get --address 0x123456789abcdef genlayer localnet validators count genlayer localnet validators delete --address 0x123456789abcdef genlayer localnet validators update 0x123456789abcdef --stake 100 --provider openai --model gpt-4 genlayer localnet validators create genlayer localnet validators create --stake 50 --provider openai --model gpt-4 genlayer localnet validators create-random --count 3 --providers openai --models gpt-4 gpt-4o ``` ### Staking Operations (Testnet) Manage staking for validators and delegators on testnet-asimov. ```bash USAGE: genlayer staking [options] VALIDATOR COMMANDS: validator-join Join as a validator by staking tokens validator-deposit Make an additional deposit as a validator validator-exit Exit as a validator by withdrawing shares validator-claim Claim validator withdrawals after unbonding period validator-prime Prime a validator to prepare for next epoch validator-info Get information about a validator set-operator Change the operator address for a validator set-identity Set validator identity metadata DELEGATOR COMMANDS: delegator-join Join as a delegator by staking with a validator delegator-exit Exit as a delegator by withdrawing shares delegator-claim Claim delegator withdrawals after unbonding period stake-info Get stake info for a delegator with a validator INFO COMMANDS: epoch-info Get current epoch and staking parameters active-validators List all active validators quarantined-validators List all quarantined validators banned-validators List all banned validators OPTIONS (validator-join): --amount Stake amount (e.g., "42000gen") --operator
Optional operator address for the validator --staking-address Override staking contract address OPTIONS (delegator-join): --validator
Validator address to delegate to (required) --amount Amount to stake (e.g., "100gen") --staking-address Override staking contract address OPTIONS (validator-exit/validator-claim): --validator
Validator wallet address (required) --shares Number of shares to withdraw (exit only) OPTIONS (delegator-exit/delegator-claim): --validator
Validator address (required) --shares Number of shares to withdraw (exit only) --staking-address Override staking contract address OPTIONS (set-identity): --validator
Validator address (required) --moniker Display name (required) --website Website URL --description Description --twitter Twitter handle --telegram Telegram handle --github GitHub handle --email Contact email --logo-uri Logo image URL EXAMPLES: # Join as validator with 42000 GEN stake genlayer staking validator-join --amount 42000gen # Join with separate operator address (recommended for security) genlayer staking validator-join --amount 42000gen --operator 0xOperator... # Set validator identity genlayer staking set-identity --validator 0x... --moniker "My Validator" --website "https://example.com" # Add more stake to validator genlayer staking validator-deposit --validator 0xValidatorWallet... --amount 1000gen # Check epoch info (includes inflation data) genlayer staking epoch-info # Get validator info genlayer staking validator-info --validator 0x... # Delegate to a validator genlayer staking delegator-join --validator 0x... --amount 100gen # Check stake info (includes projected rewards) genlayer staking stake-info --validator 0x... # Validator exit and claim (requires validator wallet address) genlayer staking validator-exit --validator 0xValidatorWallet... --shares 100 genlayer staking validator-claim --validator 0xValidatorWallet... # Delegator exit and claim (7 epoch unbonding period) genlayer staking delegator-exit --validator 0x... --shares 50 genlayer staking delegator-claim --validator 0x... # List active validators genlayer staking active-validators ``` # api-references/genlayer-js.mdx # GenLayerJS SDK Reference This document describes the key components and methods available in the GenLayerJS SDK for interacting with the GenLayer network, including comprehensive examples and integration patterns. ## Client Creation ### createClient Creates a new GenLayer client instance with various configuration options. ```typescript import { createClient } from 'genlayer-js'; import { localnet, studionet, testnetAsimov } from 'genlayer-js/chains'; // Basic client with localnet chain const client = createClient({ chain: localnet, }); // Client with account for transaction signing const client = createClient({ chain: localnet, account: account, // Optional: Use this account for subsequent calls }); // Client with address only (for MetaMask signing) const client = createClient({ chain: localnet, account: '0x1234...', // Just the address - MetaMask will handle signing }); // Client with custom RPC endpoint const client = createClient({ chain: localnet, endpoint: 'http://localhost:8545', account: account, }); ``` **Parameters:** - `chain`: The chain configuration (localnet, studionet, testnetAsimov) - `account`: (Optional) Can be either: - An account object (from `createAccount()`) for direct signing with private key - A string address (e.g., '0x1234...') for external signing (MetaMask) - `endpoint`: (Optional) Custom RPC endpoint URL **Returns:** A GenLayer client instance ## Account Management ### generatePrivateKey Generates a new private key for account creation. ```typescript import { generatePrivateKey } from 'genlayer-js'; const privateKey = generatePrivateKey(); console.log('Generated private key:', privateKey); ``` **Parameters:** None **Returns:** A new private key as string ### createAccount Creates a new account with a private key for direct transaction signing. This is different from using just an address, as it allows the SDK to sign transactions directly without external wallets. ```typescript import { createAccount } from 'genlayer-js'; // Create account with random private key const account = createAccount(); // Create account with specific private key const privateKey = '0x1234567890abcdef...'; // Replace with actual private key const accountWithKey = createAccount(privateKey); console.log('Account address:', account.address); console.log('Account private key:', account.privateKey); ``` **Parameters:** - `accountPrivateKey`: (Optional) A string representing the private key **Returns:** A new account object with address and privateKey properties **Note:** Use `createAccount()` when you want the SDK to handle transaction signing directly. For MetaMask or other external wallet integration, pass just the address string to `createClient()`. ## Contract Deployment ### initializeConsensusSmartContract Initializes the consensus smart contract before deployment or interaction. ```typescript // Always call this before deploying or interacting with contracts await client.initializeConsensusSmartContract(); ``` ### deployContract Deploys a smart contract to the GenLayer network. ```typescript import { readFileSync } from 'fs'; import { TransactionStatus } from 'genlayer-js/types'; // Read contract code from file const contractCode = readFileSync('./contracts/my_contract.py', 'utf-8'); // Deploy contract const deployParams = { code: contractCode, args: [], // Constructor arguments leaderOnly: false, // Whether only leader can execute }; const transactionHash = await client.deployContract(deployParams); // Wait for deployment to complete const receipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: TransactionStatus.ACCEPTED, retries: 50, interval: 5000, }); console.log('Contract deployed at:', receipt.data?.contract_address); ``` **Parameters:** - `code`: Contract source code as string - `args`: Array of constructor arguments - `leaderOnly`: Boolean indicating if only leader can execute **Returns:** Transaction hash ### Complete Deployment Example ```typescript import { createClient, createAccount } from 'genlayer-js'; import { localnet } from 'genlayer-js/chains'; import { readFileSync } from 'fs'; import { TransactionStatus } from 'genlayer-js/types'; async function deployContract() { // Create client and account for direct signing const account = createAccount(); const client = createClient({ chain: localnet, account: account, // Uses private key for direct signing }); // Alternative: Use address only for MetaMask signing // const client = createClient({ // chain: localnet, // account: '0x1234...', // MetaMask will handle signing // }); // Initialize consensus await client.initializeConsensusSmartContract(); // Read and deploy contract const contractCode = readFileSync('./contracts/football_bets.py', 'utf-8'); const hash = await client.deployContract({ code: contractCode, args: [], leaderOnly: false, }); // Wait for deployment const receipt = await client.waitForTransactionReceipt({ hash, status: TransactionStatus.ACCEPTED, retries: 50, interval: 5000, }); return receipt.data?.contract_address; } ``` ## Contract Interaction ### readContract Reads data from a deployed contract (view functions). ```typescript // Read contract data const result = await client.readContract({ address: contractAddress, functionName: 'get_bets', args: [], }); console.log('Contract data:', result); // Read with parameters const playerPoints = await client.readContract({ address: contractAddress, functionName: 'get_player_points', args: ['0x1234...'], // player_address parameter }); ``` **Parameters:** - `address`: The contract address - `functionName`: The name of the function to call - `args`: An array of arguments for the function call **Returns:** The result of the contract function call ### writeContract Writes data to a deployed contract. ```typescript // Write to contract const transactionHash = await client.writeContract({ address: contractAddress, functionName: 'create_bet', args: ['2024-06-20', 'Spain', 'Italy', 1], // game_date, team1, team2, predicted_winner value: 0n, }); // Wait for transaction confirmation const receipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: TransactionStatus.ACCEPTED, retries: 100, interval: 5000, }); console.log('Transaction confirmed:', receipt); ``` **Parameters:** - `address`: The contract address - `functionName`: The name of the function to call - `args`: An array of arguments for the function call - `value`: (Optional) Amount of native token to send with the transaction **Returns:** The transaction hash ### Complete Contract Interaction Example ```typescript import { createClient, createAccount } from 'genlayer-js'; import { localnet } from 'genlayer-js/chains'; import { TransactionStatus } from 'genlayer-js/types'; async function interactWithContract() { // Option 1: Direct signing with private key const account = createAccount(); const client = createClient({ chain: localnet, account: account, // SDK handles signing }); // Option 2: MetaMask signing (just provide address) // const client = createClient({ // chain: localnet, // account: '0x1234...', // MetaMask handles signing // }); await client.initializeConsensusSmartContract(); const contractAddress = '0x...'; // Your deployed contract address // Read current bets const bets = await client.readContract({ address: contractAddress, functionName: 'get_bets', args: [], }); console.log('Current bets:', bets); // Create a new bet const txHash = await client.writeContract({ address: contractAddress, functionName: 'create_bet', args: ['2024-06-20', 'Spain', 'Italy', 1], value: 0n, }); // Wait for confirmation const receipt = await client.waitForTransactionReceipt({ hash: txHash, status: TransactionStatus.ACCEPTED, }); console.log('Bet created successfully:', receipt); } ``` ## Contract Schema ### getContractSchema Retrieves the schema of a deployed contract, showing all available methods and their parameters. ```typescript // Get schema for a deployed contract const schema = await client.getContractSchema({ address: contractAddress, }); console.log('Contract schema:', schema); // Output example: // { // "ctor": {"kwparams": {}, "params": [["have_coin", "bool"]]}, // "methods": { // "ask_for_coin": { // "kwparams": {}, // "params": [["request", "string"]], // "payable": false, // "readonly": false, // "ret": "null" // }, // "ask_for_coin2": { // "kwparams": {}, // "params": [["request", "string"]], // "payable": false, // "readonly": false, // "ret": "null" // }, // "get_have_coin": { // "kwparams": {}, // "params": [], // "readonly": true, // "ret": "bool" // } // } // } ``` **Parameters:** - `address`: The contract address **Returns:** Contract schema object with constructor and methods information **Schema Structure:** - `ctor`: Constructor information with `kwparams` and `params` - `methods`: All available methods with: - `params`: Array of `[parameter_name, parameter_type]` pairs - `readonly`: Boolean indicating if method is read-only - `payable`: Boolean indicating if method accepts native tokens - `ret`: Return type of the method - `kwparams`: Keyword parameters ### getContractSchemaForCode Retrieves the schema for contract code without deploying it, useful for validating contract structure before deployment. ```typescript import { readFileSync } from 'fs'; // Read contract code from file const contractCode = readFileSync('./contracts/football_bets.py', 'utf-8'); // Get schema for contract code const schema = await client.getContractSchemaForCode({ code: contractCode, }); console.log('Contract schema for code:', schema); // Output example: // { // "ctor": {"kwparams": {}, "params": [["have_coin", "bool"]]}, // "methods": { // "ask_for_coin": { // "kwparams": {}, // "params": [["request", "string"]], // "payable": false, // "readonly": false, // "ret": "null" // }, // "ask_for_coin2": { // "kwparams": {}, // "params": [["request", "string"]], // "payable": false, // "readonly": false, // "ret": "null" // }, // "get_have_coin": { // "kwparams": {}, // "params": [], // "readonly": true, // "ret": "bool" // } // } // } ``` **Parameters:** - `code`: Contract source code as string **Returns:** Contract schema object with constructor and methods information (same structure as deployed contract) ### Complete Schema Example ```typescript import { createClient, createAccount } from 'genlayer-js'; import { localnet } from 'genlayer-js/chains'; import { readFileSync } from 'fs'; async function analyzeContract() { const account = createAccount(); const client = createClient({ chain: localnet, account: account, }); await client.initializeConsensusSmartContract(); // Option 1: Get schema for deployed contract const deployedContractAddress = '0x...'; // Your deployed contract address const deployedSchema = await client.getContractSchema({ address: deployedContractAddress, }); console.log('Deployed contract schema:', deployedSchema); // Option 2: Get schema for contract code before deployment const contractCode = readFileSync('./contracts/football_bets.py', 'utf-8'); const codeSchema = await client.getContractSchemaForCode({ code: contractCode, }); console.log('Contract code schema:', codeSchema); // Validate schema structure if (codeSchema.methods && codeSchema.methods.create_bet) { console.log('Contract has create_bet method with parameters:', codeSchema.methods.create_bet.params); } // Check if method is read-only if (codeSchema.methods.get_bets && codeSchema.methods.get_bets.readonly) { console.log('get_bets is a read-only method'); } } ``` ## Transaction Management ### getTransaction Retrieves transaction details by hash. ```typescript const transaction = await client.getTransaction({ hash: transactionHash }); console.log('Transaction details:', transaction); ``` **Parameters:** - `hash`: The transaction hash **Returns:** Transaction details object ### waitForTransactionReceipt Waits for a transaction receipt with configurable status and retry options. ```typescript // Wait for transaction to be accepted const receipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: TransactionStatus.ACCEPTED, retries: 100, interval: 5000, }); // Wait for transaction to be finalized const finalizedReceipt = await client.waitForTransactionReceipt({ hash: transactionHash, status: TransactionStatus.FINALIZED, retries: 200, interval: 3000, }); console.log('Transaction receipt:', receipt); ``` **Parameters:** - `hash`: The transaction hash - `status`: The desired transaction status ('ACCEPTED' or 'FINALIZED') - `retries`: (Optional) Number of retry attempts - `interval`: (Optional) Interval between retries in milliseconds **Returns:** Transaction receipt object ### appealTransaction Appeals a transaction to request validators to reach consensus again. ```typescript const appealHash = await client.appealTransaction({ txId: transactionHash, }); const appealReceipt = await client.waitForTransactionReceipt({ hash: appealHash, status: TransactionStatus.ACCEPTED, retries: 100, interval: 5000, }); console.log('Appeal processed:', appealReceipt); ``` **Parameters:** - `txId`: The transaction hash to appeal **Returns:** Appeal transaction hash ## Chain Information ### Available Chains GenLayerJS provides several chain configurations for different environments: - **localnet**: Local development network - **studionet**: Staging environment network - **testnetAsimov**: Test network for production testing ```typescript import { localnet, studionet, testnetAsimov } from 'genlayer-js/chains'; // Use the appropriate chain for your environment const client = createClient({ chain: localnet, // or studionet, testnetAsimov }); ``` ## Staking (Testnet) The SDK provides staking functionality for validators and delegators on testnet-asimov. ### Setup ```typescript import { testnetAsimov } from 'genlayer-js/chains'; import { createClient, createAccount } from "genlayer-js"; const account = createAccount(); const client = createClient({ chain: testnetAsimov, account, }); ``` ### getEpochInfo Get current epoch information including inflation and timing data. ```typescript const epochInfo = await client.getEpochInfo(); // { // currentEpoch: 2n, // epochMinDuration: 86400n, // 1 day in seconds // currentEpochStart: Date, // currentEpochEnd: Date | null, // nextEpochEstimate: Date | null, // validatorMinStake: "42000 GEN", // delegatorMinStake: "42 GEN", // activeValidatorsCount: 6n, // inflation: "1000 GEN", // Total inflation for current epoch // inflationRaw: 1000000000000000000000n, // totalWeight: 500000000000000000000000n, // totalClaimed: "500 GEN", // } ``` ### getActiveValidators Get list of active validators. ```typescript const validators = await client.getActiveValidators(); // ['0xa8f1...', '0xe924...', ...] ``` ### isValidator Check if an address is a validator. ```typescript const isValidator = await client.isValidator("0x..."); // true or false ``` ### getValidatorInfo Get detailed information about a validator. ```typescript const info = await client.getValidatorInfo("0x..."); // { // address: '0x...', // owner: '0x...', // operator: '0x...', // vStake: '42000 GEN', // vShares: 42000n, // dStake: '1000 GEN', // dShares: 1000n, // live: true, // banned: false, // identity: { moniker: 'My Validator', ... }, // pendingDeposits: [...], // pendingWithdrawals: [...], // } ``` ### getStakeInfo Get stake information for a delegator with a specific validator. ```typescript const stakeInfo = await client.getStakeInfo("0xDelegator...", "0xValidator..."); // { // delegator: '0x...', // validator: '0x...', // shares: 100n, // stake: '100 GEN', // stakeRaw: 100000000000000000000n, // pendingDeposits: [...], // pendingWithdrawals: [...], // } ``` ### validatorJoin Join as a validator by staking tokens. ```typescript const result = await client.validatorJoin({ amount: "42000gen", operator: "0xOperator...", // optional }); // { // transactionHash: '0x...', // blockNumber: 123n, // gasUsed: 21000n, // validatorWallet: '0x...', // operator: '0x...', // amount: '42000 GEN', // } ``` ### delegatorJoin Join as a delegator by staking with a validator. ```typescript const result = await client.delegatorJoin({ validator: "0xValidator...", amount: "100gen", }); // { // transactionHash: '0x...', // blockNumber: 123n, // gasUsed: 21000n, // validator: '0x...', // delegator: '0x...', // amount: '100 GEN', // } ``` ### validatorExit / delegatorExit Exit by withdrawing shares. Tokens enter a 7-epoch unbonding period. ```typescript // Validator exit const result = await client.validatorExit({ shares: 100n }); // Delegator exit const result = await client.delegatorExit({ validator: "0xValidator...", shares: 50n, }); ``` ### validatorClaim / delegatorClaim Claim withdrawals after the 7-epoch unbonding period. ```typescript // Validator claim const result = await client.validatorClaim({ validator: "0x..." }); // Delegator claim const result = await client.delegatorClaim({ validator: "0xValidator...", delegator: "0xDelegator...", }); ``` ### Utility Functions ```typescript import { parseStakingAmount, formatStakingAmount } from "genlayer-js"; // Parse human-readable amounts to BigInt const amount = parseStakingAmount("100gen"); // 100000000000000000000n const amount2 = parseStakingAmount("100"); // 100000000000000000000n // Format BigInt to human-readable const formatted = formatStakingAmount(100000000000000000000n); // "100 GEN" ``` # api-references/genlayer-py.mdx # GenLayerPY SDK Reference This document describes the key components and methods available in the GenLayerPY SDK for interacting with the GenLayer network. ## Client Creation ### create_client Creates a new GenLayer client instance. ```python from genlayer_py import create_client from genlayer_py.chains import localnet client = create_client( chain=localnet, account=account, # Optional: Use this account for subsequent calls ) ``` **Parameters:** - `chain`: The chain configuration (e.g., localnet) - `account`: (Optional) Sets an account to be used in subsequent calls **Returns:** A GenLayer client instance ## Transaction Handling ### get_transaction Retrieves transaction details by hash. ```python transaction = client.get_transaction(transaction_hash=transaction_hash) ``` **Parameters:** - `transaction_hash`: The transaction hash **Returns:** Genlayer transaction details object

### wait_for_transaction_receipt Waits for a transaction receipt. ```python receipt = client.wait_for_transaction_receipt( transaction_hash=transaction_hash, status='FINALIZED', # or 'ACCEPTED' ) ``` **Parameters:** - `transaction_hash`: The transaction hash - `status`: The desired transaction status ('FINALIZED' or 'ACCEPTED') **Returns:** Transaction receipt object ## Contract Interaction ### read_contract Reads data from a deployed contract. ```python result = client.read_contract( address=contract_address, function_name: 'get_complete_storage', args: [], ) ``` **Parameters:** - `address`: The contract address - `function_name`: The name of the function to call - `args`: An array of arguments for the function call **Returns:** The result of the contract function call

### write_contract Writes data to a deployed contract. ```python transaction_hash = client.write_contract( address=contract_address, function_name='storeData', args=['new_data'], value=0, # Optional: amount of native token to send with the transaction ) ``` **Parameters:** - `address`: The contract address - `function_name`: The name of the function to call - `args`: An array of arguments for the function call - `value`: (Optional) Amount of native token to send with the transaction **Returns:** The transaction hash ## Account Management ### generate_private_key Generates a new private key. ```python from genlayer_py import generate_private_key private_key = generate_private_key() ``` **Parameters:** None **Returns:** A new private key as bytes

### create_account Creates a new account, optionally using a provided private key. ```python from genlayer_py import create_account account = create_account() # Or with a specific private key: account_with_key = create_account('0x1234...') # Replace with actual private key ``` **Parameters:** - `account_private_key`: (Optional) A string representing the private key **Returns:** A new account object ## Chain Information ### localnet Provides configuration for the local GenLayer Studio chain. ```python from genlayer_py.chains import localnet ``` **Usage:** Used when creating a client to specify the chain # api-references/genlayer-test.mdx # GenLayer Testing Suite Reference This document describes the key components and methods available in the GenLayer Test SDK for testing Intelligent Contracts. For comprehensive test examples and implementation patterns, see our [Test Suite Examples](https://github.com/genlayerlabs/genlayer-testing-suite/tree/main/tests/examples). ## Installation ```bash pip install genlayer-test ``` ## Configuration The GenLayer Testing Suite can be configured using an optional `gltest.config.yaml` file in your project root. While not required, this file helps manage network configurations, contract paths, and environment settings. ### Configuration File Structure ```yaml # gltest.config.yaml networks: default: localnet # Default network to use localnet: # Local development network configuration (pre-configured) url: "http://127.0.0.1:4000/api" leader_only: false # Run in leader-only mode by default studionet: # Studio network configuration (pre-configured) # Pre-configured network - accounts are automatically generated # You can override any settings if needed testnet_asimov: # Test network configuration (pre-configured) # Pre-configured network - requires accounts to be specified accounts: - "${ACCOUNT_PRIVATE_KEY_1}" - "${ACCOUNT_PRIVATE_KEY_2}" - "${ACCOUNT_PRIVATE_KEY_3}" from: "${ACCOUNT_PRIVATE_KEY_2}" # Optional: specify default account custom_network: # Custom network configuration id: 1234 url: "http://custom.network:8545" accounts: - "${CUSTOM_ACCOUNT_1}" - "${CUSTOM_ACCOUNT_2}" from: "${CUSTOM_ACCOUNT_1}" # Optional: specify default account paths: contracts: "contracts" # Path to your contracts directory artifacts: "artifacts" # Path to your artifacts directory environment: .env # Path to your environment file containing private keys and other secrets ``` ### Configuration Sections 1. **Networks**: Define different network environments - `default`: Specifies which network to use by default - Pre-configured networks: - `localnet`: Local development network with auto-generated test accounts - `studionet`: GenLayer Studio network with auto-generated test accounts - `testnet_asimov`: Public test network (requires account configuration) - Network configurations can include: - `url`: The RPC endpoint for the network (optional for pre-configured networks) - `id`: Chain ID (optional for pre-configured networks) - `accounts`: List of account private keys (using environment variables) - `from`: Which account to use by default for transactions (optional; defaults to first account) - `leader_only`: Whether to run deployments/writes only on the leader node - For custom networks (non-pre-configured), `id`, `url`, and `accounts` are required fields 2. **Paths**: Define important directory paths - `contracts`: Location of your contract files - `artifacts`: Location to store analysis results and artifacts 3. **Environment**: Path to your `.env` file containing sensitive information like private keys If you don't provide a config file, the suite will use default values. You can override these settings using command-line arguments. ## General ### create_account Creates a new account for testing purposes. ```python from gltest import create_account account = create_account() ``` **Parameters:** None **Returns:** A new account object ### get_default_account Returns the default account used to execute transactions when no account is specified. ```python from gltest import get_default_account default_account = get_default_account() ``` **Parameters:** None **Returns:** The default account object ### get_accounts Returns a collection of accounts available for testing. When a `gltest.config.yaml` file is present with account private keys defined for the current network, this function will return those loaded accounts. By design, the first account is the default account. ```python from gltest import get_accounts, get_default_account accounts = get_accounts() default_account = get_default_account() assert default_account == accounts[0] other_account = accounts[1] # Get a different account assert default_account != other_account ``` **Parameters:** None **Returns:** A list of account objects loaded from the private keys defined in `gltest.config.yaml` for the current network, or pre-created test accounts if no config is present ## Contract Interaction For the following code examples, we'll use a Storage Intelligent Contract as a reference: ```python # { "Depends": "py-genlayer:test" } from genlayer import * class Storage(gl.Contract): # State variable to store data storage: str # Constructor - initializes the contract state def __init__(self, initial_storage: str): self.storage = initial_storage # Read method - marked with @gl.public.view decorator @gl.public.view def get_storage(self) -> str: return self.storage # Write method - marked with @gl.public.write decorator @gl.public.write def update_storage(self, new_storage: str) -> None: self.storage = new_storage ``` ### Contract Factory The Contract Factory is used to deploy and build Contract objects that can interact with Intelligent Contract methods. #### get_contract_factory Retrieves a contract factory for a specific contract. ```python from gltest import get_contract_factory def test_get_factory(): factory = get_contract_factory('Storage') ``` **Parameters:** - `contract_name`: The name of the contract class to instantiate **Returns:** A Contract Factory instance #### deploy Deploys a new contract instance and returns a Contract object. ```python from gltest import get_contract_factory, create_account def test_deploy_contract(): factory = get_contract_factory('Storage') custom_account = create_account() contract = factory.deploy( args=["initial_value"], # Constructor arguments account=custom_account, # Account to deploy from consensus_max_rotations=3, # Optional: max consensus rotations ) ``` **Parameters:** - `args`: Contract constructor arguments - `account`: (Optional) Account to use for deployment - `consensus_max_rotations`: (Optional) Maximum number of consensus rotations - `wait_interval`: (Optional) Wait interval in milliseconds for transaction status - `wait_retries`: (Optional) Number of retries for transaction status - `wait_transaction_status`: (Optional) Desired transaction status **Returns:** A Contract object #### build_contract Builds a Contract object from an existing deployed contract. ```python from gltest import get_contract_factory, create_account def test_build_contract(): factory = get_contract_factory('Storage') custom_account = create_account() contract = factory.build_contract( contract_address="0xabcd...z", account=custom_account # Optional: use this for subsequent transaction calls ) ``` **Parameters:** - `contract_address`: The address of the deployed contract - `account`: (Optional) Account to use for contract interactions **Returns:** A Contract object ### Contract Methods #### read methods Calls read-only methods on the contract. ```python from gltest import get_contract_factory def test_read_methods(): factory = get_contract_factory('Storage') contract = factory.deploy(args=["initial_value"]) # Call a read-only method result = contract.get_storage(args=[]).call() assert result == "initial_value" ``` **Parameters:** - `args`: Method arguments **Returns:** The result of the contract read call #### write methods Calls state-modifying methods on the contract. ```python from gltest import get_contract_factory from gltest.assertions import tx_execution_succeeded def test_write_methods(): factory = get_contract_factory("Storage") contract = factory.deploy(args=["initial_value"]) # Call a write method with arguments tx_receipt = contract.update_storage( args=["new_value"], # Method arguments ).transact( value=0, # Optional amount of native token to send consensus_max_rotations=3, wait_interval=1, wait_retries=10, ) # Verify the transaction was successful assert tx_execution_succeeded(tx_receipt) # Verify the value was updated assert contract.get_storage().call() == "new_value" ``` **Parameters:** - `args`: Method arguments - `value`: (Optional) Amount of native token to send with the transaction - `consensus_max_rotations`: (Optional) Maximum number of consensus rotations - `wait_interval`: (Optional) Wait interval in milliseconds for transaction status - `wait_retries`: (Optional) Number of retries for transaction status - `wait_transaction_status`: (Optional) Desired transaction status - `wait_triggered_transactions`: (Optional) Whether to wait for triggered transactions - `wait_triggered_transactions_status`: (Optional) Desired triggered transaction status **Returns:** The transaction receipt #### connect Creates a new contract instance that uses a different account for transactions. ```python from gltest import create_account other_account = create_account() contract_with_other_account = contract.connect(other_account) ``` **Parameters:** - `account`: Account to use for contract interactions **Returns:** A new Contract instance using the specified account ## Helpers ### load_fixture Runs a fixture function and returns its value at the same state in every test. `load_fixture` sets up the state on its first call and returns to that state in subsequent tests. This is particularly useful for setting up test environments that need to be in a consistent state across multiple tests. **Environment Behavior:** - **Local Studio:** The fixture's state is preserved between test runs, allowing for consistent test environments. - **Hosted Studio:** When using `https://studio.genlayer.com/api`, the fixture executes independently for each test run without state preservation. ```python from gltest import get_contract_factory from gltest.helpers import load_fixture from gltest.assertions import tx_execution_succeeded # Define a fixture that deploys a contract def deploy_contract(): factory = get_contract_factory("Storage") contract = factory.deploy(args=["initial_value"]) return contract # Test A: Verify initial state def test_initial_state(): # Load the fixture - will deploy contract on first run storage_contract = load_fixture(deploy_contract) # Verify initial state current_storage = storage_contract.get_storage(args=[]).call() assert current_storage == "initial_value" # Test B: Verify state persistence and updates def test_state_updates(): # Load the same fixture - will reuse deployed contract storage_contract = load_fixture(deploy_contract) # Verify initial state is preserved current_storage = storage_contract.get_storage(args=[]).call() assert current_storage == "initial_value" # Update the storage tx_receipt = storage_contract.update_storage( args=["new_value"] ).transact() # Verify the update was successful assert tx_execution_succeeded(tx_receipt) assert storage_contract.get_storage().call() == "new_value" ``` ## Fixtures The GenLayer Testing Suite provides reusable pytest fixtures in `gltest.fixtures` to simplify common testing operations. These fixtures can be imported and used in your test files to avoid repetitive setup code. ### Available Fixtures - `gl_client` (session scope): GenLayer client instance for network operations - `default_account` (session scope): Default account for testing and deployments - `accounts` (session scope): List of test accounts for multi-account scenarios - `setup_validators` (function scope): Function to create test validators for LLM operations #### gl_client Provides a GenLayer PY client instance that's created once per test session. ```python def test_client_operations(gl_client): tx_hash = "0x1234..." transaction = gl_client.get_transaction(tx_hash) ``` #### default_account Default account used when no account is specified. ```python def test_with_default_account(default_account): factory = get_contract_factory("MyContract") contract = factory.deploy(account=default_account) ``` #### accounts List of account objects loaded from the current network config or pre-created test accounts. ```python def test_multiple_accounts(accounts): sender = accounts[0] receiver = accounts[1] tx_receipt = contract.transfer(args=[receiver.address, 100]).transact() ``` #### setup_validators Creates test validators for localnet environment. Useful for testing LLM-based contract methods and consensus behavior. ```python def test_with_validators(setup_validators): # Default configuration setup_validators() # With custom mock responses and validator count mock_response = {"result": "mocked LLM response"} setup_validators(mock_response=mock_response, n_validators=3) contract = factory.deploy() result = contract.llm_based_method() ``` Parameters for `setup_validators`: - `mock_response` (dict, optional): Mock validator response when using `--test-with-mocks` - `n_validators` (int, optional): Number of validators to create (default: 5) ## Assertions Assertions are utility functions to verify the outcome of contract transactions in your tests. ### tx_execution_succeeded Asserts that a transaction executed successfully. ```python from gltest.assertions import tx_execution_succeeded assert tx_execution_succeeded(tx_receipt) ``` You can also match specific patterns in the transaction's stdout output: ```python # Simple string matching assert tx_execution_succeeded(tx_receipt, match_std_out="Process completed") # Regex pattern matching assert tx_execution_succeeded(tx_receipt, match_std_out=r".*code \d+") ``` ## Statistical Analysis with .analyze() The `.analyze()` method performs statistical analysis for contract methods over multiple runs. This is particularly useful for testing LLM-based contracts where outputs may vary. ```python from gltest import get_contract_factory def test_analyze_method(): factory = get_contract_factory("LlmContract") contract = factory.deploy() analysis = contract.process_with_llm(args=["input_data"]).analyze( provider="openai", model="gpt-4o", runs=100, config=None, plugin=None, plugin_config=None, ) print(f"Method: {analysis.method}") print(f"Success rate: {analysis.success_rate:.2f}%") print(f"Reliability score: {analysis.reliability_score:.2f}%") print(f"Unique states: {analysis.unique_states}") print(f"Execution time: {analysis.execution_time:.1f}s") ``` The analysis returns a summary object with: - method, args - total_runs, successful_runs, failed_runs - unique_states, reliability_score - execution_time ### tx_execution_failed Asserts that a transaction execution failed. ```python from gltest.assertions import tx_execution_failed assert tx_execution_failed(tx_receipt) ``` ## Mock LLM Responses The Mock LLM system allows you to simulate Large Language Model responses in GenLayer tests. This enables deterministic tests by providing predefined responses instead of relying on actual LLM calls. ### Basic Structure ```python mock_response = { "response": {}, # Optional: mocks gl.nondet.exec_prompt "eq_principle_prompt_comparative": {}, # Optional: mocks gl.eq_principle.prompt_comparative "eq_principle_prompt_non_comparative": {} # Optional: mocks gl.eq_principle.prompt_non_comparative } setup_validators(mock_response) ``` ### Method Mappings - "response" -> gl.nondet.exec_prompt - "eq_principle_prompt_comparative" -> gl.eq_principle.prompt_comparative - "eq_principle_prompt_non_comparative" -> gl.eq_principle.prompt_non_comparative ### How It Works The mock system performs substring matching on the internally constructed user message. If a key in your mock dictionary is contained within the actual user message, the associated response is returned. #### Substring Matching Examples Will work (partial match): ```python "eq_principle_prompt_comparative": { "The value of give_coin": True } ``` Won't work (extra words break the match): ```python "eq_principle_prompt_comparative": { "The good value of give_coin": True } ``` #### Complete Example ```python from gltest import get_contract_factory def test_with_mocked_llm(setup_validators): mock_response = { "response": { "What is the weather?": "It's sunny today", "Calculate 2+2": "4" }, "eq_principle_prompt_comparative": { "values must be equal": True, "amounts should match": False }, "eq_principle_prompt_non_comparative": { "Is this valid?": True } } setup_validators(mock_response) factory = get_contract_factory("MyLLMContract") contract = factory.deploy() result = contract.check_weather() ``` Notes: - Mock responses are available when running tests on localnet - Use with the `--test-with-mocks` flag to enable mocking You can also match specific patterns in the transaction's stderr output: ```python # Simple string matching assert tx_execution_failed(tx_receipt, match_std_err="Warning: deprecated") # Regex pattern matching assert tx_execution_failed(tx_receipt, match_std_err=r"Method.*failed") ``` **Parameters:** - `transaction_receipt`: The transaction receipt object to check - `match_std_out` (optional): String or regex pattern to match in stdout - `match_std_err` (optional): String or regex pattern to match in stderr **Returns:** `True` if the transaction failed and patterns match (if provided), otherwise `False` **Note:** The stdout/stderr matching feature is only available when running on **studionet** and **localnet**. These features are not supported on testnet. ## Running Tests The GenLayer Test SDK provides a command-line interface for executing tests with various configurations. ### Basic Usage Run all tests in the current directory: ```bash gltest ``` Run a specific test file: ```bash gltest tests/test_mycontract.py ``` ### Test Execution Control Filter tests by markers: ```bash gltest -m "integration" # Run only tests marked as integration ``` Control test output verbosity: ```bash gltest -v # Enable verbose output gltest -vv # Enable more verbose output ``` ### Configuration Options Specify a custom contracts directory (default: `contracts/`): ```bash gltest --contracts-dir ``` Specify artifacts directory (default: `artifacts/`): ```bash gltest --artifacts-dir ``` Select a network configuration from your `gltest.config.yaml`: ```bash # Run tests on localnet (default) gltest --network localnet # Run tests on Studio gltest --network studionet # Run tests on testnet gltest --network testnet_asimov ``` Set a custom RPC endpoint: ```bash gltest --rpc-url ``` Configure transaction receipt polling: ```bash # Set the polling interval in milliseconds gltest --default-wait-interval # Set the maximum number of polling attempts gltest --default-wait-retries ``` Run tests with mocked LLM responses (localnet only): ```bash gltest --test-with-mocks ``` Run tests with leader-only mode enabled (studio-based networks only: localhost, 127.0.0.1, *.genlayer.com, *.genlayerlabs.com): ```bash gltest --leader-only ``` When enabled, deployments and write operations run only on the leader node. On unsupported networks, this flag has no effect and a warning is logged. **Note:** All configuration options can be combined. For example: ```bash gltest -v --network testnet_asimov --default-wait-interval 1000 ``` # api-references/genlayer-node.mdx # GenLayer Node API The GenLayer Node provides a [JSON-RPC API](https://www.jsonrpc.org/specification) for interacting with it. This API allows you to execute contract calls, retrieve transaction information, and perform various blockchain operations. ## GenLayer Methods ### gen_call Executes a new message call immediately without creating a transaction on the blockchain. This method supports read operations, write operations, and contract deployments. **Method:** `gen_call` **Parameters:** - `request` (object, required): The contract call request parameters - `from` (string, required): The address making the call - `to` (string, required): The contract address to call - `Data` (string, required): The encoded function call data - `Type` (string, required): The type of call (`"read"`, `"write"`, or `"deploy"`) - `blockNumber` (string, optional): The block number to query at (hex-encoded). If not provided, uses latest block - `status` (string, optional): The transaction status filter (`"finalized"` or `"accepted"`). If not provided, uses accepted state - `value` (string, optional): The value to send with the call (hex-encoded) **Returns:** Hex-encoded result data **Example - Read Call (Latest Accepted State):** ```json { "jsonrpc": "2.0", "method": "gen_call", "params": [ { "Type": "read", "Data": "0xd8960e066d6574686f646c6765745f686176655f636f696e00", "from": "0xf6A60752C24Cd3BFcAf8d387a5EB62d3746F44EE", "to": "0xCe5712E63fd5475288aB1B7c0a368B9417357b81", "gas": "0x5208", "value": "0x0" } ], "id": 1 } ``` **Example - Read Call with Specific Block and Status:** ```json { "jsonrpc": "2.0", "method": "gen_call", "params": [ { "Type": "read", "Data": "0xd8960e066d6574686f646c6765745f686176655f636f696e00", "from": "0xf6A60752C24Cd3BFcAf8d387a5EB62d3746F44EE", "to": "0xCe5712E63fd5475288aB1B7c0a368B9417357b81", "blockNumber": "0x151ec5", "status": "accepted" } ], "id": 1 } ``` **Example - Write Call:** ```json { "jsonrpc": "2.0", "method": "gen_call", "params": [ { "from": "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8b6", "to": "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8b6", "data": "0xa9059cbb000000000000000000000000742d35cc6634c0532925a3b8d4c9db96c4b4d8b6", "type": "write", "gas": "0x5208", "value":"0x0" } ], "id": 1 } ``` **Notes:** - The `blockNumber` parameter can be either hex-encoded with a `0x` prefix (e.g., `"0x151ec5"`) or decimal (e.g., `"1384133"`) - Valid `status` values are `"accepted"` (default) and `"finalized"` - When both parameters are omitted, the call executes against the latest accepted state - For `read` and `write` type calls, if the contract doesn't exist at the specified block/status combination, an error will be returned - For `deploy` type calls, the `status` and `blockNumber` parameters are not used for contract state validation since no contract exists yet ### gen_getContractSchema Retrieve the schema/interface of a GenLayer contract to understand its available methods and properties. **Method:** `gen_getContractSchema` **Parameters:** - `request` (object, required): The contract schema request - `code` (string, required): Base64-encoded contract code **Returns:** Contract schema object with methods and properties ```json { "ctor": { // constructor info "kwparams": {}, // dict "params": [["value", "type"]] // list of tuples }, "methods": { // dict from method name to method info "method_name": { "kwparams": {}, // dict "params": [["value", "type"]], // list of tuples "payable": false, // bool "readonly": false, // bool "ret": "null" // string }, } } ``` **Example:** ```json { "jsonrpc": "2.0", "method": "gen_getContractSchema", "params": [ { "code": "IyB7ICJEZXBlbmRzIjogInB5LWdlbmxheWVyOnRlc3QiIH0KCmZyb20gZ2VubGF5ZXIgaW1wb3J0ICoKCgojIGNvbnRyYWN0IGNsYXNzCmNsYXNzIFN0b3JhZ2UoZ2wuQ29udHJhY3QpOgogICAgc3RvcmFnZTogc3RyCgogICAgIyBjb25zdHJ1Y3RvcgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGluaXRpYWxfc3RvcmFnZTogc3RyKToKICAgICAgICBzZWxmLnN0b3JhZ2UgPSBpbml0aWFsX3N0b3JhZ2UKCiAgICAjIHJlYWQgbWV0aG9kcyBtdXN0IGJlIGFubm90YXRlZCB3aXRoIHZpZXcKICAgIEBnbC5wdWJsaWMudmlldwogICAgZGVmIGdldF9zdG9yYWdlKHNlbGYpIC0+IHN0cjoKICAgICAgICByZXR1cm4gc2VsZi5zdG9yYWdlCgogICAgIyB3cml0ZSBtZXRob2QKICAgIEBnbC5wdWJsaWMud3JpdGUKICAgIGRlZiB1cGRhdGVfc3RvcmFnZShzZWxmLCBuZXdfc3RvcmFnZTogc3RyKSAtPiBOb25lOgogICAgICAgIHNlbGYuc3RvcmFnZSA9IG5ld19zdG9yYWdlCg==" } ], "id": 1 } ``` **Response:** ```json { "jsonrpc": "2.0", "result": { "ctor": { "kwparams": {}, "params": [["initial_storage", "string"]] }, "methods": { "get_storage": { "kwparams": {}, "params": [], "readonly": true, "ret": "string" }, "update_storage": { "kwparams": {}, "params": [["new_storage", "string"]], "payable": false, "readonly": false, "ret": "null" } } }, "id": 1 } ``` ### gen_getTransactionReceipt Retrieves the transaction receipt for a given transaction ID. This endpoint is a proxy to the underlying consensus layer's `getTransactionAllData` function, providing detailed information about a transaction that has been processed. **Method:** `gen_getTransactionReceipt` **Parameters:** - `request` (object, required): - `txId` (`string`, required): The 32-byte transaction hash as a hexadecimal string with a `0x` prefix. **Returns:** A `Transaction` object which contains the details of the transaction. The structure is based on `ITransactionsTransaction` from the consensus contracts. The object has the following fields: - `id` (`string`): The transaction ID as a hex string. - `txOrigin` (`address`): The original address that initiated the transaction. - `sender` (`address`): The address of the sender. - `recipient` (`address`): The destination address of the transaction. - `activator` (`address`): The address of the validator that activated the transaction. - `status` (`uint8`): The current status of the transaction. - `previousStatus` (`uint8`): The previous status of the transaction. - `txSlot` (`uint256`): The transaction slot number. - `initialRotations` (`uint256`): The initial number of rotations. - `numOfInitialValidators` (`uint256`): The number of initial validators. - `randomSeed` (`string`): The random seed used for the transaction as a hex string. - `txExecutionHash` (`string`): The execution hash of the transaction as a hex string. - `otherExecutionFieldsHash` (`string`): Hash of other execution fields as a hex string. - `txData` (`string`): The transaction data as a hex string. - `eqBlocksOutputs` (`string`): The equivalent blocks outputs as a hex string. - `timestamps` (`object`): Object containing various timestamps: - `Created` (`uint256`): When the transaction was created. - `Pending` (`uint256`): When the transaction became pending. - `Activated` (`uint256`): When the transaction was activated. - `Proposed` (`uint256`): When the transaction was proposed. - `Committed` (`uint256`): When the transaction was committed. - `LastVote` (`uint256`): When the last vote was cast. - `AppealSubmitted` (`uint256`): When an appeal was submitted. - `LeaderRevealed` (`uint256`): When the leader was revealed. - `result` (`uint256`): The result of the transaction execution. - `readStateBlockRange` (`object`): Block range information: - `ActivationBlock` (`uint256`): The activation block number. - `ProcessingBlock` (`uint256`): The processing block number. - `ProposalBlock` (`uint256`): The proposal block number. - `consumedValidators` (`array`): Array of validator addresses that participated. - `roundData` (`array`): Array of round data objects containing: - `round` (`uint256`): The round number. - `leaderIndex` (`uint256`): Index of the round leader. - `votesCommitted` (`uint256`): Number of votes committed. - `votesRevealed` (`uint256`): Number of votes revealed. - `appealBond` (`uint256`): The appeal bond amount. - `rotationsLeft` (`uint256`): Number of rotations remaining. - `result` (`uint256`): The round result. - `roundValidators` (`array`): Array of validator addresses for this round. - `validatorVotes` (`string`): Base64-encoded validator votes. - `validatorVotesHash` (`array`): Array of vote hashes as hex strings. - `validatorResultHash` (`array`): Array of result hashes as hex strings. **Example Request:** ```json { "jsonrpc": "2.0", "method": "gen_getTransactionReceipt", "params": [ { "txId": "0x635060dd514082096d18c8eb64682cc6a944f9ce1ae6982febf7a71e9f656f49" } ], "id": 1 } ``` **Example Response:** ```json { "jsonrpc": "2.0", "id": 1, "result": { "id": "0x635060dd514082096d18c8eb64682cc6a944f9ce1ae6982febf7a71e9f656f49", "txOrigin": "0x5b70759760a85d92bf972b67ee8558e8e8da87d4", "sender": "0x5b70759760a85d92bf972b67ee8558e8e8da87d4", "recipient": "0x73ca5a2b51edf506ceaf110a41780ec51294d89f", "activator": "0xf27b07d36ff5b9dcd37fd3a09811d6456dd4483a", "status": 14, "previousStatus": 0, "txSlot": 1, "initialRotations": 1, "numOfInitialValidators": 5, "randomSeed": "0x3d0bdff63bce1cf84b155f1557bb15e303b903b1b559325b6492794a5e498954", "txExecutionHash": "0x76744dc491b1725eb2ba08cf516855c14aac310e36711368c04442fd39d61853", "otherExecutionFieldsHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "txData": "f5b31604617267730da4017570646174656420746573742073746f72616765066d6574686f64747570646174655f73746f7261676500", "eqBlocksOutputs": "c0", "timestamps": { "Created": 1750774777, "Pending": 1750774777, "Activated": 1750774781, "Proposed": 1750774786, "Committed": 1750774791, "LastVote": 0, "AppealSubmitted": 0, "LeaderRevealed": 0 }, "result": 0, "readStateBlockRange": { "ActivationBlock": 1377797, "ProcessingBlock": 1377797, "ProposalBlock": 1377798 }, "consumedValidators": [ "0xa707a1d9dd946242f921f0ad62f61e1b7df30c85", "0xf27b07d36ff5b9dcd37fd3a09811d6456dd4483a", "0xf3738216c3208d77a9db79a1d31824e5133083c4", "0x56394354538bff1e0ee5021c2b6d3522fce30257", "0xcfdbac032f82f388d9eca76efa6610b98e7f59fe" ], "roundData": [ { "round": 0, "leaderIndex": 3, "votesCommitted": 5, "votesRevealed": 0, "appealBond": 0, "rotationsLeft": 1, "result": 0, "roundValidators": [ "0xa707a1d9dd946242f921f0ad62f61e1b7df30c85", "0xf27b07d36ff5b9dcd37fd3a09811d6456dd4483a", "0xf3738216c3208d77a9db79a1d31824e5133083c4", "0x56394354538bff1e0ee5021c2b6d3522fce30257", "0xcfdbac032f82f388d9eca76efa6610b98e7f59fe" ], "validatorVotes": "AAAAAAA=", "validatorVotesHash": [ "54e3478b02dfb009a35d46b19ac7c967b65416430a33d3860e9301a0f2b19d57", "f74a48e7283c91757bf2c612e40f8a9eb69ea0f02cf5e6b89c3c9b6ad629a3c1", "2f51c3b1d9ff35140260fb42330fbed12303a9915b8da786c9b8ed060983fa6c", "730127e27167fcf2450fe506250b85d916fbf07dd874b7f0c69a2f8ceb9e44a6", "473d57953f7e7c1a6fb1d2335618f21088025e02bd9fa30d6f85f20a55c24d15" ], "validatorResultHash": [ "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000" ] } ] } } ``` ### gen_getContractState Retrieves the current state of a GenLayer intelligent contract at a specific block height and transaction status. **Method:** `gen_getContractState` **Parameters:** - `request` (object, required): The contract state request parameters - `address` (string, required): The contract address to query - `blockNumber` (string, optional): The block number to query at (hex-encoded). If not provided, uses latest block - `status` (string, optional): The transaction status filter (`"finalized"` or `"accepted"`). If not provided, uses accepted state **Returns:** Hex-encoded contract state data **Example Request - Latest Accepted State:** ```json { "jsonrpc": "2.0", "method": "gen_getContractState", "params": [ { "address": "0x73ca5a2b51edf506ceaf110a41780ec51294d89f" } ], "id": 1 } ``` **Example Request - Specific Block and Status:** ```json { "jsonrpc": "2.0", "method": "gen_getContractState", "params": [ { "address": "0x73ca5a2b51edf506ceaf110a41780ec51294d89f", "blockNumber": "0x151ec5", "status": "accepted" } ], "id": 1 } ``` **Example Response:** ```json { "jsonrpc": "2.0", "result": "0xd9960e0773746f726167656c6e757064617465642074657374207374", "id": 1 } ``` **Notes:** - The `blockNumber` parameter should be hex-encoded with a `0x` prefix - Valid `status` values are `"accepted"` (default) and `"finalized"` - The returned state is hex-encoded binary data with a `0x` prefix - Empty contract state returns `"0x"` - If the contract doesn't exist at the specified block/status, an error will be returned **cURL Example:** ```bash # Get latest accepted state curl -X POST http://localhost:9151 \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "gen_getContractState", "params": [{ "address": "0x73ca5a2b51edf506ceaf110a41780ec51294d89f" }], "id": 1 }' # Get state at specific block with accepted status curl -X POST http://localhost:9151 \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "gen_getContractState", "params": [{ "address": "0x73ca5a2b51edf506ceaf110a41780ec51294d89f", "blockNumber": "0x151ec5", "status": "accepted" }], "id": 1 }' ``` ## Debug Methods These methods are available for debugging and testing purposes during development. ### gen_dbg_ping Simple connectivity test method that returns a "pong" response. **Method:** `gen_dbg_ping` **Parameters:** None **Returns:** "pong" string **Example:** ```json { "jsonrpc": "2.0", "method": "gen_dbg_ping", "params": [], "id": 1 } ``` **Response:** ```json { "jsonrpc": "2.0", "result": "pong", "id": 1 } ``` ### gen_dbg_trie Get trie information for debugging node internal DB state. **Method:** `gen_dbg_trie` **Parameters:** - `request` (object, required): The trie debug request - `txID` (string, required): Transaction ID (hex-encoded) - `round` (integer, required): Round number **Returns:** Trie debug information string **Example:** ```json { "jsonrpc": "2.0", "method": "gen_dbg_trie", "params": [ { "txID": "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8b6742d35Cc6634C0532925a3b8", "round": 0 } ], "id": 1 } ``` **Response:** ```json { "jsonrpc": "2.0", "result": "graph TD\nnode0@{label: \"br seq=1\"}\nnode1@{label: \"ext seq=1 0x00000000000000000000000000000000000000000000000000000000000000000000000\"}\nnode1 --\u003e data2@{label: \"seq=1\n[21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\"}\nnode0 --\u003e|0| node1\nnode3@{label: \"ext seq=1 0x72d46c3ada9f897c74d349bbfe0e450c798167c9f580f8daf85def57e96c3ea00000000\"}\nnode3 --\u003e data4@{label: \"seq=1\n[105 110 105 116 105 97 108 32 115 116 111 114 97 103 101 32 118 97 108 117 101 0 0 0 0 0 0 0 0 0 0 0]\"}\nnode0 --\u003e|3| node3\n", "id": 1 } ## Ethereum Compatibility The GenLayer Node also supports Ethereum-compatible methods that are proxied to the underlying infrastructure. These methods follow the standard [Ethereum JSON-RPC specification](https://ethereum.org/en/developers/docs/apis/json-rpc/) and are prefixed with `eth_`. **Examples of supported Ethereum methods:** - `eth_blockNumber` - `eth_getBalance` - `eth_sendTransaction` - `eth_call` - And other standard Ethereum JSON-RPC methods ## zkSync Compatibility [zkSync-compatible](https://docs.zksync.io/zksync-protocol/api/zks-rpc) methods are also supported and proxied to the underlying infrastructure. These methods are prefixed with `zksync_`. ## Usage Examples ### cURL ```bash # Test connectivity curl -X POST http://localhost:9151 \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "gen_dbg_ping", "params": [], "id": 1 }' # Execute a contract call curl -X POST http://localhost:9151 \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "gen_call", "params": [{ "from": "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8b6", "to": "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8b6", "data": "0x70a08231000000000000000000000000742d35cc6634c0532925a3b8d4c9db96c4b4d8b6", "type": "read", "transaction_hash_variant": "latest-nonfinal" }], "id": 1 }' # Get contract schema curl -X POST http://localhost:9151 \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "gen_getContractSchema", "params": [{ "code": "IyB7ICJEZXBlbmRzIjogInB5LWdlbmxheWVyOnRlc3QiIH0KCmZyb20gZ2VubGF5ZXIgaW1wb3J0ICoKCgojIGNvbnRyYWN0IGNsYXNzCmNsYXNzIFN0b3JhZ2UoZ2wuQ29udHJhY3QpOgogICAgc3RvcmFnZTogc3RyCgogICAgIyBjb25zdHJ1Y3RvcgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGluaXRpYWxfc3RvcmFnZTogc3RyKToKICAgICAgICBzZWxmLnN0b3JhZ2UgPSBpbml0aWFsX3N0b3JhZ2UKCiAgICAjIHJlYWQgbWV0aG9kcyBtdXN0IGJlIGFubm90YXRlZCB3aXRoIHZpZXcKICAgIEBnbC5wdWJsaWMudmlldwogICAgZGVmIGdldF9zdG9yYWdlKHNlbGYpIC0+IHN0cjoKICAgICAgICByZXR1cm4gc2VsZi5zdG9yYWdlCgogICAgIyB3cml0ZSBtZXRob2QKICAgIEBnbC5wdWJsaWMud3JpdGUKICAgIGRlZiB1cGRhdGVfc3RvcmFnZShzZWxmLCBuZXdfc3RvcmFnZTogc3RyKSAtPiBOb25lOgogICAgICAgIHNlbGYuc3RvcmFnZSA9IG5ld19zdG9yYWdlCg==" }], "id": 1 }' # Get debug trie information curl -X POST http://localhost:9151 \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "gen_dbg_trie", "params": [{ "txID": "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8b6742d35Cc6634C0532925a3b8", "round": 0 }], "id": 1 }' # Get transaction receipt curl -X POST http://localhost:9151 \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "gen_getTransactionReceipt", "params": [{ "txId": "0x635060dd514082096d18c8eb64682cc6a944f9ce1ae6982febf7a71e9f656f49" }], "id": 1 }' ``` ## Ops Methods These methods provide operational endpoints for monitoring the GenLayer node. ### balance Returns the configured operator's account balance in multiple formats including hexadecimal, wei, and GEN units. **Method:** `GET /balance` **Parameters:** None **Returns:** JSON object containing the operator's balance in three formats **Example Request:** ```bash curl -X GET http://localhost:9153/balance ``` **Example Response:** ```json { "balance_hex": "0x0de0b6b3a7640000", "balance_wei": "1000000000000000000", "balance_gen": "1.000" } ``` **Response Fields:** - `balance_hex` (string): The balance encoded as hexadecimal with "0x" prefix - `balance_wei` (string): The balance in wei as a decimal string - `balance_gen` (string): The balance in GEN units formatted with 3 decimal places **Notes:** - This endpoint is only available when the node is running in validator mode - The balance is always retrieved from the latest block - The operator address is configured at node startup - If the operator address is not configured, the zero address (0x0000...0000) is used - Balance conversions: 1 GEN = 1,000,000,000,000,000,000 wei (10^18 wei) - Returns HTTP 503 if the node is not in validator mode - Returns HTTP 500 if there's an error retrieving the balance **Example Response (Zero Balance):** ```json { "balance_hex": "0x", "balance_wei": "0", "balance_gen": "0.000" } ``` **Example Response (Large Balance):** ```json { "balance_hex": "0x3635c9adc5dea00000", "balance_wei": "1000000000000000000000", "balance_gen": "1000.000" } ``` **Error Response (Not in Validator Mode):** ```json { "message": "Balance endpoint not available in rollup mode" } ``` **cURL Example with Headers:** ```bash curl -X GET http://localhost:9153/balance \ -H "Accept: application/json" \ -v ``` ### health Returns the health status of the GenLayer node along with version information and the status of individual health checks. **Method:** `GET /health` **Parameters:** None **Returns:** JSON object containing the overall health status, version information, and individual check results **Example Request:** ```bash curl -X GET http://localhost:9153/health ``` **Example Response:** ```json { "status": "up", "node_version": "v1.2.3", "protocol_version": "consensus-v2.1", "checks": { "test-check": { "status": "up", "timestamp": "2024-01-15T10:30:45Z" } } } ``` **Response Fields:** - `status` (string): Overall health status - "up" if all checks pass, "down" if any check fails - `node_version` (string): The version of the GenLayer node software - `protocol_version` (string): The consensus protocol version - `checks` (object, optional): Map of individual health check results - `[check-name]` (object): Results for a specific health check - `status` (string): Check status - "up" or "down" - `timestamp` (string): ISO 8601 timestamp of when the check was performed - `error` (string, optional): Error message if check failed **HTTP Status Codes:** - `200 OK`: Node is healthy (all checks passing) - `503 Service Unavailable`: Node is unhealthy (one or more checks failing) **Notes:** - The endpoint has a 5-second timeout for all health checks - The `checks` field is only included when health checks are configured - Version fields will show "unset" if version information is not available - Individual health checks are executed concurrently with results aggregated in the response **Example Response (Unhealthy):** ```json { "status": "down", "node_version": "v1.2.3", "protocol_version": "consensus-v2.1", "checks": { "database": { "status": "down", "error": "connection timeout", "timestamp": "2024-01-15T10:30:45Z" }, "consensus": { "status": "up", "timestamp": "2024-01-15T10:30:45Z" } } } ``` **cURL Example with Headers:** ```bash curl -X GET http://localhost:9153/health \ -H "Accept: application/json" \ -v ``` ### metrics Exposes Prometheus-compatible metrics for monitoring node performance and health. **Method:** `GET /metrics` **Parameters:** None **Returns:** Prometheus-format text response with all collected metrics **Example Request:** ```bash curl -X GET http://localhost:9153/metrics ``` **Example Response:** ``` # HELP genlayer_node_cpu_usage_percent Current CPU usage percentage (0-100) # TYPE genlayer_node_cpu_usage_percent gauge genlayer_node_cpu_usage_percent{component="node"} 15.5 genlayer_node_cpu_usage_percent{component="genvm-llm"} 45.2 genlayer_node_cpu_usage_percent{component="genvm-web"} 12.8 genlayer_node_cpu_usage_percent{component="webdriver"} 5.3 # HELP genlayer_node_memory_rss_bytes Resident Set Size (RSS) memory usage in bytes # TYPE genlayer_node_memory_rss_bytes gauge genlayer_node_memory_rss_bytes{component="node"} 524288000 genlayer_node_memory_rss_bytes{component="genvm-llm"} 2147483648 # HELP genlayer_node_network_rx_bytes_total Total bytes received across all network interfaces # TYPE genlayer_node_network_rx_bytes_total counter genlayer_node_network_rx_bytes_total{component="node"} 1073741824 ``` #### Available Metrics The node collects metrics for three main components: - **Node** - The main node process - **GenVM** - The GenVM modules (LLM and Web) - **WebDriver** - The WebDriver container **CPU Metrics** **genlayer_node_cpu_usage_percent** Current CPU usage percentage (0-100). **Type:** Gauge **Labels:** - `component`: One of `node`, `genvm-llm`, `genvm-web`, `webdriver` **Example:** ``` genlayer_node_cpu_usage_percent{component="node"} 15.5 genlayer_node_cpu_usage_percent{component="genvm-llm"} 45.2 genlayer_node_cpu_usage_percent{component="genvm-web"} 12.8 genlayer_node_cpu_usage_percent{component="webdriver"} 5.3 ``` **Memory Metrics** **genlayer_node_memory_rss_bytes** Resident Set Size (RSS) memory usage in bytes. **Type:** Gauge **Labels:** - `component`: One of `node`, `genvm-llm`, `genvm-web`, `webdriver` **Example:** ``` genlayer_node_memory_rss_bytes{component="node"} 524288000 genlayer_node_memory_rss_bytes{component="genvm-llm"} 2147483648 ``` **genlayer_node_memory_vms_bytes** Virtual Memory Size (VMS) in bytes. **Type:** Gauge **Labels:** - `component`: One of `node`, `genvm-llm`, `genvm-web`, `webdriver` **Note:** Only available for node and GenVM components. **genlayer_node_memory_usage_bytes** Current memory usage in bytes (WebDriver only). **Type:** Gauge **Labels:** - `component`: `webdriver` **genlayer_node_memory_limit_bytes** Memory limit in bytes (WebDriver only). **Type:** Gauge **Labels:** - `component`: `webdriver` **genlayer_node_memory_percent** Memory usage percentage. **Type:** Gauge **Labels:** - `component`: One of `genvm-llm`, `genvm-web`, `node`, `webdriver` - `node`: Node address (hex format) **genlayer_node_memory_peak_bytes** Peak memory usage in bytes (GenVM components only). **Type:** Gauge **Labels:** - `component`: One of `genvm-llm`, `genvm-web` - `node`: Node address (hex format) **Network Metrics** **genlayer_node_network_rx_bytes_total** Total bytes received across all network interfaces. **Type:** Counter **Labels:** - `component`: One of `node`, `genvm-llm`, `genvm-web`, `webdriver` - `node`: Node address (hex format) **Example:** ``` genlayer_node_network_rx_bytes_total{component="node",node="0x84b6cbd007511352d3fea26834c5c39a440903c4"} 96879942 genlayer_node_network_rx_bytes_total{component="webdriver",node="0x84b6cbd007511352d3fea26834c5c39a440903c4"} 84 ``` **genlayer_node_network_tx_bytes_total** Total bytes transmitted across all network interfaces. **Type:** Counter **Labels:** - `component`: One of `node`, `genvm-llm`, `genvm-web`, `webdriver` - `node`: Node address (hex format) **Disk Metrics** **genlayer_node_disk_free_bytes** Available free disk space in bytes. **Type:** Gauge **Labels:** - `component`: `node` - `directory`: One of `genlayer.db`, `keystore`, `logs` - `node`: Node address (hex format) **genlayer_node_disk_total_bytes** Total disk space in bytes. **Type:** Gauge **Labels:** - `component`: `node` - `directory`: One of `genlayer.db`, `keystore`, `logs` - `node`: Node address (hex format) **genlayer_node_disk_usage_bytes** Used disk space in bytes. **Type:** Gauge **Labels:** - `component`: `node` - `directory`: One of `genlayer.db`, `keystore`, `logs` - `node`: Node address (hex format) **genlayer_node_disk_usage_percent** Used disk space as percentage. **Type:** Gauge **Labels:** - `component`: `node` - `directory`: One of `genlayer.db`, `keystore`, `logs` - `node`: Node address (hex format) **Node Status Metrics** **genlayer_node_blocks_behind** Number of blocks behind the latest block. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_latest_block** Latest block number in the network. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_processing_block** Currently processing block number. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_synced_block** Last synced block number. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_synced** Node synchronization status (1 = synced, 0 = not synced). **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_uptime_seconds** Node uptime in seconds. **Type:** Gauge **Labels:** - `component`: `node` - `node`: Node address (hex format) **Transaction Metrics** **genlayer_node_transactions_accepted_synced_total** Total number of accepted and synced transactions. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_transactions_activated_total** Total number of activated transactions. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_transactions_leader_proposed_total** Total number of transactions proposed as leader. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_transactions_leader_revealed_total** Total number of transactions revealed as leader. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_transactions_validator_commit_total** Total number of validator commit votes. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_transactions_validator_reveal_total** Total number of validator reveal votes. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **Go Runtime Metrics** The endpoint also exposes standard Go runtime metrics including: - `go_gc_duration_seconds` - Garbage collection duration summary - `go_goroutines` - Number of active goroutines - `go_memstats_*` - Go memory statistics (heap, stack, GC) - `go_threads` - Number of OS threads **Process Metrics** Standard process metrics are also available: - `process_cpu_seconds_total` - Total CPU time - `process_resident_memory_bytes` - Resident memory size - `process_virtual_memory_bytes` - Virtual memory size - `process_open_fds` - Number of open file descriptors - `process_network_receive_bytes_total` - Network bytes received - `process_network_transmit_bytes_total` - Network bytes transmitted **Prometheus Handler Metrics** Metrics about the metrics endpoint itself: - `promhttp_metric_handler_requests_total` - Total scrape requests by status code - `promhttp_metric_handler_requests_in_flight` - Current scrapes being served #### Configuration Metrics collection can be configured in the node configuration file: ```yaml metrics: interval: "15s" # Default interval for all collectors collectors: node: enabled: true # Enable/disable node metrics interval: "30s" # Optional: Override default interval genvm: enabled: true # Enable/disable GenVM metrics # Uses default interval (15s) webdriver: enabled: true # Enable/disable WebDriver metrics interval: "60s" # Optional: Override default interval ``` **Default Values** - `metrics.interval`: 15s (applies to all collectors by default) - `enabled`: true (for each collector) - `interval`: Uses metrics.interval if not specified per collector **Configuration Priority** 1. Collector-specific `interval` (if specified) 2. Global `metrics.interval` (if specified) 3. System default (15s) #### Troubleshooting **No Metrics for GenVM** GenVM processes are ephemeral and only run when executing smart contracts. If you don't see GenVM metrics, it's likely that no contracts are currently being executed. **WebDriver Metrics Missing** Ensure the WebDriver container is running: ```bash docker ps | grep genlayer-node-webdriver ``` If not running, start it: ```bash task docker:webdriver:docker-compose:up:detach ``` **Metrics Not Updating** Check if metrics collection is enabled in your configuration and that the node has been restarted after configuration changes. #### Performance Considerations - Collection intervals can be increased to reduce overhead further - Each collector runs independently and won't block others if one fails # api-references/genlayer-node/gen/gen_call.mdx ### gen_call Executes a new message call immediately without creating a transaction on the blockchain. This method supports read operations, write operations, and contract deployments. **Method:** `gen_call` **Parameters:** - `request` (object, required): The contract call request parameters - `from` (string, required): The address making the call - `to` (string, required): The contract address to call - `Data` (string, required): The encoded function call data - `Type` (string, required): The type of call (`"read"`, `"write"`, or `"deploy"`) - `blockNumber` (string, optional): The block number to query at (hex-encoded). If not provided, uses latest block - `status` (string, optional): The transaction status filter (`"finalized"` or `"accepted"`). If not provided, uses accepted state - `value` (string, optional): The value to send with the call (hex-encoded) **Returns:** Hex-encoded result data **Example - Read Call (Latest Accepted State):** ```json { "jsonrpc": "2.0", "method": "gen_call", "params": [ { "Type": "read", "Data": "0xd8960e066d6574686f646c6765745f686176655f636f696e00", "from": "0xf6A60752C24Cd3BFcAf8d387a5EB62d3746F44EE", "to": "0xCe5712E63fd5475288aB1B7c0a368B9417357b81", "gas": "0x5208", "value": "0x0" } ], "id": 1 } ``` **Example - Read Call with Specific Block and Status:** ```json { "jsonrpc": "2.0", "method": "gen_call", "params": [ { "Type": "read", "Data": "0xd8960e066d6574686f646c6765745f686176655f636f696e00", "from": "0xf6A60752C24Cd3BFcAf8d387a5EB62d3746F44EE", "to": "0xCe5712E63fd5475288aB1B7c0a368B9417357b81", "blockNumber": "0x151ec5", "status": "accepted" } ], "id": 1 } ``` **Example - Write Call:** ```json { "jsonrpc": "2.0", "method": "gen_call", "params": [ { "from": "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8b6", "to": "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8b6", "data": "0xa9059cbb000000000000000000000000742d35cc6634c0532925a3b8d4c9db96c4b4d8b6", "type": "write", "gas": "0x5208", "value":"0x0" } ], "id": 1 } ``` **Notes:** - The `blockNumber` parameter can be either hex-encoded with a `0x` prefix (e.g., `"0x151ec5"`) or decimal (e.g., `"1384133"`) - Valid `status` values are `"accepted"` (default) and `"finalized"` - When both parameters are omitted, the call executes against the latest accepted state - For `read` and `write` type calls, if the contract doesn't exist at the specified block/status combination, an error will be returned - For `deploy` type calls, the `status` and `blockNumber` parameters are not used for contract state validation since no contract exists yet # api-references/genlayer-node/gen/gen_getContractSchema.mdx ### gen_getContractSchema Retrieve the schema/interface of a GenLayer contract to understand its available methods and properties. **Method:** `gen_getContractSchema` **Parameters:** - `request` (object, required): The contract schema request - `code` (string, required): Base64-encoded contract code **Returns:** Contract schema object with methods and properties ```json { "ctor": { // constructor info "kwparams": {}, // dict "params": [["value", "type"]] // list of tuples }, "methods": { // dict from method name to method info "method_name": { "kwparams": {}, // dict "params": [["value", "type"]], // list of tuples "payable": false, // bool "readonly": false, // bool "ret": "null" // string }, } } ``` **Example:** ```json { "jsonrpc": "2.0", "method": "gen_getContractSchema", "params": [ { "code": "IyB7ICJEZXBlbmRzIjogInB5LWdlbmxheWVyOnRlc3QiIH0KCmZyb20gZ2VubGF5ZXIgaW1wb3J0ICoKCgojIGNvbnRyYWN0IGNsYXNzCmNsYXNzIFN0b3JhZ2UoZ2wuQ29udHJhY3QpOgogICAgc3RvcmFnZTogc3RyCgogICAgIyBjb25zdHJ1Y3RvcgogICAgZGVmIF9faW5pdF9fKHNlbGYsIGluaXRpYWxfc3RvcmFnZTogc3RyKToKICAgICAgICBzZWxmLnN0b3JhZ2UgPSBpbml0aWFsX3N0b3JhZ2UKCiAgICAjIHJlYWQgbWV0aG9kcyBtdXN0IGJlIGFubm90YXRlZCB3aXRoIHZpZXcKICAgIEBnbC5wdWJsaWMudmlldwogICAgZGVmIGdldF9zdG9yYWdlKHNlbGYpIC0+IHN0cjoKICAgICAgICByZXR1cm4gc2VsZi5zdG9yYWdlCgogICAgIyB3cml0ZSBtZXRob2QKICAgIEBnbC5wdWJsaWMud3JpdGUKICAgIGRlZiB1cGRhdGVfc3RvcmFnZShzZWxmLCBuZXdfc3RvcmFnZTogc3RyKSAtPiBOb25lOgogICAgICAgIHNlbGYuc3RvcmFnZSA9IG5ld19zdG9yYWdlCg==" } ], "id": 1 } ``` **Response:** ```json { "jsonrpc": "2.0", "result": { "ctor": { "kwparams": {}, "params": [["initial_storage", "string"]] }, "methods": { "get_storage": { "kwparams": {}, "params": [], "readonly": true, "ret": "string" }, "update_storage": { "kwparams": {}, "params": [["new_storage", "string"]], "payable": false, "readonly": false, "ret": "null" } } }, "id": 1 } ``` # api-references/genlayer-node/gen/gen_getTransactionReceipt.mdx ### gen_getTransactionReceipt Retrieves the transaction receipt for a given transaction ID. This endpoint is a proxy to the underlying consensus layer's `getTransactionAllData` function, providing detailed information about a transaction that has been processed. **Method:** `gen_getTransactionReceipt` **Parameters:** - `request` (object, required): - `txId` (`string`, required): The 32-byte transaction hash as a hexadecimal string with a `0x` prefix. **Returns:** A `Transaction` object which contains the details of the transaction. The structure is based on `ITransactionsTransaction` from the consensus contracts. The object has the following fields: - `id` (`string`): The transaction ID as a hex string. - `txOrigin` (`address`): The original address that initiated the transaction. - `sender` (`address`): The address of the sender. - `recipient` (`address`): The destination address of the transaction. - `activator` (`address`): The address of the validator that activated the transaction. - `status` (`uint8`): The current status of the transaction. - `previousStatus` (`uint8`): The previous status of the transaction. - `txSlot` (`uint256`): The transaction slot number. - `initialRotations` (`uint256`): The initial number of rotations. - `numOfInitialValidators` (`uint256`): The number of initial validators. - `randomSeed` (`string`): The random seed used for the transaction as a hex string. - `txExecutionHash` (`string`): The execution hash of the transaction as a hex string. - `otherExecutionFieldsHash` (`string`): Hash of other execution fields as a hex string. - `txData` (`string`): The transaction data as a hex string. - `eqBlocksOutputs` (`string`): The equivalent blocks outputs as a hex string. - `timestamps` (`object`): Object containing various timestamps: - `Created` (`uint256`): When the transaction was created. - `Pending` (`uint256`): When the transaction became pending. - `Activated` (`uint256`): When the transaction was activated. - `Proposed` (`uint256`): When the transaction was proposed. - `Committed` (`uint256`): When the transaction was committed. - `LastVote` (`uint256`): When the last vote was cast. - `AppealSubmitted` (`uint256`): When an appeal was submitted. - `LeaderRevealed` (`uint256`): When the leader was revealed. - `result` (`uint256`): The result of the transaction execution. - `readStateBlockRange` (`object`): Block range information: - `ActivationBlock` (`uint256`): The activation block number. - `ProcessingBlock` (`uint256`): The processing block number. - `ProposalBlock` (`uint256`): The proposal block number. - `consumedValidators` (`array`): Array of validator addresses that participated. - `roundData` (`array`): Array of round data objects containing: - `round` (`uint256`): The round number. - `leaderIndex` (`uint256`): Index of the round leader. - `votesCommitted` (`uint256`): Number of votes committed. - `votesRevealed` (`uint256`): Number of votes revealed. - `appealBond` (`uint256`): The appeal bond amount. - `rotationsLeft` (`uint256`): Number of rotations remaining. - `result` (`uint256`): The round result. - `roundValidators` (`array`): Array of validator addresses for this round. - `validatorVotes` (`string`): Base64-encoded validator votes. - `validatorVotesHash` (`array`): Array of vote hashes as hex strings. - `validatorResultHash` (`array`): Array of result hashes as hex strings. **Example Request:** ```json { "jsonrpc": "2.0", "method": "gen_getTransactionReceipt", "params": [ { "txId": "0x635060dd514082096d18c8eb64682cc6a944f9ce1ae6982febf7a71e9f656f49" } ], "id": 1 } ``` **Example Response:** ```json { "jsonrpc": "2.0", "id": 1, "result": { "id": "0x635060dd514082096d18c8eb64682cc6a944f9ce1ae6982febf7a71e9f656f49", "txOrigin": "0x5b70759760a85d92bf972b67ee8558e8e8da87d4", "sender": "0x5b70759760a85d92bf972b67ee8558e8e8da87d4", "recipient": "0x73ca5a2b51edf506ceaf110a41780ec51294d89f", "activator": "0xf27b07d36ff5b9dcd37fd3a09811d6456dd4483a", "status": 14, "previousStatus": 0, "txSlot": 1, "initialRotations": 1, "numOfInitialValidators": 5, "randomSeed": "0x3d0bdff63bce1cf84b155f1557bb15e303b903b1b559325b6492794a5e498954", "txExecutionHash": "0x76744dc491b1725eb2ba08cf516855c14aac310e36711368c04442fd39d61853", "otherExecutionFieldsHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "txData": "f5b31604617267730da4017570646174656420746573742073746f72616765066d6574686f64747570646174655f73746f7261676500", "eqBlocksOutputs": "c0", "timestamps": { "Created": 1750774777, "Pending": 1750774777, "Activated": 1750774781, "Proposed": 1750774786, "Committed": 1750774791, "LastVote": 0, "AppealSubmitted": 0, "LeaderRevealed": 0 }, "result": 0, "readStateBlockRange": { "ActivationBlock": 1377797, "ProcessingBlock": 1377797, "ProposalBlock": 1377798 }, "consumedValidators": [ "0xa707a1d9dd946242f921f0ad62f61e1b7df30c85", "0xf27b07d36ff5b9dcd37fd3a09811d6456dd4483a", "0xf3738216c3208d77a9db79a1d31824e5133083c4", "0x56394354538bff1e0ee5021c2b6d3522fce30257", "0xcfdbac032f82f388d9eca76efa6610b98e7f59fe" ], "roundData": [ { "round": 0, "leaderIndex": 3, "votesCommitted": 5, "votesRevealed": 0, "appealBond": 0, "rotationsLeft": 1, "result": 0, "roundValidators": [ "0xa707a1d9dd946242f921f0ad62f61e1b7df30c85", "0xf27b07d36ff5b9dcd37fd3a09811d6456dd4483a", "0xf3738216c3208d77a9db79a1d31824e5133083c4", "0x56394354538bff1e0ee5021c2b6d3522fce30257", "0xcfdbac032f82f388d9eca76efa6610b98e7f59fe" ], "validatorVotes": "AAAAAAA=", "validatorVotesHash": [ "54e3478b02dfb009a35d46b19ac7c967b65416430a33d3860e9301a0f2b19d57", "f74a48e7283c91757bf2c612e40f8a9eb69ea0f02cf5e6b89c3c9b6ad629a3c1", "2f51c3b1d9ff35140260fb42330fbed12303a9915b8da786c9b8ed060983fa6c", "730127e27167fcf2450fe506250b85d916fbf07dd874b7f0c69a2f8ceb9e44a6", "473d57953f7e7c1a6fb1d2335618f21088025e02bd9fa30d6f85f20a55c24d15" ], "validatorResultHash": [ "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000", "0000000000000000000000000000000000000000000000000000000000000000" ] } ] } } ``` # api-references/genlayer-node/gen/gen_getContractState.mdx ### gen_getContractState Retrieves the current state of a GenLayer intelligent contract at a specific block height and transaction status. **Method:** `gen_getContractState` **Parameters:** - `request` (object, required): The contract state request parameters - `address` (string, required): The contract address to query - `blockNumber` (string, optional): The block number to query at (hex-encoded). If not provided, uses latest block - `status` (string, optional): The transaction status filter (`"finalized"` or `"accepted"`). If not provided, uses accepted state **Returns:** Hex-encoded contract state data **Example Request - Latest Accepted State:** ```json { "jsonrpc": "2.0", "method": "gen_getContractState", "params": [ { "address": "0x73ca5a2b51edf506ceaf110a41780ec51294d89f" } ], "id": 1 } ``` **Example Request - Specific Block and Status:** ```json { "jsonrpc": "2.0", "method": "gen_getContractState", "params": [ { "address": "0x73ca5a2b51edf506ceaf110a41780ec51294d89f", "blockNumber": "0x151ec5", "status": "accepted" } ], "id": 1 } ``` **Example Response:** ```json { "jsonrpc": "2.0", "result": "0xd9960e0773746f726167656c6e757064617465642074657374207374", "id": 1 } ``` **Notes:** - The `blockNumber` parameter should be hex-encoded with a `0x` prefix - Valid `status` values are `"accepted"` (default) and `"finalized"` - The returned state is hex-encoded binary data with a `0x` prefix - Empty contract state returns `"0x"` - If the contract doesn't exist at the specified block/status, an error will be returned **cURL Example:** ```bash # Get latest accepted state curl -X POST http://localhost:9151 \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "gen_getContractState", "params": [{ "address": "0x73ca5a2b51edf506ceaf110a41780ec51294d89f" }], "id": 1 }' # Get state at specific block with accepted status curl -X POST http://localhost:9151 \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "gen_getContractState", "params": [{ "address": "0x73ca5a2b51edf506ceaf110a41780ec51294d89f", "blockNumber": "0x151ec5", "status": "accepted" }], "id": 1 }' ``` # api-references/genlayer-node/debug/gen_dbg_ping.mdx ### gen_dbg_ping Simple connectivity test method that returns a "pong" response. **Method:** `gen_dbg_ping` **Parameters:** None **Returns:** "pong" string **Example:** ```json { "jsonrpc": "2.0", "method": "gen_dbg_ping", "params": [], "id": 1 } ``` **Response:** ```json { "jsonrpc": "2.0", "result": "pong", "id": 1 } ``` # api-references/genlayer-node/debug/gen_dbg_trie.mdx ### gen_dbg_trie Get trie information for debugging node internal DB state. **Method:** `gen_dbg_trie` **Parameters:** - `request` (object, required): The trie debug request - `txID` (string, required): Transaction ID (hex-encoded) - `round` (integer, required): Round number **Returns:** Trie debug information string **Example:** ```json { "jsonrpc": "2.0", "method": "gen_dbg_trie", "params": [ { "txID": "0x742d35Cc6634C0532925a3b8D4C9db96c4b4d8b6742d35Cc6634C0532925a3b8", "round": 0 } ], "id": 1 } ``` **Response:** ```json { "jsonrpc": "2.0", "result": "graph TD\nnode0@{label: \"br seq=1\"}\nnode1@{label: \"ext seq=1 0x00000000000000000000000000000000000000000000000000000000000000000000000\"}\nnode1 --\u003e data2@{label: \"seq=1\n[21 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\"}\nnode0 --\u003e|0| node1\nnode3@{label: \"ext seq=1 0x72d46c3ada9f897c74d349bbfe0e450c798167c9f580f8daf85def57e96c3ea00000000\"}\nnode3 --\u003e data4@{label: \"seq=1\n[105 110 105 116 105 97 108 32 115 116 111 114 97 103 101 32 118 97 108 117 101 0 0 0 0 0 0 0 0 0 0 0]\"}\nnode0 --\u003e|3| node3\n", "id": 1 } # api-references/genlayer-node/ops/balance.mdx ### balance Returns the configured operator's account balance in multiple formats including hexadecimal, wei, and GEN units. **Method:** `GET /balance` **Parameters:** None **Returns:** JSON object containing the operator's balance in three formats **Example Request:** ```bash curl -X GET http://localhost:9153/balance ``` **Example Response:** ```json { "balance_hex": "0x0de0b6b3a7640000", "balance_wei": "1000000000000000000", "balance_gen": "1.000" } ``` **Response Fields:** - `balance_hex` (string): The balance encoded as hexadecimal with "0x" prefix - `balance_wei` (string): The balance in wei as a decimal string - `balance_gen` (string): The balance in GEN units formatted with 3 decimal places **Notes:** - This endpoint is only available when the node is running in validator mode - The balance is always retrieved from the latest block - The operator address is configured at node startup - If the operator address is not configured, the zero address (0x0000...0000) is used - Balance conversions: 1 GEN = 1,000,000,000,000,000,000 wei (10^18 wei) - Returns HTTP 503 if the node is not in validator mode - Returns HTTP 500 if there's an error retrieving the balance **Example Response (Zero Balance):** ```json { "balance_hex": "0x", "balance_wei": "0", "balance_gen": "0.000" } ``` **Example Response (Large Balance):** ```json { "balance_hex": "0x3635c9adc5dea00000", "balance_wei": "1000000000000000000000", "balance_gen": "1000.000" } ``` **Error Response (Not in Validator Mode):** ```json { "message": "Balance endpoint not available in rollup mode" } ``` **cURL Example with Headers:** ```bash curl -X GET http://localhost:9153/balance \ -H "Accept: application/json" \ -v ``` # api-references/genlayer-node/ops/health.mdx ### health Returns the health status of the GenLayer node along with version information and the status of individual health checks. **Method:** `GET /health` **Parameters:** None **Returns:** JSON object containing the overall health status, version information, and individual check results **Example Request:** ```bash curl -X GET http://localhost:9153/health ``` **Example Response:** ```json { "status": "up", "node_version": "v1.2.3", "protocol_version": "consensus-v2.1", "checks": { "test-check": { "status": "up", "timestamp": "2024-01-15T10:30:45Z" } } } ``` **Response Fields:** - `status` (string): Overall health status - "up" if all checks pass, "down" if any check fails - `node_version` (string): The version of the GenLayer node software - `protocol_version` (string): The consensus protocol version - `checks` (object, optional): Map of individual health check results - `[check-name]` (object): Results for a specific health check - `status` (string): Check status - "up" or "down" - `timestamp` (string): ISO 8601 timestamp of when the check was performed - `error` (string, optional): Error message if check failed **HTTP Status Codes:** - `200 OK`: Node is healthy (all checks passing) - `503 Service Unavailable`: Node is unhealthy (one or more checks failing) **Notes:** - The endpoint has a 5-second timeout for all health checks - The `checks` field is only included when health checks are configured - Version fields will show "unset" if version information is not available - Individual health checks are executed concurrently with results aggregated in the response **Example Response (Unhealthy):** ```json { "status": "down", "node_version": "v1.2.3", "protocol_version": "consensus-v2.1", "checks": { "database": { "status": "down", "error": "connection timeout", "timestamp": "2024-01-15T10:30:45Z" }, "consensus": { "status": "up", "timestamp": "2024-01-15T10:30:45Z" } } } ``` **cURL Example with Headers:** ```bash curl -X GET http://localhost:9153/health \ -H "Accept: application/json" \ -v ``` # api-references/genlayer-node/ops/metrics.mdx ### metrics Exposes Prometheus-compatible metrics for monitoring node performance and health. **Method:** `GET /metrics` **Parameters:** None **Returns:** Prometheus-format text response with all collected metrics **Example Request:** ```bash curl -X GET http://localhost:9153/metrics ``` **Example Response:** ``` # HELP genlayer_node_cpu_usage_percent Current CPU usage percentage (0-100) # TYPE genlayer_node_cpu_usage_percent gauge genlayer_node_cpu_usage_percent{component="node"} 15.5 genlayer_node_cpu_usage_percent{component="genvm-llm"} 45.2 genlayer_node_cpu_usage_percent{component="genvm-web"} 12.8 genlayer_node_cpu_usage_percent{component="webdriver"} 5.3 # HELP genlayer_node_memory_rss_bytes Resident Set Size (RSS) memory usage in bytes # TYPE genlayer_node_memory_rss_bytes gauge genlayer_node_memory_rss_bytes{component="node"} 524288000 genlayer_node_memory_rss_bytes{component="genvm-llm"} 2147483648 # HELP genlayer_node_network_rx_bytes_total Total bytes received across all network interfaces # TYPE genlayer_node_network_rx_bytes_total counter genlayer_node_network_rx_bytes_total{component="node"} 1073741824 ``` #### Available Metrics The node collects metrics for three main components: - **Node** - The main node process - **GenVM** - The GenVM modules (LLM and Web) - **WebDriver** - The WebDriver container **CPU Metrics** **genlayer_node_cpu_usage_percent** Current CPU usage percentage (0-100). **Type:** Gauge **Labels:** - `component`: One of `node`, `genvm-llm`, `genvm-web`, `webdriver` **Example:** ``` genlayer_node_cpu_usage_percent{component="node"} 15.5 genlayer_node_cpu_usage_percent{component="genvm-llm"} 45.2 genlayer_node_cpu_usage_percent{component="genvm-web"} 12.8 genlayer_node_cpu_usage_percent{component="webdriver"} 5.3 ``` **Memory Metrics** **genlayer_node_memory_rss_bytes** Resident Set Size (RSS) memory usage in bytes. **Type:** Gauge **Labels:** - `component`: One of `node`, `genvm-llm`, `genvm-web`, `webdriver` **Example:** ``` genlayer_node_memory_rss_bytes{component="node"} 524288000 genlayer_node_memory_rss_bytes{component="genvm-llm"} 2147483648 ``` **genlayer_node_memory_vms_bytes** Virtual Memory Size (VMS) in bytes. **Type:** Gauge **Labels:** - `component`: One of `node`, `genvm-llm`, `genvm-web`, `webdriver` **Note:** Only available for node and GenVM components. **genlayer_node_memory_usage_bytes** Current memory usage in bytes (WebDriver only). **Type:** Gauge **Labels:** - `component`: `webdriver` **genlayer_node_memory_limit_bytes** Memory limit in bytes (WebDriver only). **Type:** Gauge **Labels:** - `component`: `webdriver` **genlayer_node_memory_percent** Memory usage percentage. **Type:** Gauge **Labels:** - `component`: One of `genvm-llm`, `genvm-web`, `node`, `webdriver` - `node`: Node address (hex format) **genlayer_node_memory_peak_bytes** Peak memory usage in bytes (GenVM components only). **Type:** Gauge **Labels:** - `component`: One of `genvm-llm`, `genvm-web` - `node`: Node address (hex format) **Network Metrics** **genlayer_node_network_rx_bytes_total** Total bytes received across all network interfaces. **Type:** Counter **Labels:** - `component`: One of `node`, `genvm-llm`, `genvm-web`, `webdriver` - `node`: Node address (hex format) **Example:** ``` genlayer_node_network_rx_bytes_total{component="node",node="0x84b6cbd007511352d3fea26834c5c39a440903c4"} 96879942 genlayer_node_network_rx_bytes_total{component="webdriver",node="0x84b6cbd007511352d3fea26834c5c39a440903c4"} 84 ``` **genlayer_node_network_tx_bytes_total** Total bytes transmitted across all network interfaces. **Type:** Counter **Labels:** - `component`: One of `node`, `genvm-llm`, `genvm-web`, `webdriver` - `node`: Node address (hex format) **Disk Metrics** **genlayer_node_disk_free_bytes** Available free disk space in bytes. **Type:** Gauge **Labels:** - `component`: `node` - `directory`: One of `genlayer.db`, `keystore`, `logs` - `node`: Node address (hex format) **genlayer_node_disk_total_bytes** Total disk space in bytes. **Type:** Gauge **Labels:** - `component`: `node` - `directory`: One of `genlayer.db`, `keystore`, `logs` - `node`: Node address (hex format) **genlayer_node_disk_usage_bytes** Used disk space in bytes. **Type:** Gauge **Labels:** - `component`: `node` - `directory`: One of `genlayer.db`, `keystore`, `logs` - `node`: Node address (hex format) **genlayer_node_disk_usage_percent** Used disk space as percentage. **Type:** Gauge **Labels:** - `component`: `node` - `directory`: One of `genlayer.db`, `keystore`, `logs` - `node`: Node address (hex format) **Node Status Metrics** **genlayer_node_blocks_behind** Number of blocks behind the latest block. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_latest_block** Latest block number in the network. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_processing_block** Currently processing block number. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_synced_block** Last synced block number. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_synced** Node synchronization status (1 = synced, 0 = not synced). **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_uptime_seconds** Node uptime in seconds. **Type:** Gauge **Labels:** - `component`: `node` - `node`: Node address (hex format) **Transaction Metrics** **genlayer_node_transactions_accepted_synced_total** Total number of accepted and synced transactions. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_transactions_activated_total** Total number of activated transactions. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_transactions_leader_proposed_total** Total number of transactions proposed as leader. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_transactions_leader_revealed_total** Total number of transactions revealed as leader. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_transactions_validator_commit_total** Total number of validator commit votes. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **genlayer_node_transactions_validator_reveal_total** Total number of validator reveal votes. **Type:** Gauge **Labels:** - `node`: Node address (hex format) **Go Runtime Metrics** The endpoint also exposes standard Go runtime metrics including: - `go_gc_duration_seconds` - Garbage collection duration summary - `go_goroutines` - Number of active goroutines - `go_memstats_*` - Go memory statistics (heap, stack, GC) - `go_threads` - Number of OS threads **Process Metrics** Standard process metrics are also available: - `process_cpu_seconds_total` - Total CPU time - `process_resident_memory_bytes` - Resident memory size - `process_virtual_memory_bytes` - Virtual memory size - `process_open_fds` - Number of open file descriptors - `process_network_receive_bytes_total` - Network bytes received - `process_network_transmit_bytes_total` - Network bytes transmitted **Prometheus Handler Metrics** Metrics about the metrics endpoint itself: - `promhttp_metric_handler_requests_total` - Total scrape requests by status code - `promhttp_metric_handler_requests_in_flight` - Current scrapes being served #### Configuration Metrics collection can be configured in the node configuration file: ```yaml metrics: interval: "15s" # Default interval for all collectors collectors: node: enabled: true # Enable/disable node metrics interval: "30s" # Optional: Override default interval genvm: enabled: true # Enable/disable GenVM metrics # Uses default interval (15s) webdriver: enabled: true # Enable/disable WebDriver metrics interval: "60s" # Optional: Override default interval ``` **Default Values** - `metrics.interval`: 15s (applies to all collectors by default) - `enabled`: true (for each collector) - `interval`: Uses metrics.interval if not specified per collector **Configuration Priority** 1. Collector-specific `interval` (if specified) 2. Global `metrics.interval` (if specified) 3. System default (15s) #### Troubleshooting **No Metrics for GenVM** GenVM processes are ephemeral and only run when executing smart contracts. If you don't see GenVM metrics, it's likely that no contracts are currently being executed. **WebDriver Metrics Missing** Ensure the WebDriver container is running: ```bash docker ps | grep genlayer-node-webdriver ``` If not running, start it: ```bash task docker:webdriver:docker-compose:up:detach ``` **Metrics Not Updating** Check if metrics collection is enabled in your configuration and that the node has been restarted after configuration changes. #### Performance Considerations - Collection intervals can be increased to reduce overhead further - Each collector runs independently and won't block others if one fails # partners/genlayerlabs.mdx ## GenLayer Labs [GenLayer Labs](https://www.genlayerlabs.com/) is a pioneering AI research lab dedicated to revolutionizing human-AI interaction. They are one of the core developers of GenLayer, focusing on using AI to enhance the performance, security, and scalability of blockchain networks. By embedding AI into the blockchain's core, GenLayer Labs enables decentralized applications to make smart decisions autonomously, opening new possibilities for automation and efficiency in various industries. We encourage other developers and organizations to collaborate with GenLayer Labs on this groundbreaking project. Together, we can push the boundaries of what AI and blockchain technology can achieve. # partners/heurist.mdx # Heurist [Heurist](https://www.heurist.ai/) is a Layer 2 network for AI model hosting and inference, built on the ZK Stack. It offers serverless access to open-source AI models through a decentralized network, making AI deployment easy and efficient for developers. This approach promotes transparency and reduces bias, which is especially useful for projects like GenLayer that require detailed AI analysis. In collaboration with GenLayer, Heurist provides APIs for open-source large language models (LLMs) to enable developers building Intelligent Contracts use AI at low or no cost. Developers building on GenLayer can obtain free [Heurist API credits](https://dev-api-form.heurist.ai) by using the referral code: _"genlayer"_. This partnership underscores our commitment to providing robust tools and scalable solutions for decentralized applications. # partners/ionet.mdx # io.net io.intelligence is an AI infrastructure and API platform that democratizes access to advanced AI models and AI agents for the IO community and AI developers. It allows users to access and integrate pre-trained open-source models and custom AI agents into their applications via API calls. io.intelligence is powered by [io.net](https://io.net)'s decentralized distributed compute network. In partnership with GenLayer, [io.net](https://io.net) provides access to over 25 of the top open source models including latest versions of Deepseek, Qwen, Llama and Mistral through one unified API endpoint. Developers on Genlayer can receive free daily compute tokens to access io.intelligence for Enterprise. Complete a short [form](https://form.typeform.com/to/pDmCCViV) to get started. API Reference: https://docs.io.net/reference/get-started-with-io-intelligence-api # partners/comput3.mdx # Comput3 [Comput3](https://genlayer.comput3.ai/) is a decentralized compute network providing access to various AI models. The platform offers serverless access to open-source AI models through a distributed infrastructure, enabling developers to leverage powerful AI capabilities without the need for local hardware. In partnership with GenLayer, Comput3 provides access to inferencing APIs with support for llama3, hermes3, and qwen3 models. GenLayer Validators can use the Comput3.ai inferencing API to power their Intelligent Contracts with high-quality AI responses. Validators can obtain free [Comput3 API credits](https://genlayer.comput3.ai/) to get started with their validator setup. This partnership enhances the GenLayer ecosystem by providing reliable and scalable AI inference capabilities for decentralized applications. # FAQ.mdx --- title: "FAQ" --- # FAQ
1. What is GenLayer? GenLayer is an AI-native Layer 1 blockchain designed to run **Intelligent Contracts**—smart contracts enhanced with Large Language Models (LLMs)—enabling them to process natural language, fetch web data in real time, and execute data-driven logic.
2. How is GenLayer different from traditional blockchains? Most blockchains rely solely on deterministic logic and external oracles to interact with off-chain data. **GenLayer integrates AI at the protocol level**, allowing on-chain contracts to directly interpret text prompts, perform complex computations, and adapt to real-world events without relying on external oracles.
3. What is “Optimistic Democracy” consensus? **Optimistic Democracy** is GenLayer’s enhanced Delegated Proof of Stake (dPoS) mechanism. It randomly selects a **Lead-Validator** to process transactions and multiple **Co-Validators** to verify the results. The system is designed to handle non-deterministic (AI-driven) outputs securely by requiring a majority agreement.
4. Why does GenLayer use Large Language Models (LLMs)? LLMs give Intelligent Contracts the ability to interpret and process complex human language, as well as to analyze data in ways traditional code-based smart contracts cannot. This opens up new use cases, such as AI-driven DAOs, predictive analytics, and autonomous oracles.
5. Can I still run normal, deterministic transactions on GenLayer? Absolutely. GenLayer supports **standard blockchain transactions** and deterministic logic alongside AI-driven logic. Developers can write regular smart contracts or Intelligent Contracts depending on their needs.
6. Do I have to be an AI expert to build on GenLayer? Not necessarily. While some knowledge of AI or LLMs can help, GenLayer provides a **Python-based SDK** and user-friendly tools (like the GenLayer Studio) to simplify contract creation. You can harness AI capabilities without deep machine learning expertise.
7. How do validators handle AI computation? Each validator runs both **Validator Software** (for networking, block production, and transaction management) **and** an **AI Model Integration** via API. When a contract calls an AI-dependent function, the validator executes that function locally, **then** verifies the output through the consensus process.
8. What happens if validators disagree on an AI result? In **Optimistic Democracy**, disagreements trigger a **majority vote**. If a validator strongly believes the proposed result is incorrect, they can challenge or appeal the outcome within the **Finality Window**. An appeal bond is posted to discourage frivolous or malicious appeals.
9. How do I get started as a developer? 1. Install the **GenLayer CLI** and set up your local environment. 2. Explore the **GenLayer Studio** to write, deploy, and test your Intelligent Contracts. 3. Check out the **genlayer-project-boilerplate** for end-to-end testing setups and best practices. 4. Use **GenLayerJS** or other tools for front-end integration.
10. Can I use any LLM provider? GenLayer is designed to **integrate with multiple LLM providers**, such as GPT, LLaMA, and others. During the `genlayer init` process, you can configure your preferred LLM, including its API keys and model parameters. You can also customize or switch providers as needed.
11. How is the network secured? Security is driven by a **delegated staking** model plus the **Optimistic Democracy** consensus process: - Token holders delegate **stake** to validators, incentivizing honest behavior. - **Multi-Validator Verification** mitigates errors by checking each other’s results. - **Appeals** provide a failsafe, penalizing dishonest validators via slashing.
12. What are the typical use cases for GenLayer? - **Prediction Markets**: AI-powered event outcomes - **Performance-Based Contracting**: Automatic escrow and payments tied to real-time metrics - **Network States**: Decentralized governance frameworks - **Dispute Resolution**: Low-cost, AI-driven arbitration - **AI-Driven DAOs**: Autonomous organizations that react to off-chain data
13. How can I contribute to GenLayer? You can: - Join the community on **Discord** or **Telegram** - Contribute code and documentation in GenLayer’s GitHub repositories - Provide feedback and suggestions to improve the GenLayer ecosystem - Help grow the community by sharing GenLayer with potential developers and AI enthusiasts