Skip to content

Commit ea63add

Browse files
authored
feature: add active features check to validation tool (#192)
* feature: add active features check to validation tool * fix: increase delay between requests in the active feature check
1 parent bfad8dd commit ea63add

File tree

4 files changed

+182
-158
lines changed

4 files changed

+182
-158
lines changed

movement-migration/validation-tool/src/checks/api.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
// Copyright (c) Aptos Foundation
22
// SPDX-License-Identifier: Apache-2.0
33

4-
use crate::types::api::{MovementAptosRestClient, MovementRestClient};
4+
use crate::checks::api::active_feature_flags::GlobalFeatureCheck;
5+
use crate::types::api::MovementAptosRestClient;
56
use clap::Parser;
67

8+
mod active_feature_flags;
9+
710
#[derive(Parser)]
811
#[clap(
912
name = "migration-api-validation",
1013
about = "Validates api conformity after movement migration."
1114
)]
1215
pub struct Command {
13-
#[clap(long = "movement", help = "The url of the Movement REST endpoint.")]
14-
pub movement_rest_api_url: String,
16+
// #[clap(long = "movement", help = "The url of the Movement REST endpoint.")]
17+
// pub movement_rest_api_url: String,
1518
#[clap(value_parser)]
1619
#[clap(
1720
long = "movement-aptos",
@@ -22,10 +25,12 @@ pub struct Command {
2225

2326
impl Command {
2427
pub async fn run(self) -> anyhow::Result<()> {
25-
let _movement_rest_client = MovementRestClient::new(&self.movement_rest_api_url)?;
26-
let _movement_aptos_rest_client =
28+
// let _movement_rest_client = MovementRestClient::new(&self.movement_rest_api_url)?;
29+
let movement_aptos_rest_client =
2730
MovementAptosRestClient::new(&self.movement_aptos_rest_api_url)?;
2831

32+
GlobalFeatureCheck::satisfies(&movement_aptos_rest_client).await?;
33+
2934
Ok(())
3035
}
3136
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright (c) Aptos Foundation
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use crate::checks::error::ValidationError;
5+
use crate::types::api::MovementAptosRestClient;
6+
use aptos_rest_client::aptos_api_types::ViewFunction;
7+
use move_core_types::identifier::Identifier;
8+
use move_core_types::language_storage::ModuleId;
9+
use std::str::FromStr;
10+
use tracing::debug;
11+
12+
pub struct GlobalFeatureCheck;
13+
14+
impl GlobalFeatureCheck {
15+
pub async fn satisfies(
16+
movement_aptos_rest_client: &MovementAptosRestClient,
17+
) -> Result<(), ValidationError> {
18+
let mut errors = vec![];
19+
let expected_active: Vec<u64> = vec![
20+
1, // FeatureFlag::CODE_DEPENDENCY_CHECK
21+
2, // FeatureFlag::TREAT_FRIEND_AS_PRIVATE
22+
3, // FeatureFlag::SHA_512_AND_RIPEMD_160_NATIVES
23+
4, // FeatureFlag::APTOS_STD_CHAIN_ID_NATIVES
24+
5, // FeatureFlag::VM_BINARY_FORMAT_V6
25+
7, // FeatureFlag::MULTI_ED25519_PK_VALIDATE_V2_NATIVES
26+
8, // FeatureFlag::BLAKE2B_256_NATIVE
27+
9, // FeatureFlag::RESOURCE_GROUPS
28+
10, // FeatureFlag::MULTISIG_ACCOUNTS
29+
11, // FeatureFlag::DELEGATION_POOLS
30+
12, // FeatureFlag::CRYPTOGRAPHY_ALGEBRA_NATIVES
31+
13, // FeatureFlag::BLS12_381_STRUCTURES
32+
14, // FeatureFlag::ED25519_PUBKEY_VALIDATE_RETURN_FALSE_WRONG_LENGTH
33+
15, // FeatureFlag::STRUCT_CONSTRUCTORS
34+
18, // FeatureFlag::SIGNATURE_CHECKER_V2
35+
19, // FeatureFlag::STORAGE_SLOT_METADATA
36+
20, // FeatureFlag::CHARGE_INVARIANT_VIOLATION
37+
22, // FeatureFlag::GAS_PAYER_ENABLED
38+
23, // FeatureFlag::APTOS_UNIQUE_IDENTIFIERS
39+
24, // FeatureFlag::BULLETPROOFS_NATIVES
40+
25, // FeatureFlag::SIGNER_NATIVE_FORMAT_FIX
41+
26, // FeatureFlag::MODULE_EVENT
42+
27, // FeatureFlag::EMIT_FEE_STATEMENT
43+
28, // FeatureFlag::STORAGE_DELETION_REFUND
44+
29, // FeatureFlag::SIGNATURE_CHECKER_V2_SCRIPT_FIX
45+
30, // FeatureFlag::AGGREGATOR_V2_API
46+
31, // FeatureFlag::SAFER_RESOURCE_GROUPS
47+
32, // FeatureFlag::SAFER_METADATA
48+
33, // FeatureFlag::SINGLE_SENDER_AUTHENTICATOR
49+
34, // FeatureFlag::SPONSORED_AUTOMATIC_ACCOUNT_V1_CREATION
50+
35, // FeatureFlag::FEE_PAYER_ACCOUNT_OPTIONAL
51+
36, // FeatureFlag::AGGREGATOR_V2_DELAYED_FIELDS
52+
37, // FeatureFlag::CONCURRENT_TOKEN_V2
53+
38, // FeatureFlag::LIMIT_MAX_IDENTIFIER_LENGTH
54+
39, // FeatureFlag::OPERATOR_BENEFICIARY_CHANGE
55+
41, // FeatureFlag::RESOURCE_GROUPS_SPLIT_IN_VM_CHANGE_SET
56+
42, // FeatureFlag::COMMISSION_CHANGE_DELEGATION_POOL
57+
43, // FeatureFlag::BN254_STRUCTURES
58+
44, // FeatureFlag::WEBAUTHN_SIGNATURE
59+
46, // FeatureFlag::KEYLESS_ACCOUNTS
60+
47, // FeatureFlag::KEYLESS_BUT_ZKLESS_ACCOUNTS
61+
48, // FeatureFlag::REMOVE_DETAILED_ERROR_FROM_HASH
62+
49, // FeatureFlag::JWK_CONSENSUS
63+
50, // FeatureFlag::CONCURRENT_FUNGIBLE_ASSETS
64+
51, // FeatureFlag::REFUNDABLE_BYTES
65+
52, // FeatureFlag::OBJECT_CODE_DEPLOYMENT
66+
53, // FeatureFlag::MAX_OBJECT_NESTING_CHECK
67+
54, // FeatureFlag::KEYLESS_ACCOUNTS_WITH_PASSKEYS
68+
55, // FeatureFlag::MULTISIG_V2_ENHANCEMENT
69+
56, // FeatureFlag::DELEGATION_POOL_ALLOWLISTING
70+
57, // FeatureFlag::MODULE_EVENT_MIGRATION
71+
58, // FeatureFlag::REJECT_UNSTABLE_BYTECODE
72+
59, // FeatureFlag::TRANSACTION_CONTEXT_EXTENSION
73+
60, // FeatureFlag::COIN_TO_FUNGIBLE_ASSET_MIGRATION
74+
62, // FeatureFlag::OBJECT_NATIVE_DERIVED_ADDRESS
75+
63, // FeatureFlag::DISPATCHABLE_FUNGIBLE_ASSET
76+
66, // FeatureFlag::AGGREGATOR_V2_IS_AT_LEAST_API
77+
67, // FeatureFlag::CONCURRENT_FUNGIBLE_BALANCE
78+
69, // FeatureFlag::LIMIT_VM_TYPE_SIZE
79+
70, // FeatureFlag::ABORT_IF_MULTISIG_PAYLOAD_MISMATCH
80+
73, // FeatureFlag::GOVERNED_GAS_POOL
81+
];
82+
83+
let module =
84+
ModuleId::from_str("0x1::features").map_err(|e| ValidationError::Internal(e.into()))?;
85+
let function =
86+
Identifier::from_str("is_enabled").map_err(|e| ValidationError::Internal(e.into()))?;
87+
88+
let mut view_function = ViewFunction {
89+
module,
90+
function,
91+
ty_args: vec![],
92+
args: vec![],
93+
};
94+
95+
for feature_id in expected_active {
96+
debug!("checking feature flag {}", feature_id);
97+
let bytes =
98+
bcs::to_bytes(&feature_id).map_err(|e| ValidationError::Internal(e.into()))?;
99+
view_function.args = vec![bytes];
100+
101+
// Check feature for Maptos executor
102+
let maptos_active = movement_aptos_rest_client
103+
.view_bcs_with_json_response(&view_function, None)
104+
.await
105+
.map_err(|e| {
106+
ValidationError::Internal(
107+
format!(
108+
"failed to get Movement feature flag {}: {:?}",
109+
feature_id, e
110+
)
111+
.into(),
112+
)
113+
})?
114+
.into_inner();
115+
116+
let maptos_active = maptos_active.get(0).ok_or_else(|| {
117+
ValidationError::Internal(
118+
format!(
119+
"failed to get Movement feature flag {}: response is empty",
120+
feature_id
121+
)
122+
.into(),
123+
)
124+
})?;
125+
126+
let maptos_active = maptos_active.as_bool().ok_or_else(|| {
127+
ValidationError::Internal(
128+
format!(
129+
"failed to get Movement feature flag {}: can't convert {:?} into a bool",
130+
feature_id, maptos_active
131+
)
132+
.into(),
133+
)
134+
})?;
135+
136+
if !maptos_active {
137+
errors.push(format!(
138+
"Feature {}: Aptos={} — expected to be active",
139+
feature_id, maptos_active,
140+
));
141+
}
142+
143+
// Slow down to avoid Cloudflare rate limiting
144+
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
145+
}
146+
147+
if !errors.is_empty() {
148+
return Err(ValidationError::Unsatisfied(errors.join("\n").into()));
149+
}
150+
151+
Ok(())
152+
}
153+
}

movement-migration/validation-tool/src/checks/api/matching_feature_flags.rs

Lines changed: 0 additions & 134 deletions
This file was deleted.

movement-migration/validation-tool/src/types/api.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,25 @@
44
use aptos_rest_client::Client;
55
use std::ops::Deref;
66

7-
pub struct MovementRestClient(Client);
8-
9-
impl MovementRestClient {
10-
pub fn new(url: &str) -> Result<Self, anyhow::Error> {
11-
let client = Client::new(
12-
url.parse()
13-
.map_err(|e| anyhow::anyhow!("failed to parse Movement rest api url: {}", e))?,
14-
);
15-
Ok(Self(client))
16-
}
17-
}
18-
19-
impl Deref for MovementRestClient {
20-
type Target = Client;
21-
22-
fn deref(&self) -> &Self::Target {
23-
&self.0
24-
}
25-
}
7+
// pub struct MovementRestClient(Client);
8+
//
9+
// impl MovementRestClient {
10+
// pub fn new(url: &str) -> Result<Self, anyhow::Error> {
11+
// let client = Client::new(
12+
// url.parse()
13+
// .map_err(|e| anyhow::anyhow!("failed to parse Movement rest api url: {}", e))?,
14+
// );
15+
// Ok(Self(client))
16+
// }
17+
// }
18+
//
19+
// impl Deref for MovementRestClient {
20+
// type Target = Client;
21+
//
22+
// fn deref(&self) -> &Self::Target {
23+
// &self.0
24+
// }
25+
// }
2626

2727
pub struct MovementAptosRestClient(Client);
2828

0 commit comments

Comments
 (0)