Skip to content

Commit

Permalink
move trading key to rocksdb (#123)
Browse files Browse the repository at this point in the history
Co-authored-by: Cyberaurora <[email protected]>
  • Loading branch information
kb1ns and kb1ns authored Nov 20, 2023
1 parent df81c0f commit e3aaeda
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 112 deletions.
11 changes: 1 addition & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sidecar.toml.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
db = "mysql://username:password@localhost:3306/fxdx"
db_dir = "/tmp/sidecar"
prover = "127.0.0.1:8097"
bind_addr = "127.0.0.1:8096"
2 changes: 1 addition & 1 deletion sidecar/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ parity-scale-codec = { version = "3", features = ["derive"] }
env_logger = "0.10.1"
log = { version = "0.4", features = ["serde"] }
x25519-dalek = "1.1.1"
sqlx = { version = "0.6.2", features = ["runtime-tokio-rustls", "mysql", "decimal", "chrono"] }
rocksdb = "0.21"
hex = "0.4"
rand = "0.8.5"
hyper = "0.14"
Expand Down
40 changes: 4 additions & 36 deletions sidecar/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Config {
pub prover: String,
pub db: String,
pub db_dir: String,
pub bind_addr: String,
}

Expand All @@ -27,46 +27,14 @@ pub struct Config {
pub struct Cli {
#[arg(short('c'), long("config"), required = true, value_name = "FILE")]
pub file: std::path::PathBuf,
#[arg(long)]
pub skip_decrypt: bool,
}

impl Config {
fn decrypt(&mut self, key: &str) -> anyhow::Result<()> {
use magic_crypt::MagicCryptTrait;
let mc = magic_crypt::new_magic_crypt!(key, 64);
let dec = mc.decrypt_base64_to_string(&self.db)?;
self.db.replace_range(.., &dec);
Ok(())
}

#[allow(dead_code)]
fn encrypt(&mut self, key: &str) -> anyhow::Result<()> {
use magic_crypt::MagicCryptTrait;
let mc = magic_crypt::new_magic_crypt!(key, 64);
let enc = mc.encrypt_str_to_base64(&self.db);
self.db.replace_range(.., &enc);
Ok(())
}
}

pub fn init_config_file() -> anyhow::Result<Config> {
let opts = Cli::parse();
if opts.skip_decrypt {
init_config(&std::fs::read_to_string(&opts.file)?, None)
} else {
let key = std::env::var_os("MAGIC_KEY").ok_or(anyhow::anyhow!("env MAGIC_KEY not set"))?;
init_config(
&std::fs::read_to_string(&opts.file)?,
key.to_str().map(|s| s.to_string()),
)
}
init_config(&std::fs::read_to_string(&opts.file)?)
}

fn init_config(toml: &str, key: Option<String>) -> anyhow::Result<Config> {
let mut cfg: Config = toml::from_str(toml)?;
if let Some(key) = key {
cfg.decrypt(&key)?;
}
fn init_config(toml: &str) -> anyhow::Result<Config> {
let cfg: Config = toml::from_str(toml)?;
Ok(cfg)
}
35 changes: 10 additions & 25 deletions sidecar/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::errors::CustomRpcError;
use crate::{
backend::BackendConnection,
config::Config,
// TODO remove
db,
endpoint::{PendingOrderWrapper, TradingCommand},
AccountId32,
Sr25519Pair,
Sr25519Public,
Sr25519Signature,
errors::CustomRpcError,
AccountId32, Sr25519Pair, Sr25519Public, Sr25519Signature,
};
use dashmap::DashMap;
use galois_engine::{core::*, fusotao::OffchainSymbol, orders::PendingOrder};
use hyper::{Body, Request, Response};
use parity_scale_codec::{Decode, Encode};
use rocksdb::DB;
use rust_decimal::Decimal;
use sp_core::crypto::{Pair as Crypto, Ss58Codec};
use sqlx::mysql::MySqlConnectOptions;
use sqlx::{ConnectOptions, MySql, Pool};
use std::{
collections::BTreeSet,
error::Error,
Expand All @@ -52,7 +47,7 @@ use x25519_dalek::StaticSecret;
pub struct Context {
pub backend: BackendConnection,
pub x25519: StaticSecret,
pub db: Pool<MySql>,
pub db: DB,
pub subscribers: Arc<DashMap<String, UnboundedSender<(String, PendingOrderWrapper)>>>,
pub session_nonce: Arc<DashMap<String, Session>>,
pub markets: Arc<DashMap<Symbol, (Arc<AtomicBool>, OffchainSymbol)>>,
Expand All @@ -64,12 +59,7 @@ impl Context {
let backend = BackendConnection::new(config.prover, broadcast);
let conn = backend.clone();
let x25519 = futures::executor::block_on(async move { conn.get_x25519().await }).unwrap();
let db = futures::executor::block_on(async {
let mut option: MySqlConnectOptions = config.db.parse()?;
option.disable_statement_logging();
Pool::connect_with(option).await
})
.unwrap();
let db = DB::open_default(&config.db_dir).unwrap();
let subscribers = Arc::new(DashMap::<
String,
UnboundedSender<(String, PendingOrderWrapper)>,
Expand Down Expand Up @@ -120,13 +110,6 @@ impl Context {
}
}

pub async fn get_trading_key(&self, user_id: &String) -> anyhow::Result<Vec<u8>> {
db::query_trading_key(&self.db, user_id)
.await
.map(|k| crate::hexstr_to_vec(&k))
.flatten()
}

pub async fn get_user_nonce(&self, user_id: &String) -> anyhow::Result<u32> {
let session = self
.session_nonce
Expand All @@ -135,20 +118,22 @@ impl Context {
Ok(session.value().get_nonce().await)
}

// FIXME maybe we could calculate the shared secret on each request
/// the users' curve25519 pubkey is one-time, so is the trading key(shared secret of curve25519)
pub async fn verify_trading_signature(
&self,
data: &[u8],
user_id: &String,
user_id: &AccountId32,
sig: &[u8],
nonce: &[u8],
) -> anyhow::Result<()> {
let mut decode = nonce.clone();
let n = u32::decode(&mut decode)?;
let key = self.get_trading_key(user_id).await?;
let key = db::query_trading_key(&self.db, user_id)?;
// FIXME when sidecar reboot, the session_nonce will be empty
let session = self
.session_nonce
.get(user_id)
.get(&user_id.to_ss58check())
.ok_or(CustomRpcError::user_not_found())?;
session.value().try_occupy_nonce(n).await?;
let mut to_be_signed = vec![];
Expand Down
32 changes: 8 additions & 24 deletions sidecar/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use serde::{Deserialize, Serialize};
use sqlx::{MySql, Pool};
use crate::AccountId32;

#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq, sqlx::FromRow)]
pub struct TradingKey {
pub f_user_id: String,
pub f_trading_key: String,
pub fn query_trading_key(db: &rocksdb::DB, user_id: &AccountId32) -> anyhow::Result<Vec<u8>> {
db.get(user_id)?.ok_or(anyhow::anyhow!("Key expired"))
}

pub async fn query_trading_key(pool: &Pool<MySql>, user_id: &String) -> anyhow::Result<String> {
let r =
sqlx::query_as::<_, TradingKey>("select * from t_trading_key where f_user_id=? limit 1")
.bind(user_id)
.fetch_one(pool)
.await?;
Ok(r.f_trading_key)
}

pub async fn save_trading_key(
pool: &Pool<MySql>,
user_id: &String,
key: &String,
pub fn save_trading_key(
db: &rocksdb::DB,
user_id: &AccountId32,
key: [u8; 32],
) -> anyhow::Result<()> {
sqlx::query("replace into t_trading_key(f_user_id,f_trading_key) values(?,?)")
.bind(user_id)
.bind(key)
.execute(pool)
.await?;
db.put(user_id, key)?;
Ok(())
}
27 changes: 12 additions & 15 deletions sidecar/src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub fn export_rpc(context: Context) -> RpcModule<Context> {
.register_async_method("query_pending_orders", |p, ctx| async move {
let (symbol, user_id, signature, nonce) =
p.parse::<(String, String, String, String)>()?;
let user_id = crate::try_into_ss58(user_id)?;
let user_id = crate::try_into_account(user_id)?;
let symbol = crate::hexstr_to_vec(&symbol)?;
let signature = crate::hexstr_to_vec(&signature)?;
let nonce = crate::hexstr_to_vec(&nonce)?;
Expand All @@ -39,7 +39,7 @@ pub fn export_rpc(context: Context) -> RpcModule<Context> {
let symbol = Symbol::decode(&mut symbol.as_slice())
.map_err(|_| anyhow::anyhow!("invalid symbol"))?;
ctx.backend
.query_pending_orders(symbol, &user_id)
.query_pending_orders(symbol, &user_id.to_ss58check())
.await
.map(|r| {
r.into_iter()
Expand All @@ -52,14 +52,14 @@ pub fn export_rpc(context: Context) -> RpcModule<Context> {
module
.register_async_method("query_account", |p, ctx| async move {
let (user_id, signature, nonce) = p.parse::<(String, String, String)>()?;
let user_id = crate::try_into_ss58(user_id)?;
let user_id = crate::try_into_account(user_id)?;
let signature = crate::hexstr_to_vec(&signature)?;
let nonce = crate::hexstr_to_vec(&nonce)?;
ctx.verify_trading_signature(&[], &user_id, &signature, &nonce)
.await
.map_err(handle_error)?;
ctx.backend
.get_account(&user_id)
.get_account(&user_id.to_ss58check())
.await
.map(|r| {
r.into_iter()
Expand All @@ -73,7 +73,8 @@ pub fn export_rpc(context: Context) -> RpcModule<Context> {
.register_async_method("trade", |p, ctx| async move {
let (user_id, cmd, signature, nonce, relayer) =
p.parse::<(String, String, String, String, String)>()?;
let user_id = crate::try_into_ss58(user_id)?;
let user_id = crate::try_into_account(user_id)?;
let ss58 = user_id.to_ss58check();
let signature = crate::hexstr_to_vec(&signature)?;
let nonce = crate::hexstr_to_vec(&nonce)?;
let hex = crate::hexstr_to_vec(&cmd)?;
Expand All @@ -82,11 +83,9 @@ pub fn export_rpc(context: Context) -> RpcModule<Context> {
ctx.verify_trading_signature(&hex, &user_id, &signature, &nonce)
.await
.map_err(handle_error)?;
ctx.validate_cmd(&user_id, &cmd)
.await
.map_err(handle_error)?;
ctx.validate_cmd(&ss58, &cmd).await.map_err(handle_error)?;
ctx.backend
.submit_trading_command(user_id, cmd, relayer)
.submit_trading_command(ss58, cmd, relayer)
.await
.map(|id| crate::to_hexstr(id))
.map_err(handle_error)
Expand Down Expand Up @@ -121,8 +120,7 @@ pub fn export_rpc(context: Context) -> RpcModule<Context> {
.map_err(|_| anyhow::anyhow!("Invalid public key"))?;
let user_x25519_pub = x25519_dalek::PublicKey::from(user_x25519_pub);
let key = ctx.x25519.diffie_hellman(&user_x25519_pub).to_bytes();
let key = format!("0x{}", hex::encode(&key));
db::save_trading_key(&ctx.db, &user_id.to_ss58check(), &key).await?;
db::save_trading_key(&ctx.db, &user_id, key)?;
let init_nonce = rand::thread_rng().gen_range(1..10000);
ctx.session_nonce
.insert(user_id.to_ss58check(), Session::new(init_nonce));
Expand Down Expand Up @@ -154,8 +152,7 @@ pub fn export_rpc(context: Context) -> RpcModule<Context> {
.map_err(|_| anyhow::anyhow!("Invalid public key"))?;
let bot_x25519_pub = x25519_dalek::PublicKey::from(bot_x25519_pub);
let key = ctx.x25519.diffie_hellman(&bot_x25519_pub).to_bytes();
let key = format!("0x{}", hex::encode(&key));
db::save_trading_key(&ctx.db, &sub_id.to_ss58check(), &key).await?;
db::save_trading_key(&ctx.db, &sub_id, key)?;
let init_nonce = rand::thread_rng().gen_range(1..10000);
ctx.session_nonce
.insert(sub_id.to_ss58check(), Session::new(init_nonce));
Expand All @@ -176,7 +173,7 @@ pub fn export_rpc(context: Context) -> RpcModule<Context> {
.register_async_method("append_user", |p, ctx| async move {
let (user_id, signature, nonce, relayer) =
p.parse::<(String, String, String, String)>()?;
let user_id = crate::try_into_ss58(user_id)?;
let user_id = crate::try_into_account(user_id)?;
let signature = crate::hexstr_to_vec(&signature)?;
let nonce = crate::hexstr_to_vec(&nonce)?;
ctx.verify_trading_signature(&[], &user_id, &signature, &nonce)
Expand All @@ -187,7 +184,7 @@ pub fn export_rpc(context: Context) -> RpcModule<Context> {
.get(&format!("broker:{}", relayer))
.map(|b| b.value().clone())
.ok_or_else(|| anyhow::anyhow!("Broker not initialized."))?;
ctx.subscribers.insert(user_id, tx);
ctx.subscribers.insert(user_id.to_ss58check(), tx);
Ok(())
})
.unwrap();
Expand Down

0 comments on commit e3aaeda

Please sign in to comment.