## Building a DSL for Modular RETH Transaction Middleware
#### Isaac Patka - Shield3
---
With RETH we can extend the RPC api and add <font color="red">middleware</font>

---
With RETH we can extend the RPC api and add <font color="red">security</font> middleware

---
With RETH we can extend the RPC api and add <font color="red">modular</font> security middleware

---
## Building a DSL for modular middleware
* Make decisions based on transaction context
* Without doing simulations
* Customizable with minimal code
---
## What can we reuse from the Rust ecosystem
* <font color="#b73650">`Cedar Policy Language`</font>
* Recently open sourced by AWS
* Written in Rust
---
### ... But Cedar was not built for crypto
``` javascript [0|2|3|4|6]
permit (
principal == User::"alice",
action == Action::"view",
resource in Album::"jane_vacation"
)
unless { resource.tags.contains("private") } ;
```

---
### By combining Cedar with ethers-rs (todo alloy) we can help it understand Ethereum transaction context
``` javascript
permit (
principal,
action == Action::"EOATransaction",
resource
)
when { context.value.u256LessThan(principal.valueLimit) };
```
---
### And we can define routing for the node to execute
``` javascript [1|2|3|4-9]
@name("WARN-NATIVE-ASSET-THRESHOLD")
@advice("Warn when sending funds over X threshold")
@trigger("WEBHOOK-e03a0aa1")
forbid (
principal,
action == Action::"EOATransaction",
resource
)
when { context.value.u256GreaterThan(principal.valueLimit) };
```
---
### Policy Engine Execution
The Policy Engine needs the following data to make a decision:
* <font color="#b73650">`extensions`</font> for transaction datatypes
* <font color="#b73650">`schema`</font> for all referenced entities, actions, relationships, contexts
* <font color="#b73650">`action`</font> data of the requested operation
* <font color="#b73650">`entities`</font> data defined for the resources affected by the `action`
* <font color="#b73650">`policy`</font> statements to evaluate
---
### Extensions (ex. U256)
``` javascript [0|1|11-15]
use ethers::prelude::U256;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
struct UINT256 {
value: U256,
}
mod names {
use super::{Name, EXTENSION_NAME};
lazy_static::lazy_static! {
pub static ref UINT256_FROM_STR_NAME : Name = Name::parse_unqualified_name(EXTENSION_NAME).expect("should be a valid identifier");
pub static ref LESS_THAN : Name = Name::parse_unqualified_name("u256LessThan").expect("should be a valid identifier");
pub static ref LESS_THAN_OR_EQUAL : Name = Name::parse_unqualified_name("u256LessThanOrEqual").expect("should be a valid identifier");
pub static ref GREATER_THAN : Name = Name::parse_unqualified_name("u256GreaterThan").expect("should be a valid identifier");
pub static ref GREATER_THAN_OR_EQUAL : Name = Name::parse_unqualified_name("u256GreaterThanOrEqual").expect("should be a valid identifier");
}
}
```
---
### Schema
JSON Schema defining the shape of `contracts`, `addresses`, `networks`, `transactions`
``` javascript [0|3-15|16-30|31-44|60-70|74-87]
{
"entityTypes": {
"Contract": {
"memberOfTypes": [
"Network"
],
"shape": {
"type": "Record",
"attributes": {
"abi": {
"type": "String"
}
}
}
},
"EOA": {
"memberOfTypes": [
"Network"
],
"shape": {
"type": "Record",
"attributes": {
"valueLimit": {
"type": "Extension",
"name": "u256",
"required": false
}
}
}
},
"Network": {
"memberOfTypes": [],
"shape": {
"type": "Record",
"attributes": {
"name": {
"type": "String"
},
"chainId": {
"type": "Long"
}
}
}
}
},
"actions": {
"EOATransaction": {
"appliesTo": {
"resourceTypes": [
"EOA"
],
"principalTypes": [
"EOA"
],
"context": {
"type": "ReusedContext"
}
}
},
"ContractTransaction": {
"appliesTo": {
"resourceTypes": [
"Contract"
],
"principalTypes": [
"EOA"
],
"context": {
"type": "ReusedContext"
}
}
}
},
"commonTypes": {
"ReusedContext": {
"type": "Record",
"attributes": {
"transaction": {
"type": "String"
},
"value": {
"type": "Extension",
"name": "u256",
"required": true
}
}
}
}
}
```
---
### Actions
``` javascript [0|2|3|4|5-9]
{
"principal": "EOA::\"0x0000000000000000000000000000000000000001\"",
"action": "Action::\"ContractTransaction\"",
"resource": "Contract::\"0x0000000000000000000000000000000000000002\"",
"context": {
"value": {
"__expr": "u256(\"100\")"
}
}
}
```
---
## Entities
``` javascript [2-14|45-60|61-67]
[
{
"uid": {
"type": "EOA",
"id": "0x0000000000000000000000000000000000000001"
},
"attrs": {},
"parents": [
{
"type": "Network",
"id": "mainnet"
}
]
},
{
"uid": {
"type": "EOA",
"id": "0x0000000000000000000000000000000000000111"
},
"attrs": {
"valueLimit": {
"__expr": "u256(\"100\")"
}
},
"parents": [
{
"type": "Network",
"id": "mainnet"
}
]
},
{
"uid": {
"type": "EOA",
"id": "0x0000000000000000000000000000000000000011"
},
"attrs": {},
"parents": [
{
"type": "Network",
"id": "mainnet"
}
]
},
{
"uid": {
"type": "Contract",
"id": "0x0000000000000000000000000000000000000002"
},
"attrs": {
"abi": "DEMOABI"
},
"parents": [
{
"type": "Network",
"id": "mainnet"
}
]
},
{
"uid": {
"type": "Network",
"id": "mainnet"
},
"attrs": {
"chainId": 1
},
}
]
```
---
## Policies
``` javascript [1|2|3|4-9]
@name("WARN-NATIVE-ASSET-THRESHOLD")
@advice("Warn when sending funds over X threshold")
@notification("WEBHOOK-e03a0aa1")
forbid (
principal,
action == Action::"EOATransaction",
resource
)
when { context.value.u256GreaterThan(principal.valueLimit) };
```
---
## Build modular, customizable, composable middleware

---
## Read More
* https://hackmd.io/@shield3/intro-phage
* https://github.com/ipatka/banyan
* Twitter & TG: @isaacpatka
{"title":"Extending RETH With Programmable Middleware & Policy Language","description":"","contributors":"[{\"id\":\"e8ca9a78-d9ca-46a7-ba49-7089e65d8c39\",\"add\":15113,\"del\":7179}]"}