Giter VIP home page Giter VIP logo

machine-solidity-step's Introduction

Cartesi RISC-V Solidity Emulator

The Cartesi RISC-V Solidity Emulator is the on-chain host implementation of the Cartesi Machine Specification. The libraries and contracts are written in Solidity, and the testing scripts are written in Solidity (with the help of Foundry). Do not recommend running forge command directly, as there are many scripts and templates working together. Please use make instead.

For Cartesi's design to work, this implementation must have the exact transition function as the off-chain Cartesi RISC-V Emulator, meaning that if given the same initial state (s[i]) both implementation's step functions should reach a bit by bit consistent state s[i + 1].

Since the cost of storing a full Cartesi Machine state within the blockchain is prohibitive, all machine states are represented in the blockchain as cryptographic hashes. The contents of those states and memory represented by those hashes are only known off-chain.

Cartesi uses Merkle tree operations and properties to ensure that the blockchain has the ability to correctly verify a state transition without having full state-access. However, the RISC-V Solidity emulator abstracts these operations away and acts as if it knows the full contents of a machine state - it uses the Memory Manager interface to fetch or write any necessary words to memory.

AccessLogs

The AccessLogs.Context struct is consumed by the RISC-V Solidity emulator as if the entire state content was available - since the off and on-chain emulators match down to the order in which accesses are logged. When a dispute arises, Alice packs her off-chain state access log referent to the disagreement step in an struct AccessLogs.Context, which will guide the execution of a step (i.e state transition function).

The AccessLogs library implements the RISC-V Solidity emulator all necessary read and write operations.

It also makes sure that all accesses performed by the step function match the ones provided by Alice and are consistent with the Merkle proofs provided by her. If that is not the case, Alice loses the dispute.

Step function

step is the previously mentioned state transition function, it is meant to take the machine from state s[i] to state[i + 1], using the AccessLogs as an assistant. The step function receives IUArchState.State - which should have been populated with the AccessLogs generated by the emulator off-chain and returns an Exit code signaling the result of its execution.

During a step execution, every necessary read or write (be it to memory, registers etc) is processed and verified by the AccessLogs.

Execute Instruction

The UArchExecuteInsn contract consists of the machine instruction logic, such as decoding, executing, opcode matching and etc. The Solidity implementation is converted from the Cpp implementation directly through a translator script. This is to assure that the implementations in two languages are identical. Yet the low level differences in two languages are wrapped in the Compatibility Layer.

Compatibility Layer

The UArchCompat contract is taking care of all the differences in the two implementations. Ranging from programming languages (Cpp versus Solidity) to architectural differences (RISC-V versus EVM).

Getting Started

Run make help for a list of target options. Here are some of them:

Cleaning targets:
  clean                      - clean the cache artifacts and generated files
Generic targets:
* all                        - build solidity code. To build from a clean clone, run: make submodules all
  build                      - build solidity code
  generate-step              - generate solidity-step code from cpp
  generate-mock              - generate mock library code
  generate-prod              - generate production library code
  generate-replay            - generate replay tests
  pretest                    - download necessary files for tests
  test-all                   - test all
  test-mock                  - test binary files with mock library
  test-prod                  - test production code
  test-replay                - test log files

Prerequisite

Requirements

  • Foundry 0.2.0
  • GNU Make >= 3.81
  • GNU sed >= 4.9
  • GPP >= 2.27

Different version of tools maybe working but is not guaranteed.

Install

Install dependencies and build:

make submodules all

Run tests

There are two types of tests that can be run on the Solidity Emulator.

  1. Load binary rv64i test programs in Solidity and verify the execution result
  2. Collect step logs and proofs of a test program and replay them in Solidity, verify all accesses and proofs.

Run all tests:

make test-all

(target test-replay is very time consuming)

Contributing

Thank you for your interest in Cartesi! Head over to our Contributing Guidelines for instructions on how to sign our Contributors Agreement and get started with Cartesi!

Please note we have a Code of Conduct, please follow it in all your interactions with the project.

License

The machine-solidity-step repository and all contributions are licensed under APACHE 2.0. Please review our LICENSE file.

machine-solidity-step's People

Contributors

augustoteixeira avatar colinsteil avatar diegonehab avatar erickmoura avatar felipeargento avatar gbarros avatar gligneul avatar miltonjonat avatar mpernambuco avatar stephenctw avatar stskeeps avatar tuler avatar vfusco avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

machine-solidity-step's Issues

Add TLB implementation to log off-chain and follow implementation on-chain

At the moment, the TLB is implemented as an off-chain optimization to machine-emulator, but not on-chain in machine-solidity-step. This works for conforming software that executes a fence.vma instruction whenever the virtual memory map is changed. This is the way to ensure deterministic behavior according to the RISC-V specification. However, an ill-formed or malicious program can mess with the virtual memory map and then fail to execute fence.vma, either by accident or on purpose. This would cause the TLB to be outdated relative to the virtual memory map, and thus lead to mismatching behavior on- and off-chain.

To be on the safe side and prevent this potential source of non-determinism, we have decided to have matching TLB implementations on- and off-chain. This will require changes to the machine-emulator implementation, so it becomes possible to efficiently implement the TLB on-chain. Then, the state accesses related to the TLB will have to be logged. Once these changes have been made, a matching TLB implementation will be added to the on-chain code in machine-solidity-step.

This issue will track the progress of these changes.

See cartesi/machine-emulator#21.

Configure the log tests only for offical releases in CI

Context

CI is taking too long to finish. The bottleneck is the log tests, which can take up to 2 hours in the current version.

Possible solutions

Configure the log tests only being executed during official releases, so small PRs can be much faster and efficient. One can always run the tests in his local environment for his concern.

Implement UArchReset and MetaStep

The goal of this issue is to:

  • implement a new entrypoint contract and function MetaStep
  • the MetaStep introduces a concept of meta-machine, which hides the details of implementation difference of big-machine and micro-machine away from the user
  • implement a library and function UArchReset, which resets the micro-machine back to its pristine state
  • the MetaStep will either call UArchStep or UAarchStep + UArchReset based on the MetaCounter value
  • a big-machine step is equivilent to MetaCounter increasing 2^a, and equivilent to executing UArchStep (2^a) - 1 times and UArchStep + UArchReset once, e.g., ask the meta-machine to give the state at MetaCounter 90 + (1 << a)*27, meta-machine will call big-machine step 27 times, and then UArchStep 90 times; meta-machine could instead call (UArchStep 2^a times and one UArchReset) 27 times, and then UArchStep 90 times and it would give the same value.
  • UArchReset will receive a machine hash, a memory region hash and its corresponding proofs as validation. And it will reconstruct the machine hash by replacing the memory region hash with a pre-calculated pristine hash

cc: @mpernambuco @GCdePaula

Validate proofs as accesses are requested by step

Original post here: https://discordapp.com/channels/600597137524391947/1113159025920593930/1113160593193574451

Second alternative: since we don't need incremental stuff, let's simplify things and make the interface more generic. The idea is to verify proofs as accesses are requested by step. This way we don't need to know the type of the access beforehand.

Imagine that we receive something like a buffer called proofs, which have all the necessary data for all accesses. We create an abstraction called MemoryAccess around that buffer which holds both the last read position in that buffer and the state hash of the machine, and offers the methods:

writeRegion(&ctx, offset, log2size, merkleHash)
readRegion(&ctx, offset, log2size) returns (bytes32)
writeWordHash(&ctx, address, wordHash)
readWordHash(&ctx, address) returns (bytes32)
readWord(&ctx, address) returns (u64)

When step calls readWord, it will "eat up" from the buffer a word, sixty-one siblings, and verify whether that word really is on that position in the machine state. If so, it will return the word. When step calls writeWord, it will eat up from the buffer a hash, sixty-one siblings, verify whether that's a match, and then update the machine state. Likewise for the other methods. If a proof is incorrect, we revert. It should be exactly the same amount of code we have now, but done during step instead of on a loop before step.

We could split this buffer into two, one holding hashes and another holding words, possibly would be cleaner.

When step finishes, we read the final state stored in MemoryAccess and check whether that's the claimed final hash. If so, all's good, otherwise revert. 

cc: @GCdePaula

Allow generic memory accesses

Context

Make the MemoryAccessLog more generic so the accesses are not limited to word size but any valid aligned memory region that's larger than a word. This can be helpful for the UArchReset feature, and also let the rollups insert input drives easily.

Possible solutions

A possible solution can be found on a thread on Discord that's proposed by @GCdePaula.
https://discord.com/channels/600597137524391947/1113159025920593930/1113160593193574451

In summary, the new library would implement below functions:

writeRegion(ctx, region, newHash)
readRegion(ctx, region) returns (bytes32)
writeWordHash(ctx, addr, newHash)
readWordHash(ctx, addr) returns (bytes32)
readWord(ctx, addr) returns (u64)
writeWord(ctx, addr, newValue) returns (uint64)

The ctx is a memory struct argument that keeps track of the current machine root hash and all related proofs and hashes.
The region is a new structure that should present an aligned memory region, replacing the old (position, log2Size) tuple.

Deploy on zkSync2.0

It would be so cool to have a ZKP about a Linux machine. Which basically just means deploying this contract to the zkSync2.0 testnet. How long would it take to generate a proof for the execution of a simple python script?

Extract shadow addresses from C++ implementation

Context

CSRs addresses (such as UCYCLE, UHALT, UPC, UX0) are currently hard coded in the contract, ideally it's values should be automatically generated from the C++ implementation, therefore in case they change, the changes would be automatically be reflected in the contract by simply regenerating it.

Solution

We should first expose them in the emulator sources, then we can improve the generator script.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.