Skip to content

Commit

Permalink
Merge pull request #1092 from rainlanguage/2024-12-18-dotrain-yaml-de…
Browse files Browse the repository at this point in the history
…ployment

Implementing deployments in Dotrain Yaml
  • Loading branch information
findolor authored Jan 3, 2025
2 parents c8eed77 + ff290ce commit 0645f38
Show file tree
Hide file tree
Showing 8 changed files with 260 additions and 7 deletions.
6 changes: 6 additions & 0 deletions crates/common/src/add_order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,8 @@ price: 2e18;
orderbook: None,
};
let deployment = Deployment {
document: Arc::new(RwLock::new(StrictYaml::String("".to_string()))),
key: "".to_string(),
scenario: Arc::new(scenario),
order: Arc::new(order),
};
Expand Down Expand Up @@ -614,6 +616,8 @@ _ _: 0 0;
orderbook: None,
};
let deployment = Deployment {
document: Arc::new(RwLock::new(StrictYaml::String("".to_string()))),
key: "".to_string(),
scenario: Arc::new(scenario),
order: Arc::new(order),
};
Expand Down Expand Up @@ -758,6 +762,8 @@ _ _: 0 0;
orderbook: None,
};
let deployment = Deployment {
document: Arc::new(RwLock::new(StrictYaml::String("".to_string()))),
key: "".to_string(),
scenario: Arc::new(scenario),
order: Arc::new(order),
};
Expand Down
187 changes: 184 additions & 3 deletions crates/settings/src/deployment.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
use crate::*;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, sync::Arc};
use std::{
collections::HashMap,
sync::{Arc, RwLock},
};
use strict_yaml_rust::StrictYaml;
use thiserror::Error;
use typeshare::typeshare;
use yaml::{default_document, require_hash, require_string, YamlError, YamlParsableHash};

#[cfg(target_family = "wasm")]
use rain_orderbook_bindings::{impl_all_wasm_traits, wasm_traits::prelude::*};

#[typeshare]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "kebab-case")]
#[cfg_attr(target_family = "wasm", derive(Tsify))]
pub struct Deployment {
#[serde(skip, default = "default_document")]
pub document: Arc<RwLock<StrictYaml>>,
pub key: String,
#[typeshare(typescript(type = "Scenario"))]
pub scenario: Arc<Scenario>,
#[typeshare(typescript(type = "Order"))]
Expand All @@ -20,6 +28,82 @@ pub struct Deployment {
#[cfg(target_family = "wasm")]
impl_all_wasm_traits!(Deployment);

impl YamlParsableHash for Deployment {
fn parse_all_from_yaml(
document: Arc<RwLock<StrictYaml>>,
) -> Result<HashMap<String, Self>, YamlError> {
let document_read = document.read().map_err(|_| YamlError::ReadLockError)?;
let deployments_hash = require_hash(
&document_read,
Some("deployments"),
Some("missing field: deployments".to_string()),
)?;

deployments_hash
.iter()
.map(|(key_yaml, deployment_yaml)| {
let deployment_key = key_yaml.as_str().unwrap_or_default().to_string();

let scenario = Scenario::parse_from_yaml(
document.clone(),
&require_string(
deployment_yaml,
Some("scenario"),
Some(format!(
"scenario string missing in deployment: {deployment_key}"
)),
)?,
)?;
let order = Order::parse_from_yaml(
document.clone(),
&require_string(
deployment_yaml,
Some("order"),
Some(format!(
"order string missing in deployment: {deployment_key}"
)),
)?,
)?;

if let Some(deployer) = &order.deployer {
if deployer != &scenario.deployer {
return Err(YamlError::ParseDeploymentConfigSourceError(
ParseDeploymentConfigSourceError::NoMatch,
));
}
}

Ok((
deployment_key.clone(),
Deployment {
document: document.clone(),
key: deployment_key,
scenario: Arc::new(scenario),
order: Arc::new(order),
},
))
})
.collect()
}
}

impl Default for Deployment {
fn default() -> Self {
Self {
document: Arc::new(RwLock::new(StrictYaml::String("".to_string()))),
key: String::new(),
scenario: Arc::new(Scenario::default()),
order: Arc::new(Order::default()),
}
}
}

impl PartialEq for Deployment {
fn eq(&self, other: &Self) -> bool {
self.key == other.key && self.scenario == other.scenario && self.order == other.order
}
}

#[derive(Error, Debug, PartialEq)]
pub enum ParseDeploymentConfigSourceError {
#[error("Scenario not found: {0}")]
Expand Down Expand Up @@ -57,7 +141,12 @@ impl DeploymentConfigSource {
}
};

Ok(Deployment { scenario, order })
Ok(Deployment {
document: Arc::new(RwLock::new(StrictYaml::String("".to_string()))),
key: scenario.key.clone(),
scenario,
order,
})
}
}

Expand All @@ -67,6 +156,7 @@ mod tests {
use crate::test::*;
use std::sync::RwLock;
use strict_yaml_rust::StrictYaml;
use yaml::tests::get_document;

#[test]
fn test_try_into_deployment_success() {
Expand Down Expand Up @@ -133,4 +223,95 @@ mod tests {
Err(ParseDeploymentConfigSourceError::ScenarioNotFoundError(_))
));
}

#[test]
fn test_parse_deployments_from_yaml() {
let yaml = r#"
test: test
"#;
let error = Deployment::parse_all_from_yaml(get_document(yaml)).unwrap_err();
assert_eq!(
error,
YamlError::ParseError("missing field: deployments".to_string())
);

let yaml = r#"
deployments:
deployment1:
test: test
"#;
let error = Deployment::parse_all_from_yaml(get_document(yaml)).unwrap_err();
assert_eq!(
error,
YamlError::ParseError("scenario string missing in deployment: deployment1".to_string())
);

let yaml = r#"
networks:
network1:
rpc: https://eth.llamarpc.com
chain-id: 1
deployers:
deployer1:
address: 0x0000000000000000000000000000000000000000
network: network1
scenarios:
scenario1:
bindings:
test: test
deployer: deployer1
deployments:
deployment1:
scenario: scenario1
test: test
"#;
let error = Deployment::parse_all_from_yaml(get_document(yaml)).unwrap_err();
assert_eq!(
error,
YamlError::ParseError("order string missing in deployment: deployment1".to_string())
);

let yaml = r#"
networks:
network1:
rpc: https://eth.llamarpc.com
chain-id: 1
network2:
rpc: https://test.com
chain-id: 2
deployers:
deployer1:
address: 0x0000000000000000000000000000000000000000
network: network1
deployer2:
address: 0x0000000000000000000000000000000000000000
network: network2
scenarios:
scenario1:
bindings:
test: test
deployer: deployer1
tokens:
token1:
address: 0x0000000000000000000000000000000000000000
network: network2
orders:
order1:
inputs:
- token: token1
outputs:
- token: token1
deployer: deployer2
deployments:
deployment1:
scenario: scenario1
order: order1
"#;
let error = Deployment::parse_all_from_yaml(get_document(yaml)).unwrap_err();
assert_eq!(
error.to_string(),
YamlError::ParseDeploymentConfigSourceError(ParseDeploymentConfigSourceError::NoMatch)
.to_string()
);
}
}
2 changes: 2 additions & 0 deletions crates/settings/src/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ mod tests {
orderbook: None,
};
let deployment = Deployment {
document: Arc::new(RwLock::new(StrictYaml::String("".to_string()))),
key: "test-deployment".to_string(),
scenario: Arc::new(scenario),
order: Arc::new(order),
};
Expand Down
35 changes: 35 additions & 0 deletions crates/settings/src/scenario.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,5 +571,40 @@ scenarios:
)
.to_string()
);

let yaml = r#"
networks:
mainnet:
rpc: https://rpc.com
chain-id: 1
testnet:
rpc: https://rpc.com
chain-id: 2
deployers:
mainnet:
address: 0x1234567890123456789012345678901234567890
network: mainnet
testnet:
address: 0x1234567890123456789012345678901234567890
network: testnet
scenarios:
scenario1:
deployer: mainnet
bindings:
key1: some-value
scenarios:
scenario2:
bindings:
key2: value
deployer: testnet
"#;
let error = Scenario::parse_all_from_yaml(get_document(yaml)).unwrap_err();
assert_eq!(
error.to_string(),
YamlError::ParseScenarioConfigSourceError(
ParseScenarioConfigSourceError::ParentDeployerShadowedError("testnet".to_string())
)
.to_string()
);
}
}
26 changes: 25 additions & 1 deletion crates/settings/src/yaml/dotrain.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::*;
use crate::{Order, Scenario};
use crate::{Deployment, Order, Scenario};
use std::sync::{Arc, RwLock};

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -40,6 +40,14 @@ impl DotrainYaml {
pub fn get_scenario(&self, key: &str) -> Result<Scenario, YamlError> {
Scenario::parse_from_yaml(self.document.clone(), key)
}

pub fn get_deployment_keys(&self) -> Result<Vec<String>, YamlError> {
let deployments = Deployment::parse_all_from_yaml(self.document.clone())?;
Ok(deployments.keys().cloned().collect())
}
pub fn get_deployment(&self, key: &str) -> Result<Deployment, YamlError> {
Deployment::parse_from_yaml(self.document.clone(), key)
}
}

#[cfg(test)]
Expand Down Expand Up @@ -94,6 +102,10 @@ mod tests {
scenario2:
bindings:
key2: value2
deployments:
deployment1:
order: order1
scenario: scenario1
"#;

#[test]
Expand Down Expand Up @@ -135,5 +147,17 @@ mod tests {
*scenario2.deployer.as_ref(),
ob_yaml.get_deployer("deployer1").unwrap()
);

let deployment_keys = dotrain_yaml.get_deployment_keys().unwrap();
assert_eq!(deployment_keys.len(), 1);
let deployment = dotrain_yaml.get_deployment("deployment1").unwrap();
assert_eq!(
deployment.order,
dotrain_yaml.get_order("order1").unwrap().into()
);
assert_eq!(
deployment.scenario,
dotrain_yaml.get_scenario("scenario1").unwrap().into()
);
}
}
7 changes: 5 additions & 2 deletions crates/settings/src/yaml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ pub mod dotrain;
pub mod orderbook;

use crate::{
ParseDeployerConfigSourceError, ParseNetworkConfigSourceError, ParseOrderConfigSourceError,
ParseOrderbookConfigSourceError, ParseScenarioConfigSourceError, ParseTokenConfigSourceError,
ParseDeployerConfigSourceError, ParseDeploymentConfigSourceError,
ParseNetworkConfigSourceError, ParseOrderConfigSourceError, ParseOrderbookConfigSourceError,
ParseScenarioConfigSourceError, ParseTokenConfigSourceError,
};
use alloy::primitives::ruint::ParseError as RuintParseError;
use std::collections::HashMap;
Expand Down Expand Up @@ -96,6 +97,8 @@ pub enum YamlError {
ParseOrderConfigSourceError(#[from] ParseOrderConfigSourceError),
#[error(transparent)]
ParseScenarioConfigSourceError(#[from] ParseScenarioConfigSourceError),
#[error(transparent)]
ParseDeploymentConfigSourceError(#[from] ParseDeploymentConfigSourceError),
}
impl PartialEq for YamlError {
fn eq(&self, other: &Self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion packages/orderbook/test/js_api/gui.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ describe('Rain Orderbook JS API Package Bindgen Tests - Gui', async function ()

describe('state management tests', async () => {
let serializedState =
'H4sIAAAAAAAA_3WPTQoCMQyFZ1REb-FaUJq26TQ7j-AV0k4qg1BBZ-HxFUxdCL7Nlz_eI6fuI7DekQOkDHnIgdlxZBY_SikpcLFiLQsigCOIPpkEBYjIx1FCxLxQn60yTXWc6uUAvQ5Mv9HqfJeHzDvYt80TrPMYhkiGU34n_ut_zW3XtGxvGNMC18r5dpUK38uVEs0xvAARbQwj_QAAAA==';
'H4sIAAAAAAAA_3WNTQrCQAyFWxXRW7gWlKSdyWR2HsErzE8iRaigXXh8BVMXgm_zvfzw3qn5KBGjoqoP4rnkGFmFCrsoiQSiprdH5yoR51C7nhwrAlbKqQTJaWE5W2MexjqMlwO2toB2Y-58l4dMO9zPlyd2vfMUOELKpYr-m3_Du2bW0ogAc-HaON2uMuL3c2X0cKQXPMPJJ_0AAAA=';
let gui: DotrainOrderGui;
beforeAll(async () => {
mockServer
Expand Down
Loading

0 comments on commit 0645f38

Please sign in to comment.