kms_secp256k1_api/services/mocks/
mock_casper_keys_service.rs

1use crate::{
2    config::Config,
3    constants::{CASPER_SECP_LEN, CASPER_SECP_PREFIX},
4    services::{
5        crypto_service::CryptoService,
6        keys_service::{KeyEntry, KeysServiceTrait, SigEntry},
7        mocks::mock_keys_service::{KeyPair, MockKeysService},
8    },
9};
10use base64::Engine;
11use base64::engine::general_purpose::STANDARD;
12use casper_rust_wasm_sdk::{
13    SDK,
14    helpers::{public_key_from_secret_key, secret_key_secp256k1_generate},
15    types::{
16        transaction::Transaction, transaction_params::transaction_str_params::TransactionStrParams,
17    },
18};
19use regex::Regex;
20use tracing::error;
21
22pub struct MockCasperKeysService {
23    inner: MockKeysService,
24}
25
26#[async_trait::async_trait]
27impl KeysServiceTrait for MockCasperKeysService {
28    async fn create_key(&mut self, _config: &Config) -> Result<KeyEntry, String> {
29        let private_key = secret_key_secp256k1_generate()
30            .map_err(|e| format!("Failed to generate secret key: {e}"))?;
31        let private_key = private_key.to_pem().map_err(|e| e.to_string())?;
32
33        let address = public_key_from_secret_key(&private_key)
34            .map_err(|e| format!("Failed to get public key: {e}"))?; // generated key contains prefix
35
36        let public_key = address.replacen(CASPER_SECP_PREFIX, "", 1).clone(); // removes Casper prefix
37
38        let key_id = public_key.clone();
39
40        let public_key_base64 = STANDARD.encode(&public_key);
41
42        // Store in map
43        let key_pair = KeyPair {
44            public_key: public_key.clone(),
45            private_key,
46            address: address.clone(),
47        };
48
49        let key_entry = {
50            {
51                let mut keys = self.inner.keys.lock().await;
52                keys.entry(address.clone()).or_insert(key_pair);
53            } // lock is dropped here
54
55            KeyEntry {
56                public_key: Some(public_key).into(),
57                address: address.into(),
58                public_key_base64: public_key_base64.into(),
59                key_id: key_id.into(),
60            }
61        };
62
63        Ok(key_entry)
64    }
65
66    async fn sign_transaction_hash(
67        &mut self,
68        config: &Config,
69        transaction_hash: &str,
70        key: &str,
71    ) -> Result<SigEntry, String> {
72        let key = Self::resolve_key(key);
73        let key_pair = {
74            let keys = self.inner.keys.lock().await;
75            keys.get(&key)
76                .ok_or_else(|| "Public key not found".to_string())?
77                .clone()
78        };
79
80        let public_key = key_pair.address;
81
82        let transaction_params = TransactionStrParams::default();
83        transaction_params.set_chain_name("casper-net-1");
84        transaction_params.set_initiator_addr(&public_key);
85        transaction_params.set_payment_amount("100000000");
86        let sdk = SDK::new(None, None, None);
87        let make_transfer = sdk
88            .make_transfer_transaction(None, &public_key, "2500000000", transaction_params, None)
89            .map_err(|e| format!("Failed to create transfer transaction: {e}"))?;
90
91        let mut transaction_str = make_transfer.to_json_string().unwrap_or_default();
92
93        let re = Regex::new(r#""hash"\s*:\s*"[^"]+""#).unwrap();
94        transaction_str = re
95            .replace(&transaction_str, format!(r#""hash": "{transaction_hash}""#))
96            .to_string();
97
98        let signed_tx = self
99            .sign_transaction(config, &transaction_str, &public_key)
100            .await
101            .unwrap_or_default();
102
103        let transaction: Transaction = Transaction::from_json_string(&signed_tx)
104            .map_err(|e| format!("Failed to parse transaction: {e}"))?;
105
106        let signature = transaction
107            .approvals()
108            .first()
109            .unwrap()
110            .signature()
111            .to_hex_string();
112
113        Ok(SigEntry {
114            address: public_key.clone().into(),
115            public_key: public_key.replacen(CASPER_SECP_PREFIX, "", 1).into(),
116            signature: signature.into(),
117        })
118    }
119
120    async fn sign_transaction(
121        &mut self,
122        _config: &Config,
123        transaction_str: &str,
124        key: &str,
125    ) -> Result<String, String> {
126        let mut transaction: Transaction = Transaction::from_json_string(transaction_str)
127            .map_err(|e| format!("Failed to parse transaction: {e}"))?;
128
129        let key = Self::resolve_key(key);
130        let key_pair = {
131            let keys = self.inner.keys.lock().await;
132            keys.get(&key)
133                .ok_or_else(|| "Public key not found".to_string())?
134                .clone()
135        };
136
137        let signed_tx = transaction.sign(&key_pair.private_key);
138
139        Ok(signed_tx.to_json_string().unwrap_or_default())
140    }
141
142    async fn verify(
143        &mut self,
144        transaction_hash_hex: &str,
145        signature_hex: &str,
146        key: &str,
147    ) -> Result<bool, String> {
148        let key = Self::resolve_key(key);
149        self.inner
150            .verify(transaction_hash_hex, signature_hex, &key)
151            .map_err(|e| {
152                let msg = format!("Signature verification failed: {e}");
153                error!("{}", msg);
154                msg
155            })
156    }
157
158    async fn verify_via_kms(
159        &mut self,
160        transaction_hash_hex: &str,
161        signature_hex: &str,
162        key: &str,
163    ) -> Result<bool, String> {
164        let key = Self::resolve_key(key);
165        self.inner
166            .verify_via_kms(transaction_hash_hex, signature_hex, &key)
167            .await
168    }
169
170    async fn delete_key(&mut self, key: &str) -> Result<bool, String> {
171        let key = Self::resolve_key(key);
172        Ok(self.inner.delete_key(&key).await)
173    }
174
175    async fn list_keys(&mut self) -> Result<Vec<KeyEntry>, String> {
176        Ok(self.inner.list_keys().await)
177    }
178}
179
180impl MockCasperKeysService {
181    /// Creates a new `MockCasperKeysService` with an empty in-memory key store.
182    ///
183    /// # Arguments
184    ///
185    /// * `_config` - Unused configuration object, included for interface compatibility.
186    /// * `crypto_service` - The crypto service to use for key operations.
187    ///
188    /// # Errors
189    ///
190    /// This function currently does not return an error, but it returns a `Result`
191    /// to match a common interface and allow future fallibility.
192    pub fn new(config: Config, crypto_service: CryptoService) -> Result<Self, String> {
193        Ok(Self {
194            inner: MockKeysService::new(config, crypto_service),
195        })
196    }
197
198    fn resolve_key(key: &str) -> String {
199        if key.len() == CASPER_SECP_LEN {
200            key.to_string()
201        } else {
202            format!("{CASPER_SECP_PREFIX}{key}")
203        }
204    }
205}