Skip to content

Commit

Permalink
document precompiles (#52)
Browse files Browse the repository at this point in the history
* document precompiles

* first pass

* fix links

---------

Co-authored-by: Sebastien Guillemot <[email protected]>
  • Loading branch information
ecioppettini and SebastienGllmt authored Jul 30, 2024
1 parent 5449858 commit 9c73de7
Show file tree
Hide file tree
Showing 89 changed files with 222 additions and 78 deletions.
4 changes: 2 additions & 2 deletions docs/home/0-intro/0-what-is-paima-engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ Similarly, to give additional liquidity for NFTs for the game, it natively suppo

Paima supports the following as DA layers:
- EVM (default)
- [Avail](../300-react-to-events/3-funnel-types/800-avail-block-funnel.md)
- [Avail](../100-state-machine/300-react-to-events/3-funnel-types/800-avail-block-funnel.md)

We provide the choice, because using a DA layer makes resync of rollup state significantly cheaper & faster.
- **EVM**: syncing rollup state requires running an EVM fullnode (expensive & heavy)
Expand All @@ -145,7 +145,7 @@ ZK cryptography is often used in Web3 for two different properties:

Both these use-cases are of interest in games, as being able to prove world state helps with composability of worlds, and private inputs allow games with private state (ex: fog of war) and can also help with compliance (ex: being able to prove you know information without revealing the sensitive information publicly)

Paima already comes with [ZK layer](../300-react-to-events/3-funnel-types/600-mina-funnel.mdx) support, and we are working with [Zeko](http://zeko.io/) (based on Mina Protocol) to enable app-specific ZK rollups as well. You can learn more about the architecture of our ZK layer [here](https://blog.paimastudios.com/paima-zk-layer/).
Paima already comes with [ZK layer](../100-state-machine/300-react-to-events/3-funnel-types/600-mina-funnel.mdx) support, and we are working with [Zeko](http://zeko.io/) (based on Mina Protocol) to enable app-specific ZK rollups as well. You can learn more about the architecture of our ZK layer [here](https://blog.paimastudios.com/paima-zk-layer/).

#### Example game

Expand Down
2 changes: 1 addition & 1 deletion docs/home/1-setup/1-how-to-use-paima-engine.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ These logs denote the block height numbers that the game node is syncing from th

Now that your game node is syncing, we recommend testing to ensure that both the contract you deployed and the node itself are all in working order/configured properly.

Simply follow the [posting test game inputs to L2 contract tutorial](../200-read-write-L2-state/20-write-data.md#writing-data-from-an-external-source) and within a couple minutes you'll have experienced the end-to-end loop of using Paima Engine!
Simply follow the [posting test game inputs to L2 contract tutorial](../100-state-machine/200-direct-write/20-write-data.md#writing-data-from-an-external-source) and within a couple minutes you'll have experienced the end-to-end loop of using Paima Engine!

Of note, the above tutorial teaches you an easy way to manually submit custom-crafted game inputs, which is also useful when implementing new features as you develop your games/apps.

Expand Down
6 changes: 3 additions & 3 deletions docs/home/1-setup/20-paima-bacher.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Furthermore, batcher support is fully integrated into Paima Engine, including th

Of note, because Paima Engine games are full fledged Sovereign Rollups, this means we have a built-in mechanism for democratization & decentralization of batching (unlike the majority of rollups today). In other words, anyone can run a batcher for any game built with Paima Engine, opening up opportunities for your community & 3rd party developers to create their own web/mobile game clients, tools, websites, and services that provide players with completely novel gameplay experiences!

You can learn more about the architecture of the batcher [here](../200-read-write-L2-state/400-batched-mode.md)
You can learn more about the architecture of the batcher [here](../100-state-machine/200-direct-write/400-batched-mode.md)

## Benefits

Expand Down Expand Up @@ -88,7 +88,7 @@ for self signed inputs, otherwise it's handled by the light client.
transactions in a single round.
- `MAX_USER_INPUTS_PER_MINUTE`: Per user input submission limit.
- `MAX_USER_INPUTS_PER_DAY`: Per user input submission limit.
- `SECURITY_NAMESPACE`: [See this section for details](../200-read-write-L2-state/600-autosign.md#defining-your-namespace).
- `SECURITY_NAMESPACE`: [See this section for details](../100-state-machine/200-direct-write/600-autosign.md#defining-your-namespace).

#### Optional settings

Expand Down Expand Up @@ -133,7 +133,7 @@ to. Possible values are: `evm` and `avail`. If not set it will default to `evm`.
used for the transaction poster. [Reference](https://docs.availproject.org/docs/operate-a-node/run-a-light-client/light-client-api-reference#v2submit).
- `SECURITY_NAMESPACE`: There is no contract address in this case, so this is
required in this case. [See this section for
details](../200-read-write-L2-state/600-autosign.md#defining-your-namespace).
details](../100-state-machine/200-direct-write/600-autosign.md#defining-your-namespace).


## Usage
Expand Down
4 changes: 2 additions & 2 deletions docs/home/1-setup/4-environment-config-values.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The following is a list of possible environment variables that can be configured

## Funnel Configuration

These these variables are used if you only need to synchronize a single network for your application. If you need to synchronize multiple networks, learn more about funnel configuration [here](../300-react-to-events/3-funnel-types/200-configuration.md)
These these variables are used if you only need to synchronize a single network for your application. If you need to synchronize multiple networks, learn more about funnel configuration [here](../100-state-machine/300-react-to-events/3-funnel-types/200-configuration.md)

### Required variables

Expand All @@ -23,7 +23,7 @@ These these variables are used if you only need to synchronize a single network

#### Optional variables

- [Primitive Catalogue](../300-react-to-events/2-primitive-catalogue/1-introduction.md):
- [Primitive Catalogue](../100-state-machine/300-react-to-events/10-primitive-catalogue/1-introduction.md):
- `DEFAULT_PRESYNC_STEP_SIZE`: number of blocks to process in each step during initial presync phase. If not provided, a value of 1000 is used. Generally no need to change this value.
- `CDE_CONFIG_PATH`: allows you to specify a custom location for your `extensions.yml` that is used to initialize primitive catalogue entries
- Cardano extensions
Expand Down
2 changes: 1 addition & 1 deletion docs/home/1-setup/_category_.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"label": "Setting-up Your Environment"
"label": "Environment Setup"
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,13 @@ The `PaimaParser` grammar supports UTF8, but generally has the following reserve
- `*` See [parallelism](./200-parallelism.md)
- `@` Implicitly use the address that submitted the wallet for [parallelism](./200-parallelism.md). That is, for parallelism purposes, `@x|a` is equivalent to `x|*wallet|a`, but no actual modifications is done to the onchain format
- `?` Optional entry
- `&` At the start of a message for [wallet delegation](../700-multichain-support/2-wallet-layer/100-delegate-wallet/1-introduction.mdx)
- `&` At the start of a message for [wallet delegation](../../700-multichain-support/2-wallet-layer/100-delegate-wallet/1-introduction.mdx)
- `|` , `=` Used to define the grammar
- `-` Used for PaimaParser array notation
- ASCII 0x02 and 0x03. Use for [batched-mode](./400-batched-mode.md)
- ASCII 0x02 and 0x03. Use for [batched-mode](../200-direct-write/400-batched-mode.md)

## Conclusion

Now that you've created your parser, you can
- [read with it](./10-read-data.md)
- [write with it](./20-write-data.md)
- [write with it](../200-direct-write/20-write-data.md)
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function parse(s: string): ParsedSubmittedInput {

## Calling the parser from your STF {#stf-function}

Paima works by updating your state machine whenever happens onchain - the most common case being that somebody interacted with your Paima L2 contract. The set of actions your state machine can react to are called the [Paima Primitives](../300-react-to-events/2-primitive-catalogue/1-introduction.md).
Paima works by updating your state machine whenever happens onchain - the most common case being that somebody interacted with your Paima L2 contract. The set of actions your state machine can react to are called the [Paima Primitives](../300-react-to-events/10-primitive-catalogue/1-introduction.md).

Your parser can then be used in the _stf_ (state transition function) of your application

Expand Down Expand Up @@ -61,7 +61,7 @@ Paima comes with a Hardhat plugin as part of [@paima/evm-contracts](https://www.

To use it, make sure you have `import @paima/evm-contracts/plugin` at the top of your `hardhat.config.ts`

For reading inputs submitted to your L2 contract directly (instead of implicitly through another [Paima Primitive](../300-react-to-events/2-primitive-catalogue/1-introduction.md)), you can run `npx hardhat paima PaimaL2Contract:recentInputs`.
For reading inputs submitted to your L2 contract directly (instead of implicitly through another [Paima Primitive](../300-react-to-events/10-primitive-catalogue/1-introduction.md)), you can run `npx hardhat paima PaimaL2Contract:recentInputs`.
This command helps you see _recent_ inputs to your L2 contract (not the best tool for getting all historic interactions).

### (Explorer) See historical game inputs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ For example, maybe a game needs to update each user's wins/losses/ties record. W

As such, we need a new approach for how we can apply global side effects in a principled manner. Lucky for us, we already have a great piece of functionality implemented in Paima Engine exactly suited for this job: scheduled inputs.

Using scheduled inputs, whenever a global side effect needs to be applied, we simply create a new scheduled input for `[current block height] + 1` (see [passive events](../300-react-to-events/1-scheduled-events.md) to learn more) and ensure that it also carries a state identifier inside. Thus in our grammar, we can simply define a new type of valid (scheduled) game input which specifies that the given user's stats need to be updated with the resulting win/tie/loss:
Using scheduled inputs, whenever a global side effect needs to be applied, we simply create a new scheduled input for `[current block height] + 1` (see [passive events](../325-creating-events/50-timers-ticks.md) to learn more) and ensure that it also carries a state identifier inside. Thus in our grammar, we can simply define a new type of valid (scheduled) game input which specifies that the given user's stats need to be updated with the resulting win/tie/loss:

```typescript
const myGrammar = `
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"label": "Define your State Machine"
}
53 changes: 53 additions & 0 deletions docs/home/100-state-machine/1000-structure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# L2 Block structure

Rollups built with Paima Engine, similar to other blockchains, consist of blocks that contain transactions inside them. The key difference is that unlike typical chains, data that forms Paima blocks comes from [underlying sources](./300-react-to-events/3-funnel-types/1-common-concepts/1-intro.md) or [deterministic self-defined transitions](./325-creating-events/50-timers-ticks.md) as opposed to user inputs intrinstic to the system itself.

Paima-based rollups, unlike many chains, does not [Merklize](https://en.wikipedia.org/wiki/Merkle_tree) its state, as this comes with a [significant performance overhead](https://sovereign.mirror.xyz/jfx_cJ_15saejG9ZuQWjnGnG-NfahbazQH98i1J3NN8). Paima is not alone in doing this - this is done by other successful systems like [Solana](https://solana.com/) as well.

## Transaction hash

Knowing the transaction hash is crucial to be able to reference the state and information about a given transaction on the rollup.

Note there are a few key properties we want to get from our hash function:
1. **client-side computable**: transaction hashes should be computable locally before it actually gets included inside a block. This helps write tools where you can query the status of the transaction before it gets included in a block.
2. **low memory requirement**: transaction hashes must be computable with small amounts of memory (ex: we never hash a giant blob of data. For anything that has a large amount of data, we first hash of the data (to turn it into a small string), and then past this has to the tx hash function). This is useful to make sure that transaction hashes can be calculated on devices with limited memory (ex: hardware wallets)
3. **avoid user injection**: transaction hashes never take in directly user-specified inputs (always hash things that users have control over) to avoid any chance of users injecting things that break parsers

There are a few tricky parts to computing transaction hashes in Paima-based rollups:
1. **Differentiating similar events in different chains**: since transactions in Paima often come from an underlying chain, we heavily leverage [caip-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) which is a standard to give unique IDs for every chain. This means that two identical transactions submitted on different chains, even if they have the exact same content, will result in a different transaction hash.
1. **Flattening events**: in chains like Ethereum, one transaction may (and in fact often do) trigger multiple events. Since Paima rollups considers these events each individual transactions, it means one transaction on the underlying chain may trigger multiple transactions in a rollup. To tackle this, we give a unique incrementing ID to each event triggered from the same transaction (`indexForEvent`) so that they all get a different final tx hash.
1. **Timers IDs**: Some transactions may be initiated by [timers](./325-creating-events/50-timers-ticks.md). We differentiate timers with [precompiles](./325-creating-events/300-precompiles/100-introduction.md), but the same timer can produce the same data (ex: "reset daily leaderboard") many times, and could even generate multiple identical events in the same block. To tackle this, we include both the block number where the timer is expected to trigger as well as a unique incrementing ID to each event triggered from the same tune (`indexForEvent`) so that they all get a different final tx hash.
1. **Separating elements**: Since Paima transaction hashes need to combine multiple different inputs of different length, we use a separator `|` to separate the field.

To calculate a transaction hash, there are multiple cases that need to be handled:

1. For [primitives](./300-react-to-events/10-primitive-catalogue/1-introduction.md),
```js
'0x' +
keccak_256(
caip2Prefix |
data.tx_hash |
indexForEvent(data.tx_hash)
)
```

2. For [timers](./325-creating-events/50-timers-ticks.md),
```js
'0x' +
keccak_256(
userAddress
keccak_256(data.input_data) |
scheduledBlockHeight |
timerIndexRelativeToBlock
),
```

3. For [direct user transactions](./200-direct-write/20-write-data.md),
```js
'0x' +
keccak_256(
submittedData.caip2 |
submittedData.txHash |
indexForEvent(submittedData.txHash)
)
```
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Concise Builder

Now that you've defined you grammar in the [previous section](./1-base-format.md), you can programmatically interact with it.
Now that you've defined you grammar in the [previous section](../100-define-machine/1-base-format.md), you can programmatically interact with it.


1. Generate the data to submit
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Replay protection

Given that games made with Paima Engine are technically "open" (meaning anyone can submit valid game input), one thing which we need to look out for is replaying attacks. Replaying attacks are situations classically in blockchains (but liable to any openly accessible state machine) where a previous valid input is resubmitted to the state machine/blockchain. Usually this is done by bad actors, and can cause various issues.
Given that games made with Paima Engine are technically "open" (meaning anyone can submit valid game input), one thing which we need to look out for is [replay attacks](https://en.wikipedia.org/wiki/Replay_attack). Replay attacks are situations classically in blockchains (but liable to any openly accessible state machine) where a previous valid input is resubmitted to the state machine/blockchain. Usually this is done by bad actors, and can cause various issues.

In our case, there are a few scenarios where replays can happen:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ To tackle this, Paima introduces three different auto-sign methods that all guar

## 1. Data-only auto-signing

For apps that run [Paima batchers](../1-setup/20-paima-bacher.md) or similar systems (meta-transactions, account-abstraction or sequencers), signing data is often enough for the game
For apps that run [Paima batchers](../../1-setup/20-paima-bacher.md) or similar systems (meta-transactions, account-abstraction or sequencers), signing data is often enough for the game

Concrete examples of cases where this is sufficient:
- Blockchains with zero transaction fees (Immutable, Oasys, etc.) where you can simply have somebody submit the transaction for you
Expand Down Expand Up @@ -54,7 +54,7 @@ namespace:
### Wallets that plan to support this format
- MetaMask through the [Paima Session Snap](https://github.com/PaimaStudios/paima-session-snap)
- Any wallet for a cryptocurrency supported by Paima's [wallet layer](../700-multichain-support/2-wallet-layer/1-introduction.mdx) through the [delegate functionality](../700-multichain-support/2-wallet-layer/100-delegate-wallet/1-introduction.mdx)
- Any wallet for a cryptocurrency supported by Paima's [wallet layer](../../700-multichain-support/2-wallet-layer/1-introduction.mdx) through the [delegate functionality](../../700-multichain-support/2-wallet-layer/100-delegate-wallet/1-introduction.mdx)
## 2. Game-specific auto-signing transactions
Expand All @@ -70,4 +70,4 @@ However, in this case, adding the security namespace would add a lot of useless

For some apps, simply auto-signing data may not be enough. Instead, to safely sign transactions for the app, you want some kind of session key for the game.

This can be achieved through the [delegate functionality](../700-multichain-support/2-wallet-layer/100-delegate-wallet/1-introduction.mdx). Since Paima's [wallet layer](../700-multichain-support/2-wallet-layer/1-introduction.mdx) supports raw private key formats for some chains like EVM, you can use persistent session key login systems like the one provided by [thirdweb](https://thirdweb.com/) with Paima Engine and have the user delegate their primary wallet to the session key.
This can be achieved through the [delegate functionality](../../700-multichain-support/2-wallet-layer/100-delegate-wallet/1-introduction.mdx). Since Paima's [wallet layer](../../700-multichain-support/2-wallet-layer/1-introduction.mdx) supports raw private key formats for some chains like EVM, you can use persistent session key login systems like the one provided by [thirdweb](https://thirdweb.com/) with Paima Engine and have the user delegate their primary wallet to the session key.
3 changes: 3 additions & 0 deletions docs/home/100-state-machine/200-direct-write/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"label": "User → L2: Directly write state"
}
Loading

0 comments on commit 9c73de7

Please sign in to comment.