diff --git a/user-ops-indexer/Cargo.lock b/user-ops-indexer/Cargo.lock index 6122d7f41..0ba866a10 100644 --- a/user-ops-indexer/Cargo.lock +++ b/user-ops-indexer/Cargo.lock @@ -1170,8 +1170,10 @@ checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", "windows-targets 0.48.5", ] @@ -6465,6 +6467,7 @@ dependencies = [ "blockscout-display-bytes", "blockscout-service-launcher 0.9.0", "bytes", + "chrono", "ethabi", "ethers", "ethers-core", diff --git a/user-ops-indexer/user-ops-indexer-logic/Cargo.toml b/user-ops-indexer/user-ops-indexer-logic/Cargo.toml index 496304c92..b1dbd5bfa 100644 --- a/user-ops-indexer/user-ops-indexer-logic/Cargo.toml +++ b/user-ops-indexer/user-ops-indexer-logic/Cargo.toml @@ -41,6 +41,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] } ethers = { version = "2.0.11", features = ["ws"] } num-traits = "0.2.17" itertools = "0.11.0" +chrono = "0.4.31" [dev-dependencies] async-trait = "0.1" diff --git a/user-ops-indexer/user-ops-indexer-logic/src/indexer/v06/indexer.rs b/user-ops-indexer/user-ops-indexer-logic/src/indexer/v06/indexer.rs index 98733109b..801e9f21e 100644 --- a/user-ops-indexer/user-ops-indexer-logic/src/indexer/v06/indexer.rs +++ b/user-ops-indexer/user-ops-indexer-logic/src/indexer/v06/indexer.rs @@ -275,8 +275,8 @@ impl<'a, C: PubsubClient> IndexerV06<'a, C> { .filter_map(|(j, (raw_user_op, logs))| { match build_user_op_model( bundler, - i as u64, - j as u64, + i as u32, + j as u32, raw_user_op, logs, &tx_deposits, @@ -322,8 +322,8 @@ impl<'a, C: PubsubClient> IndexerV06<'a, C> { fn build_user_op_model( bundler: Address, - bundle_index: u64, - index: u64, + bundle_index: u32, + index: u32, raw_user_op: RawUserOperation, logs: &[Log], tx_deposits: &[DepositedFilter], @@ -411,8 +411,8 @@ fn build_user_op_model( sponsor_type, user_logs_start_index: logs .first() - .map_or(0, |l| l.log_index.map_or(0, |v| v.as_u64())), - user_logs_count: user_logs_count as u64, + .map_or(0, |l| l.log_index.map_or(0, |v| v.as_u32())), + user_logs_count: user_logs_count as u32, fee: user_op_event.actual_gas_cost, consensus: None, diff --git a/user-ops-indexer/user-ops-indexer-logic/src/repository/account.rs b/user-ops-indexer/user-ops-indexer-logic/src/repository/account.rs index 5149c6ffe..bde314cbc 100644 --- a/user-ops-indexer/user-ops-indexer-logic/src/repository/account.rs +++ b/user-ops-indexer/user-ops-indexer-logic/src/repository/account.rs @@ -134,7 +134,7 @@ mod tests { factory: Some(Address::from_low_u64_be(0xf1)), creation_transaction_hash: Some(H256::from_low_u64_be(0x3204)), creation_op_hash: Some(H256::from_low_u64_be(0x3201)), - creation_timestamp: Some(1704067260), + creation_timestamp: Some("2024-01-01T00:01:00.000000Z".to_string()), total_ops: 100, }) ); diff --git a/user-ops-indexer/user-ops-indexer-logic/src/repository/bundle.rs b/user-ops-indexer/user-ops-indexer-logic/src/repository/bundle.rs index b82e4d24e..b4cc191b8 100644 --- a/user-ops-indexer/user-ops-indexer-logic/src/repository/bundle.rs +++ b/user-ops-indexer/user-ops-indexer-logic/src/repository/bundle.rs @@ -16,9 +16,9 @@ pub async fn list_bundles( db: &DatabaseConnection, bundler_filter: Option
, entry_point_filter: Option
, - page_token: Option<(u64, H256, u64)>, + page_token: Option<(u64, H256, u32)>, limit: u64, -) -> Result<(Vec, Option<(u64, H256, u64)>), anyhow::Error> { +) -> Result<(Vec, Option<(u64, H256, u32)>), anyhow::Error> { let page_token = page_token.unwrap_or((i64::MAX as u64, H256::zero(), 0)); let bundles: Vec = BundleDB::find_by_statement(Statement::from_sql_and_values( db.get_database_backend(), diff --git a/user-ops-indexer/user-ops-indexer-logic/src/repository/user_op.rs b/user-ops-indexer/user-ops-indexer-logic/src/repository/user_op.rs index 2cae3fe7c..b09e435b1 100644 --- a/user-ops-indexer/user-ops-indexer-logic/src/repository/user_op.rs +++ b/user-ops-indexer/user-ops-indexer-logic/src/repository/user_op.rs @@ -65,9 +65,10 @@ pub async fn find_user_op_by_op_hash( let user_op = Model::from_query_result(&res, "")?; let mut user_op = UserOp::from(user_op); user_op.consensus = res.try_get("", "consensus")?; - user_op.timestamp = res - .try_get::>("", "timestamp")? - .map(|t| t.timestamp() as u64); + user_op.timestamp = res.try_get::>("", "timestamp")?.map(|t| { + t.and_utc() + .to_rfc3339_opts(chrono::SecondsFormat::Micros, true) + }); Some(user_op) } }; @@ -84,7 +85,7 @@ pub async fn list_user_ops( factory_filter: Option
, tx_hash_filter: Option, entry_point_filter: Option
, - bundle_index_filter: Option, + bundle_index_filter: Option, block_number_filter: Option, page_token: Option<(u64, H256)>, limit: u64, @@ -318,7 +319,7 @@ mod tests { block_number: 0, sender: Address::from_low_u64_be(0x0502), transaction_hash: H256::from_low_u64_be(0x0504), - timestamp: 1704067200, + timestamp: "2024-01-01T00:00:00.000000Z".to_string(), status: true, fee: U256::from(56001575011025u64), }, @@ -327,7 +328,7 @@ mod tests { block_number: 0, sender: Address::from_low_u64_be(0x0502), transaction_hash: H256::from_low_u64_be(0x0504), - timestamp: 1704067200, + timestamp: "2024-01-01T00:00:00.000000Z".to_string(), status: true, fee: U256::from(56000075000025u64), } diff --git a/user-ops-indexer/user-ops-indexer-logic/src/types/account.rs b/user-ops-indexer/user-ops-indexer-logic/src/types/account.rs index 33601d0f9..309445bb1 100644 --- a/user-ops-indexer/user-ops-indexer-logic/src/types/account.rs +++ b/user-ops-indexer/user-ops-indexer-logic/src/types/account.rs @@ -9,7 +9,7 @@ pub struct Account { pub factory: Option
, pub creation_transaction_hash: Option, pub creation_op_hash: Option, - pub creation_timestamp: Option, + pub creation_timestamp: Option, pub total_ops: u32, } @@ -20,7 +20,10 @@ impl From for Account { factory: v.factory.map(|a| Address::from_slice(&a)), creation_transaction_hash: v.creation_transaction_hash.map(|a| H256::from_slice(&a)), creation_op_hash: v.creation_op_hash.map(|a| H256::from_slice(&a)), - creation_timestamp: v.creation_timestamp.map(|t| t.timestamp() as u64), + creation_timestamp: v.creation_timestamp.map(|t| { + t.and_utc() + .to_rfc3339_opts(chrono::SecondsFormat::Micros, true) + }), total_ops: v.total_ops as u32, } } diff --git a/user-ops-indexer/user-ops-indexer-logic/src/types/bundle.rs b/user-ops-indexer/user-ops-indexer-logic/src/types/bundle.rs index 67b591091..85e1f1a7a 100644 --- a/user-ops-indexer/user-ops-indexer-logic/src/types/bundle.rs +++ b/user-ops-indexer/user-ops-indexer-logic/src/types/bundle.rs @@ -6,10 +6,10 @@ use ethers_core::{abi::AbiEncode, utils::to_checksum}; #[derive(Clone, Debug, PartialEq)] pub struct Bundle { pub transaction_hash: H256, - pub bundle_index: u64, + pub bundle_index: u32, pub block_number: u64, pub bundler: Address, - pub timestamp: u64, + pub timestamp: String, pub total_ops: u32, } @@ -17,11 +17,14 @@ impl From for Bundle { fn from(v: BundleDB) -> Self { Self { transaction_hash: H256::from_slice(&v.transaction_hash), - bundle_index: v.bundle_index as u64, + bundle_index: v.bundle_index as u32, block_number: v.block_number as u64, bundler: Address::from_slice(&v.bundler), total_ops: v.total_ops as u32, - timestamp: v.timestamp.timestamp() as u64, + timestamp: v + .timestamp + .and_utc() + .to_rfc3339_opts(chrono::SecondsFormat::Micros, true), } } } diff --git a/user-ops-indexer/user-ops-indexer-logic/src/types/user_op.rs b/user-ops-indexer/user-ops-indexer-logic/src/types/user_op.rs index 9ea7b56e3..59150fa13 100644 --- a/user-ops-indexer/user-ops-indexer-logic/src/types/user_op.rs +++ b/user-ops-indexer/user-ops-indexer-logic/src/types/user_op.rs @@ -28,8 +28,8 @@ pub struct UserOp { pub block_number: u64, pub block_hash: H256, pub bundler: Address, - pub bundle_index: u64, - pub index: u64, + pub bundle_index: u32, + pub index: u32, pub factory: Option
, pub paymaster: Option
, pub status: bool, @@ -38,12 +38,12 @@ pub struct UserOp { pub gas_price: U256, pub gas_used: u64, pub sponsor_type: SponsorType, - pub user_logs_start_index: u64, - pub user_logs_count: u64, + pub user_logs_start_index: u32, + pub user_logs_count: u32, pub fee: U256, pub consensus: Option, - pub timestamp: Option, + pub timestamp: Option, } #[derive(Clone, Debug, PartialEq)] @@ -52,7 +52,7 @@ pub struct ListUserOp { pub block_number: u64, pub sender: Address, pub transaction_hash: H256, - pub timestamp: u64, + pub timestamp: String, pub status: bool, pub fee: U256, } @@ -119,8 +119,8 @@ impl From for UserOp { block_number: v.block_number as u64, block_hash: H256::from_slice(&v.block_hash), bundler: Address::from_slice(&v.bundler), - bundle_index: v.bundle_index as u64, - index: v.index as u64, + bundle_index: v.bundle_index as u32, + index: v.index as u32, factory: v.factory.clone().map(|a| Address::from_slice(&a)), paymaster: v.paymaster.clone().map(|a| Address::from_slice(&a)), status: v.status, @@ -129,8 +129,8 @@ impl From for UserOp { gas_price: U256::from(v.gas_price.to_u128().unwrap_or(0)), gas_used: v.gas_used.to_u64().unwrap_or(0), sponsor_type: v.sponsor_type.clone(), - user_logs_start_index: v.user_logs_start_index as u64, - user_logs_count: v.user_logs_count as u64, + user_logs_start_index: v.user_logs_start_index as u32, + user_logs_count: v.user_logs_count as u32, fee: U256::from(v.gas_price.mul(v.gas_used).to_u128().unwrap_or(0)), consensus: None, @@ -145,18 +145,34 @@ impl From for user_ops_indexer_proto::blockscout::user_ops_indexer::v1:: hash: v.hash.encode_hex(), sender: to_checksum(&v.sender, None), nonce: v.nonce.encode_hex(), - init_code: v.init_code.map(|b| b.to_string()), call_data: v.call_data.to_string(), call_gas_limit: v.call_gas_limit, verification_gas_limit: v.verification_gas_limit, pre_verification_gas: v.pre_verification_gas, max_fee_per_gas: v.max_fee_per_gas.to_string(), max_priority_fee_per_gas: v.max_priority_fee_per_gas.to_string(), - paymaster_and_data: v.paymaster_and_data.map(|b| b.to_string()), signature: v.signature.to_string(), + raw: Some( + user_ops_indexer_proto::blockscout::user_ops_indexer::v1::RawUserOp { + sender: to_checksum(&v.sender, None), + nonce: U256::from(v.nonce.as_fixed_bytes()).to_string(), + init_code: v.init_code.map_or("0x".to_string(), |b| b.to_string()), + call_data: v.call_data.to_string(), + call_gas_limit: v.call_gas_limit, + verification_gas_limit: v.verification_gas_limit, + pre_verification_gas: v.pre_verification_gas, + max_fee_per_gas: v.max_fee_per_gas.to_string(), + max_priority_fee_per_gas: v.max_priority_fee_per_gas.to_string(), + paymaster_and_data: v + .paymaster_and_data + .map_or("0x".to_string(), |b| b.to_string()), + signature: v.signature.to_string(), + }, + ), aggregator: v.aggregator.map(|a| to_checksum(&a, None)), aggregator_signature: v.aggregator_signature.map(|b| b.to_string()), entry_point: to_checksum(&v.entry_point, None), + entry_point_version: "v0.6".to_string(), transaction_hash: v.transaction_hash.encode_hex(), block_number: v.block_number, block_hash: v.block_hash.encode_hex(), @@ -188,7 +204,10 @@ impl From for ListUserOp { block_number: v.block_number as u64, sender: Address::from_slice(&v.sender), transaction_hash: H256::from_slice(&v.transaction_hash), - timestamp: v.timestamp.timestamp() as u64, + timestamp: v + .timestamp + .and_utc() + .to_rfc3339_opts(chrono::SecondsFormat::Micros, true), status: v.status, fee: U256::from(v.gas_price.mul(v.gas_used).to_u128().unwrap_or(0)), } diff --git a/user-ops-indexer/user-ops-indexer-proto/proto/user-ops-indexer.proto b/user-ops-indexer/user-ops-indexer-proto/proto/user-ops-indexer.proto index f01e4c245..c460d1226 100644 --- a/user-ops-indexer/user-ops-indexer-proto/proto/user-ops-indexer.proto +++ b/user-ops-indexer/user-ops-indexer-proto/proto/user-ops-indexer.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package blockscout.userOpsIndexer.v1; +import "google/protobuf/struct.proto"; + option go_package = "github.com/blockscout/blockscout-rs/user-ops-indexer"; service UserOpsService { @@ -74,7 +76,7 @@ message ListUserOpsRequest { optional string factory = 4; optional string transaction_hash = 5; optional string entry_point = 6; - optional uint64 bundle_index = 7; + optional uint32 bundle_index = 7; optional uint64 block_number = 8; optional uint32 page_size = 9; optional string page_token = 10; @@ -120,7 +122,7 @@ message Account { optional string factory = 2; optional string creation_transaction_hash = 3; optional string creation_op_hash = 4; - optional uint64 creation_timestamp = 5; + optional string creation_timestamp = 5; uint32 total_ops = 6; } @@ -128,8 +130,8 @@ message Bundle { string transaction_hash = 1; string bundler = 2; uint64 block_number = 3; - uint64 bundle_index = 4; - uint64 timestamp = 5; + uint32 bundle_index = 4; + string timestamp = 5; uint32 total_ops = 6; } @@ -149,28 +151,42 @@ message Factory { uint32 total_accounts = 2; } +message RawUserOp { + string sender = 1; + string nonce = 2; + string init_code = 3; + string call_data = 4; + uint64 call_gas_limit = 5; + uint64 verification_gas_limit = 6; + uint64 pre_verification_gas = 7; + string max_fee_per_gas = 8; + string max_priority_fee_per_gas = 9; + string paymaster_and_data = 10; + string signature = 11; +} + message UserOp { string hash = 1; string sender = 2; string nonce = 3; - optional string init_code = 4; - string call_data = 5; - uint64 call_gas_limit = 6; - uint64 verification_gas_limit = 7; - uint64 pre_verification_gas = 8; - string max_fee_per_gas = 9; - string max_priority_fee_per_gas = 10; - optional string paymaster_and_data = 11; - string signature = 12; - optional string aggregator = 13; - optional string aggregator_signature = 14; - string entry_point = 15; + string call_data = 4; + uint64 call_gas_limit = 5; + uint64 verification_gas_limit = 6; + uint64 pre_verification_gas = 7; + string max_fee_per_gas = 8; + string max_priority_fee_per_gas = 9; + string signature = 10; + RawUserOp raw = 11; + optional string aggregator = 12; + optional string aggregator_signature = 13; + string entry_point = 14; + string entry_point_version = 15; string transaction_hash = 16; uint64 block_number = 17; string block_hash = 18; string bundler = 19; - uint64 bundle_index = 20; - uint64 index = 21; + uint32 bundle_index = 20; + uint32 index = 21; optional string factory = 22; optional string paymaster = 23; bool status = 24; @@ -179,12 +195,12 @@ message UserOp { string gas_price = 27; uint64 gas_used = 28; string sponsor_type = 29; - uint64 user_logs_start_index = 30; - uint64 user_logs_count = 31; + uint32 user_logs_start_index = 30; + uint32 user_logs_count = 31; string fee = 32; optional bool consensus = 33; - optional uint64 timestamp = 34; + optional string timestamp = 34; } message ListUserOp { @@ -192,7 +208,7 @@ message ListUserOp { uint64 block_number = 2; string transaction_hash = 3; string address = 4; - uint64 timestamp = 5; + string timestamp = 5; bool status = 6; string fee = 7; } diff --git a/user-ops-indexer/user-ops-indexer-proto/swagger/user-ops-indexer.swagger.yaml b/user-ops-indexer/user-ops-indexer-proto/swagger/user-ops-indexer.swagger.yaml index bc9efaa7e..cf51c84e8 100644 --- a/user-ops-indexer/user-ops-indexer-proto/swagger/user-ops-indexer.swagger.yaml +++ b/user-ops-indexer/user-ops-indexer-proto/swagger/user-ops-indexer.swagger.yaml @@ -258,8 +258,8 @@ paths: - name: bundle_index in: query required: false - type: string - format: uint64 + type: integer + format: int64 - name: block_number in: query required: false @@ -358,7 +358,6 @@ definitions: type: string creation_timestamp: type: string - format: uint64 total_ops: type: integer format: int64 @@ -373,11 +372,10 @@ definitions: type: string format: uint64 bundle_index: - type: string - format: uint64 + type: integer + format: int64 timestamp: type: string - format: uint64 total_ops: type: integer format: int64 @@ -464,7 +462,6 @@ definitions: type: string timestamp: type: string - format: uint64 status: type: boolean fee: @@ -494,11 +491,9 @@ definitions: total_ops: type: integer format: int64 - v1UserOp: + v1RawUserOp: type: object properties: - hash: - type: string sender: type: string nonce: @@ -524,12 +519,42 @@ definitions: type: string signature: type: string + v1UserOp: + type: object + properties: + hash: + type: string + sender: + type: string + nonce: + type: string + call_data: + type: string + call_gas_limit: + type: string + format: uint64 + verification_gas_limit: + type: string + format: uint64 + pre_verification_gas: + type: string + format: uint64 + max_fee_per_gas: + type: string + max_priority_fee_per_gas: + type: string + signature: + type: string + raw: + $ref: '#/definitions/v1RawUserOp' aggregator: type: string aggregator_signature: type: string entry_point: type: string + entry_point_version: + type: string transaction_hash: type: string block_number: @@ -540,11 +565,11 @@ definitions: bundler: type: string bundle_index: - type: string - format: uint64 + type: integer + format: int64 index: - type: string - format: uint64 + type: integer + format: int64 factory: type: string paymaster: @@ -564,15 +589,14 @@ definitions: sponsor_type: type: string user_logs_start_index: - type: string - format: uint64 + type: integer + format: int64 user_logs_count: - type: string - format: uint64 + type: integer + format: int64 fee: type: string consensus: type: boolean timestamp: type: string - format: uint64 diff --git a/user-ops-indexer/user-ops-indexer-server/src/services/user_ops.rs b/user-ops-indexer/user-ops-indexer-server/src/services/user_ops.rs index b48d144e7..f21e38bb0 100644 --- a/user-ops-indexer/user-ops-indexer-server/src/services/user_ops.rs +++ b/user-ops-indexer/user-ops-indexer-server/src/services/user_ops.rs @@ -174,7 +174,7 @@ impl UserOps for UserOpsService { let bundler_filter = inner.bundler.map(parse_filter).transpose()?; let entry_point_filter = inner.entry_point.map(parse_filter).transpose()?; - let page_token: Option<(u64, H256, u64)> = + let page_token: Option<(u64, H256, u32)> = inner.page_token.map(parse_filter_3).transpose()?; let page_size = self.normalize_page_size(inner.page_size);