Skip to content

Commit

Permalink
Merge Develop (#11)
Browse files Browse the repository at this point in the history
* Add update deployment (#4)

* Fix address validation (#7)

* Added versioning endpoint (#8)

* Add deployment endpoint (#9)

* updated readme (#10)

* updated readme

* bumped version

---------

Co-authored-by: Gabriel <[email protected]>
  • Loading branch information
0xLucca and GabrielCamba authored Nov 9, 2023
1 parent bc79e83 commit 48a5703
Show file tree
Hide file tree
Showing 16 changed files with 1,704 additions and 145 deletions.
1,529 changes: 1,428 additions & 101 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "compiler-be"
version = "0.1.0"
version = "1.2.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand All @@ -13,6 +13,8 @@ sha2 = "0.10.6"
log = "0.4"
log4rs = "1"
serde_json = "1.0.96"
sp-core = "24.0.0"
hex = "0.4.3"

[dependencies.mongodb]
version = "2.2.0"
Expand Down
118 changes: 115 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,20 @@ The project consists of four main modules:

## API Reference

#### Get API Version

Returns the current version of the API

```http
GET /version
```

Response body example:

```json
"v1.0.0"
```

#### Send contract to be compiled
Accepts a JSON payload representing a smart contract in plain text, compiles it and returns the compiled contract.

Expand Down Expand Up @@ -153,7 +167,7 @@ Response body example:
```

#### Upload contract deployment information
Accepts a JSON payload representing a smart contract deployment and stores it in the database.
Accepts a JSON payload representing a smart contract deployment and stores it in the database. It will return a unique Id when success.

```http
POST /deployments
Expand Down Expand Up @@ -190,7 +204,104 @@ Response body example:

```json
{
"data": "ok",
"data": "652ee5587fbadc38e3b17bab",
"error": null
}
```

#### Modify contract deployment information
Accepts a JSON payload representing a smart contract deployment and stores it in the database.

```http
PATCH /deployments
```
"contract_address": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", "network": "some_network", "user_address": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", "contract_name":"name", "hidden": true

| Parameter | Type | Description |
| :-------- | :------- | :-------------------------------- |
| `contract_name` | `string` | **Optional**. The name of the smart contract. |
| `contract_address` | `string` | **Required**. The address of the deployed smart contract. |
| `network` | `string` | **Required**. The network where the smart contract was deployed. |
| `user_address` | `string` | **Required**. The wallet address of the smart contract deployer. |
| `hidden` | boolean | **Optional**. True to be hidden in the UI |

Request body example:

```json
{
"contract_name": "Test Token",
"contract_address": "5Dsykc2KUHcziwcTgZkHxyDDTotBJbGNh3BakfZ5PdDGMzfn",
"network": "Rococo",
"user_address": "ZA9WeQNb3QKmqvNi1szndDMchQ66npnDFXpjWuKayXQpriW",
"hidden": true
}

#### Get the deployment by Id
Returns the deployment by the Id provided when created.

``` http
GET /deployment?{id}
```

| Parameter | Type | Description |
| :-------- | :------- | :-------------------------------- |
| `id` | `string` | **Required**. The Id of the deployment. |

Request example:

```http
GET /deployments?id=652ee5587fbadc38e3b17bab
```

Response body example:

```json
{
"data": [
{
"id": "652ee5587fbadc38e3b17bab",
"contract_name": "Test Token",
"contract_address": "5Dsykc2KUHcziwcTgZkHxyDDTotBJbGNh3BakfZ5PdDGMzfn",
"network": "Rococo",
"code_id": "5a4ce58af5294a73b22b5c6bf1b1a8886972598925ddee77c3a591ced4bae78b",
"user_address": "ZA9WeQNb3QKmqvNi1szndDMchQ66npnDFXpjWuKayXQpriW"
}
],
"error": null
}
```

#### Get the deployment by Id
Returns the deployment by the Id provided when created.

``` http
GET /deployment?{id}
```

| Parameter | Type | Description |
| :-------- | :------- | :-------------------------------- |
| `id` | `string` | **Required**. The Id of the deployment. |

Request example:

```http
GET /deployments?id=652ee5587fbadc38e3b17bab
```

Response body example:

```json
{
"data": [
{
"id": "652ee5587fbadc38e3b17bab",
"contract_name": "Test Token",
"contract_address": "5Dsykc2KUHcziwcTgZkHxyDDTotBJbGNh3BakfZ5PdDGMzfn",
"network": "Rococo",
"code_id": "5a4ce58af5294a73b22b5c6bf1b1a8886972598925ddee77c3a591ced4bae78b",
"user_address": "ZA9WeQNb3QKmqvNi1szndDMchQ66npnDFXpjWuKayXQpriW"
}
],
"error": null
}
```
Expand Down Expand Up @@ -221,6 +332,7 @@ Response body example:
{
"data": [
{
"id": "652ee5587fbadc38e3b17bab",
"contract_name": "Test Token",
"contract_address": "5Dsykc2KUHcziwcTgZkHxyDDTotBJbGNh3BakfZ5PdDGMzfn",
"network": "Rococo",
Expand Down Expand Up @@ -257,4 +369,4 @@ Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
limitations under the License.
51 changes: 43 additions & 8 deletions src/api/contract_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::sync::mpsc::channel;
use std::sync::Arc;

use crate::utils::compilation_queue::CompilationRequest;
use crate::utils::sanity_check::check_address_len;
use crate::utils::sanity_check::check_address;
use crate::{
models::{
api_models::{
Expand Down Expand Up @@ -121,8 +121,8 @@ pub fn store_deployment(
deploy_message: Json<DeployMessage>,
) -> Result<Json<ServerResponse<String>>, Custom<Json<ServerResponse<String>>>> {
// Check the address is valid
if check_address_len(&deploy_message.user_address).is_err()
|| check_address_len(&deploy_message.contract_address).is_err()
if check_address(&deploy_message.user_address).is_err()
|| check_address(&deploy_message.contract_address).is_err()
{
return Err(Custom(
Status::InternalServerError,
Expand All @@ -140,9 +140,10 @@ pub fn store_deployment(

// Evaluate the result of the save operation
match deployment_save_result {
Ok(_) => {
Ok(result) => {
let id: String = result.inserted_id.as_object_id().unwrap().to_hex();
info!(target: "compiler", "Deployment {} saved in the database", &deployment.contract_address);
Ok(Json(ServerResponse::new_valid(String::from("ok"))))
Ok(Json(ServerResponse::new_valid(id)))
}

Err(_) => {
Expand All @@ -163,8 +164,8 @@ pub fn update_deployment(
update_deploy_message: Json<UpdateDeployMessage>,
) -> Result<Json<ServerResponse<String>>, Custom<Json<ServerResponse<String>>>> {
// Check the address is valid
if check_address_len(&update_deploy_message.user_address).is_err()
|| check_address_len(&update_deploy_message.contract_address).is_err()
if check_address(&update_deploy_message.user_address).is_err()
|| check_address(&update_deploy_message.contract_address).is_err()
{
return Err(Custom(
Status::InternalServerError,
Expand Down Expand Up @@ -220,7 +221,7 @@ pub fn get_contract_deployments(
Ok(Json(ServerResponse::new_valid(deployments_unwrapped)))
}
Err(_) => {
error!(target: "compiler", "There was an error fetching the deployment for user {}", &user_address);
error!(target: "compiler", "There was an error fetching the deployments for user {}", &user_address);
Err(Custom(
Status::InternalServerError,
Json(ServerResponse::new_error(String::from(
Expand All @@ -231,6 +232,32 @@ pub fn get_contract_deployments(
}
}

// /deployments endpoint for fetching a deployment by its id
#[get("/deployment?<id>")]
pub fn get_contract_deployment_by_id(
db: &State<MongoRepo>,
id: String,
) -> Result<Json<ServerResponse<Deployment>>, Custom<Json<ServerResponse<Deployment>>>> {
let deployment = db.get_deployment_by_id(&id);

match deployment {
Ok(Some(deployment)) => {
info!(target: "compiler", "Deployment fetched from the database by ID {}.", &id);
Ok(Json(ServerResponse::new_valid(deployment)))
}
_ => {
error!(target: "compiler", "No deployment found in the database for ID {}.", &id);
Err(Custom(
Status::NotFound,
Json(ServerResponse::new_error(format!(
"No deployment found for ID {}",
&id
))),
))
}
}
}

// /contract-metadata endpoint for fetching a contract's metadata
#[get("/contract?<code_id>&<wasm>")]
pub fn get_contract(
Expand Down Expand Up @@ -280,6 +307,14 @@ pub fn get_contract(
}
}

// Endpoint for fetching api version
#[get("/version")]
pub fn get_version() -> Json<ServerResponse<String>> {
Json(ServerResponse::new_valid(String::from(env!(
"CARGO_PKG_VERSION"
))))
}

// This function creates the hash of the contract file
pub fn hash_code(code: &String) -> String {
let mut hasher = Sha256::new();
Expand Down
12 changes: 9 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use dotenv::dotenv;
extern crate rocket;

use api::contract_api::{
fetch_or_compile_contract, get_contract, get_contract_deployments, store_deployment,
update_deployment,
fetch_or_compile_contract, get_contract, get_contract_deployment_by_id,
get_contract_deployments, get_version, store_deployment, update_deployment,
};
use repository::mongodb_repo::MongoRepo;
use rocket::fairing::AdHoc;
Expand Down Expand Up @@ -72,7 +72,9 @@ fn rocket() -> _ {
store_deployment,
update_deployment,
get_contract_deployments,
get_contract
get_contract_deployment_by_id,
get_contract,
get_version
],
)
.attach(AdHoc::on_shutdown("Shutdown Handler", |_| {
Expand Down Expand Up @@ -105,3 +107,7 @@ mod main_post_deployments_test;
#[cfg(test)]
#[path = "./tests/main_get_deployments_tests.rs"]
mod main_get_deployments_test;

#[cfg(test)]
#[path = "./tests/main_get_version_test.rs"]
mod main_get_version_test;
7 changes: 3 additions & 4 deletions src/models/db_models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ pub struct Contract {

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct Deployment {
//#[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
#[serde(skip_serializing)]
pub id: Option<ObjectId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub _id: Option<ObjectId>,
pub contract_name: Option<String>,
pub contract_address: String,
pub network: String,
Expand All @@ -33,7 +32,7 @@ pub struct Deployment {
impl Deployment {
pub fn new(deploy_message: &DeployMessage) -> Self {
Deployment {
id: None,
_id: None,
contract_name: deploy_message.contract_name.clone(),
contract_address: deploy_message.contract_address.clone(),
network: deploy_message.network.clone(),
Expand Down
12 changes: 12 additions & 0 deletions src/repository/mongodb_repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::env;

use crate::models::api_models::{GetDeploymentsMessage, UpdateDeployMessage};
use crate::models::db_models::{Contract, Deployment};
use crate::utils::common::string_to_object_id;

use mongodb::results::UpdateResult;
use mongodb::{
bson::doc,
Expand Down Expand Up @@ -129,4 +131,14 @@ impl MongoRepo {

Ok(deployments_vec)
}

pub fn get_deployment_by_id(
&self,
id: &String,
) -> Result<Option<Deployment>, Box<dyn std::error::Error>> {
let obj_id = string_to_object_id(id.to_string())?;
let filter = doc! {"_id": obj_id};
let deployment = self.deployments.find_one(filter, None)?;
Ok(deployment)
}
}
2 changes: 1 addition & 1 deletion src/tests/main_get_contract_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ mod get_contract_test {
let db = client.rocket().state::<MongoRepo>().unwrap();

let body = format!(
r#"{{ "address": "4GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", "code": "{}", "features": ["psp22"] }}"#,
r#"{{ "address": "XYtLu1tuJ8zBc3NZGSDnU5kSig7j6mHY1FBg8YXNkk4NMmM", "code": "{}", "features": ["psp22"] }}"#,
VALID_INK_SC
);
client.post(uri!("/contract")).body(body).dispatch();
Expand Down
Loading

0 comments on commit 48a5703

Please sign in to comment.