diff --git a/Cargo.lock b/Cargo.lock index 42912f3..22a2503 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3771,6 +3771,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" name = "surreal-brain" version = "0.1.0" dependencies = [ + "anyhow", "bs58", "chrono", "dashmap 6.1.0", diff --git a/Cargo.toml b/Cargo.toml index 96832e2..591f753 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,3 +27,8 @@ strip = true opt-level = 3 panic = 'abort' codegen-units = 1 + +[dev-dependencies] +anyhow = "1.0.98" +bs58 = "0.5.1" +ed25519-dalek = "2.1.1" diff --git a/src/bin/migration0.rs b/src/bin/migration0.rs index 4b20757..63f3fbe 100644 --- a/src/bin/migration0.rs +++ b/src/bin/migration0.rs @@ -1,6 +1,8 @@ // After deleting this migration, also delete old_brain structs // and dangling impls from the model use std::error::Error; +use surreal_brain::constants::{DB_ADDRESS, DB_NAME, DB_NS}; +use surreal_brain::db::init; use surreal_brain::{db, old_brain}; #[tokio::main] @@ -8,6 +10,8 @@ async fn main() -> Result<(), Box> { let old_brain_data = old_brain::BrainData::load_from_disk()?; // println!("{}", serde_yaml::to_string(&old_brain_data)?); + init(DB_ADDRESS, DB_NS, DB_NAME).await?; + let result = db::migration0(&old_brain_data).await?; println!("{result:?}"); diff --git a/src/db.rs b/src/db.rs index b2ffa38..33cea67 100644 --- a/src/db.rs +++ b/src/db.rs @@ -8,11 +8,9 @@ use surrealdb::{ RecordId, Surreal, }; -use crate::constants::{ - ACCOUNT, DB_ADDRESS, DB_NAME, DB_NS, DB_PASS, DB_USER, OPERATOR, VM_CONTRACT, VM_NODE, -}; +use crate::constants::{ACCOUNT, DB_PASS, DB_USER, OPERATOR, VM_CONTRACT, VM_NODE}; -static DB: LazyLock> = LazyLock::new(Surreal::init); +pub static DB: LazyLock> = LazyLock::new(Surreal::init); #[derive(thiserror::Error, Debug)] pub enum Error { @@ -35,8 +33,6 @@ pub async fn migration0(old_data: &old_brain::BrainData) -> surrealdb::Result<() let vm_contracts: Vec = old_data.into(); let operators: Vec = old_data.into(); - init(DB_ADDRESS, DB_NS, DB_NAME).await?; - println!("Inserting accounts..."); let _: Vec = DB.insert(()).content(accounts).await?; println!("Inserting vm nodes..."); diff --git a/tests/fixtures/secret_detee_wallet_key b/tests/fixtures/secret_detee_wallet_key new file mode 100644 index 0000000..10303bf --- /dev/null +++ b/tests/fixtures/secret_detee_wallet_key @@ -0,0 +1 @@ +9RBoFzqSfMVjQmmCbnMhfNGxGEdRmTyb9eF4wDdRVX6f \ No newline at end of file diff --git a/tests/grpcs_test.rs b/tests/grpcs_test.rs new file mode 100644 index 0000000..0bdaf88 --- /dev/null +++ b/tests/grpcs_test.rs @@ -0,0 +1,80 @@ +use detee_shared::{ + common_proto::Pubkey, + general_proto::{ + brain_general_cli_client::BrainGeneralCliClient, + brain_general_cli_server::BrainGeneralCliServer, + }, + vm_proto::brain_vm_cli_server::BrainVmCliServer, +}; +use surreal_brain::grpc::{BrainGeneralCliMock, BrainVmCliMock}; +use test_utils::{get_pub_key, sign_request}; +use tokio::sync::OnceCell; +use tonic::transport::Channel; + +mod test_utils; + +const DB_URL: &str = "localhost:8000"; +const DB_NS: &str = "test_brain"; +const DB_NAME: &str = "test_migration_db"; + +const GRPC_ADDR: &str = "127.0.0.1:31337"; + +static TEST_STATE: OnceCell = OnceCell::const_new(); + +async fn prepare_test_db() { + surreal_brain::db::init(DB_URL, DB_NS, DB_NAME) + .await + .expect("Failed to initialize the database"); + + let old_brain_data = surreal_brain::old_brain::BrainData::load_from_disk().unwrap(); + // cleanup old brain data + surreal_brain::db::migration0(&old_brain_data).await.unwrap(); +} + +async fn fake_grpc_server() { + tonic::transport::Server::builder() + .add_service(BrainGeneralCliServer::new(BrainGeneralCliMock {})) + .add_service(BrainVmCliServer::new(BrainVmCliMock {})) + .serve(GRPC_ADDR.parse().unwrap()) + .await + .unwrap(); +} + +async fn fake_grpc_client() -> Channel { + let url = format!("http://{GRPC_ADDR}"); + Channel::from_shared(url).unwrap().connect().await.unwrap() +} + +async fn prepare_test_setup() { + TEST_STATE + .get_or_init(|| async { + prepare_test_db().await; + + tokio::spawn(async { + fake_grpc_server().await; + }); + + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + fake_grpc_client().await + }) + .await; +} + +#[tokio::test] +async fn test_general_balance() { + prepare_test_setup().await; + let grpc_channel = TEST_STATE.get().unwrap().clone(); + + let mut brain_general_cli_client = BrainGeneralCliClient::new(grpc_channel.clone()); + + let req_data = Pubkey { pubkey: get_pub_key().unwrap() }; + + let acc_bal = brain_general_cli_client + .get_balance(sign_request(req_data).unwrap()) + .await + .unwrap() + .into_inner(); + + assert_eq!(acc_bal.balance, 0); + assert_eq!(acc_bal.tmp_locked, 0); +} diff --git a/tests/test_utils.rs b/tests/test_utils.rs new file mode 100644 index 0000000..56f1e3a --- /dev/null +++ b/tests/test_utils.rs @@ -0,0 +1,41 @@ +use anyhow::Result; +use ed25519_dalek::Signer; +use ed25519_dalek::SigningKey; +use tonic::metadata::AsciiMetadataValue; +use tonic::Request; + +pub const WALLET_KEY_PATH: &str = "tests/fixtures/secret_detee_wallet_key"; + +pub fn sign_request(req: T) -> Result> { + let pubkey = get_pub_key()?; + let timestamp = chrono::Utc::now().to_rfc3339(); + let signature = try_sign_message(&format!("{timestamp}{req:?}"))?; + let timestamp: AsciiMetadataValue = timestamp.parse()?; + let pubkey: AsciiMetadataValue = pubkey.parse()?; + let signature: AsciiMetadataValue = signature.parse()?; + let mut req = Request::new(req); + req.metadata_mut().insert("timestamp", timestamp); + req.metadata_mut().insert("pubkey", pubkey); + req.metadata_mut().insert("request-signature", signature); + + Ok(req) +} + +fn get_signing_key() -> Result { + let key = bs58::decode(std::fs::read_to_string(WALLET_KEY_PATH)?.trim()) + .into_vec()? + .try_into() + .map_err(|e: Vec| anyhow::anyhow!("Invalid key length: {}", e.len()))?; + let key = SigningKey::from_bytes(&key); + Ok(key) +} + +pub fn get_pub_key() -> Result { + let key = get_signing_key()?; + Ok(bs58::encode(key.verifying_key().to_bytes()).into_string()) +} + +pub fn try_sign_message(message: &str) -> Result { + let key = get_signing_key()?; + Ok(bs58::encode(key.sign(message.as_bytes()).to_bytes()).into_string()) +}