Skip to content

Commit

Permalink
Event V2 Translation
Browse files Browse the repository at this point in the history
  • Loading branch information
junkil-park committed Oct 23, 2024
1 parent 114d361 commit 523e22f
Show file tree
Hide file tree
Showing 22 changed files with 664 additions and 40 deletions.
101 changes: 85 additions & 16 deletions api/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use aptos_types::{
account_address::AccountAddress,
account_config::{AccountResource, NewBlockEvent},
chain_id::ChainId,
contract_event::EventWithVersion,
contract_event::{ContractEvent, ContractEventV1, EventWithVersion},
event::EventKey,
indexer::indexer_db_reader::IndexerReader,
ledger_info::LedgerInfoWithSignatures,
Expand Down Expand Up @@ -818,12 +818,17 @@ impl Context {
.into_iter()
.zip(infos)
.enumerate()
.map(|(i, ((txn, txn_output), info))| {
let version = start_version + i as u64;
let (write_set, events, _, _, _) = txn_output.unpack();
self.get_accumulator_root_hash(version)
.map(|h| (version, txn, info, events, h, write_set).into())
})
.map(
|(i, ((txn, txn_output), info))| -> Result<TransactionOnChainData> {
let version = start_version + i as u64;
let (write_set, mut events, _, _, _) = txn_output.unpack();
if self.node_config.indexer_db_config.enable_event_translation {
let _ = self.translate_v2_to_v1_events_for_version(version, &mut events);
}
let h = self.get_accumulator_root_hash(version)?;
Ok((version, txn, info, events, h, write_set).into())
},
)
.collect()
}

Expand Down Expand Up @@ -878,7 +883,14 @@ impl Context {
})?;
txns.into_inner()
.into_iter()
.map(|t| self.convert_into_transaction_on_chain_data(t))
.map(|t| -> Result<TransactionOnChainData> {
let mut txn = self.convert_into_transaction_on_chain_data(t)?;
if self.node_config.indexer_db_config.enable_event_translation {
let _ =
self.translate_v2_to_v1_events_for_version(txn.version, &mut txn.events);
}
Ok(txn)
})
.collect::<Result<Vec<_>>>()
.context("Failed to parse account transactions")
.map_err(|err| E::internal_with_code(err, AptosErrorCode::InternalError, ledger_info))
Expand All @@ -889,10 +901,18 @@ impl Context {
hash: HashValue,
ledger_version: u64,
) -> Result<Option<TransactionOnChainData>> {
self.db
if let Some(t) = self
.db
.get_transaction_by_hash(hash, ledger_version, true)?
.map(|t| self.convert_into_transaction_on_chain_data(t))
.transpose()
{
let mut txn: TransactionOnChainData = self.convert_into_transaction_on_chain_data(t)?;
if self.node_config.indexer_db_config.enable_event_translation {
let _ = self.translate_v2_to_v1_events_for_version(txn.version, &mut txn.events);
}
Ok(Some(txn))
} else {
Ok(None)
}
}

pub async fn get_pending_transaction_by_hash(
Expand All @@ -915,11 +935,60 @@ impl Context {
version: u64,
ledger_version: u64,
) -> Result<TransactionOnChainData> {
self.convert_into_transaction_on_chain_data(self.db.get_transaction_by_version(
version,
ledger_version,
true,
)?)
let mut txn = self.convert_into_transaction_on_chain_data(
self.db
.get_transaction_by_version(version, ledger_version, true)?,
)?;
if self.node_config.indexer_db_config.enable_event_translation {
let _ = self.translate_v2_to_v1_events_for_version(version, &mut txn.events);
}
Ok(txn)
}

fn translate_v2_to_v1_events_for_version(
&self,
version: u64,
events: &mut [ContractEvent],
) -> Result<()> {
for (idx, event) in events.iter_mut().enumerate() {
let translated_event = self
.indexer_reader
.as_ref()
.ok_or(anyhow!("Internal indexer reader doesn't exist"))?
.get_translated_v1_event_by_version_and_index(version, idx as u64);
if let Ok(translated_event) = translated_event {
*event = ContractEvent::V1(translated_event);
}
}
Ok(())
}

pub fn translate_v2_to_v1_events_for_simulation(
&self,
events: &mut [ContractEvent],
) -> Result<()> {
let mut count_map: HashMap<EventKey, u64> = HashMap::new();
for event in events.iter_mut() {
if let ContractEvent::V2(v2) = event {
let translated_event = self
.indexer_reader
.as_ref()
.ok_or(anyhow!("Internal indexer reader doesn't exist"))?
.translate_event_v2_to_v1(v2)?;
if let Some(v1) = translated_event {
let count = count_map.get(&v1.key()).unwrap_or(&0);
let v1_adjusted = ContractEventV1::new(
v1.key().clone(),
v1.sequence_number() + count,
v1.type_tag().clone(),
v1.event_data().to_vec(),
);
*event = ContractEvent::V1(v1_adjusted);
count_map.insert(v1.key().clone(), count + 1);
}
}
}
Ok(())
}

pub fn get_accumulator_root_hash(&self, version: u64) -> Result<HashValue> {
Expand Down
73 changes: 73 additions & 0 deletions api/src/tests/event_v2_translation_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright © Aptos Foundation
// Parts of the project are originally copyright © Meta Platforms, Inc.
// SPDX-License-Identifier: Apache-2.0

use super::{new_test_context, new_test_context_with_db_sharding_and_internal_indexer};
use aptos_api_test_context::current_function_name;
use serde_json::json;
use std::time::Duration;
use tokio::time::sleep;

static MODULE_EVENT_MIGRATION: u64 = 57;

const SLEEP_DURATION: Duration = Duration::from_millis(250);

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_feature_enable_disable() {
let mut context = new_test_context(current_function_name!());
context.enable_feature(MODULE_EVENT_MIGRATION).await;
assert!(context.is_feature_enabled(MODULE_EVENT_MIGRATION).await);
context.disable_feature(MODULE_EVENT_MIGRATION).await;
assert!(!context.is_feature_enabled(MODULE_EVENT_MIGRATION).await);
context.enable_feature(MODULE_EVENT_MIGRATION).await;
assert!(context.is_feature_enabled(MODULE_EVENT_MIGRATION).await);
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_event_v2_translation_simulation() {
// let context = &mut new_test_context(current_function_name!());
let context =
&mut new_test_context_with_db_sharding_and_internal_indexer(current_function_name!());

let account1 = &mut context.api_create_account().await;
// let account1 = &mut context.create_account().await;

sleep(SLEEP_DURATION).await;

let account2 = &mut context.api_create_account().await;
// let account2 = &mut context.create_account().await;

sleep(SLEEP_DURATION).await;

context.enable_feature(MODULE_EVENT_MIGRATION).await;

// sleep(SLEEP_DURATION).await;

let payload = json!({
"type": "entry_function_payload",
"function": "0x1::coin::transfer",
"type_arguments": ["0x1::aptos_coin::AptosCoin"],
"arguments": [
account1.address().to_hex_literal(), "100"
]
});
let resp = context.simulate_transaction(account2, payload, 200).await;

// sleep(SLEEP_DURATION).await;

// The V2 event should not appear.
assert!(!resp[0]["events"]
.as_array()
.unwrap()
.iter()
.any(|x| x["type"] == "0x1::coin::CoinDeposit"));

// The translated V1 event should appear.
assert!(resp[0]["events"]
.as_array()
.unwrap()
.iter()
.any(|x| x["type"] == "0x1::coin::DepositEvent"
&& x["guid"]["creation_number"] == "2"
&& x["guid"]["account_address"] == account1.address().to_hex_literal()));
}
5 changes: 3 additions & 2 deletions api/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
mod accounts_test;
mod blocks_test;
mod converter_test;
mod event_v2_translation_test;
mod events_test;
mod index_test;
mod invalid_post_request_test;
Expand Down Expand Up @@ -36,7 +37,7 @@ fn new_test_context_with_config(test_name: String, node_config: NodeConfig) -> T
fn new_test_context_with_db_sharding_and_internal_indexer(test_name: String) -> TestContext {
let mut node_config = NodeConfig::default();
node_config.storage.rocksdb_configs.enable_storage_sharding = true;
node_config.indexer_db_config = InternalIndexerDBConfig::new(true, true, true, 10);
node_config.indexer_db_config = InternalIndexerDBConfig::new(true, true, true, true, 10);
let test_context = super_new_test_context(test_name, node_config, false, None);
let _ = test_context
.get_indexer_reader()
Expand All @@ -51,6 +52,6 @@ fn new_test_context_with_sharding_and_delayed_internal_indexer(
) -> TestContext {
let mut node_config = NodeConfig::default();
node_config.storage.rocksdb_configs.enable_storage_sharding = true;
node_config.indexer_db_config = InternalIndexerDBConfig::new(true, true, true, 1);
node_config.indexer_db_config = InternalIndexerDBConfig::new(true, true, true, true, 1);
super_new_test_context(test_name, node_config, false, end_version)
}
7 changes: 6 additions & 1 deletion api/src/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1439,11 +1439,16 @@ impl TransactionsApi {
output.gas_used(),
exe_status,
);
let mut events = output.events().to_vec();
let _ = self
.context
.translate_v2_to_v1_events_for_simulation(&mut events);

let simulated_txn = TransactionOnChainData {
version,
transaction: txn,
info,
events: output.events().to_vec(),
events,
accumulator_root_hash: zero_hash,
changes: output.write_set().clone(),
};
Expand Down
90 changes: 90 additions & 0 deletions api/test-context/src/test_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,52 @@ impl TestContext {
)
}

pub async fn enable_feature(&mut self, feature: u64) {
// script {
// fun main(root: &signer, feature: u64) {
// let aptos_framework = aptos_framework::aptos_governance::get_signer_testnet_only(root, @0x1);
// std::features::change_feature_flags_for_next_epoch(&aptos_framework, vector[feature], vector[]);
// aptos_framework::aptos_governance::reconfigure(&aptos_framework);
// std::features::on_new_epoch(&aptos_framework);
// }
// }
let mut root = self.root_account().await;
self.api_execute_script(
&mut root,
"a11ceb0b0700000a06010004030418051c1707336f08a2012006c201260000000100020301000101030502000100040602000101050602000102060c03010c0002060c05010303060c0a030a0301060c106170746f735f676f7665726e616e6365086665617475726573176765745f7369676e65725f746573746e65745f6f6e6c79236368616e67655f666561747572655f666c6167735f666f725f6e6578745f65706f63680b7265636f6e6669677572650c6f6e5f6e65775f65706f63680000000000000000000000000000000000000000000000000000000000000001052000000000000000000000000000000000000000000000000000000000000000010a0301000000010e0b00070011000c020e020b0140040100000000000000070111010e0211020e02110302",
json!([]),
json!([feature.to_string()]),
).await;
}

pub async fn disable_feature(&mut self, feature: u64) {
// script {
// fun main(root: &signer, feature: u64) {
// let aptos_framework = aptos_framework::aptos_governance::get_signer_testnet_only(root, @0x1);
// std::features::change_feature_flags_for_next_epoch(&aptos_framework, vector[], vector[feature]);
// aptos_framework::aptos_governance::reconfigure(&aptos_framework);
// std::features::on_new_epoch(&aptos_framework);
// }
// }
let mut root = self.root_account().await;
self.api_execute_script(
&mut root,
"a11ceb0b0700000a06010004030418051c1707336f08a2012006c201260000000100020301000101030502000100040602000101050602000102060c03010c0002060c05010303060c0a030a0301060c106170746f735f676f7665726e616e6365086665617475726573176765745f7369676e65725f746573746e65745f6f6e6c79236368616e67655f666561747572655f666c6167735f666f725f6e6578745f65706f63680b7265636f6e6669677572650c6f6e5f6e65775f65706f63680000000000000000000000000000000000000000000000000000000000000001052000000000000000000000000000000000000000000000000000000000000000010a0301000000010e0b00070011000c020e0207010b014004010000000000000011010e0211020e02110302",
json!([]),
json!([feature.to_string()]),
).await;
}

pub async fn is_feature_enabled(&self, feature: u64) -> bool {
let request = json!({
"function":"0x1::features::is_enabled",
"arguments": vec![feature.to_string()],
"type_arguments": Vec::<String>::new(),
});
let resp = self.post("/view", request).await;
resp[0].as_bool().unwrap()
}

pub fn latest_state_view(&self) -> DbStateView {
self.context
.state_view_at_version(self.get_latest_ledger_info().version())
Expand Down Expand Up @@ -395,6 +441,29 @@ impl TestContext {
account
}

pub async fn api_create_account(&mut self) -> LocalAccount {
let root = &mut self.root_account().await;
let account = self.gen_account();
self.api_execute_aptos_account_transfer(root, account.address(), TRANSFER_AMOUNT)
.await;
account
}

pub async fn api_execute_aptos_account_transfer(
&mut self,
sender: &mut LocalAccount,
receiver: AccountAddress,
amount: u64,
) {
self.api_execute_entry_function(
sender,
"0x1::aptos_account::transfer",
json!([]),
json!([receiver.to_hex_literal(), amount.to_string()]),
)
.await;
}

pub async fn create_user_account(&self, account: &LocalAccount) -> SignedTransaction {
let mut tc = self.root_account().await;
self.create_user_account_by(&mut tc, account)
Expand Down Expand Up @@ -861,6 +930,27 @@ impl TestContext {
.await;
}

pub async fn api_execute_script(
&mut self,
account: &mut LocalAccount,
bytecode: &str,
type_args: serde_json::Value,
args: serde_json::Value,
) {
self.api_execute_txn(
account,
json!({
"type": "script_payload",
"code": {
"bytecode": bytecode,
},
"type_arguments": type_args,
"arguments": args
}),
)
.await;
}

pub async fn api_execute_txn(&mut self, account: &mut LocalAccount, payload: Value) {
self.api_execute_txn_expecting(account, payload, 202).await;
}
Expand Down
9 changes: 5 additions & 4 deletions aptos-move/framework/aptos-framework/doc/coin.md
Original file line number Diff line number Diff line change
Expand Up @@ -2815,11 +2815,12 @@ Deposit the coin balance into the recipient's account and emit an event.
<a href="event.md#0x1_event_emit">event::emit</a>(
<a href="coin.md#0x1_coin_CoinDeposit">CoinDeposit</a> { coin_type: type_name&lt;CoinType&gt;(), <a href="account.md#0x1_account">account</a>: account_addr, amount: <a href="coin.md#0x1_coin">coin</a>.value }
);
} <b>else</b> {
<a href="event.md#0x1_event_emit_event">event::emit_event</a>&lt;<a href="coin.md#0x1_coin_DepositEvent">DepositEvent</a>&gt;(
&<b>mut</b> coin_store.deposit_events,
<a href="coin.md#0x1_coin_DepositEvent">DepositEvent</a> { amount: <a href="coin.md#0x1_coin">coin</a>.value },
);
};
<a href="event.md#0x1_event_emit_event">event::emit_event</a>&lt;<a href="coin.md#0x1_coin_DepositEvent">DepositEvent</a>&gt;(
&<b>mut</b> coin_store.deposit_events,
<a href="coin.md#0x1_coin_DepositEvent">DepositEvent</a> { amount: <a href="coin.md#0x1_coin">coin</a>.value },
);
<a href="coin.md#0x1_coin_merge">merge</a>(&<b>mut</b> coin_store.<a href="coin.md#0x1_coin">coin</a>, <a href="coin.md#0x1_coin">coin</a>);
} <b>else</b> {
<b>let</b> metadata = <a href="coin.md#0x1_coin_paired_metadata">paired_metadata</a>&lt;CoinType&gt;();
Expand Down
9 changes: 5 additions & 4 deletions aptos-move/framework/aptos-framework/sources/coin.move
Original file line number Diff line number Diff line change
Expand Up @@ -900,11 +900,12 @@ module aptos_framework::coin {
event::emit(
CoinDeposit { coin_type: type_name<CoinType>(), account: account_addr, amount: coin.value }
);
} else {
event::emit_event<DepositEvent>(
&mut coin_store.deposit_events,
DepositEvent { amount: coin.value },
);
};
event::emit_event<DepositEvent>(
&mut coin_store.deposit_events,
DepositEvent { amount: coin.value },
);
merge(&mut coin_store.coin, coin);
} else {
let metadata = paired_metadata<CoinType>();
Expand Down
Loading

0 comments on commit 523e22f

Please sign in to comment.