Skip to content

Commit

Permalink
feat: db reputation
Browse files Browse the repository at this point in the history
  • Loading branch information
Vid201 committed Aug 11, 2023
1 parent 33dc6e6 commit e10d0b4
Show file tree
Hide file tree
Showing 21 changed files with 920 additions and 353 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
<p align="center">Silius - <a href="https://eips.ethereum.org/EIPS/eip-4337">ERC-4337 (Account Abstraction)</a> bundler implementation in Rust.</p>

<p align="center">
<img src="./docs/images/logo.jpeg" width="300" height="300">
<img src="./docs/images/banner.png" width="450">
</p>

<p align="center"><a href="https://huggingface.co/spaces/stabilityai/stable-diffusion">Stable Diffusion</a> prompt: ethereum bundler account abstraction rust vector logo<p>

For more information: https://hackmd.io/@Vid201/aa-bundler-rust

<i>This project is still under active development.</i>
Expand Down
22 changes: 9 additions & 13 deletions crates/grpc/src/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub mod types {
use arrayref::array_ref;
use ethers::types::{Address, Bloom, U256};
use prost::bytes::Buf;
use silius_primitives::UserOperationHash;
use silius_primitives::{reputation::Status, UserOperationHash};
use std::str::FromStr;

tonic::include_proto!("types");
Expand Down Expand Up @@ -182,14 +182,10 @@ pub mod types {
addr: Some(reputation_entry.address.into()),
uo_seen: reputation_entry.uo_seen,
uo_included: reputation_entry.uo_included,
stat: match reputation_entry.status {
silius_primitives::reputation::ReputationStatus::OK => ReputationStatus::Ok,
silius_primitives::reputation::ReputationStatus::THROTTLED => {
ReputationStatus::Throttled
}
silius_primitives::reputation::ReputationStatus::BANNED => {
ReputationStatus::Banned
}
stat: match Status::from(reputation_entry.status) {
silius_primitives::reputation::Status::OK => ReputationStatus::Ok,
silius_primitives::reputation::Status::THROTTLED => ReputationStatus::Throttled,
silius_primitives::reputation::Status::BANNED => ReputationStatus::Banned,
} as i32,
}
}
Expand All @@ -209,15 +205,15 @@ pub mod types {
uo_included: reputation_entry.uo_included,
status: match reputation_entry.stat {
_ if reputation_entry.stat == ReputationStatus::Ok as i32 => {
silius_primitives::reputation::ReputationStatus::OK
silius_primitives::reputation::Status::OK.into()
}
_ if reputation_entry.stat == ReputationStatus::Throttled as i32 => {
silius_primitives::reputation::ReputationStatus::THROTTLED
silius_primitives::reputation::Status::THROTTLED.into()
}
_ if reputation_entry.stat == ReputationStatus::Banned as i32 => {
silius_primitives::reputation::ReputationStatus::BANNED
silius_primitives::reputation::Status::BANNED.into()
}
_ => silius_primitives::reputation::ReputationStatus::OK,
_ => silius_primitives::reputation::Status::OK.into(),
},
}
}
Expand Down
24 changes: 16 additions & 8 deletions crates/grpc/src/uopool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use silius_uopool::{
};
use std::{net::SocketAddr, sync::Arc, time::Duration};
use tonic::{Request, Response, Status};
use tracing::info;
use tracing::{info, warn};

const MAX_UOS_PER_UNSTAKED_SENDER: usize = 4;
const GAS_INCREASE_PERC: u64 = 10;
Expand Down Expand Up @@ -319,11 +319,15 @@ where
let ep = parse_addr(req.ep)?;
let mut uo_pool = parse_uo_pool_mut(self.get_uo_pool_mut(&ep))?;

uo_pool.set_reputation(req.rep.iter().map(|re| re.clone().into()).collect());
let res = Response::new(SetReputationResponse {
res: match uo_pool.set_reputation(req.rep.iter().map(|re| re.clone().into()).collect())
{
Ok(_) => SetReputationResult::SetReputation as i32,
Err(_) => SetReputationResult::NotSetReputation as i32,
},
});

Ok(Response::new(SetReputationResponse {
res: SetReputationResult::SetReputation as i32,
}))
Ok(res)
}
}

Expand Down Expand Up @@ -410,9 +414,13 @@ pub async fn uopool_service_run(

tokio::spawn(async move {
loop {
m_map
.iter_mut()
.for_each(|mut m| m.value_mut().reputation.update_hourly());
m_map.iter_mut().for_each(|mut m| {
let _ = m
.value_mut()
.reputation
.update_hourly()
.map_err(|e| warn!("Failed to update hourly reputation: {:?}", e));
});
tokio::time::sleep(Duration::from_secs(60 * 60)).await;
}
});
Expand Down
47 changes: 43 additions & 4 deletions crates/primitives/src/reputation.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
use educe::Educe;
use ethers::types::{Address, U256};
use ethers::{
prelude::{EthAbiCodec, EthAbiType},
types::{Address, U256},
};
use serde::{Deserialize, Serialize};

pub type ReputationStatus = u8;

pub const MIN_INCLUSION_RATE_DENOMINATOR: u64 = 10;
pub const THROTTLING_SLACK: u64 = 10;
pub const BAN_SLACK: u64 = 50;
Expand All @@ -10,16 +15,50 @@ pub const BAN_SLACK: u64 = 50;
pub const THROTTLED_MAX_INCLUDE: u64 = 1;

/// All possible reputation statuses
#[derive(Clone, Copy, Educe, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Default, Clone, Educe, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
#[educe(Debug)]
pub enum ReputationStatus {
pub enum Status {
#[default]
OK,
THROTTLED,
BANNED,
}

impl From<Status> for ReputationStatus {
fn from(status: Status) -> Self {
match status {
Status::OK => 0,
Status::THROTTLED => 1,
Status::BANNED => 2,
}
}
}

impl From<ReputationStatus> for Status {
fn from(status: ReputationStatus) -> Self {
match status {
0 => Status::OK,
1 => Status::THROTTLED,
2 => Status::BANNED,
_ => Status::OK,
}
}
}

/// Reputation entry for entities
#[derive(Clone, Copy, Educe, Eq, PartialEq, Serialize, Deserialize)]
#[derive(
Default,
Clone,
Educe,
Eq,
PartialEq,
PartialOrd,
Ord,
Serialize,
Deserialize,
EthAbiCodec,
EthAbiType,
)]
#[educe(Debug)]
pub struct ReputationEntry {
pub address: Address,
Expand Down
2 changes: 1 addition & 1 deletion crates/rpc/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl DebugApiServer for DebugApiServerImpl {
let mut uopool_grpc_client = self.uopool_grpc_client.clone();

let req = Request::new(SetReputationRequest {
rep: entries.iter().map(|re| (*re).into()).collect(),
rep: entries.iter().map(|re| re.clone().into()).collect(),
ep: Some(ep.into()),
});

Expand Down
120 changes: 120 additions & 0 deletions crates/uopool/src/database/env.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use reth_db::{
database::{Database, DatabaseGAT},
mdbx::{
tx::{self, Tx},
DatabaseFlags, Environment, EnvironmentFlags, EnvironmentKind, Geometry, Mode, PageSize,
SyncMode, RO, RW,
},
Error, TableType,
};
use std::{fmt::Display, path::PathBuf};

use super::tables::TABLES;

// Code adapted from: https://github.com/paradigmxyz/reth/blob/main/crates/storage/db/src/implementation/mdbx/mod.rs
#[derive(Debug)]
pub struct Env<E: EnvironmentKind> {
/// Libmdbx-sys environment.
pub inner: Environment<E>,
}

impl<'a, E: EnvironmentKind> DatabaseGAT<'a> for Env<E> {
type TX = tx::Tx<'a, RO, E>;
type TXMut = tx::Tx<'a, RW, E>;
}

impl<E: EnvironmentKind> Database for Env<E> {
fn tx(&self) -> Result<<Self as DatabaseGAT<'_>>::TX, Error> {
Ok(Tx::new(
self.inner
.begin_ro_txn()
.map_err(|e| Error::InitTransaction(e.into()))?,
))
}

fn tx_mut(&self) -> Result<<Self as DatabaseGAT<'_>>::TXMut, Error> {
Ok(Tx::new(
self.inner
.begin_rw_txn()
.map_err(|e| Error::InitTransaction(e.into()))?,
))
}
}

#[derive(Debug, PartialEq, Eq)]
pub enum DBError {
DBInternalError(Error),
NotFound,
}

impl From<Error> for DBError {
fn from(value: Error) -> Self {
DBError::DBInternalError(value)
}
}

impl Display for DBError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}

fn default_page_size() -> usize {
let os_page_size = page_size::get();

// source: https://gitflic.ru/project/erthink/libmdbx/blob?file=mdbx.h#line-num-821
let libmdbx_max_page_size = 0x10000;

// May lead to errors if it's reduced further because of the potential size of the
// data.
let min_page_size = 4096;

os_page_size.clamp(min_page_size, libmdbx_max_page_size)
}

impl<E: EnvironmentKind> Env<E> {
pub fn open(path: PathBuf) -> anyhow::Result<Self> {
let env = Environment::new()
.set_max_dbs(TABLES.len())
.set_geometry(Geometry {
size: Some(0..(1024 * 1024 * 1024 * 1024 * 4)), // TODO: reevaluate (4 tb)
growth_step: Some(1024 * 1024 * 256), // TODO: reevaluate (256 mb)
shrink_threshold: None,
page_size: Some(PageSize::Set(default_page_size())),
})
.set_flags(EnvironmentFlags {
mode: Mode::ReadWrite {
sync_mode: SyncMode::Durable,
},
no_rdahead: true, // TODO: reevaluate
coalesce: true,
..Default::default()
})
.open(path.as_path())
.map_err(|e| Error::DatabaseLocation(e.into()))?;

Ok(Self { inner: env })
}

/// Creates all the defined tables, if necessary
pub fn create_tables(&self) -> Result<(), Error> {
let tx = self
.inner
.begin_rw_txn()
.map_err(|e| Error::InitTransaction(e.into()))?;

for (table_type, table) in TABLES {
let flags = match table_type {
TableType::Table => DatabaseFlags::default(),
TableType::DupSort => DatabaseFlags::DUP_SORT,
};

tx.create_db(Some(table), flags)
.map_err(|e| Error::TableCreation(e.into()))?;
}

tx.commit().map_err(|e| Error::Commit(e.into()))?;

Ok(())
}
}
Loading

0 comments on commit e10d0b4

Please sign in to comment.