Skip to content

Commit 9f8d4d9

Browse files
apollo_gateway: only set proofs if they have passed tx validation in gateway
1 parent 4abd5b2 commit 9f8d4d9

File tree

4 files changed

+91
-20
lines changed

4 files changed

+91
-20
lines changed

crates/apollo_class_manager_types/src/transaction_converter.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ pub trait TransactionConverterTrait: Send + Sync {
8282
&self,
8383
tx: InternalConsensusTransaction,
8484
) -> TransactionConverterResult<ExecutableTransaction>;
85+
86+
fn get_proof_manager_client(&self) -> SharedProofManagerClient;
8587
}
8688

8789
#[derive(Clone)]
@@ -143,10 +145,11 @@ impl TransactionConverterTrait for TransactionConverter {
143145
tx: ConsensusTransaction,
144146
) -> TransactionConverterResult<InternalConsensusTransaction> {
145147
match tx {
146-
ConsensusTransaction::RpcTransaction(tx) => self
147-
.convert_rpc_tx_to_internal_rpc_tx(tx)
148-
.await
149-
.map(InternalConsensusTransaction::RpcTransaction),
148+
ConsensusTransaction::RpcTransaction(tx) => {
149+
let internal_tx =
150+
self.extract_proof_and_convert_rpc_tx_to_internal_rpc_tx(tx).await?;
151+
Ok(InternalConsensusTransaction::RpcTransaction(internal_tx))
152+
}
150153
ConsensusTransaction::L1Handler(tx) => self
151154
.convert_consensus_l1_handler_to_internal_l1_handler(tx)
152155
.map(InternalConsensusTransaction::L1Handler),
@@ -299,6 +302,10 @@ impl TransactionConverterTrait for TransactionConverter {
299302
InternalConsensusTransaction::L1Handler(tx) => Ok(ExecutableTransaction::L1Handler(tx)),
300303
}
301304
}
305+
306+
fn get_proof_manager_client(&self) -> SharedProofManagerClient {
307+
self.proof_manager_client.clone()
308+
}
302309
}
303310

304311
impl TransactionConverter {
@@ -314,6 +321,27 @@ impl TransactionConverter {
314321
)?)
315322
}
316323

324+
async fn extract_proof_and_convert_rpc_tx_to_internal_rpc_tx(
325+
&self,
326+
tx: RpcTransaction,
327+
) -> TransactionConverterResult<InternalRpcTransaction> {
328+
// Extract proof and proof_facts from v3 invoke tx before conversion.
329+
let proof_data = match &tx {
330+
RpcTransaction::Invoke(RpcInvokeTransaction::V3(invoke_tx)) => {
331+
if !invoke_tx.proof_facts.is_empty() {
332+
Some((invoke_tx.proof_facts.clone(), invoke_tx.proof.clone()))
333+
} else {
334+
None
335+
}
336+
}
337+
_ => None,
338+
};
339+
let internal_tx = self.convert_rpc_tx_to_internal_rpc_tx(tx).await?;
340+
if let Some((proof_facts, proof)) = proof_data {
341+
self.proof_manager_client.set_proof(proof_facts, proof).await?;
342+
}
343+
Ok(internal_tx)
344+
}
317345
async fn handle_proof_verification(
318346
&self,
319347
proof_facts: &ProofFacts,
@@ -335,7 +363,6 @@ impl TransactionConverter {
335363
}
336364

337365
self.verify_proof(proof_facts.clone(), proof.clone())?;
338-
self.proof_manager_client.set_proof(proof_facts.clone(), proof.clone()).await?;
339366
Ok(())
340367
}
341368

crates/apollo_class_manager_types/src/transaction_converter_test.rs

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use mempool_test_utils::starknet_api_test_utils::{
1111
};
1212
use mockall::predicate::eq;
1313
use rstest::rstest;
14+
use starknet_api::consensus_transaction::ConsensusTransaction;
1415
use starknet_api::executable_transaction::ValidateCompiledClassHashError;
1516
use starknet_api::rpc_transaction::{RpcDeclareTransaction, RpcTransaction};
1617
use starknet_api::transaction::fields::Proof;
@@ -76,16 +77,13 @@ async fn test_proof_verification_called_for_invoke_v3_with_proof_facts() {
7677
);
7778

7879
let mut mock_proof_manager_client = MockProofManagerClient::new();
80+
// Expect contains_proof to be called and return false (proof does not exist).
81+
// Expect set_proof not to be called when converting rpc tx to internal rpc tx.
7982
mock_proof_manager_client
8083
.expect_contains_proof()
8184
.once()
8285
.with(eq(proof_facts.clone()))
8386
.return_once(|_| Ok(false));
84-
mock_proof_manager_client
85-
.expect_set_proof()
86-
.once()
87-
.with(eq(proof_facts), eq(proof))
88-
.return_once(|_, _| Ok(()));
8987

9088
let mock_class_manager_client = MockClassManagerClient::new();
9189

@@ -122,8 +120,7 @@ async fn test_proof_verification_skipped_for_invoke_v3_without_proof_facts() {
122120

123121
#[rstest]
124122
#[tokio::test]
125-
async fn test_proof_verification_skipped_when_proof_already_exists() {
126-
// Create an invoke transaction with proof_facts and proof.
123+
async fn test_consensus_tx_to_internal_with_proof_facts_verifies_and_sets_proof() {
127124
let proof_facts = proof_facts![felt!("0x1"), felt!("0x2"), felt!("0x3")];
128125
let proof = Proof::from(vec![1u32, 2u32, 3u32]);
129126
let invoke_tx = invoke_tx_client_side_proving(
@@ -132,14 +129,24 @@ async fn test_proof_verification_skipped_when_proof_already_exists() {
132129
proof.clone(),
133130
);
134131

132+
let consensus_tx = ConsensusTransaction::RpcTransaction(invoke_tx);
133+
135134
let mut mock_proof_manager_client = MockProofManagerClient::new();
136-
// Expect contains_proof to be called and return true (proof already exists).
135+
136+
// Expect contains_proof to be called during convert_rpc_tx_to_internal_rpc_tx.
137137
mock_proof_manager_client
138138
.expect_contains_proof()
139139
.once()
140-
.with(eq(proof_facts))
141-
.return_once(|_| Ok(true));
142-
// Since proof already exists, expect set_proof to NOT be called.
140+
.with(eq(proof_facts.clone()))
141+
.return_once(|_| Ok(false));
142+
143+
// Expect set_proof to be called after the conversion succeeds.
144+
// This is specific to convert_consensus_tx_to_internal_consensus_tx.
145+
mock_proof_manager_client
146+
.expect_set_proof()
147+
.once()
148+
.with(eq(proof_facts), eq(proof))
149+
.return_once(|_, _| Ok(()));
143150

144151
let mock_class_manager_client = MockClassManagerClient::new();
145152

@@ -149,7 +156,10 @@ async fn test_proof_verification_skipped_when_proof_already_exists() {
149156
ChainInfo::create_for_testing().chain_id,
150157
);
151158

152-
// Convert the RPC transaction to an internal RPC transaction.
153-
// This should succeed and only call contains_proof, not set_proof.
154-
transaction_converter.convert_rpc_tx_to_internal_rpc_tx(invoke_tx).await.unwrap();
159+
// Convert the consensus transaction to an internal consensus transaction.
160+
// This should call contains_proof and set_proof.
161+
transaction_converter
162+
.convert_consensus_tx_to_internal_consensus_tx(consensus_tx)
163+
.await
164+
.unwrap();
155165
}

crates/apollo_gateway/src/gateway.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ impl Gateway {
169169
.inspect_err(|e| metric_counters.record_add_tx_failure(e))?;
170170

171171
if let Some((proof_facts, proof)) = proof_data {
172+
let proof_manager_client = self.transaction_converter.get_proof_manager_client();
173+
if let Err(e) = proof_manager_client.set_proof(proof_facts.clone(), proof.clone()).await
174+
{
175+
error!("Failed to set proof in proof manager: {}", e);
176+
}
172177
let proof_archive_writer = self.proof_archive_writer.clone();
173178
tokio::spawn(async move {
174179
if let Err(e) = proof_archive_writer.set_proof(proof_facts, proof).await {

crates/apollo_gateway/src/gateway_test.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use apollo_mempool_types::errors::MempoolError;
3636
use apollo_mempool_types::mempool_types::{AccountState, AddTransactionArgs, ValidationArgs};
3737
use apollo_metrics::metrics::HistogramValue;
3838
use apollo_network_types::network_types::BroadcastedMessageMetadata;
39+
use apollo_proof_manager_types::{MockProofManagerClient, ProofManagerClient};
3940
use apollo_test_utils::{get_rng, GetTestInstance};
4041
use blockifier::blockifier::config::ContractClassManagerConfig;
4142
use blockifier::context::ChainInfo;
@@ -53,6 +54,7 @@ use starknet_api::executable_transaction::AccountTransaction;
5354
use starknet_api::rpc_transaction::{
5455
InternalRpcTransaction,
5556
RpcDeclareTransaction,
57+
RpcInvokeTransaction,
5658
RpcTransaction,
5759
RpcTransactionLabelValue,
5860
};
@@ -136,13 +138,16 @@ fn mock_dependencies() -> MockDependencies {
136138
let mock_transaction_converter = MockTransactionConverterTrait::new();
137139
let mock_stateless_transaction_validator = mock_stateless_transaction_validator();
138140
let mock_proof_archive_writer = MockProofArchiveWriterTrait::new();
141+
let mut mock_proof_manager_client = MockProofManagerClient::new();
142+
mock_proof_manager_client.expect_contains_proof().returning(|_| Ok(false));
139143
MockDependencies {
140144
config,
141145
state_reader_factory,
142146
mock_mempool_client,
143147
mock_transaction_converter,
144148
mock_stateless_transaction_validator,
145149
mock_proof_archive_writer,
150+
mock_proof_manager_client,
146151
}
147152
}
148153

@@ -153,10 +158,18 @@ struct MockDependencies {
153158
mock_transaction_converter: MockTransactionConverterTrait,
154159
mock_stateless_transaction_validator: MockStatelessTransactionValidatorTrait,
155160
mock_proof_archive_writer: MockProofArchiveWriterTrait,
161+
mock_proof_manager_client: MockProofManagerClient,
156162
}
157163

158164
impl MockDependencies {
159-
fn gateway(self) -> Gateway {
165+
fn gateway(mut self) -> Gateway {
166+
let proof_manager_client: Arc<dyn ProofManagerClient> =
167+
Arc::new(self.mock_proof_manager_client);
168+
let pmc = proof_manager_client.clone();
169+
self.mock_transaction_converter
170+
.expect_get_proof_manager_client()
171+
.returning(move || pmc.clone());
172+
160173
register_metrics();
161174
Gateway::new(
162175
self.config,
@@ -175,6 +188,14 @@ impl MockDependencies {
175188
fn expect_validate_tx(&mut self, args: ValidationArgs, result: MempoolClientResult<()>) {
176189
self.mock_mempool_client.expect_validate_tx().once().with(eq(args)).return_once(|_| result);
177190
}
191+
192+
fn expect_set_proof(&mut self, proof_facts: ProofFacts, proof: Proof) {
193+
self.mock_proof_manager_client
194+
.expect_set_proof()
195+
.once()
196+
.with(eq(proof_facts), eq(proof))
197+
.returning(|_, _| Ok(()));
198+
}
178199
}
179200

180201
fn account_contract() -> FeatureContract {
@@ -291,6 +312,14 @@ async fn setup_mock_state(
291312
&mut mock_dependencies.state_reader_factory.state_reader.blockifier_state_reader,
292313
);
293314

315+
// If the transaction has proof facts, expect set_proof to be called on the proof manager.
316+
if let RpcTransaction::Invoke(RpcInvokeTransaction::V3(ref invoke_tx)) = input_tx {
317+
if !invoke_tx.proof_facts.is_empty() {
318+
mock_dependencies
319+
.expect_set_proof(invoke_tx.proof_facts.clone(), invoke_tx.proof.clone());
320+
}
321+
}
322+
294323
let mempool_add_tx_args = AddTransactionArgs {
295324
tx: expected_internal_tx.clone(),
296325
account_state: AccountState { address, nonce: *input_tx.nonce() },

0 commit comments

Comments
 (0)