diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 14c1b770b..2becbdb84 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -199,9 +199,9 @@ dependencies = [ [[package]] name = "aptos-indexer-test-transactions" version = "1.0.0" -source = "git+https://github.com/aptos-labs/aptos-core.git?rev=80b98ce2c8cda854f3bccf0e8649d33606e624eb#80b98ce2c8cda854f3bccf0e8649d33606e624eb" +source = "git+https://github.com/aptos-labs/aptos-core.git?rev=e80c1336de5f3a8b83dfe5539936a79ef9c1edb8#e80c1336de5f3a8b83dfe5539936a79ef9c1edb8" dependencies = [ - "aptos-protos 1.3.1 (git+https://github.com/aptos-labs/aptos-core.git?rev=80b98ce2c8cda854f3bccf0e8649d33606e624eb)", + "aptos-protos 1.3.1 (git+https://github.com/aptos-labs/aptos-core.git?rev=e80c1336de5f3a8b83dfe5539936a79ef9c1edb8)", "serde_json", ] @@ -309,7 +309,7 @@ dependencies = [ [[package]] name = "aptos-protos" version = "1.3.1" -source = "git+https://github.com/aptos-labs/aptos-core.git?rev=80b98ce2c8cda854f3bccf0e8649d33606e624eb#80b98ce2c8cda854f3bccf0e8649d33606e624eb" +source = "git+https://github.com/aptos-labs/aptos-core.git?rev=e80c1336de5f3a8b83dfe5539936a79ef9c1edb8#e80c1336de5f3a8b83dfe5539936a79ef9c1edb8" dependencies = [ "pbjson", "prost 0.13.4", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 3dbf920bc..002c14eb4 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -31,7 +31,7 @@ anyhow = "1.0.86" aptos-indexer-processor-sdk = { git = "https://github.com/aptos-labs/aptos-indexer-processor-sdk.git", rev = "b79ed8b5864b2a12a1f9c5fd01579462e029b2ae" } aptos-indexer-processor-sdk-server-framework = { git = "https://github.com/aptos-labs/aptos-indexer-processor-sdk.git", rev = "b79ed8b5864b2a12a1f9c5fd01579462e029b2ae" } aptos-protos = { git = "https://github.com/aptos-labs/aptos-core.git", rev = "1d8460a995503574ec4e9699d3442d0150d7f3b9" } -aptos-indexer-test-transactions = { git = "https://github.com/aptos-labs/aptos-core.git", rev = "80b98ce2c8cda854f3bccf0e8649d33606e624eb" } +aptos-indexer-test-transactions = { git = "https://github.com/aptos-labs/aptos-core.git", rev = "e80c1336de5f3a8b83dfe5539936a79ef9c1edb8" } aptos-indexer-testing-framework = { git = "https://github.com/aptos-labs/aptos-indexer-processor-sdk.git", rev = "b79ed8b5864b2a12a1f9c5fd01579462e029b2ae" } async-trait = "0.1.53" backtrace = "0.3.58" diff --git a/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/coin_supply.json b/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/coin_supply.json new file mode 100644 index 000000000..882b9c5cd --- /dev/null +++ b/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/coin_supply.json @@ -0,0 +1,10 @@ +[ + { + "transaction_version": 2448304257, + "coin_type_hash": "91ceb1308a98389691e05158b07ed5f079ab78461a6bb8d5a4054b1bb5cb8bb6", + "coin_type": "0x1::aptos_coin::AptosCoin", + "supply": "114337055298908041", + "transaction_timestamp": "2025-03-07T22:32:23", + "transaction_epoch": 10582 + } +] \ No newline at end of file diff --git a/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/current_fungible_asset_balances.json b/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/current_fungible_asset_balances.json new file mode 100644 index 000000000..703d27cab --- /dev/null +++ b/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/current_fungible_asset_balances.json @@ -0,0 +1,40 @@ +[ + { + "storage_id": "0x35b5700571cbb1c340c5a2fa7e1ecc32fd8b4da273881c2728058bd4c2514895", + "owner_address": "0x2dcbc03740a6fa2efee926b9df329184cce357d0573bdab09930f4d48e61a4c8", + "asset_type_v2": null, + "asset_type_v1": "0x1::aptos_coin::AptosCoin", + "is_primary": true, + "is_frozen": false, + "amount_v1": "25361327420", + "amount_v2": null, + "amount": "25361327420", + "last_transaction_version_v1": 2448304257, + "last_transaction_version_v2": null, + "last_transaction_version": 2448304257, + "last_transaction_timestamp_v1": "2025-03-07T22:32:23", + "last_transaction_timestamp_v2": null, + "last_transaction_timestamp": "2025-03-07T22:32:23", + "token_standard": "v1", + "asset_type": "0x1::aptos_coin::AptosCoin" + }, + { + "storage_id": "0xd5263bada2f6b752de987f5e8eca800ffb07f34c489633fc7eb46acea7cd5c37", + "owner_address": "0xf8e25f6c8ce40a15107fb4b4d288ca03dd434d057392f2ccb5fde505a300a0bf", + "asset_type_v2": "0x000000000000000000000000000000000000000000000000000000000000000a", + "asset_type_v1": "0x1::aptos_coin::AptosCoin", + "is_primary": true, + "is_frozen": false, + "amount_v1": "0", + "amount_v2": "49843000", + "amount": "49843000", + "last_transaction_version_v1": 2448304257, + "last_transaction_version_v2": 2448304257, + "last_transaction_version": 2448304257, + "last_transaction_timestamp_v1": "2025-03-07T22:32:23", + "last_transaction_timestamp_v2": "2025-03-07T22:32:23", + "last_transaction_timestamp": "2025-03-07T22:32:23", + "token_standard": "v1", + "asset_type": "0x1::aptos_coin::AptosCoin" + } +] \ No newline at end of file diff --git a/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/fungible_asset_activities.json b/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/fungible_asset_activities.json new file mode 100644 index 000000000..61322ab42 --- /dev/null +++ b/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/fungible_asset_activities.json @@ -0,0 +1,56 @@ +[ + { + "transaction_version": 2448304257, + "event_index": -1, + "owner_address": "0xf8e25f6c8ce40a15107fb4b4d288ca03dd434d057392f2ccb5fde505a300a0bf", + "storage_id": "0xd5263bada2f6b752de987f5e8eca800ffb07f34c489633fc7eb46acea7cd5c37", + "asset_type": "0x1::aptos_coin::AptosCoin", + "is_frozen": null, + "amount": "57000", + "type_": "0x1::aptos_coin::GasFeeEvent", + "is_gas_fee": true, + "gas_fee_payer_address": null, + "is_transaction_success": true, + "entry_function_id_str": "0xa746e980ae21949a4f084db7403430f00bce3c9a1da4101ffcf0bf45ebd35e7e::test::transfer_and_migrate", + "block_height": 300296983, + "token_standard": "v1", + "transaction_timestamp": "2025-03-07T22:32:23", + "storage_refund_amount": "0" + }, + { + "transaction_version": 2448304257, + "event_index": 0, + "owner_address": "0xf8e25f6c8ce40a15107fb4b4d288ca03dd434d057392f2ccb5fde505a300a0bf", + "storage_id": "0xd5263bada2f6b752de987f5e8eca800ffb07f34c489633fc7eb46acea7cd5c37", + "asset_type": "0x1::aptos_coin::AptosCoin", + "is_frozen": null, + "amount": "100000", + "type_": "0x1::coin::WithdrawEvent", + "is_gas_fee": false, + "gas_fee_payer_address": null, + "is_transaction_success": true, + "entry_function_id_str": "0xa746e980ae21949a4f084db7403430f00bce3c9a1da4101ffcf0bf45ebd35e7e::test::transfer_and_migrate", + "block_height": 300296983, + "token_standard": "v1", + "transaction_timestamp": "2025-03-07T22:32:23", + "storage_refund_amount": "0" + }, + { + "transaction_version": 2448304257, + "event_index": 1, + "owner_address": "0x2dcbc03740a6fa2efee926b9df329184cce357d0573bdab09930f4d48e61a4c8", + "storage_id": "0x35b5700571cbb1c340c5a2fa7e1ecc32fd8b4da273881c2728058bd4c2514895", + "asset_type": "0x1::aptos_coin::AptosCoin", + "is_frozen": null, + "amount": "100000", + "type_": "0x1::coin::DepositEvent", + "is_gas_fee": false, + "gas_fee_payer_address": null, + "is_transaction_success": true, + "entry_function_id_str": "0xa746e980ae21949a4f084db7403430f00bce3c9a1da4101ffcf0bf45ebd35e7e::test::transfer_and_migrate", + "block_height": 300296983, + "token_standard": "v1", + "transaction_timestamp": "2025-03-07T22:32:23", + "storage_refund_amount": "0" + } +] \ No newline at end of file diff --git a/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/fungible_asset_balances.json b/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/fungible_asset_balances.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/fungible_asset_balances.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/fungible_asset_metadata.json b/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/fungible_asset_metadata.json new file mode 100644 index 000000000..8b26da73c --- /dev/null +++ b/rust/integration-tests/sdk_expected_db_output_files/fungible_asset_processor/migration_with_coin_store_deletion_event/fungible_asset_metadata.json @@ -0,0 +1,19 @@ +[ + { + "asset_type": "0x000000000000000000000000000000000000000000000000000000000000000a", + "creator_address": "0x0000000000000000000000000000000000000000000000000000000000000001", + "name": "Aptos Coin", + "symbol": "APT", + "decimals": 8, + "icon_uri": "", + "project_uri": "", + "last_transaction_version": 2448304257, + "last_transaction_timestamp": "2025-03-07T22:32:23", + "supply_aggregator_table_handle_v1": null, + "supply_aggregator_table_key_v1": null, + "token_standard": "v2", + "maximum_v2": "340282366920938463463374607431768211455", + "is_token_v2": null, + "supply_v2": "118281485271096" + } +] \ No newline at end of file diff --git a/rust/integration-tests/src/sdk_tests/events_processor_tests.rs b/rust/integration-tests/src/sdk_tests/events_processor_tests.rs index 5d1012868..066385172 100644 --- a/rust/integration-tests/src/sdk_tests/events_processor_tests.rs +++ b/rust/integration-tests/src/sdk_tests/events_processor_tests.rs @@ -57,7 +57,6 @@ mod tests { }; use aptos_indexer_processor_sdk::traits::processor_trait::ProcessorTrait; use aptos_indexer_test_transactions::json_transactions::generated_transactions::{ - IMPORTED_DEVNET_TXNS_78753811_COIN_TRANSFER_WITH_V2_EVENTS, IMPORTED_DEVNET_TXNS_78753831_TOKEN_V1_MINT_TRANSFER_WITH_V2_EVENTS, IMPORTED_DEVNET_TXNS_78753832_TOKEN_V2_MINT_TRANSFER_WITH_V2_EVENTS, IMPORTED_MAINNET_TXNS_554229017_EVENTS_WITH_NO_EVENT_SIZE_INFO, @@ -133,15 +132,6 @@ mod tests { .await; } - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn devnet_events_processor_coin_module_events() { - process_single_devnet_event_txn( - IMPORTED_DEVNET_TXNS_78753811_COIN_TRANSFER_WITH_V2_EVENTS, - Some("coin_event_v2".to_string()), - ) - .await; - } - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn devnet_events_processor_token_v1_module_events() { process_single_devnet_event_txn( diff --git a/rust/integration-tests/src/sdk_tests/fungible_asset_processor_tests.rs b/rust/integration-tests/src/sdk_tests/fungible_asset_processor_tests.rs index f73d1efe7..12d9178c0 100644 --- a/rust/integration-tests/src/sdk_tests/fungible_asset_processor_tests.rs +++ b/rust/integration-tests/src/sdk_tests/fungible_asset_processor_tests.rs @@ -57,13 +57,13 @@ mod sdk_fungible_asset_processor_tests { }, }; use aptos_indexer_test_transactions::json_transactions::generated_transactions::{ - IMPORTED_DEVNET_TXNS_78753811_COIN_TRANSFER_WITH_V2_EVENTS, IMPORTED_MAINNET_TXNS_1680592683_FA_MIGRATION_COIN_INFO, IMPORTED_MAINNET_TXNS_1737056775_COIN_TRANSFER_BURN_EVENT, IMPORTED_MAINNET_TXNS_1957950162_FA_MIGRATION_V2_STORE_ONLY, IMPORTED_MAINNET_TXNS_2186504987_COIN_STORE_DELETION_NO_EVENT, IMPORTED_MAINNET_TXNS_2308282694_ASSET_TYPE_V1_NULL, IMPORTED_MAINNET_TXNS_2308283617_ASSET_TYPE_V1_NULL_2, + IMPORTED_MAINNET_TXNS_2448304257_COINSTORE_DELETION_EVENT, IMPORTED_MAINNET_TXNS_255894550_STORAGE_REFUND, IMPORTED_MAINNET_TXNS_508365567_FA_V1_EVENTS, IMPORTED_MAINNET_TXNS_550582915_MULTIPLE_TRANSFER_EVENT, @@ -178,17 +178,6 @@ mod sdk_fungible_asset_processor_tests { .await; } - /// Tests processing of coin v2 events - /// Validates the handling of updated coin event formats - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn test_fungible_asset_processor_coin_v2_events() { - process_single_batch_txns( - &[IMPORTED_DEVNET_TXNS_78753811_COIN_TRANSFER_WITH_V2_EVENTS], - Some("coin_v2_events".to_string()), - ) - .await; - } - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_fungible_asset_processor_coin_store_deletion_no_event() { process_single_batch_txns( @@ -292,6 +281,15 @@ mod sdk_fungible_asset_processor_tests { .await; } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_fungible_asset_processor_fa_migration_with_coin_store_deletion() { + process_single_batch_txns( + &[IMPORTED_MAINNET_TXNS_2448304257_COINSTORE_DELETION_EVENT], + Some("migration_with_coin_store_deletion_event".to_string()), + ) + .await; + } + /// Tests processing of two transactions sequentially /// Validates handling of multiple transactions with shared context async fn sequential_multi_transaction_helper_function( diff --git a/rust/processor/src/db/postgres/models/fungible_asset_models/v2_fungible_asset_utils.rs b/rust/processor/src/db/postgres/models/fungible_asset_models/v2_fungible_asset_utils.rs index b711a8a4b..ba7a34362 100644 --- a/rust/processor/src/db/postgres/models/fungible_asset_models/v2_fungible_asset_utils.rs +++ b/rust/processor/src/db/postgres/models/fungible_asset_models/v2_fungible_asset_utils.rs @@ -20,6 +20,35 @@ use serde::{Deserialize, Serialize}; const FUNGIBLE_ASSET_LENGTH: usize = 32; const FUNGIBLE_ASSET_SYMBOL: usize = 32; +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct CoinStoreDeletionEvent { + pub coin_type: String, + pub event_handle_creation_address: String, + #[serde(deserialize_with = "deserialize_from_string")] + pub deleted_deposit_event_handle_creation_number: u64, + #[serde(deserialize_with = "deserialize_from_string")] + pub deleted_withdraw_event_handle_creation_number: u64, +} + +impl CoinStoreDeletionEvent { + pub fn from_event(data_type: &str, data: &str, txn_version: i64) -> Option { + if data_type == "0x1::coin::CoinStoreDeletion" { + let coin_store_deletion: CoinStoreDeletionEvent = serde_json::from_str(data) + .unwrap_or_else(|_| { + tracing::error!( + transaction_version = txn_version, + data = data, + "failed to parse event for coin store deletion" + ); + panic!(); + }); + Some(coin_store_deletion) + } else { + None + } + } +} + #[derive(Serialize, Deserialize, Debug, Clone)] pub struct FeeStatement { #[serde(deserialize_with = "deserialize_from_string")] diff --git a/rust/processor/src/processors/fungible_asset_processor.rs b/rust/processor/src/processors/fungible_asset_processor.rs index 25027a004..544df256a 100644 --- a/rust/processor/src/processors/fungible_asset_processor.rs +++ b/rust/processor/src/processors/fungible_asset_processor.rs @@ -27,14 +27,14 @@ use crate::{ }, }, postgres::models::{ - coin_models::coin_supply::CoinSupply, + coin_models::{coin_supply::CoinSupply, coin_utils::EventGuidResource}, fungible_asset_models::{ v2_fungible_asset_activities::{EventToCoinType, FungibleAssetActivity}, v2_fungible_asset_balances::{ CurrentUnifiedFungibleAssetBalance, FungibleAssetBalance, }, v2_fungible_asset_to_coin_mappings::FungibleAssetToCoinMapping, - v2_fungible_asset_utils::FeeStatement, + v2_fungible_asset_utils::{CoinStoreDeletionEvent, FeeStatement}, v2_fungible_metadata::FungibleAssetMetadataModel, }, resources::{FromWriteResource, V2FungibleAssetResource}, @@ -708,6 +708,37 @@ pub async fn parse_v2_coin( fungible_asset_activities.push(gas_event); } + // The CoinStoreDeletionEvent, only need for v1 with migration + if user_request.is_some() { + events + .iter() + .filter_map(|event| { + let event_type = event.type_str.as_str(); + CoinStoreDeletionEvent::from_event(event_type, &event.data, txn_version) + }) + .for_each(|coin_store_deletion| { + let addr = standardize_address( + coin_store_deletion.event_handle_creation_address.as_str(), + ); + let deposit_event_guid = EventGuidResource { + addr: addr.clone(), + creation_num: coin_store_deletion + .deleted_deposit_event_handle_creation_number + as i64, + }; + let withdraw_event_guid = EventGuidResource { + addr, + creation_num: coin_store_deletion + .deleted_withdraw_event_handle_creation_number + as i64, + }; + event_to_v1_coin_type + .insert(deposit_event_guid, coin_store_deletion.coin_type.clone()); + event_to_v1_coin_type + .insert(withdraw_event_guid, coin_store_deletion.coin_type); + }); + } + // Loop 3 to handle events and collect additional metadata from events for v2 for (index, event) in events.iter().enumerate() { if let Some(v1_activity) = RawFungibleAssetActivity::get_v1_from_event( diff --git a/rust/processor/src/processors/parquet_processors/parquet_fungible_asset_activities_processor.rs b/rust/processor/src/processors/parquet_processors/parquet_fungible_asset_activities_processor.rs index ff086219e..522facfaf 100644 --- a/rust/processor/src/processors/parquet_processors/parquet_fungible_asset_activities_processor.rs +++ b/rust/processor/src/processors/parquet_processors/parquet_fungible_asset_activities_processor.rs @@ -22,7 +22,10 @@ use crate::{ }, parquet::models::fungible_asset_models::parquet_v2_fungible_asset_activities::FungibleAssetActivity, postgres::models::{ - fungible_asset_models::v2_fungible_asset_utils::FeeStatement, + coin_models::coin_utils::EventGuidResource, + fungible_asset_models::v2_fungible_asset_utils::{ + CoinStoreDeletionEvent, FeeStatement, + }, resources::{FromWriteResource, V2FungibleAssetResource}, }, }, @@ -323,6 +326,37 @@ async fn parse_activities( .or_insert(1); } + // The CoinStoreDeletionEvent, only need for v1 with migration + if user_request.is_some() { + events + .iter() + .filter_map(|event| { + let event_type = event.type_str.as_str(); + CoinStoreDeletionEvent::from_event(event_type, &event.data, txn_version) + }) + .for_each(|coin_store_deletion| { + let addr = standardize_address( + coin_store_deletion.event_handle_creation_address.as_str(), + ); + let deposit_event_guid = EventGuidResource { + addr: addr.clone(), + creation_num: coin_store_deletion + .deleted_deposit_event_handle_creation_number + as i64, + }; + let withdraw_event_guid = EventGuidResource { + addr, + creation_num: coin_store_deletion + .deleted_withdraw_event_handle_creation_number + as i64, + }; + event_to_v1_coin_type + .insert(deposit_event_guid, coin_store_deletion.coin_type.clone()); + event_to_v1_coin_type + .insert(withdraw_event_guid, coin_store_deletion.coin_type); + }); + } + // Loop to handle events and collect additional metadata from events for v2 for (index, event) in events.iter().enumerate() { if let Some(v1_activity) = RawFungibleAssetActivity::get_v1_from_event(