diff --git a/chain-signatures/node/src/backlog/mod.rs b/chain-signatures/node/src/backlog/mod.rs index 0f400fb5..0b88eb31 100644 --- a/chain-signatures/node/src/backlog/mod.rs +++ b/chain-signatures/node/src/backlog/mod.rs @@ -831,7 +831,7 @@ mod tests { use anchor_lang::prelude::Pubkey; use mpc_primitives::{SignArgs, SignId}; - fn create_test_tx(id: u8, status: SignStatus) -> BidirectionalTx { + fn create_test_tx(id: u8) -> BidirectionalTx { BidirectionalTx { id: BidirectionalTxId(B256::from([id; 32])), sender: [0u8; 32], @@ -850,7 +850,6 @@ mod tests { request_id: [id; 32], from_address: Address::ZERO, nonce: 0, - status, } } @@ -910,7 +909,12 @@ mod tests { ) } - fn create_execution_entry(tx: BidirectionalTx, chain: Chain, dest: &str) -> BacklogEntry { + fn create_execution_entry( + tx: BidirectionalTx, + chain: Chain, + status: SignStatus, + dest: &str, + ) -> BacklogEntry { let sign_id = SignId::new(tx.request_id); let request = IndexedSignRequest::new( sign_id, @@ -919,13 +923,14 @@ mod tests { 0, SignKind::SignBidirectional(create_test_event(dest)), ); - BacklogEntry::with_status(request, tx.status, Some(tx)) + BacklogEntry::with_status(request, status, Some(tx)) } async fn insert_bidirectional_with_status( backlog: &Backlog, chain: Chain, tx: BidirectionalTx, + status: SignStatus, dest: &str, ) { let sign_id = SignId::new(tx.request_id); @@ -933,13 +938,12 @@ mod tests { .insert(create_bidirectional_request(sign_id, chain, dest, 0)) .await; - match tx.status { + match status { SignStatus::AwaitingResponse => {} SignStatus::PendingExecution => { backlog.advance(chain, sign_id, tx).await.unwrap(); } SignStatus::Success | SignStatus::Failed => { - let status = tx.status; backlog.advance(chain, sign_id, tx).await.unwrap(); backlog.set_status(chain, &sign_id, status).await; } @@ -950,19 +954,39 @@ mod tests { async fn test_backlog_chain_isolation() { let backlog = Backlog::new(); - let tx_eth = create_test_tx(1, SignStatus::AwaitingResponse); - let tx_sol = create_test_tx(2, SignStatus::AwaitingResponse); - let tx_near = create_test_tx(3, SignStatus::AwaitingResponse); + let tx_eth = create_test_tx(1); + let tx_sol = create_test_tx(2); + let tx_near = create_test_tx(3); let sign_id_eth = SignId::new(tx_eth.request_id); let sign_id_sol = SignId::new(tx_sol.request_id); let sign_id_near = SignId::new(tx_near.request_id); // Insert into different chains - insert_bidirectional_with_status(&backlog, Chain::Ethereum, tx_eth.clone(), "ethereum") - .await; - insert_bidirectional_with_status(&backlog, Chain::Solana, tx_sol.clone(), "solana").await; - insert_bidirectional_with_status(&backlog, Chain::NEAR, tx_near.clone(), "near").await; + insert_bidirectional_with_status( + &backlog, + Chain::Ethereum, + tx_eth.clone(), + SignStatus::AwaitingResponse, + "ethereum", + ) + .await; + insert_bidirectional_with_status( + &backlog, + Chain::Solana, + tx_sol.clone(), + SignStatus::AwaitingResponse, + "solana", + ) + .await; + insert_bidirectional_with_status( + &backlog, + Chain::NEAR, + tx_near.clone(), + SignStatus::AwaitingResponse, + "near", + ) + .await; // Verify correct transactions in each chain assert!(backlog.get(Chain::Ethereum, &sign_id_eth).await.is_some()); @@ -978,17 +1002,45 @@ mod tests { let backlog = Backlog::new(); // Add transactions with different statuses to Ethereum - let tx1 = create_test_tx(1, SignStatus::AwaitingResponse); - let tx2 = create_test_tx(2, SignStatus::Success); - let tx3 = create_test_tx(3, SignStatus::PendingExecution); - - insert_bidirectional_with_status(&backlog, Chain::Ethereum, tx1, "ethereum").await; - insert_bidirectional_with_status(&backlog, Chain::Ethereum, tx2, "ethereum").await; - insert_bidirectional_with_status(&backlog, Chain::Ethereum, tx3, "ethereum").await; + let tx1 = create_test_tx(1); + let tx2 = create_test_tx(2); + let tx3 = create_test_tx(3); + + insert_bidirectional_with_status( + &backlog, + Chain::Ethereum, + tx1, + SignStatus::AwaitingResponse, + "ethereum", + ) + .await; + insert_bidirectional_with_status( + &backlog, + Chain::Ethereum, + tx2, + SignStatus::Success, + "ethereum", + ) + .await; + insert_bidirectional_with_status( + &backlog, + Chain::Ethereum, + tx3, + SignStatus::PendingExecution, + "ethereum", + ) + .await; // Add transactions to Solana - let tx4 = create_test_tx(4, SignStatus::PendingExecution); - insert_bidirectional_with_status(&backlog, Chain::Solana, tx4, "solana").await; + let tx4 = create_test_tx(4); + insert_bidirectional_with_status( + &backlog, + Chain::Solana, + tx4, + SignStatus::PendingExecution, + "solana", + ) + .await; // Filter Ethereum by Pending let eth_pending = backlog @@ -1029,8 +1081,15 @@ mod tests { for i in 0..5 { let backlog = backlog.clone(); let handle = tokio::spawn(async move { - let tx = create_test_tx(i, SignStatus::AwaitingResponse); - insert_bidirectional_with_status(&backlog, Chain::Ethereum, tx, "ethereum").await; + let tx = create_test_tx(i); + insert_bidirectional_with_status( + &backlog, + Chain::Ethereum, + tx, + SignStatus::AwaitingResponse, + "ethereum", + ) + .await; }); handles.push(handle); } @@ -1038,8 +1097,15 @@ mod tests { for i in 5..10 { let backlog = backlog.clone(); let handle = tokio::spawn(async move { - let tx = create_test_tx(i, SignStatus::AwaitingResponse); - insert_bidirectional_with_status(&backlog, Chain::Solana, tx, "solana").await; + let tx = create_test_tx(i); + insert_bidirectional_with_status( + &backlog, + Chain::Solana, + tx, + SignStatus::AwaitingResponse, + "solana", + ) + .await; }); handles.push(handle); } @@ -1078,12 +1144,26 @@ mod tests { let backlog = Backlog::new(); // Add some transactions - let tx1 = create_test_tx(1, SignStatus::PendingExecution); - let tx2 = create_test_tx(2, SignStatus::Success); + let tx1 = create_test_tx(1); + let tx2 = create_test_tx(2); backlog.set_processed_block(Chain::Ethereum, 100).await; - insert_bidirectional_with_status(&backlog, Chain::Ethereum, tx1.clone(), "ethereum").await; - insert_bidirectional_with_status(&backlog, Chain::Ethereum, tx2.clone(), "ethereum").await; + insert_bidirectional_with_status( + &backlog, + Chain::Ethereum, + tx1.clone(), + SignStatus::PendingExecution, + "ethereum", + ) + .await; + insert_bidirectional_with_status( + &backlog, + Chain::Ethereum, + tx2.clone(), + SignStatus::Success, + "ethereum", + ) + .await; let checkpoint = backlog.checkpoint(Chain::Ethereum).await; assert_eq!(checkpoint.block_height, 100); @@ -1093,27 +1173,47 @@ mod tests { #[tokio::test] async fn test_checkpoint_equality() { - let tx1 = create_test_tx(1, SignStatus::AwaitingResponse); - let tx2 = create_test_tx(2, SignStatus::AwaitingResponse); + let tx1 = create_test_tx(1); + let tx2 = create_test_tx(2); let mut pending1 = PendingRequests::new(); pending1.insert( SignId::new(tx1.request_id), - create_execution_entry(tx1.clone(), Chain::Ethereum, "ethereum"), + create_execution_entry( + tx1.clone(), + Chain::Ethereum, + SignStatus::AwaitingResponse, + "ethereum", + ), ); pending1.insert( SignId::new(tx2.request_id), - create_execution_entry(tx2.clone(), Chain::Ethereum, "ethereum"), + create_execution_entry( + tx2.clone(), + Chain::Ethereum, + SignStatus::AwaitingResponse, + "ethereum", + ), ); pending1.set_processed_block(100); let mut pending2 = PendingRequests::new(); pending2.insert( SignId::new(tx1.request_id), - create_execution_entry(tx1.clone(), Chain::Ethereum, "ethereum"), + create_execution_entry( + tx1.clone(), + Chain::Ethereum, + SignStatus::AwaitingResponse, + "ethereum", + ), ); pending2.insert( SignId::new(tx2.request_id), - create_execution_entry(tx2.clone(), Chain::Ethereum, "ethereum"), + create_execution_entry( + tx2.clone(), + Chain::Ethereum, + SignStatus::AwaitingResponse, + "ethereum", + ), ); pending2.set_processed_block(100); @@ -1130,12 +1230,17 @@ mod tests { #[tokio::test] async fn test_checkpoint_serialization() { - let tx1 = create_test_tx(1, SignStatus::AwaitingResponse); + let tx1 = create_test_tx(1); let mut pending = PendingRequests::new(); pending.insert( SignId::new(tx1.request_id), - create_execution_entry(tx1.clone(), Chain::Ethereum, "ethereum"), + create_execution_entry( + tx1.clone(), + Chain::Ethereum, + SignStatus::AwaitingResponse, + "ethereum", + ), ); pending.set_processed_block(100); let checkpoint = pending.checkpoint(Chain::Ethereum); @@ -1165,9 +1270,16 @@ mod tests { #[tokio::test] async fn test_recover_restores_execution_watchers() { let backlog = Backlog::new(); - let tx = create_test_tx(6, SignStatus::PendingExecution); - - insert_bidirectional_with_status(&backlog, Chain::Solana, tx.clone(), "ethereum").await; + let tx = create_test_tx(6); + + insert_bidirectional_with_status( + &backlog, + Chain::Solana, + tx.clone(), + SignStatus::PendingExecution, + "ethereum", + ) + .await; backlog.set_processed_block(Chain::Solana, 10).await; let checkpoint = backlog.checkpoint(Chain::Solana).await; @@ -1247,7 +1359,7 @@ mod tests { async fn test_watch_unwatch_and_set_status() { use k256::Scalar; let backlog = Backlog::new(); - let tx = create_test_tx(7, SignStatus::PendingExecution); + let tx = create_test_tx(7); let sign_id = SignId::new(tx.request_id); // Insert a pending Sign request on the source chain @@ -1296,8 +1408,15 @@ mod tests { let backlog = Backlog::new(); // Add some transactions - let tx1 = create_test_tx(1, SignStatus::PendingExecution); - insert_bidirectional_with_status(&backlog, Chain::Ethereum, tx1.clone(), "ethereum").await; + let tx1 = create_test_tx(1); + insert_bidirectional_with_status( + &backlog, + Chain::Ethereum, + tx1.clone(), + SignStatus::PendingExecution, + "ethereum", + ) + .await; let interval = Chain::Ethereum.checkpoint_interval().unwrap(); @@ -1334,8 +1453,15 @@ mod tests { let interval = Chain::Solana.checkpoint_interval().unwrap(); // Add transaction - let tx1 = create_test_tx(1, SignStatus::PendingExecution); - insert_bidirectional_with_status(&backlog, Chain::Solana, tx1.clone(), "solana").await; + let tx1 = create_test_tx(1); + insert_bidirectional_with_status( + &backlog, + Chain::Solana, + tx1.clone(), + SignStatus::PendingExecution, + "solana", + ) + .await; // Solana interval is 10 blocks for i in 1..interval { @@ -1354,7 +1480,7 @@ mod tests { #[tokio::test] async fn test_advance_rejects_plain_sign_entries() { let backlog = Backlog::new(); - let tx = create_test_tx(8, SignStatus::PendingExecution); + let tx = create_test_tx(8); let sign_id = SignId::new(tx.request_id); let args = SignArgs { diff --git a/chain-signatures/node/src/sign_bidirectional.rs b/chain-signatures/node/src/sign_bidirectional.rs index 2596f9e4..1b147b8c 100644 --- a/chain-signatures/node/src/sign_bidirectional.rs +++ b/chain-signatures/node/src/sign_bidirectional.rs @@ -62,7 +62,6 @@ pub struct BidirectionalTx { pub request_id: [u8; 32], pub from_address: Address, pub nonce: u64, - pub status: SignStatus, } impl BidirectionalTx { diff --git a/chain-signatures/node/src/storage/checkpoint_storage.rs b/chain-signatures/node/src/storage/checkpoint_storage.rs index f4a201d3..7415c58b 100644 --- a/chain-signatures/node/src/storage/checkpoint_storage.rs +++ b/chain-signatures/node/src/storage/checkpoint_storage.rs @@ -10,7 +10,7 @@ use tokio::sync::RwLock; use std::collections::HashMap; use std::sync::Arc; -const CHECKPOINT_VERSION: &str = "v2"; +const CHECKPOINT_VERSION: &str = "v3"; #[derive(Clone, Debug)] pub enum CheckpointStorage { diff --git a/chain-signatures/node/src/stream/ops.rs b/chain-signatures/node/src/stream/ops.rs index f00b580c..9d67ead1 100644 --- a/chain-signatures/node/src/stream/ops.rs +++ b/chain-signatures/node/src/stream/ops.rs @@ -425,7 +425,6 @@ pub(crate) async fn process_respond_event( request_id: respond_event.request_id(), from_address, nonce, - status: SignStatus::AwaitingResponse, }; tracing::info!( @@ -510,7 +509,7 @@ pub async fn process_execution_confirmed( ); // Remove the watcher; if it's not found, it might have been processed already - let Some((unwatched_sign_id, mut pending_tx)) = + let Some((unwatched_sign_id, pending_tx)) = backlog.unwatch_execution(target_chain, &tx_id).await else { tracing::warn!( @@ -541,7 +540,6 @@ pub async fn process_execution_confirmed( }; tracing::info!(?tx_id, ?unwatched_sign_id, updated_status = ?updated_tx.status(), "set_status returned transaction"); - pending_tx.status = status; let completed_tx = CompletedTx::new(pending_tx, block_height); let sign_request = match result { @@ -717,7 +715,6 @@ mod tests { request_id: [1u8; 32], from_address: Address::ZERO, nonce: 0, - status: SignStatus::PendingExecution, }; let sign_id = SignId::new(tx.request_id); @@ -893,7 +890,6 @@ mod tests { request_id: [2u8; 32], from_address: Address::ZERO, nonce: 0, - status: SignStatus::PendingExecution, }; let sign_id = SignId::new(tx.request_id); diff --git a/integration-tests/tests/cases/ethereum_stream.rs b/integration-tests/tests/cases/ethereum_stream.rs index ed9abf03..4536723b 100644 --- a/integration-tests/tests/cases/ethereum_stream.rs +++ b/integration-tests/tests/cases/ethereum_stream.rs @@ -255,7 +255,6 @@ async fn test_ethereum_stream_execution_confirmation() -> Result<()> { request_id: [7u8; 32], from_address: AlloyAddress::from_slice(ctx.wallet.as_bytes()), nonce: 0, - status: mpc_node::sign_bidirectional::SignStatus::PendingExecution, }; let sign_id = SignId::new([7u8; 32]); backlog.watch_execution(Chain::Ethereum, sign_id, tx).await;