Skip to content

Commit

Permalink
create endpoints to retrieve and sign bill
Browse files Browse the repository at this point in the history
  • Loading branch information
Ayush-Yadav committed Feb 13, 2024
1 parent 8b3a00d commit b9da522
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 52 deletions.
71 changes: 51 additions & 20 deletions src/billing_handler.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,66 @@
use crate::model::AppState;

use actix_web::web::Data;
use actix_web::HttpResponse;
use actix_web::web::{Data, Json};
use actix_web::{get, post, HttpResponse, Responder};
use anyhow::Context;
use k256::elliptic_curve::generic_array::sequence::Lengthen;
use serde_json::json;
use tiny_keccak::{Hasher, Keccak};

pub async fn billing_data(appstate: Data<AppState>) -> HttpResponse {
let mut execution_costs_gaurd = appstate.execution_costs.lock().unwrap();
#[derive(Debug, serde::Deserialize)]
pub struct SigningData {
nonce: String,
txhashes: Vec<String>,
}

#[get("/bill")]
pub async fn get_bill(appstate: Data<AppState>) -> impl Responder {
let execution_costs_guard = appstate.execution_costs.lock().unwrap();
if execution_costs_guard.is_empty() {
return HttpResponse::NoContent().body("No bill data available");
}

let bill = execution_costs_guard.clone();
HttpResponse::Ok().json(json!({
"bill": bill,
}))
}

#[post("/sign")]
pub async fn sign_data(appstate: Data<AppState>, data: Json<SigningData>) -> impl Responder {
let signing_data = data.into_inner();
if signing_data.nonce.is_empty() {
return HttpResponse::BadRequest().body("Nonce must not be empty");
}

if execution_costs_gaurd.is_empty() {
return HttpResponse::BadRequest().body("No billing data available");
if signing_data.txhashes.is_empty() {
return HttpResponse::BadRequest().body("List of tx hashes must not be empty");
}

let mut billing_data: Vec<u8> = Vec::new();
let mut signed_data: Vec<u8> = Vec::new();
let mut execution_costs_guard = appstate.execution_costs.lock().unwrap();

for (tx_hash, cost) in execution_costs_gaurd.iter() {
let mut bytes32_tx_hash = [0u8; 32];
if let Err(err) = hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash) {
return HttpResponse::InternalServerError()
.body(format!("Error decoding transaction hash: {:?}", err));
for txhash in signing_data.txhashes {
if let Some(cost) = execution_costs_guard.remove(&txhash) {
let mut bytes32_txhash = [0u8; 32];
if let Err(err) = hex::decode_to_slice(&txhash[2..], &mut bytes32_txhash) {
return HttpResponse::InternalServerError()
.body(format!("Error decoding transaction hash: {:?}", err));
}

signed_data.append(&mut bytes32_txhash.to_vec());
signed_data.append(&mut cost.to_be_bytes().to_vec());
} else {
return HttpResponse::BadRequest().body(format!(
"{} tx hash doesn't exist in the current bill",
txhash
));
}

billing_data.append(&mut bytes32_tx_hash.to_vec());
billing_data.append(&mut cost.to_be_bytes().to_vec());
}
signed_data.append(&mut signing_data.nonce.as_bytes().to_vec());

let mut hasher = Keccak::v256();
hasher.update(&billing_data);
hasher.update(&signed_data);

let mut hash = [0u8; 32];
hasher.finalize(&mut hash);
Expand All @@ -41,13 +73,12 @@ pub async fn billing_data(appstate: Data<AppState>) -> HttpResponse {
return HttpResponse::InternalServerError().body(format!("{}", sign.unwrap_err()));
}
let (rs, v) = sign.unwrap();
let signature = hex::encode(rs.to_bytes().append(27 + v.to_byte()).as_slice());

let billing_data = hex::encode(billing_data.as_slice());
execution_costs_gaurd.clear();
let signature = hex::encode(rs.to_bytes().append(27 + v.to_byte()).as_slice());
let signed_data = hex::encode(signed_data.as_slice());

HttpResponse::Ok().json(json!({
"billing_data": billing_data,
"signed_data": signed_data,
"signature": signature,
}))
}
23 changes: 0 additions & 23 deletions src/contracts/billing_contract_abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,5 @@
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32[]",
"name": "_txhashes",
"type": "bytes32[]"
},
{
"internalType": "uint256[]",
"name": "_amounts",
"type": "uint256[]"
},
{
"internalType": "bytes",
"name": "signature",
"type": "bytes"
}
],
"name": "settle",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ mod tests;
pub mod workerd;

use ethers::contract::abigen;
use ethers::providers::{Http, Provider};

abigen!(
BillingContract,
"src/contracts/billing_contract_abi.json",
derives(serde::Serialize, serde::Deserialize)
);

type BillContract = BillingContract<Provider<Http>>;
6 changes: 4 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use serverless::cgroups::Cgroups;
use serverless::model::AppState;
use serverless::BillingContract;

use actix_web::{web, App, HttpServer};
use actix_web::{web, App, HttpResponse, HttpServer};
use anyhow::{anyhow, Context};
use clap::Parser;
use ethers::providers::{Http, Provider};
Expand Down Expand Up @@ -116,7 +116,9 @@ async fn main() -> anyhow::Result<()> {
let billing_server = HttpServer::new(move || {
App::new()
.app_data(app_data_clone.clone())
.default_service(web::to(serverless::billing_handler::billing_data))
.service(serverless::billing_handler::get_bill)
.service(serverless::billing_handler::sign_data)
.default_service(web::to(HttpResponse::NotFound))
})
.bind(("0.0.0.0", billing_port))
.context(format!("could not bind to port {billing_port}"))?
Expand Down
6 changes: 2 additions & 4 deletions src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ use std::sync::atomic::AtomicBool;
use std::sync::Mutex;

use crate::cgroups::Cgroups;
use crate::BillingContract;

use ethers::providers::{Http, Provider};
use crate::BillContract;

pub struct AppState {
pub cgroups: Mutex<Cgroups>,
Expand All @@ -17,6 +15,6 @@ pub struct AppState {
pub rpc: String,
pub contract: String,
pub signer: k256::ecdsa::SigningKey,
pub billing_contract: BillingContract<Provider<Http>>,
pub billing_contract: BillContract,
pub execution_costs: Mutex<HashMap<String, u128>>,
}
6 changes: 3 additions & 3 deletions src/workerd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::process::Child;
use std::time::{Duration, Instant};

use crate::cgroups::{Cgroups, CgroupsError};
use crate::BillingContract;
use crate::BillContract;

use actix_web::{HttpRequest, HttpResponse};
use anyhow::Error;
Expand Down Expand Up @@ -53,7 +53,7 @@ pub enum ServerlessError {

async fn get_current_deposit(
tx_hash: &str,
billing_contract: &BillingContract<Provider<Http>>,
billing_contract: &BillContract,
) -> Result<U256, Error> {
let mut bytes32_tx_hash = [0u8; 32];
hex::decode_to_slice(&tx_hash[2..], &mut bytes32_tx_hash)?;
Expand Down Expand Up @@ -88,7 +88,7 @@ pub async fn create_code_file(
workerd_runtime_path: &str,
rpc: &str,
contract: &str,
billing_contract: &BillingContract<Provider<Http>>,
billing_contract: &BillContract,
) -> Result<(), ServerlessError> {
// get tx data
let mut tx_data = match get_transaction_data(tx_hash, rpc).await?["result"].take() {
Expand Down

0 comments on commit b9da522

Please sign in to comment.