diff --git a/README.md b/README.md index 62abce2d28..0e5cfeadb7 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,11 @@ -### Build status - -| Develop | Berkeley | Compatible | -| ------- | -------- | ---------- | -| [![Build status - develop](https://badge.buildkite.com/0c47452f3ea619d3217d388e0de522b218db28c3e161887a9a.svg?branch=develop)](https://buildkite.com/o-1-labs-2/mina-end-to-end-nightlies) | [![Build status - berkeley](https://badge.buildkite.com/0c47452f3ea619d3217d388e0de522b218db28c3e161887a9a.svg?branch=berkeley)](https://buildkite.com/o-1-labs-2/mina-end-to-end-nightlies) | [![Build status - compatible](https://badge.buildkite.com/0c47452f3ea619d3217d388e0de522b218db28c3e161887a9a.svg?branch=compatible)](https://buildkite.com/o-1-labs-2/mina-end-to-end-nightlies) - - - Mina logo - - # Zeko -[Zeko](https://twitter.com/ZekoLabs) is a fully isomorphic L2 for the Mina protocol ecosystem. Same client-side ZK private compute layer, and compatible with Mina infra and tooling, but super fast. - -This repository is a fork of the [Mina codebase](https://github.com/MinaProtocol/mina). The zeko related code is in the [zeko](./src/app/zeko) directory. - -# Mina - -Mina is the first cryptocurrency with a lightweight, constant-sized blockchain. This is the main source code repository for the Mina project and contains code for the OCaml protocol implementation, the [Mina Protocol website](https://minaprotocol.com), and wallet. Enjoy! - -## Notes - -Mina is still under active development and APIs are evolving. If you build on the APIs, be aware that breaking changes can occur. - -The Mina implementation of the Rosetta API offers a more stable and useful interface for retrieving the blockchain's state. Rosetta is run as a separate process and it relies on an archive being connected to a node. The source code for the archive and Rosetta implementation are in [src/app/archive](https://github.com/MinaProtocol/mina/tree/develop/src/app/archive) and [src/app/rosetta](https://github.com/MinaProtocol/mina/tree/develop/src/app/rosetta). Be sure to follow updates in the project if these resources are relocated. - -## What is Mina? - -### Mina Walkthrough - -- [Mina Protocol](https://docs.minaprotocol.com/) documentation -- [Installing and using a third-party wallet](https://docs.minaprotocol.com/using-mina/install-a-wallet) -- [Sending a Payment using Mina's CLI](https://docs.minaprotocol.com/node-operators/sending-a-payment) -- [Become a Node Operator](https://minaprotocol.com/docs/getting-started/) - -### Technical Papers - -- [Mina Whitepaper](https://eprint.iacr.org/2020/352.pdf) - -### Blog - -- [Mina Protocol Blog](https://minaprotocol.com/blog.html) - -## Contributing - -For information on how to make technical and non-technical contributions, see the repository contributing guidelines in [CONTRIBUTING](https://github.com/MinaProtocol/mina/blob/develop/CONTRIBUTING.md) and the [Contributing Guide](https://docs.minaprotocol.com/node-developers/contributing) docs. - -## Developers - -The [Node Developers](https://docs.minaprotocol.com/node-developers) docs contain helpful information about contributing code to Mina and using Mina APIs to build applications. - -### Quick Links - -- [Developer README](README-dev.md) -- [Running a demo node](docs/demo.md) -- [Lifecycle of a payment](https://docs.minaprotocol.com/node-operators/lifecycle-of-a-payment) - -## Community - -- Join the public Mina Protocol [Discord server](https://discord.gg/minaprotocol). Please come by if you need help or have any questions. -- Participate in our [online communities](https://docs.minaprotocol.com/participate/online-communities). -- Get the latest updates by signing up for the Mina newsletter. Select [SIGN UP FOR NEWSLETTER](https://minaprotocol.com/) on the home page of the Mina Protocol website. - -## License +[Zeko](https://twitter.com/ZekoLabs) is a fully isomorphic L2 for the Mina protocol ecosystem. +We support recursion in smart contracts natively, the exact same as Mina. -[Apache 2.0](LICENSE) +This repository is a fork of the [Mina codebase](https://github.com/MinaProtocol/mina). +The Zeko related code is in the [`zeko`](./src/app/zeko) directory. -Commits older than 2018-10-03 do not have a [LICENSE](LICENSE) file or this notice, but are distributed under the same terms. +The license for code under the `zeko` subdirectory is [RPL-1.5](https://opensource.org/license/rpl-1-5) +and is **NOT** the Apache license at the root of the repository. +The Apache license only applies to the original Mina source code. diff --git a/src/app/zeko/LICENSE b/src/app/zeko/LICENSE new file mode 100644 index 0000000000..ff9d446aa1 --- /dev/null +++ b/src/app/zeko/LICENSE @@ -0,0 +1,155 @@ +Copyright (C) 2001-2007 Technical Pursuit Inc., All Rights Reserved. + +PREAMBLE + +The Reciprocal Public License (RPL) is based on the concept of reciprocity or, if you prefer, fairness. In short, this license grew out of a desire to close loopholes in previous open source licenses, loopholes that allowed parties to acquire open source software and derive financial benefit from it without having to release their improvements or derivatives to the community which enabled them. This occurred any time an entity did not release their application to a “third party”. While there is a certain freedom in this model of licensing, it struck the authors of the RPL as being unfair to the open source community at large and to the original authors of the works in particular. After all, bug fixes, extensions, and meaningful and valuable derivatives were not consistently finding their way back into the community where they could fuel further, and faster, growth and expansion of the overall open source software base. While you should clearly read and understand the entire license, the essence of the RPL is found in two definitions: “Deploy” and “Required Components”. Regarding deployment, under the RPL your changes, bug fixes, extensions, etc. must be made available to the open source community at large when you Deploy in any form — either internally or to an outside party. Once you start running the software you have to start sharing the software. Further, under the RPL all components you author including schemas, scripts, source code, etc. — regardless of whether they’re compiled into a single binary or used as two halves of client/server application — must be shared. You have to share the whole pie, not an isolated slice of it. In addition to these goals, the RPL was authored to meet the requirements of the Open Source Definition as maintained by the Open Source Initiative (OSI). + +The specific terms and conditions of the license are defined in the remainder of this document. + +LICENSE TERMS + +1.0 General; Applicability & Definitions. + +This Reciprocal Public License Version 1.5 (“License”) applies to any programs or other works as well as any and all updates or maintenance releases of said programs or works (“Software”) not already covered by this License which the Software copyright holder (“Licensor”) makes available containing a License Notice (hereinafter defined) from the Licensor specifying or allowing use or distribution under the terms of this License. + +As used in this License: + +1.1 “Contributor” means any person or entity who created or contributed to the creation of an Extension. + +1.2 “Deploy” means to use, Serve, sublicense or distribute Licensed Software other than for Your internal Research and/or Personal Use, and includes without limitation, any and all internal use or distribution of Licensed Software within Your business or organization other than for Research and/or Personal Use, as well as direct or indirect sublicensing or distribution of Licensed Software by You to any third party in any form or manner. + +1.3 “Derivative Works” as used in this License is defined under U.S. copyright law. + +1.4 “Electronic Distribution Mechanism” means a mechanism generally accepted in the software development community for the electronic transfer of data such as download from an FTP server or web site, where such mechanism is publicly accessible. + +1.5 “Extensions” means any Modifications, Derivative Works, or Required Components as those terms are defined in this License. + +1.6 “License” means this Reciprocal Public License. + +1.7 “License Notice” means any notice contained in EXHIBIT A. + +1.8 “Licensed Software” means any Software licensed pursuant to this License. Licensed Software also includes all previous Extensions from any Contributor that You receive. + +1.9 “Licensor” means the copyright holder of any Software previously not covered by this License who releases the Software under the terms of this License. + +1.10 “Modifications” means any additions to or deletions from the substance or structure of (i) a file or other storage containing Licensed Software, or (ii) any new file or storage that contains any part of Licensed Software, or (iii) any file or storage which replaces or otherwise alters the original functionality of Licensed Software at runtime. + +1.11 “Personal Use” means use of Licensed Software by an individual solely for his or her personal, private and non-commercial purposes. An individual’s use of Licensed Software in his or her capacity as an officer, employee, member, independent contractor or agent of a corporation, business or organization (commercial or non-commercial) does not qualify as Personal Use. + +1.12 “Required Components” means any text, programs, scripts, schema, interface definitions, control files, or other works created by You which are required by a third party of average skill to successfully install and run Licensed Software containing Your Modifications, or to install and run Your Derivative Works. + +1.13 “Research” means investigation or experimentation for the purpose of understanding the nature and limits of the Licensed Software and its potential uses. + +1.14 “Serve” means to deliver Licensed Software and/or Your Extensions by means of a computer network to one or more computers for purposes of execution of Licensed Software and/or Your Extensions. + +1.15 “Software” means any computer programs or other works as well as any updates or maintenance releases of those programs or works which are distributed publicly by Licensor. + +1.16 “Source Code” means the preferred form for making modifications to the Licensed Software and/or Your Extensions, including all modules contained therein, plus any associated text, interface definition files, scripts used to control compilation and installation of an executable program or other components required by a third party of average skill to build a running version of the Licensed Software or Your Extensions. + +1.17 “User-Visible Attribution Notice” means any notice contained in EXHIBIT B. + +1.18 “You” or “Your” means an individual or a legal entity exercising rights under this License. For legal entities, “You” or “Your” includes any entity which controls, is controlled by, or is under common control with, You, where “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of fifty percent (50%) or more of the outstanding shares or beneficial ownership of such entity. + +2.0 Acceptance Of License. + +You are not required to accept this License since you have not signed it, however nothing else grants you permission to use, copy, distribute, modify, or create derivatives of either the Software or any Extensions created by a Contributor. These actions are prohibited by law if you do not accept this License. Therefore, by performing any of these actions You indicate Your acceptance of this License and Your agreement to be bound by all its terms and conditions. + +IF YOU DO NOT AGREE WITH ALL THE TERMS AND CONDITIONS OF THIS LICENSE DO NOT USE, MODIFY, CREATE DERIVATIVES, OR DISTRIBUTE THE SOFTWARE. IF IT IS IMPOSSIBLE FOR YOU TO COMPLY WITH ALL THE TERMS AND CONDITIONS OF THIS LICENSE THEN YOU CAN NOT USE, MODIFY, CREATE DERIVATIVES, OR DISTRIBUTE THE SOFTWARE. + +3.0 Grant of License From Licensor. + +Subject to the terms and conditions of this License, Licensor hereby grants You a world-wide, royalty-free, non- exclusive license, subject to Licensor’s intellectual property rights, and any third party intellectual property claims derived from the Licensed Software under this License, to do the following: + +3.1 Use, reproduce, modify, display, perform, sublicense and distribute Licensed Software and Your Extensions in both Source Code form or as an executable program. + +3.2 Create Derivative Works (as that term is defined under U.S. copyright law) of Licensed Software by adding to or deleting from the substance or structure of said Licensed Software. + +3.3 Under claims of patents now or hereafter owned or controlled by Licensor, to make, use, have made, and/or otherwise dispose of Licensed Software or portions thereof, but solely to the extent that any such claim is necessary to enable You to make, use, have made, and/or otherwise dispose of Licensed Software or portions thereof. + +3.4 Licensor reserves the right to release new versions of the Software with different features, specifications, capabilities, functions, licensing terms, general availability or other characteristics. Title, ownership rights, and intellectual property rights in and to the Licensed Software shall remain in Licensor and/or its Contributors. + +4.0 Grant of License From Contributor. + +By application of the provisions in Section 6 below, each Contributor hereby grants You a world-wide, royalty- free, non-exclusive license, subject to said Contributor’s intellectual property rights, and any third party intellectual property claims derived from the Licensed Software under this License, to do the following: + +4.1 Use, reproduce, modify, display, perform, sublicense and distribute any Extensions Deployed by such Contributor or portions thereof, in both Source Code form or as an executable program, either on an unmodified basis or as part of Derivative Works. + +4.2 Under claims of patents now or hereafter owned or controlled by Contributor, to make, use, have made, and/or otherwise dispose of Extensions or portions thereof, but solely to the extent that any such claim is necessary to enable You to make, use, have made, and/or otherwise dispose of Licensed Software or portions thereof. + +5.0 Exclusions From License Grant. Nothing in this License shall be deemed to grant any rights to trademarks, copyrights, patents, trade secrets or any other intellectual property of Licensor or any Contributor except as expressly stated herein. Except as expressly stated in Sections 3 and 4, no other patent rights, express or implied, are granted herein. Your Extensions may require additional patent licenses from Licensor or Contributors which each may grant in its sole discretion. No right is granted to the trademarks of Licensor or any Contributor even if such marks are included in the Licensed Software. Nothing in this License shall be interpreted to prohibit Licensor from licensing under different terms from this License any code that Licensor otherwise would have a right to license. + +5.1 You expressly acknowledge and agree that although Licensor and each Contributor grants the licenses to their respective portions of the Licensed Software set forth herein, no assurances are provided by Licensor or any Contributor that the Licensed Software does not infringe the patent or other intellectual property rights of any other entity. Licensor and each Contributor disclaim any liability to You for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, You hereby assume sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow You to distribute the Licensed Software, it is Your responsibility to acquire that license before distributing the Licensed Software. + +6.0 Your Obligations And Grants. + +In consideration of, and as an express condition to, the licenses granted to You under this License You hereby agree that any Modifications, Derivative Works, or Required Components (collectively Extensions) that You create or to which You contribute are governed by the terms of this License including, without limitation, Section 4. Any Extensions that You create or to which You contribute must be Deployed under the terms of this License or a future version of this License released under Section 7. You hereby grant to Licensor and all third parties a world-wide, non-exclusive, royalty-free license under those intellectual property rights You own or control to use, reproduce, display, perform, modify, create derivatives, sublicense, and distribute Licensed Software, in any form. Any Extensions You make and Deploy must have a distinct title so as to readily tell any subsequent user or Contributor that the Extensions are by You. You must include a copy of this License or directions on how to obtain a copy with every copy of the Extensions You distribute. You agree not to offer or impose any terms on any Source Code or executable version of the Licensed Software, or its Extensions that alter or restrict the applicable version of this License or the recipients’ rights hereunder. + +6.1 Availability of Source Code. You must make available, under the terms of this License, the Source Code of any Extensions that You Deploy, via an Electronic Distribution Mechanism. The Source Code for any version that You Deploy must be made available within one (1) month of when you Deploy and must remain available for no less than twelve (12) months after the date You cease to Deploy. You are responsible for ensuring that the Source Code to each version You Deploy remains available even if the Electronic Distribution Mechanism is maintained by a third party. You may not charge a fee for any copy of the Source Code distributed under this Section in excess of Your actual cost of duplication and distribution of said copy. + +6.2 Description of Modifications. You must cause any Modifications that You create or to which You contribute to be documented in the Source Code, clearly describing the additions, changes or deletions You made. You must include a prominent statement that the Modifications are derived, directly or indirectly, from the Licensed Software and include the names of the Licensor and any Contributor to the Licensed Software in (i) the Source Code and (ii) in any notice displayed by the Licensed Software You distribute or in related documentation in which You describe the origin or ownership of the Licensed Software. You may not modify or delete any pre-existing copyright notices, change notices or License text in the Licensed Software without written permission of the respective Licensor or Contributor. + +6.3 Intellectual Property Matters. a. Third Party Claims. If You have knowledge that a license to a third party’s intellectual property right is required to exercise the rights granted by this License, You must include a human-readable file with Your distribution that describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. b. Contributor APIs. If Your Extensions include an application programming interface (“API”) and You have knowledge of patent licenses that are reasonably necessary to implement that API, You must also include this information in a human-readable file supplied with Your distribution. c. Representations. You represent that, except as disclosed pursuant to 6.3(a) above, You believe that any Extensions You distribute are Your original creations and that You have sufficient rights to grant the rights conveyed by this License. + +6.4 Required Notices. a. License Text. You must duplicate this License or instructions on how to acquire a copy in any documentation You provide along with the Source Code of any Extensions You create or to which You contribute, wherever You describe recipients’ rights relating to Licensed Software. b. License Notice. You must duplicate any notice contained in EXHIBIT A (the “License Notice”) in each file of the Source Code of any copy You distribute of the Licensed Software and Your Extensions. If You create an Extension, You may add Your name as a Contributor to the Source Code and accompanying documentation along with a description of the contribution. If it is not possible to put the License Notice in a particular Source Code file due to its structure, then You must include such License Notice in a location where a user would be likely to look for such a notice. c. Source Code Availability. You must notify the software community of the availability of Source Code to Your Extensions within one (1) month of the date You initially Deploy and include in such notification a description of the Extensions, and instructions on how to acquire the Source Code. Should such instructions change you must notify the software community of revised instructions within one (1) month of the date of change. You must provide notification by posting to appropriate news groups, mailing lists, weblogs, or other sites where a publicly accessible search engine would reasonably be expected to index your post in relationship to queries regarding the Licensed Software and/or Your Extensions. d. User-Visible Attribution. You must duplicate any notice contained in EXHIBIT B (the “User-Visible Attribution Notice”) in each user-visible display of the Licensed Software and Your Extensions which delineates copyright, ownership, or similar attribution information. If You create an Extension, You may add Your name as a Contributor, and add Your attribution notice, as an equally visible and functional element of any User-Visible Attribution Notice content. To ensure proper attribution, You must also include such User-Visible Attribution Notice in at least one location in the Software documentation where a user would be likely to look for such notice. + +6.5 Additional Terms. You may choose to offer, and charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Licensed Software. However, You may do so only on Your own behalf, and not on behalf of the Licensor or any Contributor except as permitted under other agreements between you and Licensor or Contributor. You must make it clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Licensor and every Contributor for any liability plus attorney fees, costs, and related expenses due to any such action or claim incurred by the Licensor or such Contributor as a result of warranty, support, indemnity or liability terms You offer. + +6.6 Conflicts With Other Licenses. Where any portion of Your Extensions, by virtue of being Derivative Works of another product or similar circumstance, fall under the terms of another license, the terms of that license should be honored however You must also make Your Extensions available under this License. If the terms of this License continue to conflict with the terms of the other license you may write the Licensor for permission to resolve the conflict in a fashion that remains consistent with the intent of this License. Such permission will be granted at the sole discretion of the Licensor. + +7.0 Versions of This License. + +Licensor may publish from time to time revised versions of the License. Once Licensed Software has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Licensed Software under the terms of any subsequent version of the License published by Licensor. No one other than Licensor has the right to modify the terms applicable to Licensed Software created under this License. + +7.1 If You create or use a modified version of this License, which You may do only in order to apply it to software that is not already Licensed Software under this License, You must rename Your license so that it is not confusingly similar to this License, and must make it clear that Your license contains terms that differ from this License. In so naming Your license, You may not use any trademark of Licensor or of any Contributor. Should Your modifications to this License be limited to alteration of a) Section 13.8 solely to modify the legal Jurisdiction or Venue for disputes, b) EXHIBIT A solely to define License Notice text, or c) to EXHIBIT B solely to define a User-Visible Attribution Notice, You may continue to refer to Your License as the Reciprocal Public License or simply the RPL. + +8.0 Disclaimer of Warranty. + +LICENSED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN “AS IS” BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE LICENSED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. FURTHER THERE IS NO WARRANTY MADE AND ALL IMPLIED WARRANTIES ARE DISCLAIMED THAT THE LICENSED SOFTWARE MEETS OR COMPLIES WITH ANY DESCRIPTION OF PERFORMANCE OR OPERATION, SAID COMPATIBILITY AND SUITABILITY BEING YOUR RESPONSIBILITY. LICENSOR DISCLAIMS ANY WARRANTY, IMPLIED OR EXPRESSED, THAT ANY CONTRIBUTOR’S EXTENSIONS MEET ANY STANDARD OF COMPATIBILITY OR DESCRIPTION OF PERFORMANCE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LICENSED SOFTWARE IS WITH YOU. SHOULD LICENSED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (AND NOT THE LICENSOR OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. UNDER THE TERMS OF THIS LICENSOR WILL NOT SUPPORT THIS SOFTWARE AND IS UNDER NO OBLIGATION TO ISSUE UPDATES TO THIS SOFTWARE. LICENSOR HAS NO KNOWLEDGE OF ERRANT CODE OR VIRUS IN THIS SOFTWARE, BUT DOES NOT WARRANT THAT THE SOFTWARE IS FREE FROM SUCH ERRORS OR VIRUSES. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF LICENSED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +9.0 Limitation of Liability. + +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL THE LICENSOR, ANY CONTRIBUTOR, OR ANY DISTRIBUTOR OF LICENSED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY’S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10.0 High Risk Activities. + +THE LICENSED SOFTWARE IS NOT FAULT-TOLERANT AND IS NOT DESIGNED, MANUFACTURED, OR INTENDED FOR USE OR DISTRIBUTION AS ON-LINE CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT NAVIGATION OR COMMUNICATIONS SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE LICENSED SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE (“HIGH RISK ACTIVITIES”). LICENSOR AND CONTRIBUTORS SPECIFICALLY DISCLAIM ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. + +11.0 Responsibility for Claims. + +As between Licensor and Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License which specifically disclaims warranties and limits any liability of the Licensor. This paragraph is to be used in conjunction with and controlled by the Disclaimer Of Warranties of Section 8, the Limitation Of Damages in Section 9, and the disclaimer against use for High Risk Activities in Section 10. The Licensor has thereby disclaimed all warranties and limited any damages that it is or may be liable for. You agree to work with Licensor and Contributors to distribute such responsibility on an equitable basis consistent with the terms of this License including Sections 8, 9, and 10. Nothing herein is intended or shall be deemed to constitute any admission of liability. + +12.0 Termination. + +This License and all rights granted hereunder will terminate immediately in the event of the circumstances described in Section 13.6 or if applicable law prohibits or restricts You from fully and or specifically complying with Sections 3, 4 and/or 6, or prevents the enforceability of any of those Sections, and You must immediately discontinue any use of Licensed Software. + +12.1 Automatic Termination Upon Breach. This License and the rights granted hereunder will terminate automatically if You fail to comply with the terms herein and fail to cure such breach within thirty (30) days of becoming aware of the breach. All sublicenses to the Licensed Software that are properly granted shall survive any termination of this License. Provisions that, by their nature, must remain in effect beyond the termination of this License, shall survive. + +12.2 Termination Upon Assertion of Patent Infringement. If You initiate litigation by asserting a patent infringement claim (excluding declaratory judgment actions) against Licensor or a Contributor (Licensor or Contributor against whom You file such an action is referred to herein as “Respondent”) alleging that Licensed Software directly or indirectly infringes any patent, then any and all rights granted by such Respondent to You under Sections 3 or 4 of this License shall terminate prospectively upon sixty (60) days notice from Respondent (the “Notice Period”) unless within that Notice Period You either agree in writing (i) to pay Respondent a mutually agreeable reasonably royalty for Your past or future use of Licensed Software made by such Respondent, or (ii) withdraw Your litigation claim with respect to Licensed Software against such Respondent. If within said Notice Period a reasonable royalty and payment arrangement are not mutually agreed upon in writing by the parties or the litigation claim is not withdrawn, the rights granted by Licensor to You under Sections 3 and 4 automatically terminate at the expiration of said Notice Period. + +12.3 Reasonable Value of This License. If You assert a patent infringement claim against Respondent alleging that Licensed Software directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by said Respondent under Sections 3 and 4 shall be taken into account in determining the amount or value of any payment or license. + +12.4 No Retroactive Effect of Termination. In the event of termination under this Section all end user license agreements (excluding licenses to distributors and resellers) that have been validly granted by You or any distributor hereunder prior to termination shall survive termination. + +13.0 Miscellaneous. + +13.1 U.S. Government End Users. + +The Licensed Software is a “commercial item,” as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of “commercial computer software” and “commercial computer software documentation,” as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Licensed Software with only those rights set forth herein. + +13.2 Relationship of Parties. This License will not be construed as creating an agency, partnership, joint venture, or any other form of legal association between or among You, Licensor, or any Contributor, and You will not represent to the contrary, whether expressly, by implication, appearance, or otherwise. + +13.3 Independent Development. Nothing in this License will impair Licensor’s right to acquire, license, develop, subcontract, market, or distribute technology or products that perform the same or similar functions as, or otherwise compete with, Extensions that You may develop, produce, market, or distribute. + +13.4 Consent To Breach Not Waiver. Failure by Licensor or Contributor to enforce any provision of this License will not be deemed a waiver of future enforcement of that or any other provision. + +13.5 Severability. This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + +13.6 Inability to Comply Due to Statute or Regulation. If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Licensed Software due to statute, judicial order, or regulation, then You cannot use, modify, or distribute the software. + +13.7 Export Restrictions. You may be restricted with respect to downloading or otherwise acquiring, exporting, or reexporting the Licensed Software or any underlying information or technology by United States and other applicable laws and regulations. By downloading or by otherwise obtaining the Licensed Software, You are agreeing to be responsible for compliance with all applicable laws and regulations. + +13.8 Arbitration, Jurisdiction & Venue. This License shall be governed by Colorado law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. You expressly agree that any dispute relating to this License shall be submitted to binding arbitration under the rules then prevailing of the American Arbitration Association. You further agree that Adams County, Colorado USA is proper venue and grant such arbitration proceeding jurisdiction as may be appropriate for purposes of resolving any dispute under this License. Judgement upon any award made in arbitration may be entered and enforced in any court of competent jurisdiction. The arbitrator shall award attorney’s fees and costs of arbitration to the prevailing party. Should either party find it necessary to enforce its arbitration award or seek specific performance of such award in a civil court of competent jurisdiction, the prevailing party shall be entitled to reasonable attorney’s fees and costs. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. You and Licensor expressly waive any rights to a jury trial in any litigation concerning Licensed Software or this License. Any law or regulation that provides that the language of a contract shall be construed against the drafter shall not apply to this License. + +13.9 Entire Agreement. This License constitutes the entire agreement between the parties with respect to the subject matter hereof. EXHIBIT A The License Notice below must appear in each file of the Source Code of any copy You distribute of the Licensed Software or any Extensions thereto: Unless explicitly acquired and licensed from Licensor under another license, the contents of this file are subject to the Reciprocal Public License (“RPL”) Version 1.5, or subsequent versions as allowed by the RPL, and You may not copy or use this file in either source code or executable form, except in compliance with the terms and conditions of the RPL. + +All software distributed under the RPL is provided strictly on an “AS IS” basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, AND LICENSOR HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT, OR NON-INFRINGEMENT. See the RPL for specific language governing rights and limitations under the RPL. EXHIBIT B The User-Visible Attribution Notice below, when provided, must appear in each user-visible display as defined in Section 6.4 diff --git a/src/app/zeko/README.md b/src/app/zeko/README.md new file mode 100644 index 0000000000..3759b89069 --- /dev/null +++ b/src/app/zeko/README.md @@ -0,0 +1,3 @@ +The code under here is under the RPL-1.5 license. A copy is included in [./LICENSE](./LICENSE). + +You can also find the license at https://opensource.org/license/rpl-1-5 diff --git a/src/app/zeko/circuits/ase.ml b/src/app/zeko/circuits/ase.ml index 0cbc65b30e..968beacf0f 100644 --- a/src/app/zeko/circuits/ase.ml +++ b/src/app/zeko/circuits/ase.ml @@ -111,6 +111,8 @@ module With_length = struct (({ source; target } : Stmt.var), verifier) let make = Made_2.make + + let get_iterations = get_iterations end end @@ -150,5 +152,7 @@ module Without_length = struct (({ source; target } : Stmt.var), verifier) let make = Made_2.make + + let get_iterations = get_iterations end end diff --git a/src/app/zeko/circuits/ase.mli b/src/app/zeko/circuits/ase.mli index a1f5d5bbf3..d92e61e60b 100644 --- a/src/app/zeko/circuits/ase.mli +++ b/src/app/zeko/circuits/ase.mli @@ -8,6 +8,8 @@ module With_length : sig type t = { action_state : F.t; length : Checked32.t } [@@deriving snarky] end + module Init = Stmt + type trans = { source : Stmt.t; target : Stmt.t } val leaf : field list * Stmt.t -> (trans * Proof.t) Promise.t @@ -73,11 +75,14 @@ module With_length : sig -> original_stmt_t -> field list -> t + + val get_iterations : int end end module Without_length : sig module Stmt = F + module Init = Stmt type trans = { source : field; target : field } @@ -144,5 +149,7 @@ module Without_length : sig -> field -> field list -> t + + val get_iterations : int end end diff --git a/src/app/zeko/circuits/dune b/src/app/zeko/circuits/dune index f4282c7309..8458b0b6c5 100644 --- a/src/app/zeko/circuits/dune +++ b/src/app/zeko/circuits/dune @@ -1,6 +1,7 @@ (env (_ - (flags (:standard -w @a-42-40-44-70-45-41)))) + (flags + (:standard -w @a-42-40-44-70-45-41)))) (library (name zeko_circuits) @@ -10,7 +11,8 @@ transaction_snark staged_ledger_diff compile_simple - v) + v + zeko_constants) (inline_tests) (instrumentation (backend bisect_ppx)) diff --git a/src/app/zeko/circuits/indexed_merkle_tree.ml b/src/app/zeko/circuits/indexed_merkle_tree.ml index 1b6d16af14..a28cbddb0d 100644 --- a/src/app/zeko/circuits/indexed_merkle_tree.ml +++ b/src/app/zeko/circuits/indexed_merkle_tree.ml @@ -16,7 +16,7 @@ struct type t = { key : Key.t; next_key : Key.t } [@@deriving snarky] end - type t = F.t + type t = F.t [@@deriving sexp] type var = F.var @@ -33,7 +33,8 @@ struct let length = height end) - let hash_entry = var_to_hash ~init:"indexed merkle tree entry hash" Entry.typ + let hash_entry = + var_to_hash ~init:Zeko_constants.indexed_merkle_tree_salt Entry.typ (* TODO: consider different salt per level. *) let implied_root_raw (init : F.var) (path : Path.var) : F.var Checked.t = diff --git a/src/app/zeko/circuits/indexed_merkle_tree.mli b/src/app/zeko/circuits/indexed_merkle_tree.mli index 5a0bcd2e38..e9b5662f5d 100644 --- a/src/app/zeko/circuits/indexed_merkle_tree.mli +++ b/src/app/zeko/circuits/indexed_merkle_tree.mli @@ -27,7 +27,7 @@ module Make (Inputs : sig end) : sig open Inputs - type t + type t = F.t [@@deriving sexp] type var diff --git a/src/app/zeko/circuits/rollup_state.ml b/src/app/zeko/circuits/rollup_state.ml index 13c3f90d1c..b0cfc3c46f 100644 --- a/src/app/zeko/circuits/rollup_state.ml +++ b/src/app/zeko/circuits/rollup_state.ml @@ -10,7 +10,7 @@ let push_events_checked state actions = Zkapp_account.Actions.push_events_checked state actions ) module type Action_state_type = sig - include SnarkType + type t = F.t [@@deriving snarky] val empty : t @@ -27,7 +27,7 @@ module type Action_state_type = sig type without_length_var := var - include SnarkType + type t = { state : F.t; length : Checked32.t } [@@deriving snarky] val empty : t @@ -141,6 +141,8 @@ module Inner_state = struct Outer_action_state.With_length.unsafe_value_of_fields ~state ~length } + let value_to_init_state t = Zeko_util.value_to_init_state typ t + type fine = { outer_action_state : Outer_action_state.With_length.fine } (* NB! This will warn you if add a field to `t` without fixing it here. @@ -234,6 +236,10 @@ module Outer_state = struct ; Whole (Even_PC.typ, da_key) ; Whole (Account_set.typ, acc_set) ] + + let value_to_app_state t = Zeko_util.value_to_app_state typ t + + let value_of_app_state state = Zeko_util.value_of_state typ state end module Outer_action = struct diff --git a/src/app/zeko/circuits/rule_zkapp_command.ml b/src/app/zeko/circuits/rule_zkapp_command.ml index f1748cb210..afae2acd76 100644 --- a/src/app/zeko/circuits/rule_zkapp_command.ml +++ b/src/app/zeko/circuits/rule_zkapp_command.ml @@ -45,13 +45,14 @@ open struct (* We always return true because failure doesn't happen here but in the commit rule. *) Boolean.true_ | Check_protocol_state_precondition - ( (protocol_state_predicate : + ( (_protocol_state_predicate : Zkapp_precondition.Protocol_state.Checked.t ) , _global_state ) -> - Run.run_checked - Zkapp_precondition.Protocol_state.( - assert_equal ~label:__LOC__ typ protocol_state_predicate - (constant typ accept)) ; + (* FIXME: Allow for global slot precondition, as it's the fee payer's valid while *) + (* Run.run_checked + Zkapp_precondition.Protocol_state.( + assert_equal ~label:__LOC__ typ protocol_state_predicate + (constant typ accept)) ; *) Boolean.true_ | Check_account_precondition ( ({ account_update; _ } : Zkapp_call_forest.Checked.account_update) diff --git a/src/app/zeko/circuits/txn_rules.ml b/src/app/zeko/circuits/txn_rules.ml index e17a392804..411db323e7 100644 --- a/src/app/zeko/circuits/txn_rules.ml +++ b/src/app/zeko/circuits/txn_rules.ml @@ -33,3 +33,5 @@ include } ] () ) + +let make = make_unchecked diff --git a/src/app/zeko/circuits/zeko_util.ml b/src/app/zeko/circuits/zeko_util.ml index 499711668e..151c230a76 100644 --- a/src/app/zeko/circuits/zeko_util.ml +++ b/src/app/zeko/circuits/zeko_util.ml @@ -74,6 +74,29 @@ let var_to_state_generic_fine : assert (List.length r' = 8) ; Zkapp_state.V.of_list_exn r' +let value_to_state (some : field -> 'option) (none : 'option) + (typ : ('var, 'value) Typ.t) (x : 'value) : 'option Zkapp_state.V.t = + let (Typ typ) = typ in + let fields, _aux = typ.value_to_fields x in + assert (Array.length fields <= 8) ; + let missing = 8 - Array.length fields in + Zkapp_state.V.of_list_exn + @@ List.append + (List.map ~f:(fun f -> some f) @@ Array.to_list fields) + (List.init missing ~f:(fun _ -> none)) + +let value_to_init_state typ x = value_to_state (fun f -> f) Field.zero typ x + +let value_to_app_state typ x = + value_to_state (fun f -> Set_or_keep.Set f) Set_or_keep.Keep typ x + +let value_of_state (typ : ('var, 'value) Typ.t) (x : field Zkapp_state.V.t) : + 'value = + let (Typ typ) = typ in + typ.value_of_fields + ( Zkapp_state.V.to_list x |> Array.of_list + , typ.constraint_system_auxiliary () ) + let var_to_precondition_fine = var_to_state_generic_fine ( module struct @@ -96,7 +119,7 @@ let var_to_app_state_fine = (** To be used with deriving snarky, a simple field *) module F = struct - type t = field + type t = Field.t [@@deriving sexp] type var = Field.Var.t @@ -394,6 +417,10 @@ let token_owner_id : Account_id.t option -> Token_id.t = function module Even_PC = struct type t = { public_key : F.t } [@@deriving snarky] + let create_exn (public_key : Signature_lib.Public_key.Compressed.t) = + if public_key.is_odd then failwith "Odd public key" + else ({ public_key = public_key.x } : t) + let to_pc_var { public_key } : Signature_lib.Public_key.Compressed.var = { x = public_key; is_odd = Boolean.false_ } end diff --git a/src/app/zeko/circuits/zeko_util.mli b/src/app/zeko/circuits/zeko_util.mli index bdb5ef98a7..7a999d36bf 100644 --- a/src/app/zeko/circuits/zeko_util.mli +++ b/src/app/zeko/circuits/zeko_util.mli @@ -32,6 +32,13 @@ val var_to_app_state_fine : -> Field.Var.t Zkapp_basic.Set_or_keep.Checked.t Pickles_types.Vector.Vector_8.t +val value_to_init_state : ('a, 'b) Typ.t -> 'b -> field Zkapp_state.V.t + +val value_to_app_state : + ('a, 'b) Typ.t -> 'b -> field Zkapp_basic.Set_or_keep.t Zkapp_state.V.t + +val value_of_state : ('var, 'value) Typ.t -> field Zkapp_state.V.t -> 'value + val var_to_actions : ('var, 'value) Typ.t -> 'var -> Mina_base.Zkapp_account.Actions.var Checked.t @@ -39,7 +46,7 @@ val var_to_hash : init:string -> ('var, 'value) Typ.t -> 'var -> Field.Var.t Checked.t module F : sig - type t = Pasta_bindings.Fp.t + type t = Pasta_bindings.Fp.t [@@deriving sexp] type var = Field.Var.t @@ -190,6 +197,8 @@ val token_owner_id : Account_id.t option -> Token_id.t module Even_PC : sig type t = { public_key : F.t } [@@deriving snarky] + val create_exn : Signature_lib.Public_key.Compressed.t -> t + val to_pc_var : var -> Import.Public_key.Compressed.var end diff --git a/src/app/zeko/compile_simple/compile_simple.mli b/src/app/zeko/compile_simple/compile_simple.mli index 828caa27d9..d324e7df03 100644 --- a/src/app/zeko/compile_simple/compile_simple.mli +++ b/src/app/zeko/compile_simple/compile_simple.mli @@ -1,5 +1,9 @@ module Proof : sig type t [@@deriving yojson] + + val to_pickles : t -> Pickles.Side_loaded.Proof.t + + val of_pickles : Pickles.Side_loaded.Proof.t -> t end type 'tag_var tag @@ -13,6 +17,12 @@ module Verification_key : sig val typ : (var, t) Snark_params.Tick.Typ.t + val of_pickles : Pickles.Side_loaded.Verification_key.t -> t + + val to_pickles : t -> Pickles.Side_loaded.Verification_key.t + + val var_of_pickles : Pickles.Side_loaded.Verification_key.Checked.t -> var + val of_tag : 'tag_var tag -> t Promise.t val hash : t -> Snark_params.Tick.Field.t diff --git a/src/app/zeko/compile_simple/fake/compile_simple.ml b/src/app/zeko/compile_simple/fake/compile_simple.ml index b3e8133673..5fe9affa51 100644 --- a/src/app/zeko/compile_simple/fake/compile_simple.ml +++ b/src/app/zeko/compile_simple/fake/compile_simple.ml @@ -5,6 +5,12 @@ open Snark_params.Tick module Proof = struct type t = Proof of Field.t (* hash of vk and public input *) [@@deriving yojson] + + let to_pickles _ = + let open Pickles_types in + Pickles.Proof.dummy Nat.N2.n Nat.N2.n Nat.N2.n ~domain_log2:15 + + let of_pickles _ = Proof Field.one end (* TODO: this should be hash of circuit *) @@ -27,6 +33,12 @@ module Verification_key = struct let hash (Vk x) = x let hash_var (Var x) = x + + let of_pickles _ = Vk Field.one + + let to_pickles _ = Pickles.Side_loaded.Verification_key.dummy + + let var_of_pickles _ = Var (Field.Var.constant Field.one) end let force_tag _ = Promise.return () diff --git a/src/app/zeko/compile_simple/real/compile_simple.ml b/src/app/zeko/compile_simple/real/compile_simple.ml index bb0395fe3e..49042c47d8 100644 --- a/src/app/zeko/compile_simple/real/compile_simple.ml +++ b/src/app/zeko/compile_simple/real/compile_simple.ml @@ -5,7 +5,13 @@ open Checked.Let_syntax type self_width = Pickles_types.Nat.N2.n -module Proof = Pickles.Side_loaded.Proof +module Proof = struct + include Pickles.Side_loaded.Proof + + let to_pickles x = x + + let of_pickles x = x +end type 'var tag = | Tag : ('var, 'value, self_width, 'height) Pickles.Tag.t -> 'var tag @@ -15,6 +21,12 @@ module Verification_key = struct type var = Checked.t + let of_pickles x = x + + let to_pickles x = x + + let var_of_pickles x = x + let of_tag (Tag tag) = of_compiled_promise tag let hash x = diff --git a/src/app/zeko/da_layer/lib/dune b/src/app/zeko/da_layer/lib/dune index 340324e590..6596d946ca 100644 --- a/src/app/zeko/da_layer/lib/dune +++ b/src/app/zeko/da_layer/lib/dune @@ -3,14 +3,14 @@ (inline_tests) (libraries kvdb_base - zkapps_rollup + zeko_constants ;; mina ;; mina_base - mina_base.import mina_ledger signature_lib + snark_params + mina_compile_config daemon_rpcs - cli_lib ;; opam libraries ;; core core_kernel diff --git a/src/app/zeko/da_layer/lib/node.ml b/src/app/zeko/da_layer/lib/node.ml index d9e7d79fd7..b7bf2b8b58 100644 --- a/src/app/zeko/da_layer/lib/node.ml +++ b/src/app/zeko/da_layer/lib/node.ml @@ -3,7 +3,7 @@ open Mina_base open Mina_ledger open Signature_lib -let constraint_constants = Genesis_constants.Compiled.constraint_constants +let constraint_constants = Zeko_constants.constraint_constants type t = { db : Db.t; signer : Keypair.t; logger : Logger.t } @@ -141,7 +141,7 @@ let post_diff t ~ledger_openings ~diff = let account_id = let aid = Account_update.account_id account_update in if Public_key.Compressed.(Account_id.public_key aid = empty) - then Zkapps_rollup.inner_account_id + then Zeko_constants.inner_account_id else aid in let%bind.Result old_receipt_chain_hash = diff --git a/src/app/zeko/dune b/src/app/zeko/dune index 81cf00035f..ba657d3574 100644 --- a/src/app/zeko/dune +++ b/src/app/zeko/dune @@ -1,23 +1,7 @@ -(env (_ (flags (:standard -w @a-42-40-44-70-45-41)))) - (library - (name zeko_util) - (libraries zeko_circuits) + (name zeko_constants) + (libraries mina_base signature_lib snark_params genesis_constants currency) (inline_tests) (instrumentation (backend bisect_ppx)) - (preprocess - (pps ppx_deriving.show ppx_deriving_snarky ppx_snarky ppx_mina ppx_version ppx_jane ppx_compare h_list.ppx)) - (modules zeko_util) - ) - -(library - (name zkapps_rollup) - (libraries zeko_util) - (inline_tests) - (instrumentation - (backend bisect_ppx)) - (preprocess - (pps ppx_deriving.show ppx_deriving_snarky ppx_snarky ppx_mina ppx_version ppx_jane ppx_compare h_list.ppx)) - (modules zkapps_rollup) - ) + (modules zeko_constants)) diff --git a/src/app/zeko/indexed_merkle_tree/dune b/src/app/zeko/indexed_merkle_tree/dune new file mode 100644 index 0000000000..97a9bd63ef --- /dev/null +++ b/src/app/zeko/indexed_merkle_tree/dune @@ -0,0 +1,19 @@ +(library + (name indexed_merkle_tree) + (inline_tests) + (libraries + zeko_constants + ;; mina ;; + mina_base + mina_ledger + ;; opam libraries ;; + core_kernel) + (preprocess + (pps + ppx_version + ppx_let + ppx_custom_printf + ppx_base + ppx_deriving_yojson + ppx_inline_test + ppx_assert))) diff --git a/src/app/zeko/indexed_merkle_tree/indexed_merkle_tree.ml b/src/app/zeko/indexed_merkle_tree/indexed_merkle_tree.ml new file mode 100644 index 0000000000..ef178114b2 --- /dev/null +++ b/src/app/zeko/indexed_merkle_tree/indexed_merkle_tree.ml @@ -0,0 +1,291 @@ +open Core +open Signature_lib +open Merkle_ledger +open Mina_base +module Field = Snark_params.Tick.Field + +module Location_at_depth : Merkle_ledger.Location_intf.S = + Merkle_ledger.Location.T + +module Location_binable = struct + module Arg = struct + type t = Location_at_depth.t = + | Generic of Location.Bigstring.Stable.Latest.t + | Account of Location_at_depth.Addr.Stable.Latest.t + | Hash of Location_at_depth.Addr.Stable.Latest.t + [@@deriving bin_io_unversioned, hash, sexp, compare] + end + + type t = Arg.t = + | Generic of Location.Bigstring.t + | Account of Location_at_depth.Addr.t + | Hash of Location_at_depth.Addr.t + [@@deriving hash, sexp, compare] + + include Comparable.Make_binable (Arg) + include Hashable.Make_binable (Arg) [@@deriving sexp, compare, hash, yojson] +end + +module Kvdb : Intf.Key_value_database with type config := string = + Rocksdb.Database + +module Storage_locations : Intf.Storage_locations = struct + let key_value_db_dir = "mina_key_value_db" +end + +module Account_id = struct + include Account_id + + let with_empty_key tid = create Public_key.Compressed.empty tid +end + +module Entry = struct + [%%versioned + module Stable = struct + module V2 = struct + type t = + { value : Token_id.Stable.V2.t; value_next : Token_id.Stable.V2.t } + [@@deriving equal, compare, sexp, yojson] + + let to_latest = Fn.id + + let identifier { value; _ } = Account_id.with_empty_key value + + let balance _ = Currency.Balance.zero + + let empty = + { value = Token_id.of_field Field.zero + ; value_next = Token_id.of_field Field.zero + } + + let token { value; _ } = value + end + end] + + let data_hash { value; value_next } = + Random_oracle.hash + ~init:(Hash_prefix_create.salt Zeko_constants.indexed_merkle_tree_salt) + [| Token_id.to_field_unsafe value; Token_id.to_field_unsafe value_next |] +end + +module Hash = struct + module Arg = struct + type t = Ledger_hash.Stable.Latest.t + [@@deriving sexp, compare, hash, bin_io_unversioned] + end + + [%%versioned + module Stable = struct + module V1 = struct + type t = Ledger_hash.Stable.V1.t + [@@deriving sexp, compare, hash, equal, yojson] + + let (_ : (t, Arg.t) Type_equal.t) = Type_equal.T + + let to_latest = Fn.id + + include Hashable.Make_binable (Arg) + + let to_base58_check = Ledger_hash.to_base58_check + + let merge ~height:_ (h1 : t) (h2 : t) = + Random_oracle.hash + ~init: + (Hash_prefix_create.salt + Zeko_constants.indexed_merkle_tree_merge_salt ) + [| (h1 :> Field.t); (h2 :> Field.t) |] + |> Ledger_hash.of_hash + + let hash_account = Entry.data_hash + + let empty_account = + Ledger_hash.of_digest (Lazy.force Account.empty_digest) + end + end] + + let merge = Ledger_hash.merge +end + +module Inputs = struct + module Key = Public_key.Compressed + module Token_id = Token_id + module Account_id = Account_id + + module Balance = struct + include Currency.Balance + + let to_int = to_nanomina_int + end + + module Account = Entry.Stable.Latest + module Hash = Hash.Stable.Latest + module Kvdb = Kvdb + module Location = Location_at_depth + module Location_binable = Location_binable + module Storage_locations = Storage_locations +end + +module type Ledger_db_intf = + Merkle_ledger.Intf.Ledger.DATABASE + with module Location = Location_at_depth + with module Addr = Location_at_depth.Addr + with type root_hash := Ledger_hash.t + and type hash := Ledger_hash.t + and type key := Public_key.Compressed.t + and type token_id := Token_id.t + and type token_id_set := Token_id.Set.t + and type account := Entry.t + and type account_id_set := Account_id.Set.t + and type account_id := Account_id.t + and type zeko_kvdb := Kvdb.t + +module type Database_intf = sig + type t + + type index = int + + module Path : Merkle_path.S with type hash := Ledger_hash.t + + val merkle_root : t -> Hash.t + + val create : ?directory_name:string -> depth:index -> unit -> t + + val get_or_create_entry_exn : + t + -> Token_id.t + -> [> `Added | `Existed ] + * ( [ `X of Token_id.t ] + * [ `X_path of Path.t ] + * [ `Y of Token_id.t ] + * [ `Y_path of Path.t ] + * [ `Z of Token_id.t ] ) + + val find_lower_entry_tid : t -> Token_id.t -> Token_id.t option +end + +let lowest_key = Token_id.of_field Field.zero + +let highest_key = + Token_id.of_field + (Field.of_string Bigint.(Field.size - of_int 1 |> to_string)) + +let lowest_entry = { Entry.value = lowest_key; value_next = highest_key } + +let highest_entry = { Entry.value = highest_key; value_next = highest_key } + +let base_entries = + [ (Account_id.with_empty_key lowest_key, lowest_entry) + ; (Account_id.with_empty_key highest_key, highest_entry) + ] + +module Db : Database_intf = struct + include Database.Make (Inputs) + + module Db_error = struct + [@@@warning "-4"] (* due to deriving sexp below *) + + type t = + | Account_location_not_found + | Out_of_leaves + | Malformed_database of string + [@@deriving sexp] + + let ok_exn = function + | Ok x -> + x + | Error e -> + raise (Exn.create_s ([%sexp_of: t] e)) + end + + let get_raw t location = + Kvdb.get (zeko_kvdb t) + ~key:(Location.serialize ~ledger_depth:(depth t) location) + + let get_generic t location = + assert (Location.is_generic location) ; + get_raw t location + + module Account_location = struct + let build_location account_id = + Location.build_generic + (Bigstring.of_string + ( "$" + ^ Format.sprintf + !"%{sexp: Public_key.Compressed.t}!%{sexp: Token_id.t}" + (Account_id.public_key account_id) + (Account_id.token_id account_id) ) ) + end + + let find_lower_entry_location_exn t tid = + if Token_id.equal lowest_key tid then + failwith "There is no lower key than the 0" ; + let location_key = + Account_location.build_location (Account_id.with_empty_key tid) + in + let prev_location_key = + Kvdb.prev_key (zeko_kvdb t) + ~key:(Location.serialize ~ledger_depth:(depth t) location_key) + |> Location.parse ~ledger_depth:(depth t) + |> Result.map_error ~f:(fun () -> + Db_error.Malformed_database "Failed to parse prev location key" ) + |> Db_error.ok_exn + in + get_generic t prev_location_key + |> Option.value_exn ~message:"Failed to find prev location" + |> Location.parse ~ledger_depth:(depth t) + |> Result.map_error ~f:(fun _ -> + Db_error.Malformed_database "Failed to parse prev location" ) + |> Db_error.ok_exn + + let find_lower_entry_tid t tid = + let lower_entry_location = find_lower_entry_location_exn t tid in + get t lower_entry_location + |> Option.map ~f:(fun entry -> Entry.(entry.value)) + + let create ?directory_name ~depth () = + let db = create ?directory_name ~depth () in + let (_ : [ `Added | `Existed ] * Location_at_depth.t) = + get_or_create_account db + (Account_id.with_empty_key lowest_key) + lowest_entry + |> Or_error.ok_exn + in + let (_ : [ `Added | `Existed ] * Location_at_depth.t) = + get_or_create_account db + (Account_id.with_empty_key highest_key) + highest_entry + |> Or_error.ok_exn + in + db + + let get_or_create_entry_exn t tid = + let lower_entry_location = find_lower_entry_location_exn t tid in + let lower_entry = + get t lower_entry_location + |> Result.of_option + ~error:(Db_error.Malformed_database "Could not find lower entry") + |> Db_error.ok_exn + in + let new_entry = + { Entry.value = tid; value_next = lower_entry.value_next } + in + match get_or_create_account t (Account_id.with_empty_key tid) new_entry with + | Ok (`Existed, new_location) -> + ( `Existed + , ( `X lower_entry.value + , `X_path (merkle_path t lower_entry_location) + , `Y new_entry.value + , `Y_path (merkle_path t new_location) + , `Z new_entry.value_next ) ) + | Ok (`Added, new_location) -> + let lower_entry = { lower_entry with value_next = tid } in + set t lower_entry_location lower_entry ; + ( `Added + , ( `X lower_entry.value + , `X_path (merkle_path t lower_entry_location) + , `Y new_entry.value + , `Y_path (merkle_path t new_location) + , `Z new_entry.value_next ) ) + | Error e -> + Error.raise e +end diff --git a/src/app/zeko/kvdb_base/dune b/src/app/zeko/kvdb_base/dune index b3c1b54418..e0a83beff0 100644 --- a/src/app/zeko/kvdb_base/dune +++ b/src/app/zeko/kvdb_base/dune @@ -3,8 +3,6 @@ (inline_tests) (libraries ;; mina ;; - mina_base - mina_base.import mina_ledger ;; opam libraries ;; core_kernel)) diff --git a/src/app/zeko/parallel_merger/parallel_merger.ml b/src/app/zeko/parallel_merger/parallel_merger.ml index 08423b4364..6bcc065042 100644 --- a/src/app/zeko/parallel_merger/parallel_merger.ml +++ b/src/app/zeko/parallel_merger/parallel_merger.ml @@ -6,11 +6,11 @@ let generate_id () = Uuid_unix.create () |> Uuid.to_string module Make (Context : sig type t end) (Merge : sig - type t [@@deriving yojson] + type t val process : Context.t -> t -> t -> t Deferred.t end) (Base : sig - type t [@@deriving yojson] + type t val process : Context.t -> t -> Merge.t Deferred.t end) (Commit : sig @@ -20,17 +20,16 @@ end) (Commit : sig end) = struct module Available_job = struct - type t = Base of Base.t | Merge of Merge.t * Merge.t [@@deriving yojson] + type t = Base of Base.t | Merge of Merge.t * Merge.t end (* Finished job will be always of type `Merge.t` *) module Finished_job = struct - type t = Merge.t [@@deriving yojson] + type t = Merge.t end module Job_status = struct type t = Todo of Available_job.t | Done of Finished_job.t - [@@deriving yojson] end module With_id = struct @@ -54,7 +53,6 @@ struct ; ready_to_commit : unit Ivar.t (** All jobs are done and ready to commit *) } - [@@deriving yojson] let create () = { jobs = [] @@ -167,9 +165,7 @@ struct let is_empty t = List.is_empty t.jobs end - type t = { mutable trees : Tree.t list } [@@deriving yojson] - - let pp t = Core.printf "%s\n%!" (Yojson.Safe.pretty_to_string @@ to_yojson t) + type t = { mutable trees : Tree.t list } let create () = { trees = [] } diff --git a/src/app/zeko/sequencer/Dockerfile b/src/app/zeko/sequencer/Dockerfile deleted file mode 100644 index 7dc24b3300..0000000000 --- a/src/app/zeko/sequencer/Dockerfile +++ /dev/null @@ -1,279 +0,0 @@ -################################################################################################# -# The "build-deps" stage -# - Installs all compilers/interpreters, tools, and OS packages on the given debian or ubuntu image -################################################################################################# -# Supports debian:buster-slim, debian:bullseye-slim, and ubuntu:focal -FROM --platform=linux/amd64 ubuntu:focal AS build-deps - -# Ocaml Version -ARG OCAML_VERSION=4.14 -ARG OCAML_REVISION=.0 -ARG OCAML_VARIANT= -ARG OCAML_PACKAGE= -ARG OPAM_VERSION=2.0.7 - -# Golang version number used to detemine tarball name -ARG GO_VERSION=1.18.2 - -# Go Capnp Version (for capnpc dependency) -ARG GO_CAPNP_VERSION=v3.0.0-alpha.5 - -# Rust Version passed into rustup-init, can also be "stable", "nightly" or similar -ARG RUST_VERSION=1.63.0 -# Nightly Rust Version used for WebAssembly builds -ARG RUST_NIGHTLY=2022-09-12 -# wasm-pack version -ARG WASM_PACK_VERSION=v0.10.3 - -# Rocksdb commit tag/branch to clone -ARG ROCKSDB_VERSION=v5.18.4 - -# --- OS package dependencies -# Organized as two alphabetized lists, first libraries and then tools/other packages -ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update --quiet \ - && apt-get upgrade --quiet --yes \ - && apt-get install --no-install-recommends --quiet --yes \ - libboost-dev \ - libboost-program-options-dev \ - libbz2-dev \ - libcap-dev \ - libffi-dev \ - libgflags-dev \ - libgmp-dev \ - libgmp3-dev \ - libjemalloc-dev \ - liblmdb-dev \ - liblmdb0 \ - libpq-dev \ - libprocps-dev \ - libsodium-dev \ - libssl-dev \ - build-essential \ - ca-certificates \ - capnproto \ - cmake \ - curl \ - file \ - git \ - '(^lld-10$|^lld-11$)' \ - m4 \ - pkg-config \ - rsync \ - sudo \ - unzip \ - zlib1g-dev \ - && rm -rf /var/lib/apt/lists/* - -# Symlink image-specific lld version to a single lld executable -RUN if command -v ld.lld-10 &> /dev/null; then ln -sf $(which ld.lld-10) /usr/bin/ld.lld; fi -RUN if command -v ld.lld-11 &> /dev/null; then ln -sf $(which ld.lld-11) /usr/bin/ld.lld; fi - -# --- Create opam user (for later) and give sudo to make opam happy -RUN adduser --uid 65533 --disabled-password --gecos '' opam \ - && passwd -l opam \ - && chown -R opam:opam /home/opam \ - && echo 'opam ALL=(ALL:ALL) NOPASSWD:ALL' > /etc/sudoers.d/opam \ - && chmod 440 /etc/sudoers.d/opam \ - && chown root:root /etc/sudoers.d/opam \ - && chmod 777 /tmp - -# --- Quiet git warnings about detatched head states, which are used frequently in later stages -RUN git config --global advice.detachedHead false - -# --- Opam install of a given OPAM_VERSION from github release -RUN curl -sL \ - "https://github.com/ocaml/opam/releases/download/${OPAM_VERSION}/opam-${OPAM_VERSION}-x86_64-linux" \ - -o /usr/bin/opam \ - && chmod +x /usr/bin/opam - -# --- Golang install of a given GO_VERSION (add -v for spam output of each file from the go dist) -RUN curl -s "https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz" | tar -xz -C /usr/lib/ - -# --- Rust install via rustup-init to a given RUST_VERSION -# --- Additionally, install RUST_NIGHTLY via rustup -# For more about rustup-init see: https://github.com/rust-lang/rustup/blob/master/README.md -# As opposed to introducing another shell script here (that mostly just determines the platform) -# we just download the binary for the only platform we care about in this docker environment -USER opam -RUN curl --proto '=https' --tlsv1.2 -sSf -o /tmp/rustup-init \ - https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init \ - && chmod +x /tmp/rustup-init \ - && /tmp/rustup-init -y --default-toolchain "${RUST_VERSION}" --profile minimal --component rust-src --target wasm32-unknown-unknown \ - && $HOME/.cargo/bin/rustup toolchain install "nightly-${RUST_NIGHTLY}" --profile minimal --component rust-src --target wasm32-unknown-unknown --no-self-update \ - && rm /tmp/rustup-init -USER root - -# --- Install rust wasm-pack version WASM_PACK_VERSION manually via curl/tar -RUN curl -sL https://github.com/rustwasm/wasm-pack/releases/download/${WASM_PACK_VERSION}/wasm-pack-${WASM_PACK_VERSION}-x86_64-unknown-linux-musl.tar.gz \ - | tar --extract --gzip --strip-components=1 --directory=/usr/bin --file=- - -# --- RocksDB Installation of a given ROCKSDB_VERSION -# These flags turn some errors into warnings for running with G++ 9 or higher -# The build command below checks for the g++ major version and removes CXXFLAGS if its less than 9 -ENV CXXFLAGS '-Wno-error=deprecated-copy -Wno-error=pessimizing-move -Wno-error=class-memaccess -Wno-error' -# This builds and installs just the rocksdb static lib for us, and cleans up after itself -# Send error output to /dev/null as its noisy with compiler warnings -RUN git clone https://github.com/facebook/rocksdb \ - --depth 1 --shallow-submodules \ - -b "${ROCKSDB_VERSION}" /rocksdb \ - && test $(g++ -dumpversion | cut -c 1 -) -lt 9 \ - && CXXFLAGS='' make -C /rocksdb static_lib PORTABLE=1 -j$(nproc) 2>/dev/null \ - || make -C /rocksdb static_lib PORTABLE=1 -j$(nproc) 2>/dev/null \ - && cp /rocksdb/librocksdb.a /usr/local/lib/librocksdb_coda.a \ - && rm -rf /rocksdb \ - && strip -S /usr/local/lib/librocksdb_coda.a -# Clear CXXFLAGS afterwards to avoid affecting other code -ENV CXXFLAGS="" - -########################################################################################### -# Initialize opam in a minimal fashion -########################################################################################### - -# Set up environment for running as opam user -WORKDIR /home/opam -USER opam -ENV HOME=/home/opam - -# --- Create the following user directory configs as the Opam user: -## Add go + rust to the path, unlimit the opam user, -## unlimit stack for future shells that might use spacetime, -## disable ipv6 -## disable sandboxing to allow unprivledged builds -RUN mkdir --mode=700 ~/.gnupg \ - && echo 'export PATH="$PATH:/usr/lib/go/bin:$HOME/.cargo/bin"' >> ~/.bashrc \ - && echo 'ulimit -s unlimited' >> ~/.bashrc \ - && echo "disable-ipv6" >> ~/.gnupg/dirmngr.conf - -ENV PATH="$PATH:/usr/lib/go/bin:$HOME/.cargo/bin" - -# --- Ocaml install of a given OCAML_VERSION via opam switch -# additionally initializes opam with sandboxing disabled, as we did not install bubblewrap above. -RUN git clone \ - https://github.com/ocaml/opam-repository.git \ - --depth 1 \ - /home/opam/opam-repository \ - && opam init --disable-sandboxing -k git -a ~/opam-repository --bare \ - && opam repository add --yes --all --set-default o1-labs https://github.com/o1-labs/opam-repository.git \ - && opam switch create "${OCAML_VERSION}${OCAML_REVISION}" "${OCAML_PACKAGE}${OCAML_VERSION}${OCAML_REVISION}${OCAML_VARIANT}" \ - && opam switch "${OCAML_VERSION}${OCAML_REVISION}" - -# --- Build and install capnproto go compiler -# This package was particularly tricky to get to install correctly because of how the package's source code is structured. -# To work around this, we install it as a dependency for a local go module and build the binary from the GOPATH. -RUN mkdir go-tmp \ - && cd go-tmp \ - && /usr/lib/go/bin/go mod init local/build \ - && /usr/lib/go/bin/go get capnproto.org/go/capnp/v3@$GO_CAPNP_VERSION \ - && /usr/lib/go/bin/go build -o capnpc-go capnproto.org/go/capnp/v3/capnpc-go \ - && sudo mv capnpc-go /usr/local/bin \ - && cd - \ - && sudo rm -rf go-tmp - - - -################################################################################################# -# The "opam-deps" Stage -# - Continues from the build-deps image -# - Installs all opam dependencies and pins from mina's github -# - Includes the entire mina codebase and submodules in "${MINA_DIR}" (must be writable by opam user) -# - Largely mirrors/replaces ./scripts/setup-opam.sh -################################################################################################# -FROM build-deps AS builder - -# location of repo used for pins and external package commits -ARG MINA_DIR=zeko - -# location of external packages -ARG EXTERNAL_PKG_DIR=$MINA_DIR/src/external - -# don't keep build directories -# to force reinstall of pinned packages from Mina sources -# and to keep Docker image reasonable size -ENV OPAMKEEPBUILDDIR false -ENV OPAMREUSEBUILDDIR false -# Limit logs for opam install errors to 20 lines per error -ENV OPAMERRLOGLEN 20 - -WORKDIR $HOME/$MINA_DIR - -ENV OPAMYES 1 - -# --- Import Opam Switch -# TODO: handle this opam work without cloning the full repository (directly pull opam.export) -COPY ./opam.export . -RUN opam switch import opam.export --quiet - -RUN eval $(opam config env) \ - && opam install fileutils \ - && opam install websocket-async - -# --- Copy the entire zeko repo into the image -COPY . . - -# --- Pin external packages / submodules -# TODO: Would be really nice to pull this script, the git submodules, and opam.export exclusively in this stage -# Remove .ppx and the .ppx-cache so they can be built on each run -RUN eval $(opam config env) \ - && scripts/pin-external-packages.sh \ - && opam clean --logs -cs --quiet - -RUN git config --global --add safe.directory /home/opam/zeko \ - && git config --global --add safe.directory /home/opam/zeko/src/lib/crypto/proof-systems - -# --- Build zeko binaries -RUN eval $(opam config env) \ - && dune build --profile=devnet \ - src/app/zkapps_examples/rollup/sequencer/run.exe \ - src/app/zkapps_examples/rollup/sequencer/archive_relay/run.exe - - - -################################################################################################# -# The "zeko" Stage -# - final stage -################################################################################################# -FROM --platform=linux/amd64 ubuntu:focal AS zeko - -ENV DEBIAN_FRONTEND noninteractive - -# --- Dependencies across many platforms -RUN apt-get update --quiet --yes \ - && apt-get upgrade --quiet --yes \ - && apt-get install --quiet --yes --no-install-recommends \ - apt-utils \ - apt-transport-https \ - curl \ - ca-certificates \ - dnsutils \ - dumb-init \ - gettext \ - gnupg2 \ - libgmp10 \ - libgomp1 \ - libssl1.1 \ - tzdata \ - jq \ - sudo \ - libjemalloc2 \ - libprocps8 \ - libffi7 \ - libpq-dev \ - && rm -rf /var/lib/apt/lists/* - -RUN curl -sL https://deb.nodesource.com/setup_18.x | bash \ - && apt-get update --quiet --yes \ - && apt-get install --quiet --yes nodejs - -WORKDIR /zeko/sequencer - -COPY --from=builder /home/opam/zeko/_build/default/src/app/zkapps_examples/rollup/sequencer/run.exe /zeko/sequencer/sequencer -COPY --from=builder /home/opam/zeko/_build/default/src/app/zkapps_examples/rollup/sequencer/archive_relay/run.exe /zeko/sequencer/archive_relay -COPY --from=builder /home/opam/zeko/src/app/zkapps_examples/rollup/da-layer /zeko/da-layer -COPY --from=builder /home/opam/zeko/src/app/zkapps_examples/rollup/sequencer/tests/testing_accounts.json /zeko/testing_accounts.json - -RUN cd /zeko/da-layer && npm install && npm run compile - -ENV PATH="$PATH:/zeko/sequencer" - -ENTRYPOINT [ "sequencer", "--test-accounts-path", "../testing_accounts.json" ] diff --git a/src/app/zeko/sequencer/Dockerfile.dockerignore b/src/app/zeko/sequencer/Dockerfile.dockerignore deleted file mode 100644 index b5d8a46e71..0000000000 --- a/src/app/zeko/sequencer/Dockerfile.dockerignore +++ /dev/null @@ -1,11 +0,0 @@ -.graphql_ppx_cache/ -.vscode/ -_build/ -src/app/zkapps_examples/rollup/da-layer/.DS_Store -src/app/zkapps_examples/rollup/da-layer/artifacts/ -src/app/zkapps_examples/rollup/da-layer/cache/ -src/app/zkapps_examples/rollup/da-layer/container.log -src/app/zkapps_examples/rollup/da-layer/geth_db/geth/ -src/app/zkapps_examples/rollup/da-layer/node_modules/ -src/app/zkapps_examples/rollup/da-layer/typechain-types/ -src/app/zkapps_examples/rollup/sequencer/db/ diff --git a/src/app/zeko/sequencer/Makefile b/src/app/zeko/sequencer/Makefile deleted file mode 100644 index 9b11c44b31..0000000000 --- a/src/app/zeko/sequencer/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -build: - DUNE_PROFILE=devnet dune build - -docker: - cd ../../../../.. ; \ - docker build -t zeko -f src/app/zkapps_examples/rollup/sequencer/Dockerfile . diff --git a/src/app/zeko/sequencer/README.md b/src/app/zeko/sequencer/README.md index 23afd47086..bdcb53605f 100644 --- a/src/app/zeko/sequencer/README.md +++ b/src/app/zeko/sequencer/README.md @@ -17,18 +17,23 @@ DUNE_PROFILE=devnet dune build ## Tests +Move to the root of the repo and run the following commands: + ```bash -# Run local network to imitate L1 -DUNE_PROFILE=devnet dune exec ./tests/testing_ledger/run.exe -- --db-dir l1_db +cd src/app/zeko/sequencer -# Run provers -DUNE_PROFILE=devnet dune exec ./prover/cli.exe -- run-server --port 9990 -DUNE_PROFILE=devnet dune exec ./prover/cli.exe -- run-server --port 9991 +# Run testing ledger to imitate L1 +dune exec ./tests/testing_ledger/run.exe -- --db-dir l1_db # Run da node -DUNE_PROFILE=devnet dune exec ../da_layer/cli.exe -- run-node --port 8555 --random-sk +dune exec ../da_layer/cli.exe -- run-node --port 8555 --random-sk + +# Run provers +dune exec ./prover/cli_fake.exe -- run-server --port 9990 +dune exec ./prover/cli_fake.exe -- run-server --port 9991 -DUNE_PROFILE=devnet dune runtest +# Run tests +dune exec ./tests/sequencer_test.exe ``` ## Run diff --git a/src/app/zeko/sequencer/archive_relay/dune b/src/app/zeko/sequencer/archive_relay/dune index 2bd53d550c..9a0828f576 100644 --- a/src/app/zeko/sequencer/archive_relay/dune +++ b/src/app/zeko/sequencer/archive_relay/dune @@ -1,6 +1,7 @@ (executable (name run) (libraries + zeko_constants da_layer mina_lib mina_ledger diff --git a/src/app/zeko/sequencer/archive_relay/run.ml b/src/app/zeko/sequencer/archive_relay/run.ml index 60997e6795..dba7d900ef 100644 --- a/src/app/zeko/sequencer/archive_relay/run.ml +++ b/src/app/zeko/sequencer/archive_relay/run.ml @@ -4,7 +4,26 @@ open Mina_base open Mina_lib open Mina_ledger -let constraint_constants = Genesis_constants.Compiled.constraint_constants +let constraint_constants = Zeko_constants.constraint_constants + +let compile_time_genesis = + let consensus_constants = + let protocol_constants : Genesis_constants.Protocol.t = + { k = 1 + ; slots_per_epoch = 1000 + ; slots_per_sub_window = 1 + ; grace_period_slots = 1 + ; delta = 1 + ; genesis_state_timestamp = Int64.one + } + in + Consensus.Constants.create ~constraint_constants ~protocol_constants + in + Mina_state.Genesis_protocol_state.t + ~genesis_ledger:Genesis_ledger.(Packed.t for_unit_tests) + ~genesis_epoch_data:Consensus.Genesis_epoch_data.for_unit_tests + ~constraint_constants ~consensus_constants + ~genesis_body_reference:Staged_ledger_diff.genesis_body_reference let rec rmrf path = match Sys.is_directory path with @@ -15,21 +34,6 @@ let rec rmrf path = | false -> Sys.remove path -let compile_time_genesis_state = - let genesis_constants = Genesis_constants.Compiled.genesis_constants in - let consensus_constants = - Consensus.Constants.create ~constraint_constants - ~protocol_constants:genesis_constants.protocol - in - let compile_time_genesis = - Mina_state.Genesis_protocol_state.t - ~genesis_ledger:Genesis_ledger.(Packed.t for_unit_tests) - ~genesis_epoch_data:Consensus.Genesis_epoch_data.for_unit_tests - ~constraint_constants ~consensus_constants - ~genesis_body_reference:Staged_ledger_diff.genesis_body_reference - in - compile_time_genesis.data - let time ~logger label (d : 'a Deferred.t) = let start = Time.now () in let%bind x = d in @@ -84,7 +88,7 @@ let sync_archive ~(state : State.t) ~hash = ~target_ledger_hash:hash in Ledger.with_ledger ~depth:constraint_constants.ledger_depth ~f:(fun ledger -> - let protocol_state = ref compile_time_genesis_state in + let protocol_state = ref compile_time_genesis.data in Deferred.List.iter diffs ~f:(fun diff -> match Da_layer.Diff.Stable.Latest.command_with_action_step_flags diff @@ -105,8 +109,8 @@ let sync_archive ~(state : State.t) ~hash = (Ledger.apply_transaction_first_pass ~constraint_constants ~global_slot:Mina_numbers.Global_slot_since_genesis.zero ~txn_state_view: - Mina_state.Protocol_state.( - Body.view @@ body compile_time_genesis_state) + (Mina_state.Protocol_state.Body.view + compile_time_genesis.data.body ) ledger (Command command) ) (Ledger.apply_transaction_second_pass ledger) in @@ -122,7 +126,7 @@ let sync_archive ~(state : State.t) ~hash = ~txn: (Mina_transaction_logic.Transaction_applied .transaction_with_status txn_applied ) - ~dummy_fee_payer:Zkapps_rollup.inner_public_key + ~dummy_fee_payer:Zeko_constants.inner_public_key ~timestamp:(Da_layer.Diff.Stable.Latest.timestamp diff) in protocol_state := new_protocol_state ; diff --git a/src/app/zeko/sequencer/deploy.ml b/src/app/zeko/sequencer/deploy.ml index 301ecf93b6..5f1e83bac9 100644 --- a/src/app/zeko/sequencer/deploy.ml +++ b/src/app/zeko/sequencer/deploy.ml @@ -2,6 +2,7 @@ open Core open Mina_base open Async open Mina_ledger +open Signature_lib module L = Ledger let constraint_constants = Genesis_constants.Compiled.constraint_constants @@ -24,7 +25,7 @@ module Test_accounts = struct List.map accounts ~f:(fun { pk; balance } -> let account_id = Account_id.create - (Signature_lib.Public_key.Compressed.of_base58_check_exn pk) + (Public_key.Compressed.of_base58_check_exn pk) Token_id.default in let account = @@ -34,73 +35,101 @@ module Test_accounts = struct (account_id, account) ) end -module T = Transaction_snark.Make (struct - let constraint_constants = constraint_constants - - let proof_level = Genesis_constants.Proof_level.Full -end) - -module M = Zkapps_rollup.Make (T) - -let run ~l1_uri ~sk ~initial_state ~da_nodes () = +let run ~l1_uri ~sk ~initial_state ~da_nodes ~pause_key ~sequencer_key ~da_key + () = let logger = Logger.create () in let sender_keypair = - Signature_lib.( - Keypair.of_private_key_exn @@ Private_key.of_base58_check_exn sk) + Keypair.of_private_key_exn @@ Private_key.of_base58_check_exn sk in - let zkapp_keypair = Signature_lib.Keypair.create () in + let zkapp_keypair = Keypair.create () in printf "zkapp secret key: %s\n%!" - (Signature_lib.Private_key.to_base58_check zkapp_keypair.private_key) ; + (Private_key.to_base58_check zkapp_keypair.private_key) ; printf "zkapp public key: %s\n%!" - Signature_lib.Public_key.( - Compressed.to_base58_check @@ compress zkapp_keypair.public_key) ; + Public_key.(Compressed.to_base58_check @@ compress zkapp_keypair.public_key) ; - let nonce = - Thread_safe.block_on_async_exn (fun () -> + Thread_safe.block_on_async_exn (fun () -> + let%bind nonce = Sequencer_lib.Gql_client.infer_nonce l1_uri - (Signature_lib.Public_key.compress sender_keypair.public_key) ) - in + (Public_key.compress sender_keypair.public_key) + in + let%bind initial_inner_account = + Sequencer_lib.Deploy.Z.Inner.initial_account () + in + let ledger, imt_hash = + let ledger = + L.create_ephemeral ~depth:constraint_constants.ledger_depth () + in + L.create_new_account_exn ledger Zeko_constants.inner_account_id + initial_inner_account ; + match initial_state with + | `None -> + ( ledger + , Indexed_merkle_tree.Db.( + create ~depth:constraint_constants.ledger_depth () + |> merkle_root) ) + | `Test_accounts test_accounts_path -> + let accounts = + Test_accounts.parse_accounts_exn ~test_accounts_path + in + let tids = + List.map accounts ~f:(fun (aid, _) -> + Account_id.derive_token_id ~owner:aid ) + in + let imt_hash = + let db = + Indexed_merkle_tree.Db.create + ~depth:constraint_constants.ledger_depth () + in + List.iter tids ~f:(fun tid -> + let _, _ = + Indexed_merkle_tree.Db.get_or_create_entry_exn db tid + in + () ) ; + Indexed_merkle_tree.Db.merkle_root db + in - let ledger = - let ledger = - L.create_ephemeral ~depth:constraint_constants.ledger_depth () - in - L.create_new_account_exn ledger M.Inner.account_id M.Inner.initial_account ; - match initial_state with - | `None -> - ledger - | `Test_accounts test_accounts_path -> - List.fold ~init:ledger - (Test_accounts.parse_accounts_exn ~test_accounts_path) - ~f:(fun ledger (account_id, account) -> - L.create_new_account_exn ledger account_id account ; - ledger ) - | `Db_dir db_dir -> - L.of_database - @@ L.Db.create ~directory_name:db_dir - ~depth:constraint_constants.ledger_depth () - in - let command = - Sequencer_lib.Deploy.deploy_command_exn ~signer:sender_keypair - ~zkapp:zkapp_keypair - ~fee:(Currency.Fee.of_mina_int_exn 1) - ~nonce ~constraint_constants ~initial_ledger:ledger - (module M) - in + let ledger = + List.fold ~init:ledger accounts + ~f:(fun ledger (account_id, account) -> + L.create_new_account_exn ledger account_id account ; + ledger ) + in + (ledger, imt_hash) + | `Db_dir (db_dir, imt_dir) -> + let imt_hash = + Indexed_merkle_tree.Db.( + create ~directory_name:imt_dir + ~depth:constraint_constants.ledger_depth () + |> merkle_root) + in + let db = + L.of_database + @@ L.Db.create ~directory_name:db_dir + ~depth:constraint_constants.ledger_depth () + in + (db, imt_hash) + in + let%bind command = + Sequencer_lib.Deploy.deploy_command_exn ~signer:sender_keypair + ~zkapp:zkapp_keypair + ~fee:(Currency.Fee.of_mina_int_exn 1) + ~nonce ~constraint_constants ~initial_ledger:ledger + ~account_set_hash:imt_hash ~pause_key ~sequencer:sequencer_key ~da_key + in - (* Post genesis batch *) - Thread_safe.block_on_async_exn (fun () -> - let config = Da_layer.Client.Config.{ nodes = da_nodes } in - match%bind - Da_layer.Client.distribute_genesis_diff ~logger ~config ~ledger - with - | Ok _ -> - return () - | Error e -> - Error.raise e ) ; + (* Post genesis batch *) + let%bind () = + let config = Da_layer.Client.Config.{ nodes = da_nodes } in + match%bind + Da_layer.Client.distribute_genesis_diff ~logger ~config ~ledger + with + | Ok _ -> + return () + | Error e -> + Error.raise e + in - (* Deploy contract *) - Thread_safe.block_on_async_exn (fun () -> + (* Deploy contract *) match%bind Sequencer_lib.Gql_client.send_zkapp l1_uri command with | Ok _ -> Deferred.unit @@ -122,10 +151,17 @@ let () = and init_db_dir = flag "--init-db-dir" (optional string) ~doc:"string Path to the initial db" + and init_imt_dir = + flag "--init-imt-dir" (optional string) + ~doc:"string Path to the initial imt" and da_nodes = flag "--da-node" (listed string) ~doc:"string Address of the DA node, can be supplied multiple times" - in + and pause_key = + flag "--pause-key" (required string) ~doc:"string Pause key" + and sequencer_key = + flag "--sequencer-key" (required string) ~doc:"string Sequencer key" + and da_key = flag "--da-key" (required string) ~doc:"string Da key" in let sk = Sys.getenv_exn "MINA_PRIVATE_KEY" in let da_nodes = List.mapi da_nodes ~f:(fun i uri -> @@ -135,17 +171,29 @@ let () = } ) in let initial_state = - match (test_accounts_path, init_db_dir) with - | Some _, Some _ -> + match (test_accounts_path, init_db_dir, init_imt_dir) with + | Some _, Some _, _ | Some _, _, Some _ -> failwith "Cannot specify both test accounts and initial db" - | Some test_accounts_path, None -> + | None, Some _, None | None, None, Some _ -> + failwith "Cannot specify only one of db and imt" + | Some test_accounts_path, None, None -> `Test_accounts test_accounts_path - | None, Some init_db_dir -> - `Db_dir init_db_dir - | None, None -> + | None, Some init_db_dir, Some init_imt_dir -> + `Db_dir (init_db_dir, init_imt_dir) + | None, None, None -> `None in + + let string_to_even_pc x = + Public_key.Compressed.of_base58_check_exn x + |> Zeko_circuits.Zeko_util.Even_PC.create_exn + in + let pause_key = string_to_even_pc pause_key in + let sequencer_key = string_to_even_pc sequencer_key in + let da_key = string_to_even_pc da_key in + let l1_uri : Uri.t Cli_lib.Flag.Types.with_name = Cli_lib.Flag.Types.{ value = Uri.of_string l1_uri; name = "l1-uri" } in - run ~l1_uri ~sk ~initial_state ~da_nodes ) + run ~l1_uri ~sk ~initial_state ~da_nodes ~pause_key ~sequencer_key + ~da_key ) diff --git a/src/app/zeko/sequencer/dune b/src/app/zeko/sequencer/dune index 3a43ca3b06..01779c1487 100644 --- a/src/app/zeko/sequencer/dune +++ b/src/app/zeko/sequencer/dune @@ -30,7 +30,6 @@ (name deploy) (libraries sequencer_lib - zkapps_rollup ;; mina ;; mina_base mina_numbers diff --git a/src/app/zeko/sequencer/lib/analytics.ml b/src/app/zeko/sequencer/lib/analytics.ml deleted file mode 100644 index c572225111..0000000000 --- a/src/app/zeko/sequencer/lib/analytics.ml +++ /dev/null @@ -1,206 +0,0 @@ -open Core_kernel -open Async -open Mina_base -open Signature_lib -open Mina_ledger -module Field = Snark_params.Tick.Field - -module User_activity = struct - type t = - { total_accounts : int; new_accounts_30d : int; active_accounts_30d : int } -end - -module Zkapp_activity = struct - type t = { total_zkapps : int; new_zkapps_30d : int; active_zkapps_30d : int } -end - -module Transaction_activity = struct - type t = - { total_deposits : int - ; total_signed_commands : int - ; total_zkapp_commands : int - } -end - -module Transaction_statistics = struct - type t = { avg_fee : float; avg_pfs : float (* proofs per second *) } -end - -module Top_zkapps = struct - type t = (string * int) list -end - -module Lumina_activity = struct - type t = { total_swaps : int; total_liquidity_pools : int } - - let get ~archive_uri ~zkapp_pk ~lumina_factory = - let%bind lps = - Gql_client.fetch_events archive_uri lumina_factory - >>| List.join - >>| List.filter_map ~f:(function - | _sender_x :: _sender_oddity :: pool_x :: pool_oddity :: _ -> - (* only one event type, so no index *) - (* https://github.com/Lumina-DEX/lumina-mvp/blob/284341acc924bf21ac6947514e23cce7088e68ed/contracts/src/PoolFactory.ts#L39 *) - Some - ( { x = pool_x - ; is_odd = - ( if Field.equal pool_oddity Field.zero then false - else true ) - } - : Public_key.Compressed.t ) - | _ -> - None ) - in - let%bind swaps = - Deferred.List.map ~how:`Parallel lps ~f:(fun lp -> - Gql_client.fetch_events archive_uri lp - >>| List.join - >>| List.filter ~f:(function - | event_type :: _ -> - (* [1] is event type [addLiquidity] *) - (* https://github.com/Lumina-DEX/lumina-mvp/blob/284341acc924bf21ac6947514e23cce7088e68ed/contracts/src/PoolMina.ts#L61 *) - if Field.equal event_type Field.one then true else false - | _ -> - false ) ) - >>| List.length - in - return { total_swaps = swaps; total_liquidity_pools = List.length lps } -end - -module State = struct - type timestamps = { created_at : Time.t; last_active_at : Time.t } - - type avg_fee = { total_fee : int; total_commands : int } - - type t = - { account_map : timestamps Account_id.Map.t - ; zkapp_map : timestamps Account_id.Map.t - ; total_signed_commands : int - ; total_zkapp_commands : int - ; avg_fee : avg_fee - } - - let empty = - { account_map = Account_id.Map.empty - ; zkapp_map = Account_id.Map.empty - ; total_signed_commands = 0 - ; total_zkapp_commands = 0 - ; avg_fee = { total_fee = 0; total_commands = 0 } - } - - let update_with_command t command ledger = - let now = Time.now () in - let accounts = User_command.accounts_accessed command Applied in - let t = - List.fold accounts ~init:t ~f:(fun t (account_id, _) -> - { t with - account_map = - Map.update t.account_map account_id ~f:(function - | None -> - { created_at = now; last_active_at = now } - | Some ts -> - { ts with last_active_at = now } ) - ; zkapp_map = - (let account = - let%bind.Option location = - Ledger.location_of_account ledger account_id - in - Ledger.get ledger location - in - match account with - | Some { zkapp = Some zkapp; _ } -> - Map.update t.zkapp_map account_id ~f:(function - | None -> - { created_at = now; last_active_at = now } - | Some ts -> - { ts with last_active_at = now } ) - | _ -> - t.zkapp_map ) - } ) - in - let t = - { t with - avg_fee = - { total_fee = - t.avg_fee.total_fee - + (Currency.Fee.to_mina_int @@ User_command.fee command) - ; total_commands = t.avg_fee.total_commands + 1 - } - } - in - match command with - | Signed_command _ -> - { t with total_signed_commands = t.total_signed_commands + 1 } - | Zkapp_command _ -> - { t with total_zkapp_commands = t.total_zkapp_commands + 1 } -end - -type t = - { user_activity : User_activity.t - ; zkapp_activity : Zkapp_activity.t - ; transaction_activity : Transaction_activity.t - ; transaction_statistics : Transaction_statistics.t - ; top_zkapps : Top_zkapps.t - ; lumina_activity : Lumina_activity.t - } - -let get (state : State.t) ~archive_uri ~zkapp_pk ~lumina_factory = - let now = Time.now () in - let before_30d = Time.(sub (now ()) (Span.of_day 30.)) in - let user_activity = - User_activity. - { total_accounts = Map.length state.account_map - ; new_accounts_30d = - Map.filter state.account_map ~f:(fun ts -> - Time.between ts.created_at ~low:before_30d ~high:now ) - |> Map.length - ; active_accounts_30d = - Map.filter state.account_map ~f:(fun ts -> - Time.between ts.last_active_at ~low:before_30d ~high:now ) - |> Map.length - } - in - let zkapp_activity = - Zkapp_activity. - { total_zkapps = Map.length state.zkapp_map - ; new_zkapps_30d = - Map.filter state.zkapp_map ~f:(fun ts -> - Time.between ts.created_at ~low:before_30d ~high:now ) - |> Map.length - ; active_zkapps_30d = - Map.filter state.zkapp_map ~f:(fun ts -> - Time.between ts.last_active_at ~low:before_30d ~high:now ) - |> Map.length - } - in - let%bind deposits = - Gql_client.fetch_transfers archive_uri zkapp_pk >>| List.length - in - let transaction_activity = - Transaction_activity. - { total_deposits = deposits - ; total_signed_commands = state.total_signed_commands - ; total_zkapp_commands = state.total_zkapp_commands - } - in - let transaction_statistics = - Transaction_statistics. - { avg_fee = - Float.( / ) - (Int.to_float state.avg_fee.total_fee) - (Int.to_float state.avg_fee.total_commands) - ; avg_pfs = 0. (* TODO: when I do parallel proving will update this *) - } - in - let top_zkapps = Top_zkapps.[] in - let%bind lumina_activity = - Lumina_activity.get ~archive_uri ~zkapp_pk ~lumina_factory - in - return - { user_activity - ; zkapp_activity - ; transaction_activity - ; transaction_statistics - ; top_zkapps - ; lumina_activity - } diff --git a/src/app/zeko/sequencer/lib/committer.ml b/src/app/zeko/sequencer/lib/committer.ml index fea73d2130..1aa7123049 100644 --- a/src/app/zeko/sequencer/lib/committer.ml +++ b/src/app/zeko/sequencer/lib/committer.ml @@ -3,6 +3,8 @@ open Async open Mina_base open Signature_lib open Mina_ledger +open Zeko_circuits +open Zeko_prover.Zeko_types module Field = Snark_params.Tick.Field module Commit_witness = struct @@ -12,7 +14,7 @@ module Commit_witness = struct ; old_deposits_pointer : Frozen_ledger_hash.t ; processed_deposits_pointer : Frozen_ledger_hash.t ; signatures : Signature.t list - ; last_snark : Zkapps_rollup.t + ; txn_snark : Txn_snark.serializable } [@@deriving yojson] end @@ -111,27 +113,26 @@ let prove_commit ~provers ~(executor : Executor.t) ~zkapp_pk ~archive_uri ; old_deposits_pointer ; processed_deposits_pointer ; signatures - ; last_snark + ; txn_snark } : Commit_witness.t ) = - (* FIXME: pass this check into circuit *) - assert (List.length signatures <> 0) ; - let%bind new_deposits = - Gql_client.fetch_transfers archive_uri - ~from_action_state:old_deposits_pointer + let%bind new_actions = + Gql_client.fetch_actions archive_uri ~from_action_state:old_deposits_pointer ~end_action_state:processed_deposits_pointer zkapp_pk - |> Deferred.map ~f:(List.map ~f:fst) + >>| List.map ~f:fst >>| List.rev + >>| List.map ~f:Account_update.Actions.hash in - let%bind unprocessed_deposits = - Gql_client.fetch_transfers archive_uri + let%bind unprocessed_actions = + Gql_client.fetch_actions archive_uri ~from_action_state:processed_deposits_pointer zkapp_pk - |> Deferred.map ~f:(List.map ~f:fst) + >>| List.map ~f:fst >>| List.rev + >>| List.map ~f:Account_update.Actions.hash in let%bind account_update = - Zeko_prover.Client.outer_step ~proving_timeout:30. provers ~last:last_snark - ~outer_public_key:zkapp_pk ~new_deposits:(List.rev new_deposits) - ~unprocessed_deposits:(List.rev unprocessed_deposits) - ~old_inner_ledger ~new_inner_ledger + Zeko_prover.Client.outer_commit ~proving_timeout:30. provers ~txn_snark + ~public_key:zkapp_pk ~new_actions ~unprocessed_actions ~old_inner_ledger + ~new_inner_ledger ~da_signature:(List.hd_exn signatures) + ~da_key:(failwith "Not implemented") in let command : Zkapp_command.t = { fee_payer = diff --git a/src/app/zeko/sequencer/lib/deploy.ml b/src/app/zeko/sequencer/lib/deploy.ml index 8594e9b147..ab6f2013ca 100644 --- a/src/app/zeko/sequencer/lib/deploy.ml +++ b/src/app/zeko/sequencer/lib/deploy.ml @@ -1,18 +1,107 @@ +open Async open Mina_base open Account_update open Signature_lib module L = Mina_ledger.Ledger +module Z = struct + open Zeko_circuits + + let proof_permissions : Permissions.t = + { edit_state = Proof + ; send = Proof + ; receive = None + ; set_delegate = Proof + ; set_permissions = Proof + ; set_verification_key = (Either, Mina_numbers.Txn_version.current) + ; set_zkapp_uri = Proof + ; edit_action_state = Proof + ; set_token_symbol = Proof + ; increment_nonce = None + ; set_voting_for = Proof + ; set_timing = Proof + ; access = Proof + } + + module Inner = struct + let initial_account () = + let%bind vk = + Compile_simple.Verification_key.of_tag Inner_rules.tag + |> Promise.to_deferred + in + return + { Account.empty with + public_key = Zeko_constants.inner_public_key + ; balance = Currency.Balance.max_int + ; permissions = + { proof_permissions with access = Permissions.Auth_required.None } + ; zkapp = + Some + { Zkapp_account.default with + app_state = + Rollup_state.Inner_state.(value_to_init_state default) + ; verification_key = + Some + (Verification_key_wire.Stable.Latest.M.of_binable + (Compile_simple.Verification_key.to_pickles vk) ) + } + } + end + + module Outer = struct + let unsafe_deploy ~pause_key ~ledger_hash ~sequencer ~da_key ~acc_set = + let%bind vk = + Compile_simple.Verification_key.of_tag Outer_rules.tag + |> Promise.to_deferred + in + return + { Update.dummy with + app_state = + Rollup_state.Outer_state.( + value_to_app_state + ( { pause_key + ; paused = false + ; ledger_hash + ; inner_action_state = + Rollup_state.Inner_action_state.With_length.empty + ; sequencer + ; da_key + ; acc_set + } + : t )) + ; verification_key = + Set + (Verification_key_wire.Stable.Latest.M.of_binable + (Compile_simple.Verification_key.to_pickles vk) ) + ; permissions = Set proof_permissions + } + + let deploy_exn (l : L.t) = + if + not + (Public_key.Compressed.equal Zeko_constants.inner_public_key + (L.get_at_index_exn l 0).public_key ) + then failwith "zeko outer deploy: ledger invalid" + else () ; + unsafe_deploy ~ledger_hash:(L.merkle_root l) + end +end + let deploy_command_exn ~(signer : Keypair.t) ~(fee : Currency.Fee.t) ~(nonce : Account.Nonce.t) ~(zkapp : Keypair.t) ~(initial_ledger : L.t) + ~account_set_hash ~(constraint_constants : Genesis_constants.Constraint_constants.t) - (module Z : Zkapps_rollup.S) : Zkapp_command.t = + ~pause_key ~sequencer ~da_key = + let%bind update = + Z.Outer.deploy_exn ~pause_key ~sequencer ~da_key ~acc_set:account_set_hash + initial_ledger + in let zkapp_update = { body = { Body.dummy with public_key = Public_key.compress zkapp.public_key ; implicit_account_creation_fee = false - ; update = Z.Outer.deploy_exn initial_ledger + ; update ; use_full_commitment = true ; authorization_kind = Signature } @@ -69,18 +158,20 @@ let deploy_command_exn ~(signer : Keypair.t) ~(fee : Currency.Fee.t) zkapp.private_key (Random_oracle.Input.Chunked.field full_commitment) in - { command with - fee_payer = { command.fee_payer with authorization = sender_signature } - ; account_updates = - Zkapp_command.Call_forest.accumulate_hashes ~hash_account_update:(fun p -> - Zkapp_command.Digest.Account_update.create p ) - @@ Zkapp_command.Call_forest.of_account_updates - ~account_update_depth:(fun _ -> 0) - [ { zkapp_update with - authorization = Control.Signature zkapp_signature - } - ; { sender_update with - authorization = Control.Signature sender_signature - } - ] - } + return + { command with + fee_payer = { command.fee_payer with authorization = sender_signature } + ; account_updates = + Zkapp_command.Call_forest.accumulate_hashes + ~hash_account_update:(fun p -> + Zkapp_command.Digest.Account_update.create p ) + @@ Zkapp_command.Call_forest.of_account_updates + ~account_update_depth:(fun _ -> 0) + [ { zkapp_update with + authorization = Control.Signature zkapp_signature + } + ; { sender_update with + authorization = Control.Signature sender_signature + } + ] + } diff --git a/src/app/zeko/sequencer/lib/dune b/src/app/zeko/sequencer/lib/dune index f4b15c4652..07773a40b9 100644 --- a/src/app/zeko/sequencer/lib/dune +++ b/src/app/zeko/sequencer/lib/dune @@ -2,11 +2,12 @@ (name sequencer_lib) (inline_tests) (libraries - zkapps_rollup kvdb_base da_layer zeko_prover parallel_merger + zeko_constants + indexed_merkle_tree ;; mina ;; mina_base mina_base.import @@ -52,7 +53,6 @@ random_oracle random_oracle_input init - cli_lib ;; opam libraries ;; base_quickcheck uri diff --git a/src/app/zeko/sequencer/lib/gql.ml b/src/app/zeko/sequencer/lib/gql.ml index 05070213ba..3a6ef43dfc 100644 --- a/src/app/zeko/sequencer/lib/gql.ml +++ b/src/app/zeko/sequencer/lib/gql.ml @@ -1273,19 +1273,18 @@ module Types = struct let arg_typ = enum "TransferDirection" ~values: - [ enum_value "DEPOSIT" ~value:Zeko_sequencer.Transfer.Deposit - ; enum_value "WITHDRAW" ~value:Zeko_sequencer.Transfer.Withdraw + [ enum_value "DEPOSIT" ~value:Transfer.Deposit + ; enum_value "WITHDRAW" ~value:Transfer.Withdraw ] end - module Transfer = struct - type input = Zkapps_rollup.TR.t + module Transfer_input = struct + type input = Transfer.TR.t let arg_typ = obj "TransferInput" ~coerce:(fun amount recipient -> - Zkapps_rollup.TR.{ amount = Amount.of_uint64 amount; recipient } - ) + Transfer.TR.{ amount = Amount.of_uint64 amount; recipient } ) ~split:(fun f (x : input) -> f (Currency.Amount.to_uint64 x.amount) x.recipient ) ~fields: @@ -1295,16 +1294,15 @@ module Types = struct end module Request = struct - type input = Zeko_sequencer.Transfer.t + type input = Transfer.t let arg_typ = obj "TransferRequestInput" - ~coerce:(fun transfer direction -> - Zeko_sequencer.Transfer.{ transfer; direction } ) + ~coerce:(fun transfer direction -> Transfer.{ transfer; direction }) ~split:(fun f ({ transfer; direction } : input) -> f transfer direction ) ~fields: - [ arg "transfer" ~typ:(non_null Transfer.arg_typ) + [ arg "transfer" ~typ:(non_null Transfer_input.arg_typ) ; arg "direction" ~typ:(non_null @@ Direction.arg_typ) ] end @@ -1312,12 +1310,12 @@ module Types = struct module Claim = struct open Snark_params.Tick - type input = Zeko_sequencer.Transfer.claim + type input = Transfer.claim let arg_typ = obj "TransferClaimInput" ~coerce:(fun is_new pointer before after transfer -> - Zeko_sequencer.Transfer. + Transfer. { is_new ; pointer = Field.of_string pointer ; before @@ -1330,8 +1328,10 @@ module Types = struct ~fields: [ arg "isNew" ~typ:(non_null bool) ; arg "pointer" ~typ:(non_null string) - ; arg "before" ~typ:(non_null (list @@ non_null Transfer.arg_typ)) - ; arg "after" ~typ:(non_null (list @@ non_null Transfer.arg_typ)) + ; arg "before" + ~typ:(non_null (list @@ non_null Transfer_input.arg_typ)) + ; arg "after" + ~typ:(non_null (list @@ non_null Transfer_input.arg_typ)) ; arg "transfer" ~typ:(non_null Request.arg_typ) ] end @@ -1384,140 +1384,6 @@ module Types = struct end end - module Analytics = struct - module User_activity = struct - type t = Analytics.User_activity.t - - let t : ('context, t option) typ = - let open Analytics.User_activity in - obj "UserActivity" ~fields:(fun _ -> - [ field "totalAccounts" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> x.total_accounts) - ; field "newAccounts30d" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> x.new_accounts_30d) - ; field "activeAccounts30d" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> x.active_accounts_30d) - ] ) - end - - module Zkapp_activity = struct - type t = Analytics.Zkapp_activity.t - - let t : ('context, t option) typ = - let open Analytics.Zkapp_activity in - obj "ZkappActivity" ~fields:(fun _ -> - [ field "totalZkapps" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> x.total_zkapps) - ; field "newZkapps30d" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> x.new_zkapps_30d) - ; field "activeZkapps30d" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> x.active_zkapps_30d) - ] ) - end - - module Transaction_activity = struct - type t = Analytics.Transaction_activity.t - - let t : ('context, t option) typ = - let open Analytics.Transaction_activity in - obj "TransactionActivity" ~fields:(fun _ -> - [ field "totalDeposits" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> x.total_deposits) - ; field "totalSignedCommands" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> x.total_signed_commands) - ; field "totalZkappCommands" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> x.total_zkapp_commands) - ; field "totalTransactions" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> - x.total_signed_commands + x.total_zkapp_commands ) - ] ) - end - - module Transaction_statistics = struct - type t = Analytics.Transaction_statistics.t - - let t : ('context, t option) typ = - let open Analytics.Transaction_statistics in - obj "TransactionStatistics" ~fields:(fun _ -> - [ field "averageFee" ~typ:(non_null float) - ~args:Arg.[] - ~resolve:(fun _ x -> x.avg_fee) - ; field "averagePFS" ~typ:(non_null float) - ~args:Arg.[] - ~resolve:(fun _ x -> x.avg_pfs) - ] ) - end - - module Top_zkapps = struct - type t = Analytics.Top_zkapps.t - - let t : ('context, t option) typ = - let open Analytics.Top_zkapps in - list @@ non_null - @@ obj "TopZkapps" ~fields:(fun _ -> - [ field "zkapp" ~typ:(non_null string) - ~args:Arg.[] - ~resolve:(fun _ x -> fst x) - ; field "count" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> snd x) - ] ) - end - - module Lumina_activity = struct - type t = Analytics.Lumina_activity.t - - let t : ('context, t option) typ = - let open Analytics.Lumina_activity in - obj "LuminaActivity" ~fields:(fun _ -> - [ field "totalSwaps" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> x.total_swaps) - ; field "totalLiquidityPools" ~typ:(non_null int) - ~args:Arg.[] - ~resolve:(fun _ x -> x.total_liquidity_pools) - ] ) - end - - type t = Analytics.t - - let t : ('context, t option) typ = - obj "Analytics" ~fields:(fun _ -> - [ field "userActivity" ~typ:(non_null User_activity.t) - ~args:Arg.[] - ~resolve:(fun _ x -> Analytics.(x.user_activity)) - ; field "zkappActivity" - ~typ:(non_null Zkapp_activity.t) - ~args:Arg.[] - ~resolve:(fun _ x -> Analytics.(x.zkapp_activity)) - ; field "transactionActivity" - ~typ:(non_null Transaction_activity.t) - ~args:Arg.[] - ~resolve:(fun _ x -> Analytics.(x.transaction_activity)) - ; field "transactionStatistics" - ~typ:(non_null Transaction_statistics.t) - ~args:Arg.[] - ~resolve:(fun _ x -> Analytics.(x.transaction_statistics)) - ; field "topZkapps" ~typ:(non_null Top_zkapps.t) - ~args:Arg.[] - ~resolve:(fun _ x -> Analytics.(x.top_zkapps)) - ; field "luminaActivity" - ~typ:(non_null Lumina_activity.t) - ~args:Arg.[] - ~resolve:(fun _ x -> Analytics.(x.lumina_activity)) - ] ) - end - module Archive = struct module BlockInfo = struct type t = Archive.Block_info.t @@ -1758,10 +1624,11 @@ module Mutations = struct with | Error err -> return (Error (Error.to_string_mach err)) - | Ok (_, command_witness) -> - don't_wait_for - @@ Zeko_sequencer.Merger.P.add_job sequencer.merger - sequencer.merger_ctx ~data:command_witness ; + | Ok witnesses -> + List.iter witnesses ~f:(fun witness -> + don't_wait_for + @@ Zeko_sequencer.Merger.P.add_job sequencer.merger + sequencer.merger_ctx ~data:witness ) ; let cmd = { Types.User_command.With_status.data = Signed_command.forget_check command @@ -1789,10 +1656,11 @@ module Mutations = struct with | Error err -> return (Error (Error.to_string_mach err)) - | Ok (_, command_witness) -> - don't_wait_for - @@ Zeko_sequencer.Merger.P.add_job sequencer.merger - sequencer.merger_ctx ~data:command_witness ; + | Ok witnesses -> + List.iter witnesses ~f:(fun witness -> + don't_wait_for + @@ Zeko_sequencer.Merger.P.add_job sequencer.merger + sequencer.merger_ctx ~data:witness ) ; let cmd = { Types.Zkapp_command.With_status.data = zkapp_command ; status = Applied @@ -1814,8 +1682,9 @@ module Mutations = struct ~resolve:(fun { ctx = sequencer; _ } () transfer -> let key = Int.to_string @@ Random.int Int.max_value in don't_wait_for - @@ Zeko_sequencer.Snark_queue.enqueue_prove_transfer_request + @@ Snark_queue.enqueue_prove_transfer_request Zeko_sequencer.(sequencer.snark_q) + ~zkapp_pk:Zeko_sequencer.(sequencer.config.zkapp_pk) ~key ~transfer ; return (Ok key) ) @@ -1826,8 +1695,9 @@ module Mutations = struct ~resolve:(fun { ctx = sequencer; _ } () claim -> let key = Int.to_string @@ Random.int Int.max_value in don't_wait_for - @@ Zeko_sequencer.Snark_queue.enqueue_prove_transfer_claim + @@ Snark_queue.enqueue_prove_transfer_claim Zeko_sequencer.(sequencer.snark_q) + ~zkapp_pk:Zeko_sequencer.(sequencer.config.zkapp_pk) ~key ~claim ; return (Ok key) ) @@ -1935,7 +1805,7 @@ module Queries = struct ~args:Arg.[ arg "key" ~typ:(non_null string) ] ~resolve:(fun { ctx = sequencer; _ } () key -> match - Transfers_memory.get + Transfer.Transfers_memory.get Zeko_sequencer.(sequencer.snark_q.transfers_memory) key with @@ -1969,21 +1839,6 @@ module Queries = struct let%map account_id = Ledger.token_owner l token in Types.AccountObj.get_best_ledger_account l account_id ) - let analytics = - io_field "analytics" - ~typ:(non_null Types.Analytics.t) - ~args: - Arg. - [ arg "luminaFactory" ~typ:(non_null Types.Input.PublicKey.arg_typ) ] - ~resolve:(fun { ctx = sequencer; _ } () lumina_factory -> - let%bind analytics = - let open Zeko_sequencer in - Analytics.get sequencer.analytics_state - ~archive_uri:sequencer.config.archive_uri - ~zkapp_pk:sequencer.config.zkapp_pk ~lumina_factory - in - return (Ok analytics) ) - module Archive = struct let actions = io_field "actions" @@ -2031,7 +1886,6 @@ module Queries = struct ; state_hashes ; token_owner ; network_id - ; analytics ] @ Archive.commands end @@ -2039,23 +1893,7 @@ end module Subscriptions = struct open Schema - let state_hashes_changed = - subscription_field "stateHashesChanged" - ~doc: - "Event that triggers when some of the state hashes are changed. Max \ - once per minute." - ~typ:(non_null Types.State_hashes.t) - ~args:Arg.[] - ~resolve:(fun { ctx = sequencer; _ } -> - let r, w = - Zeko_sequencer.Subscriptions.add_state_hashes_subscriber - sequencer.subscriptions - in - Pipe.write_without_pushback_if_open w - (Zeko_sequencer.get_latest_state sequencer) ; - return (Ok r) ) - - let commands = [ state_hashes_changed ] + let commands = [] end let schema = diff --git a/src/app/zeko/sequencer/lib/gql_client.ml b/src/app/zeko/sequencer/lib/gql_client.ml index 8f97e0532c..a3ecd7ad76 100644 --- a/src/app/zeko/sequencer/lib/gql_client.ml +++ b/src/app/zeko/sequencer/lib/gql_client.ml @@ -55,7 +55,8 @@ let fetch_action_state uri pk = result |> member "account" |> member "actionState" |> index 0 |> to_string) |> Field.of_string -let fetch_transfers uri ?from_action_state ?end_action_state pk = +let fetch_actions uri ?from_action_state ?end_action_state pk : + (Account_update.Actions.t * int) list Deferred.t = let ok_exn = function | Ppx_deriving_yojson_runtime.Result.Ok x -> x @@ -120,18 +121,8 @@ let fetch_transfers uri ?from_action_state ?end_action_state pk = List.map result.actions ~f:(fun { actionData; blockInfo } -> let block_height = blockInfo.height in List.map actionData ~f:(fun { data } -> - let amount = List.nth_exn data 0 in - let public_key_x = List.nth_exn data 1 in - let is_odd = List.nth_exn data 2 |> Int.of_string in - ( Zkapps_rollup.TR. - { amount = Currency.Amount.of_string amount - ; recipient = - Signature_lib.Public_key.Compressed. - { x = Field.of_string public_key_x - ; is_odd = (match is_odd with 0 -> false | _ -> true) - } - } - , block_height ) ) ) + let fields = List.map data ~f:Field.of_string |> List.to_array in + ([ fields ], block_height) ) ) |> List.join |> (* Drop the first transfer if it's not the initial state *) @@ -287,9 +278,15 @@ let fetch_committed_state uri pk = end in let%map result = Graphql_client.query_json_exn q uri in - Yojson.Safe.Util.( - result |> member "account" |> member "zkappState" |> index 0 |> to_string) - |> Frozen_ledger_hash.of_decimal_string + let open Zeko_circuits.Rollup_state in + let ({ ledger_hash; _ } : Outer_state.t) = + Yojson.Safe.Util.( + result |> member "account" |> member "zkappState" |> to_list + |> List.map ~f:to_string + |> List.map ~f:Field.of_string + |> Zkapp_state.V.of_list_exn |> Outer_state.value_of_app_state) + in + ledger_hash let infer_committed_state uri ~zkapp_pk ~signer_pk = let%bind committed_state = fetch_committed_state uri zkapp_pk diff --git a/src/app/zeko/sequencer/lib/snark_queue.ml b/src/app/zeko/sequencer/lib/snark_queue.ml new file mode 100644 index 0000000000..8ae0482dd1 --- /dev/null +++ b/src/app/zeko/sequencer/lib/snark_queue.ml @@ -0,0 +1,85 @@ +open Core_kernel +open Async +open Mina_base + +type t = + { q : unit Throttle.t + ; transfers_memory : Transfer.Transfers_memory.t + ; provers : Zeko_prover.Client.State.t + } + +let create ~config ~provers = + { q = Throttle.create ~continue_on_error:false ~max_concurrent_jobs:1 + ; transfers_memory = + Transfer.Transfers_memory.create ~lifetime:Float.(60. * 10.) + ; provers + } + +let queue_size t = Throttle.num_jobs_waiting_to_start t.q + +let enqueue t f = + Throttle.enqueue t.q (fun () -> + let%map result = f () in + result ) + +let enqueue_prove_transfer_request t ~key ~zkapp_pk ~(transfer : Transfer.t) = + Throttle.enqueue t.q (fun () -> + let%bind result = + try_with (fun () -> + match transfer with + | { direction = Deposit; transfer } -> + Zeko_prover.Client.submit_deposit t.provers ~outer_pk:zkapp_pk + ~deposit:transfer + | { direction = Withdraw; transfer } -> + Zeko_prover.Client.submit_withdrawal t.provers + ~withdrawal:transfer ) + in + let () = + match result with + | Ok tree -> + Transfer.Transfers_memory.add t.transfers_memory key + (Ok (Zkapp_command.Call_forest.cons_tree tree [])) + | Error e -> + printf "Warning: prove_transfer_request failed %s\n%!" + (Exn.to_string e) ; + Transfer.Transfers_memory.add t.transfers_memory key + (Error (Exn.to_string e)) + in + return () ) + +let enqueue_prove_transfer_claim t ~key ~zkapp_pk ~(claim : Transfer.claim) = + Throttle.enqueue t.q (fun () -> + let%bind result = + try_with (fun () -> + match claim with + | { transfer = { direction = Deposit; transfer } + ; is_new + ; pointer + ; before + ; after + } -> + Zeko_prover.Client.process_deposit t.provers ~is_new ~pointer + ~before ~after ~deposit:transfer + | { transfer = { direction = Withdraw; transfer } + ; is_new + ; pointer + ; before + ; after + } -> + Zeko_prover.Client.process_withdrawal t.provers + ~outer_pk:zkapp_pk ~is_new ~pointer ~before ~after + ~withdrawal:transfer ) + in + let () = + match result with + | Ok forest -> + Transfer.Transfers_memory.add t.transfers_memory key (Ok forest) + | Error e -> + printf "Warning: prove_transfer_claim failed %s\n%!" + (Exn.to_string e) ; + Transfer.Transfers_memory.add t.transfers_memory key + (Error (Exn.to_string e)) + in + return () ) + +let wait_to_finish t = Throttle.capacity_available t.q diff --git a/src/app/zeko/sequencer/lib/transfers_memory.ml b/src/app/zeko/sequencer/lib/transfer.ml similarity index 73% rename from src/app/zeko/sequencer/lib/transfers_memory.ml rename to src/app/zeko/sequencer/lib/transfer.ml index 548ef1e8c2..b96610ba73 100644 --- a/src/app/zeko/sequencer/lib/transfers_memory.ml +++ b/src/app/zeko/sequencer/lib/transfer.ml @@ -1,12 +1,34 @@ +open Mina_base +module Field = Snark_params.Tick.Field + +type direction = Deposit | Withdraw + +module TR = struct + (* FIXME *) + type t = + { amount : Currency.Amount.t + ; recipient : Signature_lib.Public_key.Compressed.t + } + [@@deriving yojson] +end + +type t = { transfer : TR.t; direction : direction } + +type claim = + { is_new : bool + ; pointer : Field.t + ; before : TR.t list + ; after : TR.t list + ; transfer : t + } + (** Hash table that holds the item only for the specified lifetime. Used to store proved transfer requested by users. *) - -open Base -open Mina_base - module Transfers_memory = struct + open Base + type t_ = ( ( Account_update.t , Zkapp_command.Digest.Account_update.t @@ -48,5 +70,3 @@ module Transfers_memory = struct let get t key = Hashtbl.find t.table key end - -include Transfers_memory diff --git a/src/app/zeko/sequencer/lib/utils.ml b/src/app/zeko/sequencer/lib/utils.ml index 45a9ae9b60..141fa407e5 100644 --- a/src/app/zeko/sequencer/lib/utils.ml +++ b/src/app/zeko/sequencer/lib/utils.ml @@ -27,7 +27,6 @@ let print_time label (d : 'a Deferred.t) = printf "%s: %s\n%!" label (Time.Span.to_string_hum t) ; return x -(* Finds the account_id's account update and returns the 0th state update *) let get_state_transition pk command = let account_id = Account_id.create pk Token_id.default in let%bind.Option account_update = @@ -38,26 +37,29 @@ let get_state_transition pk command = |> Account_id.equal account_id ) in let body = Account_update.body account_update in - let zeroth l = List.nth_exn l 0 in + (* Use the Rollup_state.Outer_state.t to determine which is ledger hash *) + let third l = List.nth_exn l 2 in let source = body |> Account_update.Body.preconditions |> Account_update.Preconditions.account |> Zkapp_precondition.Account.state - |> Zkapp_state.V.to_list |> zeroth |> Zkapp_basic.Or_ignore.to_option + |> Zkapp_state.V.to_list |> third |> Zkapp_basic.Or_ignore.to_option |> Option.value ~default:Field.zero in let target = body |> Account_update.Body.update |> Account_update.Update.app_state - |> Zkapp_state.V.to_list |> zeroth |> Zkapp_basic.Set_or_keep.to_option + |> Zkapp_state.V.to_list |> third |> Zkapp_basic.Set_or_keep.to_option |> Option.value ~default:Field.zero in Some (source, target) let get_inner_deposits_state_exn l = - let (old_deposits_commit :: _) = + let open Zeko_circuits in + let ({ outer_action_state } : Rollup_state.Inner_state.t) = let idx = - Mina_ledger.Ledger.index_of_account_exn l Zkapps_rollup.inner_account_id + Mina_ledger.Ledger.index_of_account_exn l Zeko_constants.inner_account_id in let inner_acc = Mina_ledger.Ledger.get_at_index_exn l idx in (Option.value_exn inner_acc.zkapp).app_state + |> Rollup_state.Inner_state.value_of_app_state in - old_deposits_commit + outer_action_state diff --git a/src/app/zeko/sequencer/lib/zeko_sequencer.ml b/src/app/zeko/sequencer/lib/zeko_sequencer.ml index aedbff9c0a..e127bd9953 100644 --- a/src/app/zeko/sequencer/lib/zeko_sequencer.ml +++ b/src/app/zeko/sequencer/lib/zeko_sequencer.ml @@ -5,19 +5,20 @@ open Async_kernel open Mina_base open Mina_ledger open Signature_lib +open Zeko_prover.Zeko_types +module C = Zeko_circuits module L = Ledger module Field = Snark_params.Tick.Field -let constraint_constants = Genesis_constants.Compiled.constraint_constants - module Sequencer = struct - let constraint_constants = constraint_constants + let constraint_constants = Zeko_constants.constraint_constants module Config = struct type t = { max_pool_size : int ; commitment_period_sec : float ; db_dir : string option + ; imt_dir : string option ; zkapp_pk : Public_key.Compressed.t ; signer : Keypair.t ; l1_uri : Uri.t Cli_lib.Flag.Types.with_name @@ -27,36 +28,6 @@ module Sequencer = struct } end - module Transfer = struct - type direction = Deposit | Withdraw - - type t = { transfer : Zkapps_rollup.TR.t; direction : direction } - - type claim = - { is_new : bool - ; pointer : Field.t - ; before : Zkapps_rollup.TR.t list - ; after : Zkapps_rollup.TR.t list - ; transfer : t - } - end - - let genesis_constants = Genesis_constants.Compiled.genesis_constants - - let compile_time_genesis_state = - let consensus_constants = - Consensus.Constants.create ~constraint_constants - ~protocol_constants:genesis_constants.protocol - in - let compile_time_genesis = - Mina_state.Genesis_protocol_state.t - ~genesis_ledger:Genesis_ledger.(Packed.t for_unit_tests) - ~genesis_epoch_data:Consensus.Genesis_epoch_data.for_unit_tests - ~constraint_constants ~consensus_constants - ~genesis_body_reference:Staged_ledger_diff.genesis_body_reference - in - compile_time_genesis.data - let keypair = Keypair.create () let sok_digest = @@ -64,163 +35,20 @@ module Sequencer = struct @@ Sok_message.create ~fee:Currency.Fee.zero ~prover:(Public_key.compress keypair.public_key) - module Snark_queue = struct - type t = - { q : unit Throttle.t - ; config : Config.t - ; transfers_memory : Transfers_memory.t - ; provers : Zeko_prover.Client.State.t - } - - let create ~config ~provers = - { q = Throttle.create ~continue_on_error:false ~max_concurrent_jobs:1 - ; config - ; transfers_memory = Transfers_memory.create ~lifetime:Float.(60. * 10.) - ; provers - } - - let queue_size t = Throttle.num_jobs_waiting_to_start t.q - - let enqueue t f = - Throttle.enqueue t.q (fun () -> - let%map result = f () in - result ) - - let enqueue_prove_transfer_request t ~key ~(transfer : Transfer.t) = - Throttle.enqueue t.q (fun () -> - let%bind result = - try_with (fun () -> - match transfer with - | { direction = Deposit; transfer } -> - Zeko_prover.Client.submit_deposit t.provers - ~outer_pk:t.config.zkapp_pk ~deposit:transfer - | { direction = Withdraw; transfer } -> - Zeko_prover.Client.submit_withdrawal t.provers - ~withdrawal:transfer ) - in - let () = - match result with - | Ok tree -> - Transfers_memory.add t.transfers_memory key - (Ok (Zkapp_command.Call_forest.cons_tree tree [])) - | Error e -> - printf "Warning: prove_transfer_request failed %s\n%!" - (Exn.to_string e) ; - Transfers_memory.add t.transfers_memory key - (Error (Exn.to_string e)) - in - return () ) - - let enqueue_prove_transfer_claim t ~key ~(claim : Transfer.claim) = - Throttle.enqueue t.q (fun () -> - let%bind result = - try_with (fun () -> - match claim with - | { transfer = { direction = Deposit; transfer } - ; is_new - ; pointer - ; before - ; after - } -> - Zeko_prover.Client.process_deposit t.provers ~is_new - ~pointer ~before ~after ~deposit:transfer - | { transfer = { direction = Withdraw; transfer } - ; is_new - ; pointer - ; before - ; after - } -> - Zeko_prover.Client.process_withdrawal t.provers - ~outer_pk:t.config.zkapp_pk ~is_new ~pointer ~before - ~after ~withdrawal:transfer ) - in - let () = - match result with - | Ok forest -> - Transfers_memory.add t.transfers_memory key (Ok forest) - | Error e -> - printf "Warning: prove_transfer_claim failed %s\n%!" - (Exn.to_string e) ; - Transfers_memory.add t.transfers_memory key - (Error (Exn.to_string e)) - in - return () ) - - let wait_to_finish t = Throttle.capacity_available t.q - end - module Merger = struct - module Command_witness = struct - type t = - | Signed_command of - Sparse_ledger.t - * Signed_command.With_valid_signature.t Transaction_protocol_state.t - * Transaction_snark.Statement.With_sok.t - | Zkapp_command of - ( Transaction_witness.Zkapp_command_segment_witness.t - * Transaction_snark.Zkapp_command_segment.Basic.t - * Mina_state.Snarked_ledger_state.With_sok.t ) - list - * Zkapp_command.t - [@@deriving yojson] - end - - let wrap provers txn_snark = - Zeko_prover.Client.wrapper_wrap provers ~txn_snark - - let merge provers a b = Zeko_prover.Client.wrapper_merge provers a b - - let prove_signed_command provers ~sparse_ledger ~user_command_in_block - ~statement = - let%bind txn_snark = - Utils.print_time "Transaction_snark.of_signed_command" - (Zeko_prover.Client.transaction_snark_of_signed_command provers - ~statement ~user_command_in_block ~sparse_ledger ) - in - wrap provers txn_snark - - let prove_zkapp_command provers ~witnesses ~zkapp_command = - let%bind txn_snark = - match witnesses with - | [] -> - failwith "No witnesses" - | (witness, spec, statement) :: rest -> - let%bind p1 = - Utils.print_time "Transaction_snark.of_zkapp_command_segment" - (Zeko_prover.Client.transaction_snark_of_zkapp_command_segment - provers ~statement ~witness ~spec ) - in - Deferred.List.fold ~init:p1 rest - ~f:(fun acc (witness, spec, statement) -> - let%bind prev = return acc in - let%bind curr = - Utils.print_time "Transaction_snark.of_zkapp_command_segment" - (Zeko_prover.Client - .transaction_snark_of_zkapp_command_segment provers - ~statement ~witness ~spec ) - in - let%bind merged = - Utils.print_time "Transaction_snark.merge" - (Zeko_prover.Client.transaction_snark_merge provers curr - prev ) - in - return merged ) - in - wrap provers txn_snark - module Context = struct module State = struct type t = { mutable previous_committed_ledger : Sparse_ledger.t option ; mutable previous_committed_ledger_hash : Ledger_hash.t option - ; mutable commands : Command_witness.t list + ; mutable witnesses : Txn_snark_witness.t list } [@@deriving yojson] let create () = { previous_committed_ledger = None ; previous_committed_ledger_hash = None - ; commands = [] + ; witnesses = [] } end @@ -276,45 +104,40 @@ module Sequencer = struct State.create () let reset_state t ledger = - t.state.commands <- [] ; + t.state.witnesses <- [] ; t.state.previous_committed_ledger <- Some ledger ; t.state.previous_committed_ledger_hash <- Some (Sparse_ledger.merkle_root ledger) ; save_state t - let add_command t command = - t.state.commands <- t.state.commands @ [ command ] ; + let add_witness t w = + t.state.witnesses <- t.state.witnesses @ [ w ] ; save_state t end module Merge = struct - type t = Zkapps_rollup.t [@@deriving yojson] + type t = Txn_snark.serializable - let process ({ provers; _ } : Context.t) a b = merge provers a b + let process ({ provers; _ } : Context.t) ((left, left_proof) : t) + ((right, right_proof) : t) = + Zeko_prover.Client.transaction_snark provers + (Merge { left; left_proof; right; right_proof }) end module Base = struct - type t = Command_witness.t [@@deriving yojson] - - let process (ctx : Context.t) command_witness = - Context.add_command ctx command_witness ; - match command_witness with - | Command_witness.Signed_command - (sparse_ledger, user_command_in_block, statement) -> - prove_signed_command ctx.provers ~sparse_ledger - ~user_command_in_block ~statement - | Command_witness.Zkapp_command (witnesses, zkapp_command) -> - prove_zkapp_command ctx.provers ~witnesses ~zkapp_command + type t = Txn_snark_witness.t [@@deriving yojson] + + let process (ctx : Context.t) witness = + Context.add_witness ctx witness ; + match witness with + | Zkapp_command segment -> + Zeko_prover.Client.transaction_snark ctx.provers + (Zkapp_command segment) + | Signed_command w -> + Zeko_prover.Client.transaction_snark ctx.provers (Signed_command w) end module Commit = struct - (* Only for yojson serialization of Field *) - module Field = Data_hash.Make_full_size (struct - let description = "Field" - - let version_byte = '\x00' - end) - type t = { new_inner_ledger : Sparse_ledger.t ; old_deposits_pointer : Field.t @@ -326,7 +149,7 @@ module Sequencer = struct ({ da_client; provers; executor; config; kvdb; state } as ctx : Context.t ) { new_inner_ledger; old_deposits_pointer; processed_deposits_pointer } - last_snark = + txn_snark = let%bind signatures = Da_layer.Client.Sequencer.get_signatures da_client ~ledger_hash:(Sparse_ledger.merkle_root new_inner_ledger) @@ -344,7 +167,7 @@ module Sequencer = struct ; old_deposits_pointer ; processed_deposits_pointer ; signatures - ; last_snark + ; txn_snark } in Committer.Store.store_commit kvdb commit_witness @@ -363,12 +186,12 @@ module Sequencer = struct module P = Parallel_merger.Make (Context) (Merge) (Base) (Commit) let requeue_after_restart t (ctx : Context.t) = - let commands_to_requeue = ctx.state.commands in + let witnesses_to_requeue = ctx.state.witnesses in (* Adding jobs will repopulate the list *) - ctx.state.commands <- [] ; - printf "Requeueing %d commands\n%!" (List.length commands_to_requeue) ; - List.iter commands_to_requeue ~f:(fun command -> - don't_wait_for @@ P.add_job t ctx ~data:command ) + ctx.state.witnesses <- [] ; + printf "Requeueing %d proofs\n%!" (List.length witnesses_to_requeue) ; + List.iter witnesses_to_requeue ~f:(fun witness -> + don't_wait_for @@ P.add_job t ctx ~data:witness ) end module State_hashes = struct @@ -379,39 +202,20 @@ module Sequencer = struct } end - module Subscriptions = struct - type t = - { mutable state_hashes_changed : State_hashes.t Pipe.Writer.t list } - - let create () = { state_hashes_changed = [] } - - let add_state_hashes_subscriber t = - let r, w = Pipe.create () in - t.state_hashes_changed <- w :: t.state_hashes_changed ; - (r, w) - end - type t = { db : L.Db.t + ; imt : Indexed_merkle_tree.Db.t ; logger : Logger.t ; archive : Archive.t ; config : Config.t ; snark_q : Snark_queue.t ; merger : Merger.P.t ; merger_ctx : Merger.Context.t - ; stop : unit Ivar.t ; da_client : Da_layer.Client.Sequencer.t ; apply_q : unit Sequencer.t (* Applying of the user command is async operation, but we need to keep the application synchronous *) - ; mutable subscriptions : Subscriptions.t - ; mutable analytics_state : Analytics.State.t } - let close t = - L.Db.close t.db ; - Ivar.fill_if_empty t.stop () ; - Throttle.kill t.snark_q.q - let add_account t account_id account = ( L.Db.get_or_create_account t.db account_id account |> Or_error.ok_exn : [ `Added | `Existed ] * L.Db.Location.t ) @@ -441,87 +245,6 @@ module Sequencer = struct ; committed_ledger_hash = Field.zero } - let trigger_state_hashes_changed t = - let state_hashes = get_latest_state t in - List.iter t.subscriptions.state_hashes_changed ~f:(fun w -> - Pipe.write_without_pushback_if_open w state_hashes ) - - (** Apply user command to the ledger without checking the validity of the command *) - let apply_user_command_without_check l archive command ~global_slot - ~state_body ~analytics_state = - let accounts_referenced = User_command.accounts_referenced command in - - let first_pass_ledger = - Sparse_ledger.of_ledger_subset_exn l accounts_referenced - in - let%bind.Result partialy_applied_txn = - L.apply_transaction_first_pass ~constraint_constants ~global_slot - ~txn_state_view:(Mina_state.Protocol_state.Body.view state_body) - l (Command command) - in - - let second_pass_ledger = - Sparse_ledger.of_ledger_subset_exn l accounts_referenced - in - let%map.Result txn_applied = - let%bind.Result txn_applied = - L.apply_transaction_second_pass l partialy_applied_txn - in - match - Mina_transaction_logic.Transaction_applied.transaction_status - txn_applied - with - | Failed failure -> - Error - ( Error.of_string @@ Yojson.Safe.to_string - @@ Transaction_status.Failure.Collection.to_yojson failure ) - | Applied -> - Ok txn_applied - in - - let target_ledger_hash = L.merkle_root l in - - L.Mask.Attached.commit l ; - - (* Add events and actions to the memory *) - let () = - match command with - | Signed_command _ -> - () - | Zkapp_command zkapp_command -> - Zkapp_command.( - Call_forest.iteri (account_updates zkapp_command) - ~f:(fun _ update -> - let account = - let account_id = - Account_id.create - (Account_update.public_key update) - (Account_update.token_id update) - in - let location = - L.location_of_account l account_id |> Option.value_exn - in - L.get l location |> Option.value_exn - in - Archive.add_account_update archive update account - (Some - Archive.Transaction_info. - { status = Applied - ; hash = - Mina_transaction.Transaction_hash.hash_command - (Zkapp_command zkapp_command) - ; memo = Zkapp_command.memo zkapp_command - ; authorization_kind = - Account_update.Body.authorization_kind - @@ Account_update.body update - } ) )) - in - ( first_pass_ledger - , second_pass_ledger - , txn_applied - , target_ledger_hash - , Analytics.State.update_with_command analytics_state command l ) - (** Apply user command to the sequencer's state, including the check of command validity *) let apply_user_command t ?(skip_validity_check = false) (command : User_command.t) = @@ -541,9 +264,6 @@ module Sequencer = struct (* the protocol state from sequencer has dummy values which wouldn't pass the txn snark *) let global_slot = Mina_numbers.Global_slot_since_genesis.zero in - let state_body = - Mina_state.Protocol_state.body compile_time_genesis_state - in let l = L.of_database t.db in let%bind.Deferred.Result () = @@ -571,16 +291,16 @@ module Sequencer = struct return (Error e) in - let%bind.Deferred.Result ( first_pass_ledger - , second_pass_ledger - , txn_applied - , target_ledger_hash - , new_analytics_state ) = + let%bind.Deferred.Result source_ledger, witnesses = + let sequencer_pk = + Even_PC.create_exn + @@ Public_key.compress t.config.signer.public_key + in return - (apply_user_command_without_check l t.archive command ~global_slot - ~state_body ~analytics_state:t.analytics_state ) + (Zeko_transaction_logic.apply_user_command_unchecked ~sequencer_pk + ~zeko_env:Zeko_transaction_logic.zeko_dummy_env + ~constraint_constants ~global_slot l t.imt t.archive command ) in - t.analytics_state <- new_analytics_state ; (* Post transaction to the DA layer *) let changed_accounts = @@ -588,7 +308,7 @@ module Sequencer = struct User_command.accounts_referenced command |> List.map ~f:(fun id -> if Public_key.Compressed.(Account_id.public_key id = empty) - then Zkapps_rollup.inner_account_id + then Zeko_constants.inner_account_id else id ) |> List.stable_dedup in @@ -598,7 +318,7 @@ module Sequencer = struct in let diff = Da_layer.Diff.create - ~source_ledger_hash:(Sparse_ledger.merkle_root first_pass_ledger) + ~source_ledger_hash:(Sparse_ledger.merkle_root source_ledger) ~changed_accounts ~command_with_action_step_flags: (Some @@ -611,105 +331,45 @@ module Sequencer = struct |> List.map ~f:(fun _ -> true) ) ) in Da_layer.Client.Sequencer.enqueue_distribute_diff t.da_client - ~ledger_openings:first_pass_ledger ~diff ~target_ledger_hash ; - - trigger_state_hashes_changed t ; - - let pc : Transaction_snark.Pending_coinbase_stack_state.t = - (* No coinbase to add to the stack. *) - let stack_with_state global_slot = - Pending_coinbase.Stack.push_state - (Mina_state.Protocol_state.Body.hash state_body) - global_slot Pending_coinbase.Stack.empty - in - { source = stack_with_state global_slot - ; target = stack_with_state global_slot - } - in + ~ledger_openings:source_ledger ~diff + ~target_ledger_hash:(Ledger.Db.merkle_root t.db) ; - return - @@ - match command with - | Signed_command signed_command -> - let user_command_in_block = - { Transaction_protocol_state.Poly.transaction = - Signed_command.check_only_for_signature signed_command - |> Option.value_exn - ; block_data = state_body - ; global_slot - } - in - let source_ledger_hash = - Sparse_ledger.merkle_root first_pass_ledger - in - let (statement : Transaction_snark.Statement.With_sok.t) = - Transaction_snark.Statement.Poly.with_empty_local_state - ~source_first_pass_ledger:source_ledger_hash - ~target_first_pass_ledger:target_ledger_hash - ~source_second_pass_ledger:target_ledger_hash - ~target_second_pass_ledger:target_ledger_hash - ~connecting_ledger_left:target_ledger_hash - ~connecting_ledger_right:target_ledger_hash ~sok_digest - ~fee_excess: - ( Mina_transaction.Transaction.fee_excess (Command command) - |> Or_error.ok_exn ) - ~supply_increase: - ( Mina_transaction_logic.Transaction_applied.supply_increase - ~constraint_constants txn_applied - |> Or_error.ok_exn ) - ~pending_coinbase_stack_state:pc - in - Result.return - ( txn_applied - , Merger.Command_witness.Signed_command - (first_pass_ledger, user_command_in_block, statement) ) - | Zkapp_command zkapp_command -> - let witnesses = - Transaction_snark.zkapp_command_witnesses_exn - ~constraint_constants ~global_slot ~state_body - ~fee_excess: - ( Currency.Amount.Signed.of_unsigned - @@ Currency.Amount.of_fee (Zkapp_command.fee zkapp_command) - ) - [ ( `Pending_coinbase_init_stack Pending_coinbase.Stack.empty - , `Pending_coinbase_of_statement pc - , `Sparse_ledger first_pass_ledger - , `Sparse_ledger second_pass_ledger - , `Connecting_ledger_hash - (Sparse_ledger.merkle_root second_pass_ledger) - , zkapp_command ) - ] - in - Result.return - ( txn_applied - , Merger.Command_witness.Zkapp_command (witnesses, zkapp_command) - ) ) + return (Ok witnesses) ) let update_inner_account t = - let old_deposits_state = - Utils.get_inner_deposits_state_exn (L.of_database t.db) + let old_deposits_state, old_deposits_length = + let s = Utils.get_inner_deposits_state_exn (L.of_database t.db) in + C.Rollup_state.Outer_action_state.With_length.(raw s, length s) in - let%bind new_deposits = - Gql_client.fetch_transfers t.config.archive_uri + let%bind all_new_actions = + Gql_client.fetch_actions t.config.archive_uri ~from_action_state:old_deposits_state t.config.zkapp_pk in let%bind current_height = Gql_client.fetch_block_height t.config.l1_uri in (* Find pointer for deposits to be processed *) - let processed_pointer = - List.fold new_deposits ~init:old_deposits_state - ~f:(fun curr_state (transfer, block_height) -> + let processed_pointer, processed_new_actions = + List.fold all_new_actions ~init:(old_deposits_state, []) + ~f:(fun (curr_state, curr_actions) (action, block_height) -> if block_height + t.config.deposit_delay_blocks <= current_height then - Zkapp_account.Actions.push_events curr_state - (Zkapps_rollup.TR.to_actions transfer) - else curr_state ) + ( Zkapp_account.Actions.push_events curr_state action + , action :: curr_actions ) + else (curr_state, curr_actions) ) in if Field.equal old_deposits_state processed_pointer then (* In case no new deposits are to process, we don't need to update inner account *) return (old_deposits_state, old_deposits_state) else let%bind inner_account_update = - Zeko_prover.Client.inner_step t.snark_q.provers - ~all_deposits:processed_pointer + Zeko_prover.Client.inner_sync t.snark_q.provers + ~public_key:Zeko_constants.inner_public_key + ~ase_elms: + (List.map processed_new_actions ~f:Account_update.Actions.hash) + ~ase_source: + ( C.Rollup_state.Outer_action_state.With_length. + { action_state = old_deposits_state + ; length = old_deposits_length + } + : C.Ase.With_length.Stmt.t ) in let fee = Currency.Fee.of_mina_int_exn 0 in let command : Zkapp_command.t = @@ -729,29 +389,20 @@ module Sequencer = struct ; memo = Signed_command_memo.empty } in - let%bind command_witness = + let%bind witnesses = match%bind (* Skip validity check because dummy fee payer triggers invalid public key error *) apply_user_command t ~skip_validity_check:true (Zkapp_command command) with - | Ok (status, witness) -> ( - match - Mina_transaction_logic.Transaction_applied.transaction_status - status - with - | Applied -> - return witness - | Failed failure -> - failwithf - !"Failed to apply inner account update \ - %{sexp:Transaction_status.Failure.Collection.t}" - failure () ) + | Ok witness -> + return witness | Error e -> Error.raise e in let () = - don't_wait_for - @@ Merger.P.add_job t.merger t.merger_ctx ~data:command_witness + List.iter witnesses ~f:(fun witness -> + don't_wait_for + @@ Merger.P.add_job t.merger t.merger_ctx ~data:witness ) in return (old_deposits_state, processed_pointer) @@ -760,7 +411,7 @@ module Sequencer = struct let target_ledger = Sparse_ledger.of_ledger_subset_exn L.(of_database t.db) - [ Zkapps_rollup.inner_account_id ] + [ Zeko_constants.inner_account_id ] in if Merger.P.current_tree t.merger @@ -780,7 +431,7 @@ module Sequencer = struct if Float.(t.config.commitment_period_sec <= 0.) then () else let period = Time_ns.Span.of_sec t.config.commitment_period_sec in - every ~start:(after period) ~stop:(Ivar.read t.stop) period (fun () -> + every ~start:(after period) period (fun () -> don't_wait_for @@ Deferred.ignore_m @@ commit t ) let bootstrap ~logger ({ config; _ } as t) da_config = @@ -799,6 +450,9 @@ module Sequencer = struct ~source_ledger_hash:`Genesis ~target_ledger_hash:committed_ledger_hash |> Deferred.map ~f:Or_error.ok_exn in + let sequencer_pk = + Even_PC.create_exn @@ Public_key.compress t.config.signer.public_key + in let%bind () = Deferred.List.iter ~how:`Sequential diffs ~f:(fun diff -> assert ( @@ -818,21 +472,26 @@ module Sequencer = struct List.iter changed_accounts ~f:(fun (index, account) -> L.set_at_index_exn mask index account ) ; L.Mask.Attached.commit mask ; + (* Add to Indexed Merkle Tree *) + List.iter changed_accounts ~f:(fun (_, account) -> + let aid = Account.identifier account in + let _w = + Indexed_merkle_tree.Db.get_or_create_entry_exn t.imt + (Account_id.derive_token_id ~owner:aid) + in + () ) ; return () | Some (command, _) -> (* Apply command *) let mask = L.of_database t.db in let global_slot = Mina_numbers.Global_slot_since_genesis.zero in - let state_body = - Mina_state.Protocol_state.body compile_time_genesis_state - in - let _, _, _, _, analytics_state = - apply_user_command_without_check mask t.archive command - ~global_slot ~state_body ~analytics_state:t.analytics_state + let _, _ = + Zeko_transaction_logic.apply_user_command_unchecked + ~sequencer_pk ~zeko_env:Zeko_transaction_logic.zeko_dummy_env + ~constraint_constants ~global_slot mask t.imt t.archive + command |> Or_error.ok_exn in - t.analytics_state <- analytics_state ; - L.Mask.Attached.commit mask ; return () ) in @@ -845,23 +504,28 @@ module Sequencer = struct let sparse_ledger = Sparse_ledger.of_ledger_subset_exn L.(of_database t.db) - [ Zkapps_rollup.inner_account_id ] + [ Zeko_constants.inner_account_id ] in Merger.Context.reset_state t.merger_ctx sparse_ledger ; return () let create ~logger ~zkapp_pk ~max_pool_size ~commitment_period_sec ~da_config - ~da_quorum ~db_dir ~l1_uri ~archive_uri ~signer ~network_id + ~da_quorum ~db_dir ~imt_dir ~l1_uri ~archive_uri ~signer ~network_id ~deposit_delay_blocks ~provers = let db = L.Db.create ?directory_name:db_dir ~depth:constraint_constants.ledger_depth () in + let imt = + Indexed_merkle_tree.Db.create ?directory_name:imt_dir + ~depth:constraint_constants.ledger_depth () + in let config = Config. { max_pool_size ; commitment_period_sec ; db_dir + ; imt_dir ; l1_uri ; archive_uri ; zkapp_pk @@ -882,6 +546,7 @@ module Sequencer = struct let executor = Executor.create ~l1_uri:config.l1_uri ~signer ~kvdb () in let t = { db + ; imt ; logger ; archive = Archive.create ~kvdb:(L.Db.zeko_kvdb db) ; config @@ -896,10 +561,7 @@ module Sequencer = struct ; kvdb ; state = Merger.Context.load_state kvdb } - ; stop = Ivar.create () ; apply_q = Sequencer.create () - ; subscriptions = Subscriptions.create () - ; analytics_state = Analytics.State.empty } in let%bind () = @@ -924,680 +586,3 @@ module Sequencer = struct in return t end - -let%test_module "Sequencer tests" = - ( module struct - let start_time = Time.now () - - let () = Base.Backtrace.elide := false - - let logger = Logger.create () - - module T = Transaction_snark.Make (struct - let constraint_constants = constraint_constants - - let proof_level = Genesis_constants.Proof_level.Full - end) - - module M = Zkapps_rollup.Make (T) - open Sequencer - - let number_of_transactions = 5 - - let gql_uri = - { Cli_lib.Flag.Types.value = Uri.of_string "http://localhost:8080/graphql" - ; name = "gql-uri" - } - - let da_config = Da_layer.Client.Config.of_string_list [ "127.0.0.1:8555" ] - - let provers = - [ Host_and_port.create ~host:"localhost" ~port:9990 - ; Host_and_port.create ~host:"localhost" ~port:9991 - ] - - module Sequencer_test_spec = struct - type t = - { zkapp_keypair : Keypair.t - ; signer : Keypair.t - ; ephemeral_ledger : L.t (* The ledger to test the expected outcome *) - ; specs : Mina_transaction_logic.For_tests.Transaction_spec.t list - (* Transaction specs *) - ; sequencer : Sequencer.t - } - - let gen ?(delay_deposit = 0) () = - let zkapp_keypair = Keypair.create () in - - (* Create signer *) - let signer = Keypair.create () in - Thread_safe.block_on_async_exn (fun () -> - let%bind _res = - Gql_client.For_tests.create_account gql_uri - (Public_key.compress signer.public_key) - in - return () ) ; - - let%bind.Quickcheck.Generator { init_ledger; specs } = - Mina_transaction_logic.For_tests.Test_spec.mk_gen - ~num_transactions:number_of_transactions () - in - - let genesis_accounts = - (M.Inner.account_id, M.Inner.initial_account) - :: ( Array.map init_ledger ~f:(fun (keypair, balance) -> - let pk = - Signature_lib.Public_key.compress keypair.public_key - in - let account_id = Account_id.create pk Token_id.default in - let balance = Unsigned.UInt64.of_int64 balance in - let account = - Account.create account_id - (Currency.Balance.of_uint64 balance) - in - (account_id, account) ) - |> Array.to_list ) - in - - (* Init ephemeral ledger *) - let ephemeral_ledger = - L.create_ephemeral ~depth:constraint_constants.ledger_depth () - in - List.iter genesis_accounts ~f:(fun (aid, acc) -> - L.create_new_account_exn ephemeral_ledger aid acc ) ; - - (* Post genesis batch *) - Thread_safe.block_on_async_exn (fun () -> - match%bind - Da_layer.Client.distribute_genesis_diff ~logger ~config:da_config - ~ledger:ephemeral_ledger - with - | Ok _ -> - return () - | Error e -> - Error.raise e ) ; - - (* Deploy *) - Thread_safe.block_on_async_exn (fun () -> - ( print_endline - @@ Public_key.( - Compressed.to_base58_check @@ compress zkapp_keypair.public_key) - ) ; - let%bind nonce = - Gql_client.infer_nonce gql_uri - (Public_key.compress signer.public_key) - in - let command = - Deploy.deploy_command_exn ~signer ~zkapp:zkapp_keypair - ~fee:(Currency.Fee.of_mina_int_exn 1) - ~nonce ~initial_ledger:ephemeral_ledger ~constraint_constants - (module M) - in - let%bind _ = Gql_client.send_zkapp gql_uri command in - let%bind _created = Gql_client.For_tests.create_new_block gql_uri in - return () ) ; - - (* Init sequencer *) - let sequencer = - Thread_safe.block_on_async_exn (fun () -> - Sequencer.create ~logger - ~zkapp_pk: - Signature_lib.Public_key.(compress zkapp_keypair.public_key) - ~max_pool_size:10 ~commitment_period_sec:0. ~da_config - ~da_quorum:1 ~db_dir:None ~l1_uri:gql_uri ~archive_uri:gql_uri - ~signer ~network_id:"testnet" - ~deposit_delay_blocks:delay_deposit ~provers ) - in - - Quickcheck.Generator.return - { zkapp_keypair; signer; ephemeral_ledger; specs; sequencer } - end - - let sign_cmd (cmd : Zkapp_command.t) (keys : Keypair.t list) : - Zkapp_command.t = - let full_commitment = - Zkapp_command.Transaction_commitment.create_complete - (Zkapp_command.commitment cmd) - ~memo_hash:(Signed_command_memo.hash cmd.memo) - ~fee_payer_hash: - (Zkapp_command.Digest.Account_update.create - (Account_update.of_fee_payer cmd.fee_payer) ) - in - let sign_raw (pk : Public_key.Compressed.t) msg = - printf "Signing for %s\n" (Public_key.Compressed.to_base58_check pk) ; - let rec go (keys : Keypair.t list) msg = - match keys with - | (kp : Keypair.t) :: keys -> - if - Public_key.Compressed.equal - (Public_key.compress kp.public_key) - pk - then ( - printf "key found\n" ; - Signature_lib.Schnorr.Chunked.sign - ~signature_kind:Mina_signature_kind.Testnet kp.private_key - (Random_oracle.Input.Chunked.field msg) ) - else ( - printf "not equal to %s\n" - Public_key.( - kp.public_key |> compress |> Compressed.to_base58_check) ; - go keys msg ) - | [] -> - failwithf "key not found: %s\n" - (Public_key.Compressed.to_base58_check pk) - () - in - go keys msg - in - let rec sign_tree (tree : Zeko_util.call_forest_tree) : - Zeko_util.call_forest_tree = - { tree with - account_update = - { tree.account_update with - authorization = - ( match tree.account_update.body.authorization_kind with - | Signature -> - assert tree.account_update.body.use_full_commitment ; - Signature - (sign_raw tree.account_update.body.public_key - full_commitment ) - | _ -> - tree.account_update.authorization ) - } - ; calls = sign_forest tree.calls - } - and sign_forest (forest : Zeko_util.call_forest) : Zeko_util.call_forest = - List.map ~f:(fun tree -> { tree with elt = sign_tree tree.elt }) forest - in - { cmd with - fee_payer = - { cmd.fee_payer with - authorization = - ( if - Public_key.Compressed.( - equal empty cmd.fee_payer.body.public_key) - then cmd.fee_payer.authorization - else sign_raw cmd.fee_payer.body.public_key full_commitment ) - } - ; account_updates = sign_forest cmd.account_updates - } - - let%test_unit "apply commands and commit" = - print_endline "Started test 'apply commands and commit'" ; - Quickcheck.test ~trials:1 (Sequencer_test_spec.gen ()) - ~f:(fun { zkapp_keypair; signer; ephemeral_ledger; specs; sequencer } -> - let batch1, batch2 = List.split_n specs 3 in - - (* Apply first batch *) - let () = - Thread_safe.block_on_async_exn (fun () -> - let source_ledger_hash = get_root sequencer in - - [%test_eq: Ledger_hash.t] source_ledger_hash - (L.merkle_root ephemeral_ledger) ; - - let%bind () = - Deferred.List.iteri batch1 ~f:(fun i spec -> - [%test_eq: Ledger_hash.t] (get_root sequencer) - (L.merkle_root ephemeral_ledger) ; - let%map result = - match i % 2 = 0 with - | true -> - let command = - Mina_transaction_logic.For_tests - .account_update_send spec - in - ( match - L.apply_zkapp_command_unchecked ephemeral_ledger - command ~constraint_constants - ~global_slot: - Mina_numbers.Global_slot_since_genesis.zero - ~state_view: - Mina_state.Protocol_state.( - Body.view - @@ body compile_time_genesis_state) - with - | Ok (applied, _) -> - [%test_eq: Transaction_status.t] - applied.command.status Applied - | Error e -> - Error.raise - (Error.create "Expected ledger apply failed" e - Error.sexp_of_t ) ) ; - - apply_user_command sequencer (Zkapp_command command) - | false -> - let command = - Mina_transaction_logic.For_tests.command_send spec - in - ( match - L.apply_user_command_unchecked ephemeral_ledger - command ~constraint_constants - ~txn_global_slot: - Mina_numbers.Global_slot_since_genesis.zero - with - | Ok applied -> - [%test_eq: Transaction_status.t] - applied.common.user_command.status Applied - | Error e -> - Error.raise - (Error.create "Expected ledger apply failed" e - Error.sexp_of_t ) ) ; - - apply_user_command sequencer (Signed_command command) - in - - let txn_applied, command_witness = - match result with - | Ok result -> - result - | Error e -> - Error.raise e - in - don't_wait_for - @@ Merger.P.add_job sequencer.merger sequencer.merger_ctx - ~data:command_witness ; - - let status = - Mina_transaction_logic.Transaction_applied - .transaction_status txn_applied - in - [%test_eq: Transaction_status.t] status Applied ) - in - - let target_ledger_hash = get_root sequencer in - - [%test_eq: Ledger_hash.t] target_ledger_hash - (L.merkle_root ephemeral_ledger) ; - - return () ) - in - - (* First commit *) - Thread_safe.block_on_async_exn (fun () -> - let%bind _ = commit sequencer in - let%bind () = Snark_queue.wait_to_finish sequencer.snark_q in - let%bind () = - Executor.wait_to_finish sequencer.merger_ctx.executor - in - let%bind committed_ledger_hash = - Gql_client.infer_committed_state gql_uri - ~signer_pk:(Public_key.compress signer.public_key) - ~zkapp_pk:(Public_key.compress zkapp_keypair.public_key) - in - let target_ledger_hash = get_root sequencer in - [%test_eq: Ledger_hash.t] committed_ledger_hash target_ledger_hash ; - - Deferred.unit ) ; - - (* To test nonce inferring from pool *) - (* The first commit is still in the pool *) - Executor.refresh_nonce sequencer.merger_ctx.executor ; - - (* Apply second batch *) - Thread_safe.block_on_async_exn (fun () -> - let source_ledger_hash = get_root sequencer in - - [%test_eq: Ledger_hash.t] source_ledger_hash - (L.merkle_root ephemeral_ledger) ; - - let%bind () = - Deferred.List.iteri batch2 ~f:(fun i spec -> - let%map result = - match i % 2 = 0 with - | true -> - let command = - Mina_transaction_logic.For_tests.account_update_send - spec - in - ( match - L.apply_zkapp_command_unchecked ephemeral_ledger - command ~constraint_constants - ~global_slot: - Mina_numbers.Global_slot_since_genesis.zero - ~state_view: - Mina_state.Protocol_state.( - Body.view @@ body compile_time_genesis_state) - with - | Ok _ -> - () - | Error e -> - Error.raise - (Error.create "Expected ledger apply failed" e - Error.sexp_of_t ) ) ; - - apply_user_command sequencer (Zkapp_command command) - | false -> - let command = - Mina_transaction_logic.For_tests.command_send spec - in - ( match - L.apply_user_command_unchecked ephemeral_ledger - command ~constraint_constants - ~txn_global_slot: - Mina_numbers.Global_slot_since_genesis.zero - with - | Ok _ -> - () - | Error e -> - Error.raise - (Error.create "Expected ledger apply failed" e - Error.sexp_of_t ) ) ; - - apply_user_command sequencer (Signed_command command) - in - - let txn_applied, command_witness = - match result with - | Ok result -> - result - | Error e -> - Error.raise e - in - don't_wait_for - @@ Merger.P.add_job sequencer.merger sequencer.merger_ctx - ~data:command_witness ; - - let status = - Mina_transaction_logic.Transaction_applied - .transaction_status txn_applied - in - [%test_eq: Transaction_status.t] status Applied ) - in - - let target_ledger_hash = get_root sequencer in - - [%test_eq: Ledger_hash.t] target_ledger_hash - (L.merkle_root ephemeral_ledger) ; - - return () ) ; - - (* Second commit *) - let final_ledger_hash = - Thread_safe.block_on_async_exn (fun () -> - let%bind _ = commit sequencer in - let%bind () = Snark_queue.wait_to_finish sequencer.snark_q in - let%bind () = - Executor.wait_to_finish sequencer.merger_ctx.executor - in - let%bind _created = - Gql_client.For_tests.create_new_block gql_uri - in - let%bind committed_ledger_hash = - Gql_client.fetch_committed_state gql_uri - Signature_lib.Public_key.(compress zkapp_keypair.public_key) - in - let target_ledger_hash = get_root sequencer in - [%test_eq: Ledger_hash.t] committed_ledger_hash - target_ledger_hash ; - - return target_ledger_hash ) - in - - (* Try to bootstrap again *) - Thread_safe.block_on_async_exn (fun () -> - let%bind new_sequencer = - Sequencer.create ~logger - ~zkapp_pk: - Signature_lib.Public_key.(compress zkapp_keypair.public_key) - ~max_pool_size:10 ~commitment_period_sec:0. ~da_config - ~da_quorum:1 ~db_dir:None ~l1_uri:gql_uri ~archive_uri:gql_uri - ~signer ~network_id:"testnet" ~deposit_delay_blocks:0 ~provers - in - return - @@ [%test_eq: Frozen_ledger_hash.t] (get_root new_sequencer) - final_ledger_hash ) ) - - let%test_unit "dummy signature should fail" = - print_endline "Started test 'dummy signature should fail'" ; - Quickcheck.test ~trials:1 (Sequencer_test_spec.gen ()) - ~f:(fun { zkapp_keypair; signer; ephemeral_ledger; specs; sequencer } -> - let dummy_signature_command : Zkapp_command.t = - let command = - Mina_transaction_logic.For_tests.account_update_send - (List.hd_exn specs) - in - { command with - account_updates = - Zkapp_command.Call_forest.map command.account_updates - ~f:(fun account_update -> - match Account_update.authorization account_update with - | Signature _ -> - { account_update with - authorization = Signature Signature.dummy - } - | _ -> - account_update ) - } - in - let result = - Thread_safe.block_on_async_exn (fun () -> - apply_user_command sequencer - (Zkapp_command dummy_signature_command) ) - in - match result with - | Error e - when String.is_substring ~substring:"Invalid_signature" - (Error.to_string_hum e) -> - () - | Ok _ -> - failwith "Transaction should have failed" - | Error unexpected_error -> - Error.raise unexpected_error ) - - let%test_unit "deposits" = - print_endline "Started test 'deposits'" ; - Quickcheck.test ~trials:1 (Sequencer_test_spec.gen ~delay_deposit:2 ()) - ~f:(fun { zkapp_keypair; signer; ephemeral_ledger; specs; sequencer } -> - (* Create l1 accounts *) - let l1_accounts = - Array.create ~len:5 () - |> Array.map ~f:Signature_lib.Keypair.create - |> Array.to_list - in - Thread_safe.block_on_async_exn (fun () -> - Deferred.List.iter l1_accounts ~f:(fun keypair -> - let%bind _res = - Gql_client.For_tests.create_account gql_uri - (Signature_lib.Public_key.compress keypair.public_key) - in - return () ) ) ; - - (* Send deposits *) - let deposits = - Thread_safe.block_on_async_exn (fun () -> - let submit_deposit ~fee (signer : Keypair.t) deposit = - let%bind nonce = - Gql_client.fetch_nonce gql_uri - (Signature_lib.Public_key.compress signer.public_key) - in - let fee_payer = - Account_update.Fee_payer. - { body = - { public_key = Public_key.compress signer.public_key - ; fee = Currency.Fee.of_mina_int_exn fee - ; valid_until = None - ; nonce = Account.Nonce.of_uint32 nonce - } - ; authorization = Signature.dummy - } - in - let%bind transfer_update = - M.Outer.submit_deposit - ~outer_public_key: - (Public_key.compress zkapp_keypair.public_key) - ~deposit - in - let transferrer_update : Account_update.t = - { body = - { Account_update.Body.dummy with - public_key = Public_key.compress signer.public_key - ; balance_change = - Currency.Amount.Signed.( - negate @@ of_unsigned deposit.amount) - ; use_full_commitment = true - ; authorization_kind = Signature - } - ; authorization = Signature Signature.dummy - } - in - let transfer_cmd : Zkapp_command.t = - { fee_payer - ; account_updates = - Zkapp_command.Call_forest.( - cons_tree transfer_update @@ accumulate_hashes' - @@ of_account_updates - ~account_update_depth:(fun _ -> 0) - [ transferrer_update ]) - ; memo = Signed_command_memo.empty - } - in - return @@ sign_cmd transfer_cmd [ signer ] - in - let account1 = List.nth_exn l1_accounts 0 in - let account2 = List.nth_exn l1_accounts 1 in - let account3 = List.nth_exn l1_accounts 2 in - let account4 = List.nth_exn l1_accounts 3 in - let account5 = List.nth_exn l1_accounts 4 in - - let deposit1 : Zkapps_rollup.TR.t = - { recipient = Public_key.compress account1.public_key - ; amount = Currency.Amount.of_mina_int_exn 10 - } - in - let deposit2 : Zkapps_rollup.TR.t = - { recipient = Public_key.compress account2.public_key - ; amount = Currency.Amount.of_mina_int_exn 20 - } - in - let deposit3 : Zkapps_rollup.TR.t = - { recipient = Public_key.compress account3.public_key - ; amount = Currency.Amount.of_mina_int_exn 30 - } - in - let deposit4 : Zkapps_rollup.TR.t = - { recipient = Public_key.compress account4.public_key - ; amount = Currency.Amount.of_mina_int_exn 40 - } - in - let deposit5 : Zkapps_rollup.TR.t = - { recipient = Public_key.compress account5.public_key - ; amount = Currency.Amount.of_mina_int_exn 50 - } - in - - (* Send deposits for accounts 1 and 2 *) - let%bind _ = - submit_deposit ~fee:5 account1 deposit1 - >>= Gql_client.send_zkapp gql_uri - in - let%bind _ = - submit_deposit ~fee:4 account2 deposit2 - >>= Gql_client.send_zkapp gql_uri - in - - (* Create 2 new blocks for delay *) - let%bind _created = - Gql_client.For_tests.create_new_block gql_uri - in - let%bind _created = - Gql_client.For_tests.create_new_block gql_uri - in - - (* Send deposits for accounts 3, 4 and 5 which won't be processed *) - let%bind _ = - submit_deposit ~fee:3 account3 deposit3 - >>= Gql_client.send_zkapp gql_uri - in - let%bind _ = - submit_deposit ~fee:2 account4 deposit4 - >>= Gql_client.send_zkapp gql_uri - in - let%bind _ = - submit_deposit ~fee:1 account5 deposit5 - >>= Gql_client.send_zkapp gql_uri - in - let%bind _created = - Gql_client.For_tests.create_new_block gql_uri - in - return [ deposit1; deposit2; deposit3; deposit4; deposit5 ] ) - in - - (* Commit should process first 2 deposits *) - Thread_safe.block_on_async_exn (fun () -> - let%bind _ = commit sequencer in - let%bind () = Snark_queue.wait_to_finish sequencer.snark_q in - let%bind () = - Executor.wait_to_finish sequencer.merger_ctx.executor - in - let%bind _created = - Gql_client.For_tests.create_new_block gql_uri - in - let%bind committed_ledger_hash = - Gql_client.fetch_committed_state gql_uri - Signature_lib.Public_key.(compress zkapp_keypair.public_key) - in - let target_ledger_hash = get_root sequencer in - [%test_eq: Ledger_hash.t] committed_ledger_hash target_ledger_hash ; - - return () ) ; - - let deposits_state = - Utils.get_inner_deposits_state_exn (L.of_database sequencer.db) - in - let expected_deposits_state = - (* Expected should be only first 2 deposits *) - List.take deposits 2 - |> List.fold ~init:Zkapp_account.Actions.empty_state_element - ~f:(fun acc transfer -> - Zkapp_account.Actions.push_events acc - (Zkapps_rollup.TR.to_actions transfer) ) - in - [%test_eq: Field.t] deposits_state expected_deposits_state ; - - print_endline "Processing remaining deposits" ; - - (* Create new blocks to process remaining deposits *) - Thread_safe.block_on_async_exn (fun () -> - let%bind _created = - Gql_client.For_tests.create_new_block gql_uri - in - let%bind _created = - Gql_client.For_tests.create_new_block gql_uri - in - return () ) ; - - (* Commit should process remaining deposits *) - Thread_safe.block_on_async_exn (fun () -> - let%bind _ = commit sequencer in - let%bind () = Snark_queue.wait_to_finish sequencer.snark_q in - let%bind () = - Executor.wait_to_finish sequencer.merger_ctx.executor - in - let%bind _created = - Gql_client.For_tests.create_new_block gql_uri - in - let%bind committed_ledger_hash = - Gql_client.fetch_committed_state gql_uri - Signature_lib.Public_key.(compress zkapp_keypair.public_key) - in - let target_ledger_hash = get_root sequencer in - [%test_eq: Ledger_hash.t] committed_ledger_hash target_ledger_hash ; - - return () ) ; - - let deposits_state = - Utils.get_inner_deposits_state_exn (L.of_database sequencer.db) - in - let expected_deposits_state = - List.fold deposits ~init:Zkapp_account.Actions.empty_state_element - ~f:(fun acc transfer -> - Zkapp_account.Actions.push_events acc - (Zkapps_rollup.TR.to_actions transfer) ) - in - [%test_eq: Field.t] deposits_state expected_deposits_state ) - - let () = - printf "Sequencer tests took %s\n" - (Time.Span.to_string (Time.diff (Time.now ()) start_time)) - end ) diff --git a/src/app/zeko/sequencer/lib/zeko_transaction_logic.ml b/src/app/zeko/sequencer/lib/zeko_transaction_logic.ml new file mode 100644 index 0000000000..559e12446f --- /dev/null +++ b/src/app/zeko/sequencer/lib/zeko_transaction_logic.ml @@ -0,0 +1,472 @@ +open Core_kernel +open Mina_base +open Mina_ledger +open Mina_transaction_logic +open Zeko_prover.Zeko_types +module Field = Snark_params.Tick.Field + +module Inputs = struct + open struct + module Zeko_local_state = Local_state + end + + include Ledger.Inputs + + module Global_state = struct + type t = { fee_excess : Amount.Signed.t; supply_increase : Amount.Signed.t } + + let fee_excess { fee_excess; _ } = fee_excess + + let set_fee_excess t fee_excess = { t with fee_excess } + + let supply_increase { supply_increase; _ } = supply_increase + + let set_supply_increase t supply_increase = { t with supply_increase } + + let block_global_slot _ = Global_slot_since_genesis.zero + end + + module Call_stack = struct + include Call_stack + + let with_hash t = + let rec accumulate_call_stack_hashes + ~(hash_frame : 'frame -> Mina_base.Stack_frame.Digest.t) + (frames : 'frame list) : + ('frame, Call_stack_digest.t) With_stack_hash.t list = + match frames with + | [] -> + [] + | f :: fs -> + let h_f = hash_frame f in + let tl = accumulate_call_stack_hashes ~hash_frame fs in + let h_tl = + match tl with + | [] -> + Call_stack_digest.empty + | t :: _ -> + t.stack_hash + in + { stack_hash = Call_stack_digest.cons h_f h_tl; elt = f } :: tl + in + List.map t + ~f:(With_hash.of_data ~hash_data:Mina_base.Stack_frame.Digest.create) + |> accumulate_call_stack_hashes ~hash_frame:(fun x -> x.With_hash.hash) + + let hash with_hash = + List.hd with_hash + |> Option.value_map ~default:Call_stack_digest.empty + ~f:With_stack_hash.stack_hash + end + + module Local_state = struct + include Local_state + + let to_zeko + ({ stack_frame + ; call_stack + ; transaction_commitment + ; full_transaction_commitment + ; excess + ; account_update_index + } : + ( Mina_base.Stack_frame.value + , ( ( ( Token_id.t + , ( Account_update.t + , Zkapp_command.Digest.Account_update.t + , Zkapp_command.Digest.Forest.t ) + Zkapp_command.Call_forest.t ) + Mina_base.Stack_frame.t + , Mina_base.Stack_frame.Digest.t ) + With_hash.t + , Call_stack_digest.t ) + With_stack_hash.t + list + , Currency.Amount.Signed.t + , Ledger.t + , bool + , Outer_action_state.t + , Unsigned.uint32 + , 'a list ) + Zkapp_command_logic.Local_state.t ) : Zeko_local_state.t = + Zeko_local_state. + { stack_frame_digest = Mina_base.Stack_frame.Digest.create stack_frame + ; call_stack_digest = Call_stack.hash call_stack + ; transaction_commitment + ; full_transaction_commitment + ; excess + ; account_update_index + } + end +end + +type zeko_env = + < zeko_mark_shifted_and_get_previous_shiftedness : Account_id.t -> bool > + +let zeko_dummy_env : zeko_env = + object + method zeko_mark_shifted_and_get_previous_shiftedness _ = true + end + +let perform ~(zeko_env : zeko_env) ~global_slot (type r) + (eff : + ( r + , < bool : Bool.t + ; account : Account.t + ; account_update : Account_update.t + ; local_state : Inputs.Local_state.t + ; .. > ) + Zkapp_command_logic.Eff.t ) : r = + match eff with + | Check_valid_while_precondition (valid_while, _global_state) -> + Zkapp_precondition.Valid_while.check valid_while global_slot + |> Or_error.is_ok + | Check_protocol_state_precondition + ((predicate : Zkapp_precondition.Protocol_state.t), _global_state) -> + (* FIXME: Zkapp_precondition.Protocol_state.(equal predicate accept) *) + (* Allow for global slot precondition, as it's the fee payer's valid while *) + true + | Check_account_precondition + (account_update, account, new_account, local_state) -> + let local_state = ref local_state in + let check failure b = + local_state := Inputs.Local_state.add_check !local_state failure b + in + Zkapp_precondition.Account.check ~new_account ~check + account_update.body.preconditions.account account ; + !local_state + | Init_account { account_update = _; account = a } -> + a + | Get_shift_action_state a -> + zeko_env#zeko_mark_shifted_and_get_previous_shiftedness + (Account_id.create a.public_key a.token_id) + +module Logic = Zkapp_command_logic.Make (Inputs) + +let apply_signed_command_unchecked ~sequencer_pk ~constraint_constants + ~global_slot ledger imt (command : Signed_command.t) = + let source_ledger = + let accounts_referenced = + User_command.accounts_referenced (Signed_command command) + in + Sparse_ledger.of_ledger_subset_exn ledger accounts_referenced + in + let source_imt = Indexed_merkle_tree.Db.merkle_root imt in + let%bind.Result status, new_accounts = + Or_error.try_with_join (fun () -> + match + Ledger.apply_user_command_unchecked ~constraint_constants + ~txn_global_slot:global_slot ledger command + with + | Ok + { common = { user_command = { status; _ }; _ } + ; body = Payment { new_accounts } + } -> + Ok (status, new_accounts) + | Ok _ -> + failwith "Internal error: it should be payment" + | Error err -> + Error err ) + in + Ledger.commit ledger ; + let update_acc_set_witness = + let fee_payer = Signed_command.fee_payer command in + let receiver = Signed_command.receiver command in + let tids = + List.map [ fee_payer; fee_payer; receiver ] ~f:(fun owner -> + Account_id.derive_token_id ~owner ) + in + List.fold tids ~init:Acc_set_witness.empty ~f:(fun acc tid -> + let _, witness = + Indexed_merkle_tree.Db.get_or_create_entry_exn imt tid + in + Acc_set_witness.add acc witness ) + in + match status with + | Applied -> + Ok + ( source_ledger + , Base_input. + { source_ledger = Sparse_ledger.merkle_root source_ledger + ; source_acc_set = source_imt + ; sequencer = sequencer_pk + ; transaction = command + ; witness = + Base_witness. + { ledger_path_handler = source_ledger + ; update_acc_set_witness + } + } ) + | Failed failures -> + Or_error.error_string + (sprintf "Transaction failed: %s" + (Yojson.Safe.pretty_to_string + (Transaction_status.Failure.Collection.to_yojson failures) ) ) + +let apply_zkapp_command_unchecked ~sequencer_pk ~zeko_env ~constraint_constants + ~global_slot ledger imt archive (command : Zkapp_command.t) = + let hash_local_state l = + Zkapp_command_logic.Local_state. + { l with call_stack = Inputs.Call_stack.with_hash l.call_stack } + in + let source_ledger = + let accounts_referenced = + User_command.accounts_referenced (Zkapp_command command) + in + Sparse_ledger.of_ledger_subset_exn ledger accounts_referenced + in + let state : Inputs.Global_state.t * _ Zkapp_command_logic.Local_state.t = + let open Inputs in + ( { fee_excess = Amount.(Signed.of_unsigned zero) + ; supply_increase = Amount.(Signed.of_unsigned zero) + } + , { stack_frame = + Stack_frame.make ~calls:(Call_forest.empty ()) + ~caller:Token_id.default ~caller_caller:Token_id.default + ; call_stack = Call_stack.empty () + ; transaction_commitment = Transaction_commitment.empty + ; full_transaction_commitment = Transaction_commitment.empty + ; excess = Amount.(Signed.of_unsigned zero) + ; supply_increase = Amount.(Signed.of_unsigned zero) + ; ledger + ; success = true + ; account_update_index = Index.zero + ; failure_status_tbl = [] + ; will_succeed = true + } ) + in + let account_updates = Zkapp_command.all_account_updates command in + let perform eff = perform ~zeko_env:zeko_dummy_env ~global_slot eff in + let witnesses = + let l = hash_local_state (snd state) in + let account_id = Zkapp_command.fee_payer command in + [ ( account_id + , fun ~imt_hash ~imt_witness -> + Txn_snark_witness.Zkapp_command_segment.Single_unproved + Zkapp_single_unproved_input. + { base = + { source_ledger = Sparse_ledger.merkle_root source_ledger + ; source_local_state = Inputs.Local_state.to_zeko l + ; sequencer = sequencer_pk + ; source_acc_set = imt_hash + ; witness = + (let l = snd state in + Zkapp_rule_input_witness. + { stack_frame = l.stack_frame + ; call_stack = Inputs.Call_stack.with_hash l.call_stack + ; source_ledger_sparse = source_ledger + ; update_acc_set_witness = imt_witness + } ) + } + ; first = + (let account_updates = + Zkapp_command.all_account_updates command + in + Per_account_update. + { account_updates = + Zkapp_command.Call_forest.hash account_updates + ; account_updates_data = account_updates + ; memo_hash = + Signed_command_memo.hash @@ Zkapp_command.memo command + ; shift_action_state = + (* This should come from env, but would ruin later *) + true + } ) + } ) + ] + in + let%bind.Result state = + Or_error.try_with (fun () -> + Logic.start ~constraint_constants + { account_updates + ; memo_hash = Signed_command_memo.hash command.memo + ; will_succeed = true + } + { perform } state ) + in + let rec step_all (g, l) witnesses = function + | [] -> + Or_error.error_string "Internal error: empty account_updates" + | account_update :: rest -> + if + List.is_empty + Zkapp_command_logic.Local_state.(l.stack_frame.Stack_frame.calls) + then Ok (l.failure_status_tbl, witnesses) + else + let account_id = Account_update.account_id account_update in + let%bind.Result w = + let incomplete_base ~imt_hash ~imt_witness = + let l = hash_local_state (snd state) in + Zkapp_rule_input. + { source_ledger = Ledger.merkle_root ledger + ; source_local_state = Inputs.Local_state.to_zeko l + ; sequencer = sequencer_pk + ; source_acc_set = imt_hash + ; witness = + (let l = snd state in + Zkapp_rule_input_witness. + { stack_frame = l.stack_frame + ; call_stack = Inputs.Call_stack.with_hash l.call_stack + ; source_ledger_sparse = + Sparse_ledger.of_ledger_subset_exn ledger + [ account_id ] + ; update_acc_set_witness = imt_witness + } ) + } + in + let empty_start_data = + Per_account_update. + { account_updates_data = + Mina_base.Zkapp_command.Call_forest.accumulate_hashes' [] + ; memo_hash = Field.zero + ; account_updates = + Mina_base.Zkapp_command.Call_forest.accumulate_hashes' [] + |> Mina_base.Zkapp_command.Call_forest.hash + ; shift_action_state = true + } + in + match Account_update.authorization account_update with + | None_given | Signature _ -> + Ok + (fun ~imt_hash ~imt_witness -> + Txn_snark_witness.Zkapp_command_segment.Single_unproved + Zkapp_single_unproved_input. + { base = incomplete_base ~imt_hash ~imt_witness + ; first = empty_start_data + } ) + | Proof proof -> + let%bind.Result vk = + (let%bind.Option loc = + Ledger.location_of_account ledger account_id + in + let%bind.Option acc = Ledger.get ledger loc in + let%bind.Option zkapp = Account.zkapp acc in + zkapp.verification_key ) + |> Result.of_option + ~error:(Error.of_string "No verification key") + in + Ok + (fun ~imt_hash ~imt_witness -> + Txn_snark_witness.Zkapp_command_segment.Single_proved + Zkapp_single_proved_input. + { base = incomplete_base ~imt_hash ~imt_witness + ; first = empty_start_data + ; vk = + Compile_simple.Verification_key.of_pickles vk.data + ; zkapp_proof = Compile_simple.Proof.of_pickles proof + } ) + in + let witnesses = (account_id, w) :: witnesses in + let%bind.Result state = + Or_error.try_with (fun () -> + Logic.step ~constraint_constants { perform } (g, l) ) + in + step_all state witnesses rest + in + let%bind.Result failures, witnesses = + step_all state witnesses (Zkapp_command.Call_forest.to_list account_updates) + in + let%bind.Result () = + if Transaction_status.Failure.Collection.is_empty failures then Ok () + else + Or_error.error_string + (sprintf "Transaction failed: %s" + (Yojson.Safe.pretty_to_string + (Transaction_status.Failure.Collection.to_yojson failures) ) ) + in + Ledger.commit ledger ; + let witnesses = + List.map witnesses ~f:(fun (aid, incomplete_witness) -> + let imt_hash = Indexed_merkle_tree.Db.merkle_root imt in + let imt_witness = + let _, w = + Indexed_merkle_tree.Db.get_or_create_entry_exn imt + (Account_id.derive_token_id ~owner:aid) + in + Acc_set_witness.(add empty w) + in + incomplete_witness ~imt_hash ~imt_witness ) + in + + (* let rec pair_unproved : + Txn_snark_witness.Zkapp_command_segment.t list + -> Txn_snark_witness.Zkapp_command_segment.t list = function + | [] -> + [] + | Single_unproved { base; first } + :: Single_unproved + { base = { witness = { update_acc_set_witness = second_imt } } + ; first = second + } + :: rest -> + let w = + Zkapp_double_unproved_input. + { base = + { base with + witness = + { base.witness with + update_acc_set_witness = + Acc_set_witness.join base.witness.update_acc_set_witness + second_imt + } + } + ; first + ; second + } + in + Double_unproved w :: pair_unproved rest + | hd :: tl -> + hd :: pair_unproved tl + in + let witnesses = pair_unproved witnesses in *) + + (* Add events and actions to the memory *) + let () = + Zkapp_command.( + Call_forest.iteri (account_updates command) ~f:(fun _ update -> + let account = + let account_id = + Account_id.create + (Account_update.public_key update) + (Account_update.token_id update) + in + let location = + Ledger.location_of_account ledger account_id + |> Option.value_exn + ~message:"Internal error, account should be present" + in + Ledger.get ledger location + |> Option.value_exn + ~message:"Internal error, account should be present" + in + Archive.add_account_update archive update account + (Some + Archive.Transaction_info. + { status = Applied + ; hash = + Mina_transaction.Transaction_hash.hash_command + (Zkapp_command command) + ; memo = Zkapp_command.memo command + ; authorization_kind = + Account_update.Body.authorization_kind update.body + } ) )) + in + Ok (source_ledger, witnesses) + +let apply_user_command_unchecked ~sequencer_pk ~zeko_env ~constraint_constants + ~global_slot ledger imt archive (command : User_command.t) = + match command with + | Signed_command ({ payload = { body = Payment _; _ }; _ } as command) -> + let%map.Result source_ledger, w = + apply_signed_command_unchecked ~sequencer_pk ~constraint_constants + ~global_slot ledger imt command + in + (source_ledger, [ Txn_snark_witness.Signed_command w ]) + | Zkapp_command command -> + let%map.Result source_ledger, w = + apply_zkapp_command_unchecked ~sequencer_pk ~zeko_env + ~constraint_constants ~global_slot ledger imt archive command + in + (source_ledger, List.map w ~f:(fun w -> Txn_snark_witness.Zkapp_command w)) + | Signed_command _ -> + Or_error.error_string "Invalid signed command, we allow only payments" diff --git a/src/app/zeko/sequencer/prover/cli.ml b/src/app/zeko/sequencer/prover/cli.ml index 7d15e9f863..65153e9e35 100644 --- a/src/app/zeko/sequencer/prover/cli.ml +++ b/src/app/zeko/sequencer/prover/cli.ml @@ -1,7 +1,5 @@ -open Core open Async open Signature_lib -module Server = Zeko_prover.Prover let run_server = ( "run-server" @@ -11,14 +9,7 @@ let run_server = in let logger = Logger.create () in [%log info] "Compiling circuits" ; - let module T = Transaction_snark.Make (struct - let constraint_constants = Server.constraint_constants - - let proof_level = Genesis_constants.Proof_level.Full - end) in - let module M = Zkapps_rollup.Make (T) in - let module S = Server.Make (T) (M) in - fun () -> S.run ~logger ~port ) ) + fun () -> Zeko_prover.Prover.run ~logger ~port ) ) let () = Command.group ~summary:"Zeko prover CLI" [ run_server ] |> Command_unix.run diff --git a/src/app/zeko/sequencer/prover/cli_fake.ml b/src/app/zeko/sequencer/prover/cli_fake.ml new file mode 100644 index 0000000000..65153e9e35 --- /dev/null +++ b/src/app/zeko/sequencer/prover/cli_fake.ml @@ -0,0 +1,15 @@ +open Async +open Signature_lib + +let run_server = + ( "run-server" + , Command.async ~summary:"Run prover server" + (let%map_open.Command port = + flag "--port" (required int) ~doc:"int Port to listen on" + in + let logger = Logger.create () in + [%log info] "Compiling circuits" ; + fun () -> Zeko_prover.Prover.run ~logger ~port ) ) + +let () = + Command.group ~summary:"Zeko prover CLI" [ run_server ] |> Command_unix.run diff --git a/src/app/zeko/sequencer/prover/dune b/src/app/zeko/sequencer/prover/dune index 028ba95451..7d6a784727 100644 --- a/src/app/zeko/sequencer/prover/dune +++ b/src/app/zeko/sequencer/prover/dune @@ -2,14 +2,27 @@ (name cli) (libraries zeko_prover - zkapps_rollup - mina_lib - mina_ledger - core_unix.command_unix - yojson - cohttp - cohttp-async - async_kernel) + ;; mina ;; + mina_base + signature_lib + ;; opam ;; + async + core_unix.command_unix) (preprocess (pps ppx_jane ppx_mina)) (modules cli)) + +(executable + (name cli_fake) + (libraries + zeko_prover + compile_simple_fake + ;; mina ;; + mina_base + signature_lib + ;; opam ;; + async + core_unix.command_unix) + (preprocess + (pps ppx_jane ppx_mina)) + (modules cli_fake)) diff --git a/src/app/zeko/sequencer/prover/lib/client.ml b/src/app/zeko/sequencer/prover/lib/client.ml index 849ab4251c..ab78b3ff2e 100644 --- a/src/app/zeko/sequencer/prover/lib/client.ml +++ b/src/app/zeko/sequencer/prover/lib/client.ml @@ -1,5 +1,10 @@ open Async open Core_kernel +open Mina_base +open Mina_ledger +open Zeko_circuits +open Zeko_types +module Field = Snark_params.Tick.Field let try_connect where_to_connect = match%bind try_with (fun () -> Tcp.connect where_to_connect) with @@ -32,7 +37,7 @@ module State = struct in { provers = connections; next = 0 } - let rec next_prover (t : t) = + let rec next_prover t = let rotate l n = let left, right = List.split_n l n in right @ left @@ -44,7 +49,9 @@ module State = struct match !status with `Available -> true | `In_use -> false ) with | Some prover -> - return prover + let status = trd3 prover in + status := `In_use ; + return (prover, fun () -> status := `Available) | None -> let%bind () = Clock.after (Time.Span.of_sec 1.) in next_prover t @@ -54,7 +61,7 @@ end If it fails to connect or times out, replace the reference with new connection and try whole thing again *) let rec send ?(proving_timeout = 10.) ?(wait_for_prover_timeout = 600.) ?(attempts = 5) t (input : Prover.Input.t) : Prover.Output.t Deferred.t = - let%bind connection_ref, where_to_connect, status = + let%bind (connection_ref, where_to_connect, status), release_prover = match%bind Async.with_timeout (Time.Span.of_sec wait_for_prover_timeout) @@ -65,7 +72,6 @@ let rec send ?(proving_timeout = 10.) ?(wait_for_prover_timeout = 600.) | `Timeout -> failwith "Timeout while getting prover" in - status := `In_use ; match%bind Async.with_timeout (Time.Span.of_sec proving_timeout) @@ -91,12 +97,11 @@ let rec send ?(proving_timeout = 10.) ?(wait_for_prover_timeout = 600.) failwith "Error parsing response" ) | None -> failwith "Timeout while proving" ) ) + >>| fun r -> release_prover () ; r with | `Result (`Ok r) -> - status := `Available ; return r | `Timeout | `Result `Connection_error -> - status := `Available ; printf "Timeout while proving %f, retrying attempts remaining: %d\n%!" proving_timeout attempts ; if attempts > 0 then ( @@ -104,88 +109,156 @@ let rec send ?(proving_timeout = 10.) ?(wait_for_prover_timeout = 600.) send ~proving_timeout ~attempts:(attempts - 1) t input ) else failwith "Timeout while proving" -let wrapper_wrap ?proving_timeout t ~txn_snark = - send ?proving_timeout t (Prover.Input.Wrapper_wrap txn_snark) +let transaction_snark ?proving_timeout t input = + send ?proving_timeout t (Prover.Input.Txn_snark input) >>| function - | Prover.Output.Wrapper_wrap x -> x | _ -> failwith "Unexpected response" + | Prover.Output.Txn_snark snark -> + snark + | _ -> + failwith "Unexpected response from prover" -let wrapper_merge ?proving_timeout t a b = - send ?proving_timeout t (Prover.Input.Wrapper_merge (a, b)) +let ase_with_length ?proving_timeout t input = + send ?proving_timeout t (Prover.Input.Ase (With_length input)) >>| function - | Prover.Output.Wrapper_merge x -> x | _ -> failwith "Unexpected response" + | Prover.Output.Ase (With_length ase) -> + ase + | _ -> + failwith "Unexpected response from prover" -let transaction_snark_of_signed_command ?proving_timeout t ~statement - ~user_command_in_block ~sparse_ledger = - send ?proving_timeout t - (Prover.Input.Transaction_snark_of_signed_command - (statement, user_command_in_block, sparse_ledger) ) +let ase_without_length ?proving_timeout t input = + send ?proving_timeout t (Prover.Input.Ase (Without_length input)) >>| function - | Prover.Output.Transaction_snark_of_signed_command x -> - x + | Prover.Output.Ase (Without_length ase) -> + ase | _ -> - failwith "Unexpected response" + failwith "Unexpected response from prover" -let transaction_snark_of_zkapp_command_segment ?proving_timeout t ~statement - ~witness ~spec = - send ?proving_timeout t - (Prover.Input.Transaction_snark_of_zkapp_command_segment - (statement, witness, spec) ) +let ase (type target) t ~source ~elems ~max_excess + (prover : _ -> _ -> (Compile_simple.Proof.t option * target) Deferred.t) = + let elems_to_prove, excess = + let i = ref 0 in + let l = List.length elems in + List.split_while elems ~f:(fun _ -> + let r = !i < l - max_excess in + i := !i + 1 ; + r ) + in + match elems_to_prove with + | [] -> + return (None, source, excess) + | elems_to_prove -> + let%bind proof, target = prover t (source, elems_to_prove) in + return (proof, target, excess) + +let inner_sync ?proving_timeout t ~public_key ~ase_source ~ase_elms = + let%bind ase = + let%map proof, target, excess = + ase t ~source:ase_source ~elems:ase_elms + ~max_excess:Inner_sync.Ase_inst.get_iterations ase_with_length + in + Inner_sync.Ase_inst. + { proof; proof_target = target; init = ase_source; excess } + in + send ?proving_timeout t (Prover.Input.Inner_sync { public_key; ase }) >>| function - | Prover.Output.Transaction_snark_of_zkapp_command_segment x -> - x + | Prover.Output.Call_forest_tree tree -> + tree | _ -> - failwith "Unexpected response" + failwith "Unexpected response from prover" -let transaction_snark_merge ?proving_timeout t a b = - send ?proving_timeout t (Prover.Input.Transaction_snark_merge (a, b)) +let verify_both_ases ?proving_timeout t input = + send ?proving_timeout t (Prover.Input.Verify_both_ases input) >>| function - | Prover.Output.Transaction_snark_merge x -> - x + | Prover.Output.Verify_both_ases snark -> + snark | _ -> - failwith "Unexpected response" + failwith "Unexpected response from prover" -let submit_deposit ?proving_timeout t ~outer_pk ~deposit = - send ?proving_timeout t (Prover.Input.Submit_deposit (outer_pk, deposit)) +let outer_commit ?proving_timeout t ~txn_snark ~public_key ~new_actions + ~unprocessed_actions ~old_inner_ledger ~new_inner_ledger ~da_signature + ~da_key = + let get_inner_acc ledger = + let inner_acc = + Sparse_ledger.get_exn ledger Zeko_constants.inner_account_index + in + let inner_acc_path = + Sparse_ledger.path_exn ledger Zeko_constants.inner_account_index + |> List.map ~f:(function + | `Left _ -> + ( { right_side = Field.zero } + : Outer_rules.Rule_commit_inst.PathElt.t ) + | `Right _ -> + { right_side = Field.one } ) + in + (inner_acc, inner_acc_path) + in + let old_inner_acc, old_inner_acc_path = get_inner_acc old_inner_ledger in + let new_inner_acc, new_inner_acc_path = get_inner_acc new_inner_ledger in + + let%bind inner_ase = + let ({ outer_action_state } : Rollup_state.Inner_state.t) = + Rollup_state.Inner_state.value_of_app_state + (Option.value_exn old_inner_acc.zkapp).app_state + in + let action_state : Ase.With_length.Stmt.t = + Rollup_state.Outer_action_state.With_length. + { action_state = raw outer_action_state + ; length = length outer_action_state + } + in + let%map proof, target, excess = + ase t ~source:action_state ~elems:new_actions + ~max_excess:Outer_commit.Ase_inner_inst.get_iterations ase_with_length + in + Outer_commit.Ase_inner_inst. + { proof; proof_target = target; init = action_state; excess } + in + let%bind outer_ase = + let ({ outer_action_state } : Rollup_state.Inner_state.t) = + Rollup_state.Inner_state.value_of_app_state + (Option.value_exn new_inner_acc.zkapp).app_state + in + let action_state = + Rollup_state.Outer_action_state.With_length.raw outer_action_state + in + let%map proof, target, excess = + ase t ~source:action_state ~elems:unprocessed_actions + ~max_excess:Outer_commit.Ase_outer_inst.get_iterations + ase_without_length + in + Outer_commit.Ase_outer_inst. + { proof; proof_target = target; init = action_state; excess } + in + let%bind verify_both_ases = verify_both_ases t (outer_ase, inner_ase) in + + send ?proving_timeout t + (Prover.Input.Outer_commit + { txn_snark + ; public_key + ; verify_both_ases + ; old_inner_acc + ; old_inner_acc_path + ; new_inner_acc + ; new_inner_acc_path + ; da_signature + ; da_key + } ) >>| function - | Prover.Output.Submit_deposit x -> x | _ -> failwith "Unexpected response" + | Prover.Output.Call_forest_tree tree -> + tree + | _ -> + failwith "Unexpected response from prover" + +let submit_deposit ?proving_timeout t ~outer_pk ~deposit = + failwith "Not implemented" let submit_withdrawal ?proving_timeout t ~withdrawal = - send ?proving_timeout t (Prover.Input.Submit_withdrawal withdrawal) - >>| function - | Prover.Output.Submit_withdrawal x -> x | _ -> failwith "Unexpected response" + failwith "Not implemented" let process_deposit ?proving_timeout t ~is_new ~pointer ~before ~after ~deposit = - send ?proving_timeout t - (Prover.Input.Process_deposit (is_new, pointer, before, after, deposit)) - >>| function - | Prover.Output.Process_deposit x -> x | _ -> failwith "Unexpected response" + failwith "Not implemented" let process_withdrawal ?proving_timeout t ~outer_pk ~is_new ~pointer ~before ~after ~withdrawal = - send ?proving_timeout t - (Prover.Input.Process_withdrawal - (outer_pk, is_new, pointer, before, after, withdrawal) ) - >>| function - | Prover.Output.Process_withdrawal x -> - x - | _ -> - failwith "Unexpected response" - -let outer_step ?proving_timeout t ~last ~outer_public_key ~new_deposits - ~unprocessed_deposits ~old_inner_ledger ~new_inner_ledger = - send ?proving_timeout t - (Prover.Input.Outer_step - ( last - , outer_public_key - , new_deposits - , unprocessed_deposits - , old_inner_ledger - , new_inner_ledger ) ) - >>| function - | Prover.Output.Outer_step x -> x | _ -> failwith "Unexpected response" - -let inner_step ?proving_timeout t ~all_deposits = - send ?proving_timeout t (Prover.Input.Inner_step all_deposits) - >>| function - | Prover.Output.Inner_step x -> x | _ -> failwith "Unexpected response" + failwith "Not implemented" diff --git a/src/app/zeko/sequencer/prover/lib/dune b/src/app/zeko/sequencer/prover/lib/dune index 8ef9fb3da3..29d6b2b892 100644 --- a/src/app/zeko/sequencer/prover/lib/dune +++ b/src/app/zeko/sequencer/prover/lib/dune @@ -1,10 +1,13 @@ (library (name zeko_prover) (libraries - zkapps_rollup - mina_lib + zeko_circuits + indexed_merkle_tree + zeko_constants + ;; mina ;; + mina_base mina_ledger - yojson + ;; opam ;; cohttp cohttp-async async_kernel) diff --git a/src/app/zeko/sequencer/prover/lib/prover.ml b/src/app/zeko/sequencer/prover/lib/prover.ml index 0d199d0658..f304201cf4 100644 --- a/src/app/zeko/sequencer/prover/lib/prover.ml +++ b/src/app/zeko/sequencer/prover/lib/prover.ml @@ -1,15 +1,15 @@ open Core_kernel open Async open Mina_base -open Mina_ledger -open Signature_lib +open Zeko_circuits +open Zeko_types -(* Only for yojson serialization of Field *) -module Field = Data_hash.Make_full_size (struct - let description = "Field" - - let version_byte = '\x00' -end) +let mktree (account_update, account_update_digest, calls) proof = + let account_update : Account_update.t = + { body = account_update; authorization = Proof proof } + in + Zkapp_command.Call_forest.Tree. + { account_update; account_update_digest; calls } let constraint_constants = Genesis_constants.Compiled.constraint_constants @@ -22,154 +22,247 @@ let time ~logger label (d : 'a Deferred.t) = (Time.Span.to_string_hum @@ Time.diff stop start) ; return x -let dummy_sok = - Sok_message.digest - @@ Sok_message.create ~fee:Currency.Fee.zero - ~prover:(Public_key.compress (Keypair.create ()).public_key) +module Make_folder (System : sig + module Stmt : sig + type t [@@deriving yojson] + end + + type trans = { source : Stmt.t; target : Stmt.t } + + val leaf : F.t list * Stmt.t -> (trans * Compile_simple.Proof.t) Promise.t + + val leaf_option : + F.t list * Stmt.t -> (trans * Compile_simple.Proof.t) Promise.t + + val extend : + F.t list * (trans * Compile_simple.Proof.t) + -> (trans * Compile_simple.Proof.t) Promise.t + + val extend_option : + F.t list * (trans * Compile_simple.Proof.t) + -> (trans * Compile_simple.Proof.t) Promise.t + + val leaf_iterations : int + + val leaf_option_iterations : int + + val extend_iterations : int + + val extend_option_iterations : int +end) = +struct + type out_t = Compile_simple.Proof.t option * System.Stmt.t [@@deriving yojson] + + let fold ~source ~elems : out_t Promise.t = + match elems with + | [] -> + (* No need for folding, everything goes to excess *) + Promise.return (None, source) + | elems_to_prove -> + (* Need to fold *) + let leaf_prover, (leaf_elems, rest) = + if List.length elems_to_prove > System.leaf_iterations then + (* Full leaf *) + (System.leaf, List.split_n elems_to_prove System.leaf_iterations) + else + (* Partial leaf *) + ( System.leaf_option + , List.split_n elems_to_prove System.leaf_option_iterations ) + in + let%bind.Promise leaf = leaf_prover (leaf_elems, source) in + let rec extend_rest elems_to_prove acc = + match elems_to_prove with + | [] -> + Promise.return acc + | elems_to_prove -> + let extend_prover, (extend_elems, rest) = + if List.length elems_to_prove > System.extend_iterations then + (* Full node *) + ( System.extend + , List.split_n elems_to_prove System.extend_iterations ) + else + (* Partial node *) + ( System.extend_option + , List.split_n elems_to_prove System.extend_option_iterations + ) + in + let%bind.Promise acc = extend_prover (extend_elems, acc) in + extend_rest rest acc + in + let%bind.Promise trans, proof = extend_rest rest leaf in + Promise.return (Some proof, trans.target) +end + +module Folder_with_length = Make_folder (Ase.With_length) +module Folder_without_length = Make_folder (Ase.Without_length) (* Unfortunately yojson doesn't support GADTs so it can't be one type, or maybe I'm just bad *) module Input = struct + module Txn_snark = struct + type t = + | Signed_command of Base_input.serializable + | Zkapp_command of Txn_snark_witness.Zkapp_command_segment.t + | Merge of Merge_input.t + [@@deriving yojson] + end + + module Ase = struct + type t = + | With_length of (Ase.With_length.Stmt.t * F.t list) + | Without_length of (Ase.Without_length.Stmt.t * F.t list) + [@@deriving yojson] + end + type t = - | Wrapper_wrap of Transaction_snark.t - | Wrapper_merge of (Zkapps_rollup.t * Zkapps_rollup.t) - | Transaction_snark_of_signed_command of - ( Mina_state.Snarked_ledger_state.With_sok.t - * Signed_command.With_valid_signature.t Transaction_protocol_state.t - * Sparse_ledger.t ) - | Transaction_snark_of_zkapp_command_segment of - ( Mina_state.Snarked_ledger_state.With_sok.t - * Transaction_witness.Zkapp_command_segment_witness.t - * Transaction_snark.Zkapp_command_segment.Basic.t ) - | Transaction_snark_merge of (Transaction_snark.t * Transaction_snark.t) - | Submit_deposit of (Public_key.Compressed.t * Zkapps_rollup.TR.t) - | Submit_withdrawal of Zkapps_rollup.TR.t - | Process_deposit of - ( bool - * Field.t - * Zkapps_rollup.TR.t list - * Zkapps_rollup.TR.t list - * Zkapps_rollup.TR.t ) - | Process_withdrawal of - ( Public_key.Compressed.t - * bool - * Field.t - * Zkapps_rollup.TR.t list - * Zkapps_rollup.TR.t list - * Zkapps_rollup.TR.t ) - | Outer_step of - ( Zkapps_rollup.t - * Public_key.Compressed.t - * Zkapps_rollup.TR.t list - * Zkapps_rollup.TR.t list - * Sparse_ledger.t - * Sparse_ledger.t ) - | Inner_step of Field.t + | Txn_snark of Txn_snark.t + | Ase of Ase.t + | Inner_sync of Inner_sync.Witness.serializable + | Verify_both_ases of + ( Outer_commit.Ase_outer_inst.serializable + * Outer_commit.Ase_inner_inst.serializable ) + | Outer_commit of Outer_commit.Witness.serializable [@@deriving yojson] end -let asd = Ledger_hash.to_yojson - module Output = struct + module Ase = struct + type t = + | With_length of Folder_with_length.out_t + | Without_length of Folder_without_length.out_t + [@@deriving yojson] + end + type t = - | Wrapper_wrap of Zkapps_rollup.t - | Wrapper_merge of Zkapps_rollup.t - | Transaction_snark_of_signed_command of Transaction_snark.t - | Transaction_snark_of_zkapp_command_segment of Transaction_snark.t - | Transaction_snark_merge of Transaction_snark.t - | Submit_deposit of Zeko_util.call_forest_tree - | Submit_withdrawal of Zeko_util.call_forest_tree - | Process_deposit of Zeko_util.call_forest - | Process_withdrawal of Zeko_util.call_forest - | Outer_step of Zeko_util.call_forest_tree - | Inner_step of Zeko_util.call_forest_tree + | Txn_snark of (Zeko_stmt.t * Compile_simple.Proof.t) + | Ase of Ase.t + | Verify_both_ases of Outer_commit.Verify_both_ases.serializable + | Call_forest_tree of + ( Account_update.t + , Zkapp_command.Digest.Account_update.t + , Zkapp_command.Digest.Forest.t ) + Zkapp_command.Call_forest.Tree.t [@@deriving yojson] end -module Make (T : Transaction_snark.S) (M : Zkapps_rollup.S) = struct - let prove ~logger : Input.t -> Output.t Deferred.t = function - | Wrapper_wrap txn_snark -> - time ~logger "Wrapper.wrap" (M.Wrapper.wrap txn_snark) - >>| fun x -> Output.Wrapper_wrap x - | Wrapper_merge (last, wrapped) -> - time ~logger "Wrapper.merge" (M.Wrapper.merge last wrapped) - >>| fun x -> Output.Wrapper_merge x - | Transaction_snark_of_signed_command - (statement, user_command_in_block, sparse_ledger) -> - let handler = unstage @@ Sparse_ledger.handler sparse_ledger in - time ~logger "Transaction_snark.of_signed_command" - (T.of_user_command ~init_stack:Mina_base.Pending_coinbase.Stack.empty - ~statement user_command_in_block handler ) - >>| fun x -> Output.Transaction_snark_of_signed_command x - | Transaction_snark_of_zkapp_command_segment (statement, witness, spec) -> - time ~logger "Transaction_snark.of_zkapp_command_segment" - (T.of_zkapp_command_segment_exn ~statement ~witness ~spec) - >>| fun x -> Output.Transaction_snark_of_zkapp_command_segment x - | Transaction_snark_merge (a, b) -> - time ~logger "Transaction_snark.merge" - (T.merge a b ~sok_digest:dummy_sok) - >>| Or_error.ok_exn - >>| fun x -> Output.Transaction_snark_merge x - | Submit_deposit (outer_public_key, deposit) -> - time ~logger "Outer.Submit_deposit" - (M.Outer.submit_deposit ~outer_public_key ~deposit) - >>| fun x -> Output.Submit_deposit x - | Submit_withdrawal withdrawal -> - time ~logger "Inner.Submit_withdrawal" - (M.Inner.submit_withdrawal ~withdrawal) - >>| fun x -> Output.Submit_withdrawal x - | Process_deposit (is_new, pointer, before, after, deposit) -> - time ~logger "Inner.Process_deposit" - (M.Inner.process_deposit ~is_new ~pointer ~before ~after ~deposit) - >>| fun (_, x) -> Output.Process_deposit x - | Process_withdrawal - (outer_public_key, is_new, pointer, before, after, withdrawal) -> - time ~logger "Outer.Process_withdrawal" - (M.Outer.process_withdrawal ~outer_public_key ~is_new ~pointer ~before - ~after ~withdrawal ) - >>| fun (_, x) -> Output.Process_withdrawal x - | Outer_step - ( last - , outer_public_key - , new_deposits - , unprocessed_deposits - , old_inner_ledger - , new_inner_ledger ) -> - time ~logger "Outer.step" - (M.Outer.step last ~outer_public_key ~new_deposits - ~unprocessed_deposits ~old_inner_ledger ~new_inner_ledger ) - >>| fun x -> Output.Outer_step x - | Inner_step all_deposits -> - time ~logger "Inner.step" (M.Inner.step ~all_deposits) - >>| fun x -> Output.Inner_step x - - let run ~logger ~port = - ignore - @@ Tcp.Server.create (Tcp.Where_to_listen.of_port port) - ~on_handler_error:`Ignore (fun s r w -> - [%log info] "Accepted connection from %s" - (Socket.Address.Inet.to_string s) ; - let%bind () = - Pipe.transfer' ~max_queue_length:1 (Reader.pipe r) (Writer.pipe w) - ~f: - (Deferred.Queue.map ~how:`Sequential ~f:(fun input -> - Yojson.Safe.from_string input - |> Input.of_yojson - |> function - | Ok input -> ( - match%bind - try_with (fun () -> prove ~logger input) - with - | Ok output -> - Output.to_yojson output |> Yojson.Safe.to_string - |> fun s -> String.concat [ s; "\n" ] |> return - | Error e -> - return (Exn.to_string e) ) - | Error e -> - return e ) ) - in - return - ([%log info] "Closed connection from %s" - (Socket.Address.Inet.to_string s) ) ) ; - [%log info] "Listening on port %d\n" port ; - Deferred.never () -end +let prove ~logger : Input.t -> Output.t Deferred.t = function + | Txn_snark (Signed_command input) -> + let Compile_simple.[ prove; _; _; _; _ ] = Txn_rules.provers in + let%map stmt, proof = + time ~logger "Txn_rules.single_signed_command" + (prove (Base_input.of_serializable input) |> Promise.to_deferred) + in + Output.Txn_snark (stmt, proof) + | Txn_snark (Zkapp_command (Single_unproved input)) -> + let Compile_simple.[ _; prove; _; _; _ ] = Txn_rules.provers in + let%map stmt, proof = + time ~logger "Txn_rules.single_unproved_zkapp_command" + ( prove (Zkapp_single_unproved_input.of_serializable input) + |> Promise.to_deferred ) + in + Output.Txn_snark (stmt, proof) + | Txn_snark (Zkapp_command (Double_unproved input)) -> + let Compile_simple.[ _; _; prove; _; _ ] = Txn_rules.provers in + let%map stmt, proof = + time ~logger "Txn_rules.double_unproved_zkapp_command" + ( prove (Zkapp_double_unproved_input.of_serializable input) + |> Promise.to_deferred ) + in + Output.Txn_snark (stmt, proof) + | Txn_snark (Zkapp_command (Single_proved input)) -> + let Compile_simple.[ _; _; _; prove; _ ] = Txn_rules.provers in + let%map stmt, proof = + time ~logger "Txn_rules.single_proved_zkapp_command" + ( prove (Zkapp_single_proved_input.of_serializable input) + |> Promise.to_deferred ) + in + Output.Txn_snark (stmt, proof) + | Txn_snark (Merge input) -> + let Compile_simple.[ _; _; _; _; prove ] = Txn_rules.provers in + let%map stmt, proof = + time ~logger "Txn_rules.merge" (prove input |> Promise.to_deferred) + in + Output.Txn_snark (stmt, proof) + | Inner_sync input -> + let Compile_simple.[ prove; _ ] = Inner_rules.provers in + let%bind vk_hash = + Compile_simple.Verification_key.of_tag Inner_rules.tag + |> Promise.to_deferred + >>| Fn.compose Zkapp_account.digest_vk + Compile_simple.Verification_key.to_pickles + in + let%map (a, au), proof = + time ~logger "Inner_rules.inner_sync" + ( prove (Inner_sync.Witness.of_serializable ~vk_hash input) + |> Promise.to_deferred ) + in + Output.Call_forest_tree + (mktree au (Compile_simple.Proof.to_pickles proof)) + | Ase (With_length (source, elems)) -> + let%map snark = + time ~logger "Folder_with_length.fold" + (Folder_with_length.fold ~source ~elems |> Promise.to_deferred) + in + Output.(Ase (With_length snark)) + | Ase (Without_length (source, elems)) -> + let%map snark = + time ~logger "Folder_without_length.fold" + (Folder_without_length.fold ~source ~elems |> Promise.to_deferred) + in + Output.(Ase (Without_length snark)) + | Verify_both_ases (outer, inner) -> + let Compile_simple.[ prove ] = Rule_commit.Verify_both_ases.provers in + let%map stmt, proof = + time ~logger "Rule_commit.verify_both_ases" + ( prove + Outer_commit. + ( Ase_outer_inst.of_serializable outer + , Ase_inner_inst.of_serializable inner ) + |> Promise.to_deferred ) + in + Output.Verify_both_ases (stmt, proof) + | Outer_commit input -> + let Compile_simple.[ prove; _; _ ] = Outer_rules.provers in + let%bind vk_hash = + Compile_simple.Verification_key.of_tag Outer_rules.tag + |> Promise.to_deferred + >>| Fn.compose Zkapp_account.digest_vk + Compile_simple.Verification_key.to_pickles + in + let%map (a, au), proof = + time ~logger "Outer_rules.commit" + ( prove (Outer_commit.Witness.of_serializable ~vk_hash input) + |> Promise.to_deferred ) + in + Output.Call_forest_tree + (mktree au (Compile_simple.Proof.to_pickles proof)) + +let run ~logger ~port = + ignore + @@ Tcp.Server.create (Tcp.Where_to_listen.of_port port) + ~on_handler_error:`Ignore (fun s r w -> + [%log info] "Accepted connection from %s" + (Socket.Address.Inet.to_string s) ; + let%bind () = + Pipe.transfer' ~max_queue_length:1 (Reader.pipe r) (Writer.pipe w) + ~f: + (Deferred.Queue.map ~how:`Sequential ~f:(fun input -> + Yojson.Safe.from_string input + |> Input.of_yojson + |> function + | Ok input -> ( + match%bind try_with (fun () -> prove ~logger input) with + | Ok output -> + Output.to_yojson output |> Yojson.Safe.to_string + |> fun s -> String.concat [ s; "\n" ] |> return + | Error e -> + let err = Exn.to_string e in + [%log error] "Error proving: %s" err ; + return err ) + | Error e -> + return e ) ) + in + return + ([%log info] "Closed connection from %s" + (Socket.Address.Inet.to_string s) ) ) ; + [%log info] "Listening on port %d\n" port ; + Deferred.never () diff --git a/src/app/zeko/sequencer/prover/lib/zeko_types.ml b/src/app/zeko/sequencer/prover/lib/zeko_types.ml new file mode 100644 index 0000000000..ec3b438182 --- /dev/null +++ b/src/app/zeko/sequencer/prover/lib/zeko_types.ml @@ -0,0 +1,650 @@ +open Core_kernel +open Mina_base +open Mina_ledger +open Zeko_circuits +open Zeko_util +open Snark_params.Tick +open Signature_lib + +let ok_exn = function + | Ppx_deriving_yojson_runtime.Result.Ok x -> + x + | Error e -> + failwith e + +module F = struct + include F + + type t = Field.t [@@deriving yojson] +end + +module Make_serializable_path (Inputs : sig + module PathStep : sig + type t [@@deriving yojson] + end +end) = +struct + open Inputs + + type t = PathStep.t list [@@deriving yojson] +end + +module Account_set = struct + include Account_set + + type t = F.t [@@deriving yojson] +end + +module Acc_set_witness = struct + module Path = Make_serializable_path (struct + module PathStep = struct + type t = Account_set.PathStep.t + + let to_yojson ({ hash_other; is_right } : t) = + `Assoc + [ ("hash_other", Field.to_yojson hash_other) + ; ("is_right", `Bool is_right) + ] + + let of_yojson step_json = + let open Yojson.Safe.Util in + try + Ok + ( { hash_other = + member "hash_other" step_json |> Field.of_yojson |> ok_exn + ; is_right = member "is_right" step_json |> to_bool + } + : Account_set.PathStep.t ) + with e -> Error (Exn.to_string e) + end + end) + + type t = Txn_state.update_acc_set_witness = + { get_account_set_x : unit -> Token_id.t + ; get_account_set_z : unit -> Token_id.t + ; get_account_set_x_path : unit -> Path.t + ; get_account_set_y_path : unit -> Path.t + } + + type serializable = + { x : Token_id.t list + ; z : Token_id.t list + ; x_path : Path.t list + ; y_path : Path.t list + } + [@@deriving yojson] + + let of_serializable ({ x; z; x_path; y_path } : serializable) : t = + let list_to_fun l = + let l = ref l in + fun () -> + match !l with + | [] -> + failwith "empty!" + | x :: xs -> + l := xs ; + x + in + { get_account_set_x = list_to_fun x + ; get_account_set_z = list_to_fun z + ; get_account_set_x_path = list_to_fun x_path + ; get_account_set_y_path = list_to_fun y_path + } + + let empty = { x = []; x_path = []; y_path = []; z = [] } + + let add t + ((x, x_path, _, y_path, z) : + [ `X of Token_id.t ] + * [ `X_path of Ledger.Path.t ] + * [ `Y of Token_id.t ] + * [ `Y_path of [ `Left of Field.t | `Right of Field.t ] list ] + * [ `Z of Token_id.t ] ) = + let mina_path_to_zeko_path path = + let open Account_set in + List.map path ~f:(function + | `Left hash_other -> + ({ PathStep.hash_other; is_right = false } : PathStep.t) + | `Right hash_other -> + ({ PathStep.hash_other; is_right = true } : PathStep.t) ) + in + let x = match x with `X x -> x in + let x_path = match x_path with `X_path path -> path in + let y_path = match y_path with `Y_path path -> path in + let z = match z with `Z z -> z in + { x = t.x @ [ x ] + ; x_path = t.x_path @ [ mina_path_to_zeko_path x_path ] + ; y_path = t.y_path @ [ mina_path_to_zeko_path y_path ] + ; z = t.z @ [ z ] + } + + let join t1 t2 = + { x = t1.x @ t2.x + ; x_path = t1.x_path @ t2.x_path + ; y_path = t1.y_path @ t2.y_path + ; z = t1.z @ t2.z + } +end + +module Zkapp_rule_input_witness = struct + type t = Rule_zkapp_command.Zkapp_rule_input_witness.t = + { stack_frame : + ( Token_id.Stable.V2.t + , Zkapp_command.Call_forest.With_hashes.Stable.V1.t ) + Stack_frame.Stable.V1.t + ; call_stack : + ( ( ( Token_id.Stable.V2.t + , Zkapp_command.Call_forest.With_hashes.Stable.V1.t ) + Stack_frame.Stable.V1.t + , Stack_frame.Digest.Stable.V1.t ) + With_hash.t + , Call_stack_digest.Stable.V1.t ) + With_stack_hash.Stable.V1.t + list + ; source_ledger_sparse : Mina_ledger.Sparse_ledger.t + ; update_acc_set_witness : Acc_set_witness.t + } + + type serializable = + { stack_frame : + ( Token_id.Stable.V2.t + , Zkapp_command.Call_forest.With_hashes.Stable.V1.t ) + Stack_frame.Stable.V1.t + ; call_stack : + ( ( ( Token_id.Stable.V2.t + , Zkapp_command.Call_forest.With_hashes.Stable.V1.t ) + Stack_frame.Stable.V1.t + , Stack_frame.Digest.Stable.V1.t ) + With_hash.t + , Call_stack_digest.Stable.V1.t ) + With_stack_hash.Stable.V1.t + list + ; source_ledger_sparse : Mina_ledger.Sparse_ledger.t + ; update_acc_set_witness : Acc_set_witness.serializable + } + [@@deriving yojson] + + let of_serializable + ({ stack_frame; call_stack; source_ledger_sparse; update_acc_set_witness } : + serializable ) : t = + { stack_frame + ; call_stack + ; source_ledger_sparse + ; update_acc_set_witness = + Acc_set_witness.of_serializable update_acc_set_witness + } +end + +module Even_PC = struct + include Zeko_util.Even_PC + + type t = Zeko_util.Even_PC.t = { public_key : F.t } [@@deriving yojson] +end + +module Local_state = struct + type t = Txn_state.Local_state.t = + { stack_frame_digest : Stack_frame.Digest.t + ; call_stack_digest : Call_stack_digest.t + ; transaction_commitment : F.t + ; full_transaction_commitment : F.t + ; excess : Currency.Amount.Signed.t + ; account_update_index : Mina_numbers.Index.t + } + [@@deriving yojson] +end + +module Zkapp_rule_input = struct + type t = Rule_zkapp_command.Zkapp_rule_input.t = + { source_ledger : Ledger_hash.t + ; source_local_state : Local_state.t + ; sequencer : Even_PC.t + ; source_acc_set : Account_set.t + ; witness : Zkapp_rule_input_witness.t + } + + type serializable = + { source_ledger : Ledger_hash.t + ; source_local_state : Local_state.t + ; sequencer : Even_PC.t + ; source_acc_set : Account_set.t + ; witness : Zkapp_rule_input_witness.serializable + } + [@@deriving yojson] + + let of_serializable + ({ source_ledger; source_local_state; sequencer; source_acc_set; witness } : + serializable ) : t = + { source_ledger + ; source_local_state + ; sequencer + ; source_acc_set + ; witness = Zkapp_rule_input_witness.of_serializable witness + } +end + +module Per_account_update = struct + type t = Rule_zkapp_command.Per_account_update.t = + { account_updates : Zkapp_command.Digest.Forest.t + ; memo_hash : F.t + ; account_updates_data : Mina_base.Zkapp_command.Call_forest.With_hashes.t + ; shift_action_state : bool + } + [@@deriving yojson] +end + +module Verification_key = struct + type t = Compile_simple.Verification_key.t + + let to_yojson = + Fn.compose Pickles.Side_loaded.Verification_key.to_yojson + Compile_simple.Verification_key.to_pickles + + let of_yojson json : t Ppx_deriving_yojson_runtime.error_or = + match Pickles.Side_loaded.Verification_key.of_yojson json with + | Ok vk -> + Ok (Compile_simple.Verification_key.of_pickles vk) + | Error e -> + Error e +end + +module Zkapp_single_proved_input = struct + type t = Rule_zkapp_command.Zkapp_single_proved_input.t = + { base : Zkapp_rule_input.t + ; vk : Verification_key.t + ; zkapp_proof : Proof.t + ; first : Per_account_update.t + } + + type serializable = + { base : Zkapp_rule_input.serializable + ; vk : Verification_key.t + ; zkapp_proof : Proof.t + ; first : Per_account_update.t + } + [@@deriving yojson] + + let of_serializable ({ base; vk; zkapp_proof; first } : serializable) : t = + { base = Zkapp_rule_input.of_serializable base; vk; zkapp_proof; first } +end + +module Zkapp_single_unproved_input = struct + type t = Rule_zkapp_command.Zkapp_single_unproved_input.t = + { base : Zkapp_rule_input.t; first : Per_account_update.t } + + type serializable = + { base : Zkapp_rule_input.serializable; first : Per_account_update.t } + [@@deriving yojson] + + let of_serializable ({ base; first } : serializable) : t = + { base = Zkapp_rule_input.of_serializable base; first } +end + +module Zkapp_double_unproved_input = struct + type t = Rule_zkapp_command.Zkapp_double_unproved_input.t = + { base : Zkapp_rule_input.t + ; first : Per_account_update.t + ; second : Per_account_update.t + } + + type serializable = + { base : Zkapp_rule_input.serializable + ; first : Per_account_update.t + ; second : Per_account_update.t + } + [@@deriving yojson] + + let of_serializable ({ base; first; second } : serializable) : t = + { base = Zkapp_rule_input.of_serializable base; first; second } +end + +module Sparse_ledger_handler = struct + include Handler + + let of_yojson json : t Ppx_deriving_yojson_runtime.error_or = + match Sparse_ledger.of_yojson json with + | Ok sparse_ledger -> + Ok (unstage @@ Sparse_ledger.handler sparse_ledger) + | Error e -> + Error e +end + +module Base_witness = struct + type t = Rule_signed_command.Base_witness.t = + { ledger_path_handler : Handler.t + ; update_acc_set_witness : Acc_set_witness.t + } + + type serializable = + { ledger_path_handler : Sparse_ledger.t + ; update_acc_set_witness : Acc_set_witness.serializable + } + [@@deriving yojson] + + let of_serializable + ({ ledger_path_handler; update_acc_set_witness } : serializable) : t = + { ledger_path_handler = unstage @@ Sparse_ledger.handler ledger_path_handler + ; update_acc_set_witness = + Acc_set_witness.of_serializable update_acc_set_witness + } +end + +module Base_input = struct + type t = Rule_signed_command.Base_input.t = + { source_ledger : Ledger_hash.t + ; source_acc_set : Account_set.t + ; sequencer : Even_PC.t + ; transaction : Mina_transaction.Transaction_union.t + ; witness : Base_witness.t + } + + type serializable = + { source_ledger : Ledger_hash.t + ; source_acc_set : Account_set.t + ; sequencer : Even_PC.t + ; transaction : Signed_command.t + ; witness : Base_witness.serializable + } + [@@deriving yojson] + + let of_serializable + ({ source_ledger; source_acc_set; sequencer; transaction; witness } : + serializable ) : t = + { source_ledger + ; source_acc_set + ; sequencer + ; transaction = + Mina_transaction.Transaction_union.of_transaction (Command transaction) + ; witness = Base_witness.of_serializable witness + } +end + +module Txn_snark_witness = struct + module Zkapp_command_segment = struct + type t = + | Single_unproved of Zkapp_single_unproved_input.serializable + | Double_unproved of Zkapp_double_unproved_input.serializable + | Single_proved of Zkapp_single_proved_input.serializable + [@@deriving yojson] + end + + type t = + | Signed_command of Base_input.serializable + | Zkapp_command of Zkapp_command_segment.t + [@@deriving yojson] +end + +module Slot_range = struct + type t = Zeko_util.Slot_range.t = { lower : Slot.t; upper : Slot.t } + [@@deriving yojson] +end + +module Zeko_stmt = struct + type t = Txn_state.Zeko_stmt.t = + { source_ledger : Ledger_hash.t + ; target_ledger : Ledger_hash.t + ; source_acc_set : Account_set.t + ; target_acc_set : Account_set.t + ; sequencer : Even_PC.t + ; accumulated_fees : Currency.Amount.Signed.t + ; slot_range : Slot_range.t + ; source_local_state : Local_state.t + ; target_local_state : Local_state.t + } + [@@deriving yojson] +end + +module Merge_input = struct + type t = Rule_txn_merge.Merge_input.t = + { left : Zeko_stmt.t + ; left_proof : Proof.t + ; right : Zeko_stmt.t + ; right_proof : Proof.t + } + [@@deriving yojson] +end + +module Make_serializable_snark (Inputs : sig + module Stmt : sig + type t [@@deriving yojson] + end + + module System : sig + type t + + val make_unchecked : ?proof:Proof_V.t -> Stmt.t -> t + end +end) = +struct + open Inputs + + type t = System.t + + type serializable = Stmt.t * Proof.t [@@deriving yojson] + + let of_serializable (stmt, proof) : t = System.make_unchecked ~proof stmt +end + +module Txn_snark = Make_serializable_snark (struct + module Stmt = Zeko_stmt + module System = Txn_rules +end) + +module Ase = struct + module With_length = struct + include Ase.With_length + + module Stmt = struct + type t = Ase.With_length.Stmt.t = + { action_state : F.t; length : Checked32.t } + [@@deriving yojson] + end + + type trans = Ase.With_length.trans = { source : Stmt.t; target : Stmt.t } + [@@deriving yojson] + end + + module Without_length = struct + include Ase.Without_length + + module Stmt = struct + type t = F.t [@@deriving yojson] + end + + type trans = Ase.Without_length.trans = { source : Stmt.t; target : Stmt.t } + [@@deriving yojson] + end + + module type Ase_inst_intf = sig + type t + + module Ase_state : sig + type t [@@deriving yojson] + end + + module Action_state : sig + type t [@@deriving yojson] + end + + module Stmt : sig + type t = { source : Action_state.t; target : Action_state.t } + end + + val make : + proof_source:Ase_state.t + -> proof_target:Ase_state.t + -> ?proof:Proof_V.t + -> Ase_state.t + -> field list + -> t + + val get_iterations : int + end + + module Make_serializable_ase (Inputs : sig + module Ase_system : sig + module Stmt : sig + type t [@@deriving yojson] + end + end + + module Action_state : sig + type t [@@deriving yojson] + end + + module Ase_inst : + Ase_inst_intf + with module Ase_state := Ase_system.Stmt + and module Action_state := Action_state + end) = + struct + open Inputs + include Ase_inst + + type t = Ase_inst.t + + module Stmt = struct + type t = Ase_inst.Stmt.t = + { source : Action_state.t; target : Action_state.t } + [@@deriving yojson] + end + + type serializable = + { proof : Compile_simple.Proof.t option + ; proof_target : Ase_system.Stmt.t + ; init : Ase_system.Stmt.t + ; excess : F.t list + } + [@@deriving yojson] + + let of_serializable ({ proof; proof_target; init; excess } : serializable) : + t = + Ase_inst.make ?proof ~proof_source:init ~proof_target init excess + end +end + +module Make_serializable_action_state + (Action_state : Rollup_state.Action_state_type) = +struct + type t = F.t [@@deriving yojson] + + module With_length = struct + type t = Action_state.With_length.t = { state : F.t; length : Checked32.t } + [@@deriving yojson] + end +end + +module Inner_action_state = + Make_serializable_action_state (Rollup_state.Inner_action_state) +module Outer_action_state = + Make_serializable_action_state (Rollup_state.Outer_action_state) + +module Inner_sync = struct + module Ase_inst = Ase.Make_serializable_ase (struct + module Ase_system = Ase.With_length + module Action_state = Outer_action_state.With_length + module Ase_inst = Rule_inner_sync.Ase_inst + end) + + module Witness = struct + type t = Rule_inner_sync.Witness.t = + { public_key : Public_key.Compressed.t; vk_hash : F.t; ase : Ase_inst.t } + + type serializable = + { public_key : Public_key.Compressed.t; ase : Ase_inst.serializable } + [@@deriving yojson] + + let of_serializable ({ public_key; ase } : serializable) ~vk_hash : t = + { public_key; vk_hash; ase = Ase_inst.of_serializable ase } + end +end + +module Outer_commit = struct + module Path = Make_serializable_path (struct + module PathStep = struct + type t = Outer_rules.Rule_commit_inst.PathElt.t + + let to_yojson ({ right_side } : t) = + `Assoc [ ("right_side", Field.to_yojson right_side) ] + + let of_yojson json : t Ppx_deriving_yojson_runtime.error_or = + let open Yojson.Safe.Util in + try + Ok + { right_side = member "right_side" json |> Field.of_yojson |> ok_exn + } + with e -> Error (Exn.to_string e) + end + end) + + module Ase_outer_inst = Ase.Make_serializable_ase (struct + module Ase_system = Ase.Without_length + module Action_state = Outer_action_state + module Ase_inst = Rule_commit.Ase_outer_inst + end) + + module Ase_inner_inst = Ase.Make_serializable_ase (struct + module Ase_system = Ase.With_length + module Action_state = Inner_action_state.With_length + module Ase_inst = Rule_commit.Ase_inner_inst + end) + + module Verify_both_ases = Make_serializable_snark (struct + module Stmt = struct + type t = Ase_outer_inst.Stmt.t * Ase_inner_inst.Stmt.t [@@deriving yojson] + end + + module System = Rule_commit.Verify_both_ases + end) + + module Witness = struct + type t = Outer_rules.Rule_commit_inst.Witness.t = + { txn_snark : Txn_snark.t + ; public_key : Public_key.Compressed.t + ; vk_hash : F.t + ; verify_both_ases : Verify_both_ases.t + ; old_inner_acc : Account.t + ; old_inner_acc_path : Path.t + ; new_inner_acc : Account.t + ; new_inner_acc_path : Path.t + ; da_signature : Signature_lib.Schnorr.Chunked.Signature.t + ; da_key : Even_PC.t + } + + type serializable = + { txn_snark : Txn_snark.serializable + ; public_key : Public_key.Compressed.t + ; verify_both_ases : Verify_both_ases.serializable + ; old_inner_acc : Account.t + ; old_inner_acc_path : Path.t + ; new_inner_acc : Account.t + ; new_inner_acc_path : Path.t + ; da_signature : Signature.t + ; da_key : Even_PC.t + } + [@@deriving yojson] + + let of_serializable + ({ txn_snark + ; public_key + ; verify_both_ases + ; old_inner_acc + ; old_inner_acc_path + ; new_inner_acc + ; new_inner_acc_path + ; da_signature + ; da_key + } : + serializable ) ~vk_hash : t = + { txn_snark = Txn_snark.of_serializable txn_snark + ; public_key + ; vk_hash + ; verify_both_ases = Verify_both_ases.of_serializable verify_both_ases + ; old_inner_acc + ; old_inner_acc_path + ; new_inner_acc + ; new_inner_acc_path + ; da_signature + ; da_key + } + end +end diff --git a/src/app/zeko/sequencer/run.ml b/src/app/zeko/sequencer/run.ml index 61cb7d3d11..9abd922442 100644 --- a/src/app/zeko/sequencer/run.ml +++ b/src/app/zeko/sequencer/run.ml @@ -7,8 +7,8 @@ module Graphql_cohttp_async = module Sequencer = Zeko_sequencer.Sequencer let run ~port ~zkapp_pk ~max_pool_size ~commitment_period ~da_config ~da_quorum - ~db_dir ~l1_uri ~archive_uri ~signer ~network_id ~deposit_delay_blocks - ~provers () = + ~db_dir ~imt_dir ~l1_uri ~archive_uri ~signer ~network_id + ~deposit_delay_blocks ~provers () = let zkapp_pk = Option.( value ~default:Signature_lib.Public_key.Compressed.empty @@ -17,9 +17,9 @@ let run ~port ~zkapp_pk ~max_pool_size ~commitment_period ~da_config ~da_quorum let sequencer = Thread_safe.block_on_async_exn (fun () -> Sequencer.create ~logger:(Logger.create ()) ~zkapp_pk ~max_pool_size - ~da_config ~da_quorum ~db_dir:(Some db_dir) ~l1_uri ~archive_uri - ~commitment_period_sec:commitment_period ~network_id - ~deposit_delay_blocks + ~da_config ~da_quorum ~db_dir:(Some db_dir) ~imt_dir:(Some imt_dir) + ~l1_uri ~archive_uri ~commitment_period_sec:commitment_period + ~network_id ~deposit_delay_blocks ~signer: Signature_lib.( Keypair.of_private_key_exn @@ -78,7 +78,11 @@ let () = and db_dir = flag "--db-dir" (optional_with_default "db" string) - ~doc:"string Directory to store the database" + ~doc:"string Directory to store the Ledger database" + and imt_dir = + flag "--imt-dir" + (optional_with_default "db" string) + ~doc:"string Directory to store the Indexed Merkle Tree database" and network_id = flag "--network-id" (optional_with_default "testnet" string) @@ -99,6 +103,6 @@ let () = in let provers = List.map provers ~f:Host_and_port.of_string in run ~port ~zkapp_pk ~max_pool_size ~commitment_period ~da_config ~da_quorum - ~db_dir ~l1_uri ~archive_uri ~signer ~network_id ~deposit_delay_blocks - ~provers ) + ~db_dir ~imt_dir ~l1_uri ~archive_uri ~signer ~network_id + ~deposit_delay_blocks ~provers ) |> Command_unix.run diff --git a/src/app/zeko/sequencer/tests/dune b/src/app/zeko/sequencer/tests/dune new file mode 100644 index 0000000000..59f0f4c598 --- /dev/null +++ b/src/app/zeko/sequencer/tests/dune @@ -0,0 +1,6 @@ +(executable + (name sequencer_test) + (libraries sequencer_lib compile_simple_fake) + (preprocess + (pps ppx_let ppx_jane ppx_mina)) + (modules sequencer_test)) diff --git a/src/app/zeko/sequencer/tests/sequencer_test.ml b/src/app/zeko/sequencer/tests/sequencer_test.ml new file mode 100644 index 0000000000..0d5d9f4ba5 --- /dev/null +++ b/src/app/zeko/sequencer/tests/sequencer_test.ml @@ -0,0 +1,704 @@ +open Core_kernel +open Async +open Mina_base +open Signature_lib +open Sequencer_lib +open Zeko_sequencer +open Sequencer + +let constraint_constants = Zeko_constants.constraint_constants + +let compile_time_genesis = + let consensus_constants = + let protocol_constants : Genesis_constants.Protocol.t = + { k = 1 + ; slots_per_epoch = 1000 + ; slots_per_sub_window = 1 + ; grace_period_slots = 1 + ; delta = 1 + ; genesis_state_timestamp = Int64.one + } + in + Consensus.Constants.create ~constraint_constants ~protocol_constants + in + Mina_state.Genesis_protocol_state.t + ~genesis_ledger:Genesis_ledger.(Packed.t for_unit_tests) + ~genesis_epoch_data:Consensus.Genesis_epoch_data.for_unit_tests + ~constraint_constants ~consensus_constants + ~genesis_body_reference:Staged_ledger_diff.genesis_body_reference + +let start_time = Time.now () + +let logger = Logger.create () + +module T = Transaction_snark.Make (struct + let constraint_constants = Zeko_constants.constraint_constants + + let proof_level = Genesis_constants.Proof_level.Full +end) + +let number_of_transactions = 5 + +let gql_uri = + { Cli_lib.Flag.Types.value = Uri.of_string "http://localhost:8080/graphql" + ; name = "gql-uri" + } + +let da_config = Da_layer.Client.Config.of_string_list [ "127.0.0.1:8555" ] + +let provers = + [ Host_and_port.create ~host:"localhost" ~port:9990 + ; Host_and_port.create ~host:"localhost" ~port:9991 + ] + +module Sequencer_test_spec = struct + type t = + { zkapp_keypair : Keypair.t + ; signer : Keypair.t + ; ephemeral_ledger : L.t (* The ledger to test the expected outcome *) + ; specs : Mina_transaction_logic.For_tests.Transaction_spec.t list + (* Transaction specs *) + ; sequencer : Sequencer.t + } + + let gen ?(delay_deposit = 0) () = + let zkapp_keypair = Keypair.create () in + + (* Create signer *) + let rec create_even_signer () = + let signer = Keypair.create () in + let compressed = Public_key.compress signer.public_key in + if compressed.is_odd then create_even_signer () else signer + in + let signer = create_even_signer () in + Thread_safe.block_on_async_exn (fun () -> + let%bind _res = + Gql_client.For_tests.create_account gql_uri + (Public_key.compress signer.public_key) + in + return () ) ; + + let%bind.Quickcheck.Generator { init_ledger; specs } = + Mina_transaction_logic.For_tests.Test_spec.mk_gen + ~num_transactions:number_of_transactions () + in + + let initial_inner_account = + Thread_safe.block_on_async_exn Deploy.Z.Inner.initial_account + in + let genesis_accounts = + (Zeko_constants.inner_account_id, initial_inner_account) + :: ( Array.map init_ledger ~f:(fun (keypair, balance) -> + let pk = Signature_lib.Public_key.compress keypair.public_key in + let account_id = Account_id.create pk Token_id.default in + let balance = Unsigned.UInt64.of_int64 balance in + let account = + Account.create account_id (Currency.Balance.of_uint64 balance) + in + (account_id, account) ) + |> Array.to_list ) + in + + (* Init ephemeral ledger *) + let ephemeral_ledger = + L.create_ephemeral ~depth:constraint_constants.ledger_depth () + in + List.iter genesis_accounts ~f:(fun (aid, acc) -> + L.create_new_account_exn ephemeral_ledger aid acc ) ; + let account_set_hash = + let db = + Indexed_merkle_tree.Db.create ~depth:constraint_constants.ledger_depth + () + in + let tids = + List.map genesis_accounts ~f:(fun (aid, _) -> + Account_id.derive_token_id ~owner:aid ) + in + List.iter tids ~f:(fun tid -> + let _, _ = Indexed_merkle_tree.Db.get_or_create_entry_exn db tid in + () ) ; + Indexed_merkle_tree.Db.merkle_root db + in + + (* Post genesis batch *) + Thread_safe.block_on_async_exn (fun () -> + match%bind + Da_layer.Client.distribute_genesis_diff ~logger ~config:da_config + ~ledger:ephemeral_ledger + with + | Ok _ -> + return () + | Error e -> + Error.raise e ) ; + + let stub_pk = + Public_key.compress signer.public_key |> C.Zeko_util.Even_PC.create_exn + in + + (* Deploy *) + Thread_safe.block_on_async_exn (fun () -> + ( print_endline + @@ Public_key.( + Compressed.to_base58_check @@ compress zkapp_keypair.public_key) ) ; + let%bind nonce = + Gql_client.infer_nonce gql_uri (Public_key.compress signer.public_key) + in + let%bind command = + Deploy.deploy_command_exn ~signer ~zkapp:zkapp_keypair + ~fee:(Currency.Fee.of_mina_int_exn 1) + ~nonce ~initial_ledger:ephemeral_ledger ~constraint_constants + ~account_set_hash ~pause_key:stub_pk ~sequencer:stub_pk + ~da_key:stub_pk + in + let%bind _ = Gql_client.send_zkapp gql_uri command in + let%bind _created = Gql_client.For_tests.create_new_block gql_uri in + return () ) ; + + (* Init sequencer *) + let sequencer = + Thread_safe.block_on_async_exn (fun () -> + Sequencer.create ~logger + ~zkapp_pk: + Signature_lib.Public_key.(compress zkapp_keypair.public_key) + ~max_pool_size:10 ~commitment_period_sec:0. ~da_config ~da_quorum:1 + ~db_dir:None ~imt_dir:None ~l1_uri:gql_uri ~archive_uri:gql_uri + ~signer ~network_id:"testnet" ~deposit_delay_blocks:delay_deposit + ~provers ) + in + + Quickcheck.Generator.return + { zkapp_keypair; signer; ephemeral_ledger; specs; sequencer } +end + +(* let sign_cmd (cmd : Zkapp_command.t) (keys : Keypair.t list) : + Zkapp_command.t = + let full_commitment = + Zkapp_command.Transaction_commitment.create_complete + (Zkapp_command.commitment cmd) + ~memo_hash:(Signed_command_memo.hash cmd.memo) + ~fee_payer_hash: + (Zkapp_command.Digest.Account_update.create + (Account_update.of_fee_payer cmd.fee_payer) ) + in + let sign_raw (pk : Public_key.Compressed.t) msg = + printf "Signing for %s\n" (Public_key.Compressed.to_base58_check pk) ; + let rec go (keys : Keypair.t list) msg = + match keys with + | (kp : Keypair.t) :: keys -> + if + Public_key.Compressed.equal + (Public_key.compress kp.public_key) + pk + then ( + printf "key found\n" ; + Signature_lib.Schnorr.Chunked.sign + ~signature_kind:Mina_signature_kind.Testnet kp.private_key + (Random_oracle.Input.Chunked.field msg) ) + else ( + printf "not equal to %s\n" + Public_key.( + kp.public_key |> compress |> Compressed.to_base58_check) ; + go keys msg ) + | [] -> + failwithf "key not found: %s\n" + (Public_key.Compressed.to_base58_check pk) + () + in + go keys msg + in + let rec sign_tree (tree : Zeko_util.call_forest_tree) : + Zeko_util.call_forest_tree = + { tree with + account_update = + { tree.account_update with + authorization = + ( match tree.account_update.body.authorization_kind with + | Signature -> + assert tree.account_update.body.use_full_commitment ; + Signature + (sign_raw tree.account_update.body.public_key + full_commitment ) + | _ -> + tree.account_update.authorization ) + } + ; calls = sign_forest tree.calls + } + and sign_forest (forest : Zeko_util.call_forest) : Zeko_util.call_forest = + List.map ~f:(fun tree -> { tree with elt = sign_tree tree.elt }) forest + in + { cmd with + fee_payer = + { cmd.fee_payer with + authorization = + ( if + Public_key.Compressed.( + equal empty cmd.fee_payer.body.public_key) + then cmd.fee_payer.authorization + else sign_raw cmd.fee_payer.body.public_key full_commitment ) + } + ; account_updates = sign_forest cmd.account_updates + } *) + +let () = + print_endline "Started test 'apply commands and commit'" ; + Quickcheck.test ~trials:1 (Sequencer_test_spec.gen ()) + ~f:(fun { zkapp_keypair; signer; ephemeral_ledger; specs; sequencer } -> + let batch1, batch2 = List.split_n specs 3 in + + (* Apply first batch *) + let () = + Thread_safe.block_on_async_exn (fun () -> + let source_ledger_hash = get_root sequencer in + + [%test_eq: Ledger_hash.t] source_ledger_hash + (L.merkle_root ephemeral_ledger) ; + + let%bind () = + Deferred.List.iteri batch1 ~f:(fun i spec -> + [%test_eq: Ledger_hash.t] (get_root sequencer) + (L.merkle_root ephemeral_ledger) ; + let%map result = + match i % 2 = 0 with + | true -> + let command = + Mina_transaction_logic.For_tests.account_update_send + spec + in + ( match + L.apply_zkapp_command_unchecked ephemeral_ledger + command ~constraint_constants + ~global_slot: + Mina_numbers.Global_slot_since_genesis.zero + ~state_view: + (Mina_state.Protocol_state.Body.view + compile_time_genesis.data.body ) + with + | Ok (applied, _) -> + [%test_eq: Transaction_status.t] + applied.command.status Applied + | Error e -> + Error.raise + (Error.create "Expected ledger apply failed" e + Error.sexp_of_t ) ) ; + + apply_user_command sequencer (Zkapp_command command) + | false -> + let command = + Mina_transaction_logic.For_tests.command_send spec + in + ( match + L.apply_user_command_unchecked ephemeral_ledger + command ~constraint_constants + ~txn_global_slot: + Mina_numbers.Global_slot_since_genesis.zero + with + | Ok applied -> + [%test_eq: Transaction_status.t] + applied.common.user_command.status Applied + | Error e -> + Error.raise + (Error.create "Expected ledger apply failed" e + Error.sexp_of_t ) ) ; + + apply_user_command sequencer (Signed_command command) + in + + let witnesses = + match result with + | Ok result -> + result + | Error e -> + Error.raise e + in + List.iter witnesses ~f:(fun witness -> + don't_wait_for + @@ Merger.P.add_job sequencer.merger sequencer.merger_ctx + ~data:witness ) ) + in + + let target_ledger_hash = get_root sequencer in + + [%test_eq: Ledger_hash.t] target_ledger_hash + (L.merkle_root ephemeral_ledger) ; + + return () ) + in + + (* First commit *) + Thread_safe.block_on_async_exn (fun () -> + let%bind _ = commit sequencer in + let%bind () = Snark_queue.wait_to_finish sequencer.snark_q in + let%bind () = Executor.wait_to_finish sequencer.merger_ctx.executor in + let%bind committed_ledger_hash = + Gql_client.infer_committed_state gql_uri + ~signer_pk:(Public_key.compress signer.public_key) + ~zkapp_pk:(Public_key.compress zkapp_keypair.public_key) + in + let target_ledger_hash = get_root sequencer in + [%test_eq: Ledger_hash.t] committed_ledger_hash target_ledger_hash ; + + Deferred.unit ) ; + + (* To test nonce inferring from pool *) + (* The first commit is still in the pool *) + Executor.refresh_nonce sequencer.merger_ctx.executor ; + + (* Apply second batch *) + Thread_safe.block_on_async_exn (fun () -> + let source_ledger_hash = get_root sequencer in + + [%test_eq: Ledger_hash.t] source_ledger_hash + (L.merkle_root ephemeral_ledger) ; + + let%bind () = + Deferred.List.iteri batch2 ~f:(fun i spec -> + let%map result = + match i % 2 = 0 with + | true -> + let command = + Mina_transaction_logic.For_tests.account_update_send + spec + in + ( match + L.apply_zkapp_command_unchecked ephemeral_ledger + command ~constraint_constants + ~global_slot: + Mina_numbers.Global_slot_since_genesis.zero + ~state_view: + (Mina_state.Protocol_state.Body.view + compile_time_genesis.data.body ) + with + | Ok _ -> + () + | Error e -> + Error.raise + (Error.create "Expected ledger apply failed" e + Error.sexp_of_t ) ) ; + + apply_user_command sequencer (Zkapp_command command) + | false -> + let command = + Mina_transaction_logic.For_tests.command_send spec + in + ( match + L.apply_user_command_unchecked ephemeral_ledger + command ~constraint_constants + ~txn_global_slot: + Mina_numbers.Global_slot_since_genesis.zero + with + | Ok _ -> + () + | Error e -> + Error.raise + (Error.create "Expected ledger apply failed" e + Error.sexp_of_t ) ) ; + + apply_user_command sequencer (Signed_command command) + in + + let witnesses = + match result with + | Ok result -> + result + | Error e -> + Error.raise e + in + + List.iter witnesses ~f:(fun witness -> + don't_wait_for + @@ Merger.P.add_job sequencer.merger sequencer.merger_ctx + ~data:witness ) ) + in + + let target_ledger_hash = get_root sequencer in + + [%test_eq: Ledger_hash.t] target_ledger_hash + (L.merkle_root ephemeral_ledger) ; + + return () ) ; + + (* Second commit *) + let final_ledger_hash = + Thread_safe.block_on_async_exn (fun () -> + let%bind _ = commit sequencer in + let%bind () = Snark_queue.wait_to_finish sequencer.snark_q in + let%bind () = + Executor.wait_to_finish sequencer.merger_ctx.executor + in + let%bind _created = Gql_client.For_tests.create_new_block gql_uri in + let%bind committed_ledger_hash = + Gql_client.fetch_committed_state gql_uri + Signature_lib.Public_key.(compress zkapp_keypair.public_key) + in + let target_ledger_hash = get_root sequencer in + [%test_eq: Ledger_hash.t] committed_ledger_hash target_ledger_hash ; + + return target_ledger_hash ) + in + + (* Try to bootstrap again *) + Thread_safe.block_on_async_exn (fun () -> + let%bind new_sequencer = + Sequencer.create ~logger + ~zkapp_pk: + Signature_lib.Public_key.(compress zkapp_keypair.public_key) + ~max_pool_size:10 ~commitment_period_sec:0. ~da_config + ~da_quorum:1 ~db_dir:None ~imt_dir:None ~l1_uri:gql_uri + ~archive_uri:gql_uri ~signer ~network_id:"testnet" + ~deposit_delay_blocks:0 ~provers + in + return + @@ [%test_eq: Frozen_ledger_hash.t] (get_root new_sequencer) + final_ledger_hash ) ) + +let () = + print_endline "Started test 'dummy signature should fail'" ; + Quickcheck.test ~trials:1 (Sequencer_test_spec.gen ()) + ~f:(fun { zkapp_keypair; signer; ephemeral_ledger; specs; sequencer } -> + let dummy_signature_command : Zkapp_command.t = + let command = + Mina_transaction_logic.For_tests.account_update_send + (List.hd_exn specs) + in + { command with + account_updates = + Zkapp_command.Call_forest.map command.account_updates + ~f:(fun account_update -> + match Account_update.authorization account_update with + | Signature _ -> + { account_update with + authorization = Signature Signature.dummy + } + | _ -> + account_update ) + } + in + let result = + Thread_safe.block_on_async_exn (fun () -> + apply_user_command sequencer (Zkapp_command dummy_signature_command) ) + in + match result with + | Error e + when String.is_substring ~substring:"Invalid_signature" + (Error.to_string_hum e) -> + () + | Ok _ -> + failwith "Transaction should have failed" + | Error unexpected_error -> + Error.raise unexpected_error ) + +(* let () = + print_endline "Started test 'deposits'" ; + Quickcheck.test ~trials:1 (Sequencer_test_spec.gen ~delay_deposit:2 ()) + ~f:(fun { zkapp_keypair; signer; ephemeral_ledger; specs; sequencer } -> + (* Create l1 accounts *) + let l1_accounts = + Array.create ~len:5 () + |> Array.map ~f:Signature_lib.Keypair.create + |> Array.to_list + in + Thread_safe.block_on_async_exn (fun () -> + Deferred.List.iter l1_accounts ~f:(fun keypair -> + let%bind _res = + Gql_client.For_tests.create_account gql_uri + (Signature_lib.Public_key.compress keypair.public_key) + in + return () ) ) ; + + (* Send deposits *) + let deposits = + Thread_safe.block_on_async_exn (fun () -> + let submit_deposit ~fee (signer : Keypair.t) deposit = + let%bind nonce = + Gql_client.fetch_nonce gql_uri + (Signature_lib.Public_key.compress signer.public_key) + in + let fee_payer = + Account_update.Fee_payer. + { body = + { public_key = Public_key.compress signer.public_key + ; fee = Currency.Fee.of_mina_int_exn fee + ; valid_until = None + ; nonce = Account.Nonce.of_uint32 nonce + } + ; authorization = Signature.dummy + } + in + let%bind transfer_update = + M.Outer.submit_deposit + ~outer_public_key: + (Public_key.compress zkapp_keypair.public_key) + ~deposit + in + let transferrer_update : Account_update.t = + { body = + { Account_update.Body.dummy with + public_key = Public_key.compress signer.public_key + ; balance_change = + Currency.Amount.Signed.( + negate @@ of_unsigned deposit.amount) + ; use_full_commitment = true + ; authorization_kind = Signature + } + ; authorization = Signature Signature.dummy + } + in + let transfer_cmd : Zkapp_command.t = + { fee_payer + ; account_updates = + Zkapp_command.Call_forest.( + cons_tree transfer_update @@ accumulate_hashes' + @@ of_account_updates + ~account_update_depth:(fun _ -> 0) + [ transferrer_update ]) + ; memo = Signed_command_memo.empty + } + in + return @@ sign_cmd transfer_cmd [ signer ] + in + let account1 = List.nth_exn l1_accounts 0 in + let account2 = List.nth_exn l1_accounts 1 in + let account3 = List.nth_exn l1_accounts 2 in + let account4 = List.nth_exn l1_accounts 3 in + let account5 = List.nth_exn l1_accounts 4 in + + let deposit1 : Zkapps_rollup.TR.t = + { recipient = Public_key.compress account1.public_key + ; amount = Currency.Amount.of_mina_int_exn 10 + } + in + let deposit2 : Zkapps_rollup.TR.t = + { recipient = Public_key.compress account2.public_key + ; amount = Currency.Amount.of_mina_int_exn 20 + } + in + let deposit3 : Zkapps_rollup.TR.t = + { recipient = Public_key.compress account3.public_key + ; amount = Currency.Amount.of_mina_int_exn 30 + } + in + let deposit4 : Zkapps_rollup.TR.t = + { recipient = Public_key.compress account4.public_key + ; amount = Currency.Amount.of_mina_int_exn 40 + } + in + let deposit5 : Zkapps_rollup.TR.t = + { recipient = Public_key.compress account5.public_key + ; amount = Currency.Amount.of_mina_int_exn 50 + } + in + + (* Send deposits for accounts 1 and 2 *) + let%bind _ = + submit_deposit ~fee:5 account1 deposit1 + >>= Gql_client.send_zkapp gql_uri + in + let%bind _ = + submit_deposit ~fee:4 account2 deposit2 + >>= Gql_client.send_zkapp gql_uri + in + + (* Create 2 new blocks for delay *) + let%bind _created = + Gql_client.For_tests.create_new_block gql_uri + in + let%bind _created = + Gql_client.For_tests.create_new_block gql_uri + in + + (* Send deposits for accounts 3, 4 and 5 which won't be processed *) + let%bind _ = + submit_deposit ~fee:3 account3 deposit3 + >>= Gql_client.send_zkapp gql_uri + in + let%bind _ = + submit_deposit ~fee:2 account4 deposit4 + >>= Gql_client.send_zkapp gql_uri + in + let%bind _ = + submit_deposit ~fee:1 account5 deposit5 + >>= Gql_client.send_zkapp gql_uri + in + let%bind _created = + Gql_client.For_tests.create_new_block gql_uri + in + return [ deposit1; deposit2; deposit3; deposit4; deposit5 ] ) + in + + (* Commit should process first 2 deposits *) + Thread_safe.block_on_async_exn (fun () -> + let%bind _ = commit sequencer in + let%bind () = Snark_queue.wait_to_finish sequencer.snark_q in + let%bind () = + Executor.wait_to_finish sequencer.merger_ctx.executor + in + let%bind _created = + Gql_client.For_tests.create_new_block gql_uri + in + let%bind committed_ledger_hash = + Gql_client.fetch_committed_state gql_uri + Signature_lib.Public_key.(compress zkapp_keypair.public_key) + in + let target_ledger_hash = get_root sequencer in + [%test_eq: Ledger_hash.t] committed_ledger_hash target_ledger_hash ; + + return () ) ; + + let deposits_state = + Utils.get_inner_deposits_state_exn (L.of_database sequencer.db) + in + let expected_deposits_state = + (* Expected should be only first 2 deposits *) + List.take deposits 2 + |> List.fold ~init:Zkapp_account.Actions.empty_state_element + ~f:(fun acc transfer -> + Zkapp_account.Actions.push_events acc + (Zkapps_rollup.TR.to_actions transfer) ) + in + [%test_eq: Field.t] deposits_state expected_deposits_state ; + + print_endline "Processing remaining deposits" ; + + (* Create new blocks to process remaining deposits *) + Thread_safe.block_on_async_exn (fun () -> + let%bind _created = + Gql_client.For_tests.create_new_block gql_uri + in + let%bind _created = + Gql_client.For_tests.create_new_block gql_uri + in + return () ) ; + + (* Commit should process remaining deposits *) + Thread_safe.block_on_async_exn (fun () -> + let%bind _ = commit sequencer in + let%bind () = Snark_queue.wait_to_finish sequencer.snark_q in + let%bind () = + Executor.wait_to_finish sequencer.merger_ctx.executor + in + let%bind _created = + Gql_client.For_tests.create_new_block gql_uri + in + let%bind committed_ledger_hash = + Gql_client.fetch_committed_state gql_uri + Signature_lib.Public_key.(compress zkapp_keypair.public_key) + in + let target_ledger_hash = get_root sequencer in + [%test_eq: Ledger_hash.t] committed_ledger_hash target_ledger_hash ; + + return () ) ; + + let deposits_state = + Utils.get_inner_deposits_state_exn (L.of_database sequencer.db) + in + let expected_deposits_state = + List.fold deposits ~init:Zkapp_account.Actions.empty_state_element + ~f:(fun acc transfer -> + Zkapp_account.Actions.push_events acc + (Zkapps_rollup.TR.to_actions transfer) ) + in + [%test_eq: Field.t] deposits_state expected_deposits_state ) *) + +let () = + printf "Sequencer tests took %s\n" + (Time.Span.to_string (Time.diff (Time.now ()) start_time)) diff --git a/src/app/zeko/sequencer/tests/testing_ledger/dune b/src/app/zeko/sequencer/tests/testing_ledger/dune index 979a32e861..261988be90 100644 --- a/src/app/zeko/sequencer/tests/testing_ledger/dune +++ b/src/app/zeko/sequencer/tests/testing_ledger/dune @@ -1,75 +1,8 @@ (executable (name run) (libraries - zkapps_rollup sequencer_lib - ;; mina ;; - mina_base - mina_base.import - mina_ledger - mina_transaction - mina_transaction_logic - mina_state - mina_wire_types - mina_numbers - mina_graphql - mina_signature_kind - graphql_wrapper - transaction_snark - transaction_protocol_state - transaction_witness - genesis_constants - genesis_ledger - consensus - staged_ledger_diff - with_hash - currency - signature_lib - sgn - fields_derivers.graphql - fields_derivers_zkapps - snark_params - unsigned_extended - pickles - pickles.backend - pickles_types - transition_frontier - transition_frontier_base - base58_check - graphql_lib - data_hash_lib - sync_status - daemon_rpcs - rocksdb - snarky.intf - snarky.backendless - key_value_database - random_oracle - random_oracle_input - init - cli_lib - ;; opam libraries ;; - uri - re2 - stdio - graphql - graphql-async - graphql_parser - integers - core - core_kernel - async_kernel - async - async_unix - base - base.caml - yojson - sexplib - sexplib0 - fileutils - ppx_inline_test.config - cohttp - cohttp-async + ;; opam ;; core_unix.command_unix) (preprocess (pps ppx_jane ppx_mina)) diff --git a/src/app/zeko/sequencer/tests/testing_ledger/gql.ml b/src/app/zeko/sequencer/tests/testing_ledger/gql.ml index e35794fb0b..b0ce9c94c9 100644 --- a/src/app/zeko/sequencer/tests/testing_ledger/gql.ml +++ b/src/app/zeko/sequencer/tests/testing_ledger/gql.ml @@ -1523,26 +1523,35 @@ module Mutations = struct | None -> return (Error "Signature verification failed") ) in + let hash = + Transaction_hash.hash_command + (Signed_command (Signed_command.forget_check command)) + in let%bind.Deferred.Result status = match State.add_command_to_pool t ~command:(Signed_command command) with | `Applied -> + printf "Applied with hash %s\n%!" + (Transaction_hash.to_base58_check hash) ; return (Ok Types.Command_status.Applied) | `Enqueued -> + printf "Enqueued with hash %s\n%!" + (Transaction_hash.to_base58_check hash) ; return (Ok Types.Command_status.Enqueued) | `Failed err -> + printf "Failed with hash %s, error: %s\n%!" + (Transaction_hash.to_base58_check hash) + (Error.to_string_hum err) ; return (Error (Error.to_string_hum err)) in - let command = Signed_command.forget_check command in let cmd = + let command = Signed_command.forget_check command in { Types.User_command.With_status.data = command; status = Applied } in let cmd_with_hash = Types.User_command.With_status.map cmd ~f:(fun cmd -> - { With_hash.data = cmd - ; hash = Transaction_hash.hash_command (Signed_command cmd) - } ) + { With_hash.data = cmd; hash } ) in Deferred.Result.return (Types.User_command.mk_payment cmd_with_hash) ) diff --git a/src/app/zeko/sequencer/tests/testing_ledger/state.ml b/src/app/zeko/sequencer/tests/testing_ledger/state.ml index eff57746d1..9dc1656281 100644 --- a/src/app/zeko/sequencer/tests/testing_ledger/state.ml +++ b/src/app/zeko/sequencer/tests/testing_ledger/state.ml @@ -10,23 +10,26 @@ module Ledger = Mina_ledger.Ledger let logger = Logger.create () module Constants = struct - let constraint_constants = Genesis_constants.Compiled.constraint_constants - - let genesis_constants = Genesis_constants.Compiled.genesis_constants + let constraint_constants = Zeko_constants.constraint_constants let consensus_constants = - Consensus.Constants.create ~constraint_constants - ~protocol_constants:genesis_constants.protocol - - let state_body = - let compile_time_genesis = - Mina_state.Genesis_protocol_state.t - ~genesis_ledger:Genesis_ledger.(Packed.t for_unit_tests) - ~genesis_epoch_data:Consensus.Genesis_epoch_data.for_unit_tests - ~constraint_constants ~consensus_constants - ~genesis_body_reference:Staged_ledger_diff.genesis_body_reference + let protocol_constants : Genesis_constants.Protocol.t = + { k = 1 + ; slots_per_epoch = 1000 + ; slots_per_sub_window = 1 + ; grace_period_slots = 1 + ; delta = 1 + ; genesis_state_timestamp = Int64.one + } in - Mina_state.Protocol_state.body compile_time_genesis.data + Consensus.Constants.create ~constraint_constants ~protocol_constants + + let compile_time_genesis = + Mina_state.Genesis_protocol_state.t + ~genesis_ledger:Genesis_ledger.(Packed.t for_unit_tests) + ~genesis_epoch_data:Consensus.Genesis_epoch_data.for_unit_tests + ~constraint_constants ~consensus_constants + ~genesis_body_reference:Staged_ledger_diff.genesis_body_reference end type t = @@ -50,7 +53,9 @@ let apply_command t ~command = Ledger.apply_transaction_first_pass ~constraint_constants:Constants.constraint_constants ~global_slot:Mina_numbers.Global_slot_since_genesis.zero - ~txn_state_view:(Mina_state.Protocol_state.Body.view Constants.state_body) + ~txn_state_view: + (Mina_state.Protocol_state.Body.view + Constants.compile_time_genesis.data.body ) l (Command command) in let%bind.Result txn_applied = @@ -59,9 +64,23 @@ let apply_command t ~command = Ledger.Mask.Attached.commit l ; + let txn_hash = + Transaction_hash.to_base58_check @@ Transaction_hash.hash_command command + in + Hashtbl.add_exn t.commands ~key:txn_hash + ~data: + ( command + , Mina_transaction_logic.Transaction_applied.transaction_status + txn_applied ) ; + + let status = + Mina_transaction_logic.Transaction_applied.transaction_status txn_applied + in + printf !"Applied command: %{sexp: Transaction_status.t\n}\n%!" status ; + let () = - match command with - | Zkapp_command zkapp_command -> + match (status, command) with + | Applied, Zkapp_command zkapp_command -> Zkapp_command.( Call_forest.iteri (account_updates zkapp_command) ~f:(fun _ update -> let account = @@ -89,23 +108,10 @@ let apply_command t ~command = Account_update.Body.authorization_kind @@ Account_update.body update } ) )) - | Signed_command _ -> + | _ -> () in - let txn_hash = - Transaction_hash.to_base58_check @@ Transaction_hash.hash_command command - in - Hashtbl.add_exn t.commands ~key:txn_hash - ~data: - ( command - , Mina_transaction_logic.Transaction_applied.transaction_status - txn_applied ) ; - - print_endline @@ "applied zkapp command: " ^ txn_hash ^ " " - ^ Yojson.Safe.pretty_to_string @@ Transaction_status.to_yojson - @@ Mina_transaction_logic.Transaction_applied.transaction_status txn_applied ; - Ok () let get_account t account_id = diff --git a/src/app/zeko/zeko_constants.ml b/src/app/zeko/zeko_constants.ml new file mode 100644 index 0000000000..695f715867 --- /dev/null +++ b/src/app/zeko/zeko_constants.ml @@ -0,0 +1,32 @@ +open Mina_base +open Signature_lib +module Field = Snark_params.Tick.Run.Field + +let constraint_constants : Genesis_constants.Constraint_constants.t = + { sub_windows_per_window = 1 + ; ledger_depth = 35 + ; work_delay = 1 + ; block_window_duration_ms = 1 + ; transaction_capacity_log_2 = 1 + ; pending_coinbase_depth = 1 + ; coinbase_amount = Currency.Amount.zero + ; supercharged_coinbase_factor = 1 + ; account_creation_fee = Currency.Fee.of_mina_string_exn "0.1" + ; fork = None + } + +let inner_public_key = + let pk = + Snark_params.Tick.Inner_curve.( + to_affine_exn @@ point_near_x @@ Field.Constant.of_int 123456789) + in + Public_key.compress pk + +let inner_account_id = + Account_id.of_public_key (Public_key.decompress_exn inner_public_key) + +let inner_account_index = 0 + +let indexed_merkle_tree_salt = "indexed merkle tree entry hash" + +let indexed_merkle_tree_merge_salt = "indexed merkle tree" diff --git a/src/app/zeko/zeko_util.ml b/src/app/zeko/zeko_util.ml deleted file mode 100644 index 860f986cff..0000000000 --- a/src/app/zeko/zeko_util.ml +++ /dev/null @@ -1,15 +0,0 @@ -open Mina_base - -type call_forest = - ( Account_update.t - , Zkapp_command.Digest.Account_update.t - , Zkapp_command.Digest.Forest.t ) - Zkapp_command.Call_forest.t -[@@deriving yojson] - -type call_forest_tree = - ( Account_update.t - , Zkapp_command.Digest.Account_update.t - , Zkapp_command.Digest.Forest.t ) - Zkapp_command.Call_forest.Tree.t -[@@deriving yojson] diff --git a/src/app/zeko/zkapps_rollup.ml b/src/app/zeko/zkapps_rollup.ml deleted file mode 100644 index bd6e3cf9e7..0000000000 --- a/src/app/zeko/zkapps_rollup.ml +++ /dev/null @@ -1,137 +0,0 @@ -open Mina_base -open Zeko_util -open Snark_params.Tick -open Signature_lib - -let inner_public_key = Zeko_circuits.Outer_rules.Inputs.inner_public_key - -let inner_account_id = Account_id.create inner_public_key Token_id.default - -type t = unit - -let to_yojson _ = failwith "FIXME" - -let of_yojson _ = failwith "FIXME" - -module TR = struct - type t = - { amount : Currency.Amount.t - ; recipient : Signature_lib.Public_key.Compressed.t - } - - let to_yojson = to_yojson - - let of_yojson = of_yojson - - let to_actions _ = failwith "FIXME" -end - -module type S = sig - open Async - - module Wrapper : sig - (** Wrap a ledger transition. - - The wrapped transition must be "whole", and must be made using - inner_pending_coinbase and inner_pending_coinbase_init, - such that the pc target and source are equal. - The connecting ledger must be the ledger between the two passes, - i.e., the end of the first pass, and the beginning of the second pass, - and as such, the passes must be connected. - You can not wrap a single zkapp command segment either, - you can only wrap at least a whole zkapp command. - *) - val wrap : Transaction_snark.t -> t Deferred.t - - (** Merge two wrapped ledger transitions, they must connect or this will fail. *) - val merge : t -> t -> t Deferred.t - end - - module Inner : sig - (** Account update for withdrawing *) - val submit_withdrawal : withdrawal:TR.t -> call_forest_tree Deferred.t - - val process_deposit : - is_new:bool (** Has this recipient been deposited to before? *) - -> pointer:field - -> before:TR.t list (** deposits before last recorded from new to old *) - -> after:TR.t list (** deposits after last recorded from new to old *) - -> deposit:TR.t - -> ([ `Pointer of field ] * call_forest) Deferred.t - - val step : all_deposits:field -> call_forest_tree Deferred.t - - (** Account ID using public key *) - val account_id : Account_id.t - - (** Initial state of inner account in new rollup *) - val initial_account : Account.t - end - - module Outer : sig - (** Account update for depositing *) - val submit_deposit : - outer_public_key:Public_key.Compressed.t - -> deposit:TR.t - -> call_forest_tree Deferred.t - - val process_withdrawal : - is_new:bool (** Has this recipient been withdrawn to before? *) - -> outer_public_key:Public_key.Compressed.t - -> pointer:field - -> before:TR.t list - -> after:TR.t list - -> withdrawal:TR.t - -> ([ `Pointer of field ] * call_forest) Deferred.t - - val step : - t (** The transition, must include Inner.step account update *) - -> outer_public_key:Public_key.Compressed.t - -> new_deposits:TR.t list (** new deposits from new to old *) - -> unprocessed_deposits:TR.t list - (** from new deposits to the current action state *) - -> old_inner_ledger:Mina_ledger.Sparse_ledger.t - (** Old sparse inner ledger including inner account *) - -> new_inner_ledger:Mina_ledger.Sparse_ledger.t - (** New sparse inner ledger including inner account *) - -> call_forest_tree Deferred.t - - (** Create an account update update for deploying the zkapp, given a valid ledger for it. *) - val deploy_exn : Mina_ledger.Ledger.t -> Account_update.Update.t - end -end - -module Make (_ : sig end) : S = struct - module Wrapper = struct - let wrap _ = failwith "FIXME" - - let merge _ _ = failwith "FIXME" - end - - module Outer = struct - let submit_deposit ~outer_public_key:_ ~deposit:_ = failwith "FIXME" - - let process_withdrawal ~is_new:_ ~outer_public_key:_ ~pointer:_ ~before:_ - ~after:_ ~withdrawal:_ = - failwith "FIXME" - - let step _ ~outer_public_key:_ ~new_deposits:_ ~unprocessed_deposits:_ - ~old_inner_ledger:_ ~new_inner_ledger:_ = - failwith "FIXME" - - let deploy_exn _ = failwith "FIXME" - end - - module Inner = struct - let submit_withdrawal ~withdrawal:_ = failwith "FIXME" - - let process_deposit ~is_new:_ ~pointer:_ ~before:_ ~after:_ ~deposit:_ = - failwith "FIXME" - - let step ~all_deposits:_ = failwith "FIXME" - - let account_id = inner_account_id - - let initial_account = Account.empty - end -end diff --git a/src/lib/merkle_ledger/intf.ml b/src/lib/merkle_ledger/intf.ml index 0f8391af23..b3da87c1fd 100644 --- a/src/lib/merkle_ledger/intf.ml +++ b/src/lib/merkle_ledger/intf.ml @@ -201,6 +201,8 @@ module type Key_value_database = sig -> ('a, 'b) Continue_or_stop.t ) -> finish:('a -> 'b) -> 'b + + val prev_key : t -> key:Bigstring.t -> Bigstring.t end module type Storage_locations = sig diff --git a/src/lib/rocksdb/database.ml b/src/lib/rocksdb/database.ml index 1621df8a10..14f2abdc98 100644 --- a/src/lib/rocksdb/database.ml +++ b/src/lib/rocksdb/database.ml @@ -119,6 +119,12 @@ let fold_until : in finish @@ loop init +let prev_key t ~(key : Bigstring.t) : Bigstring.t = + let iterator = Rocks.Iterator.create t.db in + Rocks.Iterator.seek iterator key ; + Rocks.Iterator.prev iterator ; + Rocks.Iterator.get_key iterator + let to_bigstring = Bigstring.of_string let%test_unit "get_batch" = diff --git a/src/lib/rocksdb/database.mli b/src/lib/rocksdb/database.mli index 8b66cf176d..9d4daf7cad 100644 --- a/src/lib/rocksdb/database.mli +++ b/src/lib/rocksdb/database.mli @@ -53,6 +53,8 @@ val fold_until : -> finish:('a -> 'b) -> 'b +val prev_key : t -> key:Bigstring.t -> Bigstring.t + module Batch : sig type t = Rocks.WriteBatch.t diff --git a/src/lib/transaction_logic/mina_transaction_logic.ml b/src/lib/transaction_logic/mina_transaction_logic.ml index a7bf1711fe..bab4ecd6ab 100644 --- a/src/lib/transaction_logic/mina_transaction_logic.ml +++ b/src/lib/transaction_logic/mina_transaction_logic.ml @@ -20,6 +20,31 @@ module type S = sig type location + module Inputs : + Zkapp_command_logic.Inputs_intf + with type Account.t = Account.t + and type Account_update.t = Account_update.t + and type Account_update.call_forest = Zkapp_call_forest.t + and type Account_update.transaction_commitment = + Snark_params.Tick.Field.t + and type Field.t = Snark_params.Tick.Field.t + and type Bool.t = bool + and type Bool.failure_status = Transaction_status.Failure.t option + and type Bool.failure_status_tbl = + Transaction_status.Failure.Collection.t + and type Ledger.t = ledger + and type Global_slot_since_genesis.t = Global_slot_since_genesis.t + and type Protocol_state_precondition.t = + Zkapp_precondition.Protocol_state.t + and type Valid_while_precondition.t = + Global_slot_since_genesis.t Zkapp_precondition.Closed_interval.t + Zkapp_basic.Or_ignore.t + and type Stack_frame.t = Stack_frame.value + and type Call_stack.t = Stack_frame.value list + and type Amount.Signed.t = Currency.Amount.Signed.t + and type Index.t = Unsigned.uint32 + and type Token_id.t = Token_id.t + val transaction_of_applied : Transaction_applied.t -> Transaction.t With_status.t @@ -789,7 +814,7 @@ module Make (L : Ledger_intf.S) : if should_update then L.apply_mask t.first_pass_ledger ~masked:ledger ; t - let second_pass_ledger { second_pass_ledger; _ } = + let _second_pass_ledger { second_pass_ledger; _ } = L.create_masked second_pass_ledger let _set_second_pass_ledger ~should_update t ledger = @@ -1658,7 +1683,7 @@ module Make (L : Ledger_intf.S) : let initial_state : Inputs.Global_state.t * _ Zkapp_command_logic.Local_state.t = ( { protocol_state = state_view - ; first_pass_ledger = ledger + ; first_pass_ledger = L.empty ~depth:0 () ; second_pass_ledger = (* We stub out the second_pass_ledger initially, and then poke the correct value in place after the first pass is finished. @@ -1678,7 +1703,9 @@ module Make (L : Ledger_intf.S) : ; full_transaction_commitment = Inputs.Transaction_commitment.empty ; excess = Currency.Amount.(Signed.of_unsigned zero) ; supply_increase = Currency.Amount.(Signed.of_unsigned zero) - ; ledger = L.empty ~depth:0 () + ; ledger + (* ; ledger = L.empty ~depth:0 () *) + (* ZEKO NOTE: by removing 2 pass logic this is the ledger being used in first pass *) ; success = true ; account_update_index = Inputs.Index.zero ; failure_status_tbl = [] @@ -1794,18 +1821,20 @@ module Make (L : Ledger_intf.S) : *) let global_state = { c.global_state with second_pass_ledger = ledger } in let local_state = - if List.is_empty c.local_state.stack_frame.Stack_frame.calls then - (* Don't mess with the local state; we've already finished the - transaction after the fee payer. - *) - c.local_state - else - (* Install the ledger that should already be in the local state, but - may not be in some situations depending on who the caller is. - *) - { c.local_state with - ledger = Global_state.second_pass_ledger global_state - } + (* if List.is_empty c.local_state.stack_frame.Stack_frame.calls then + (* Don't mess with the local state; we've already finished the + transaction after the fee payer. + *) + c.local_state + else + (* Install the ledger that should already be in the local state, but + may not be in some situations depending on who the caller is. + *) + { c.local_state with + ledger = Global_state.second_pass_ledger global_state + } *) + (* ZEKO NOTE: we are not using passes *) + c.local_state in let start = (global_state, local_state) in match step_all (f init start) start with diff --git a/src/lib/transaction_snark/test/util.ml b/src/lib/transaction_snark/test/util.ml index f4711161da..dd4cd21a03 100644 --- a/src/lib/transaction_snark/test/util.ml +++ b/src/lib/transaction_snark/test/util.ml @@ -7,16 +7,35 @@ module Impl = Pickles.Impls.Step module Zkapp_command_segment = Transaction_snark.Zkapp_command_segment module Statement = Transaction_snark.Statement -let constraint_constants = Genesis_constants.Compiled.constraint_constants - let genesis_constants = Genesis_constants.Compiled.genesis_constants (* Always run tests with proof-level Full *) let proof_level = Genesis_constants.Proof_level.Full +let constraint_constants : Genesis_constants.Constraint_constants.t = + { sub_windows_per_window = 1 + ; ledger_depth = 35 + ; work_delay = 1 + ; block_window_duration_ms = 1 + ; transaction_capacity_log_2 = 1 + ; pending_coinbase_depth = 1 + ; coinbase_amount = Currency.Amount.zero + ; supercharged_coinbase_factor = 1 + ; account_creation_fee = Currency.Fee.of_mina_string_exn "0.1" + ; fork = None + } + +let protocol_constants : Genesis_constants.Protocol.t = + { k = 1 + ; slots_per_epoch = 1000 + ; slots_per_sub_window = 1 + ; grace_period_slots = 1 + ; delta = 1 + ; genesis_state_timestamp = Int64.one + } + let consensus_constants = - Consensus.Constants.create ~constraint_constants - ~protocol_constants:genesis_constants.protocol + Consensus.Constants.create ~constraint_constants ~protocol_constants module Ledger = struct include Mina_ledger.Ledger