Skip to content

Commit

Permalink
feat: add delegate call voucher to rollup-http
Browse files Browse the repository at this point in the history
  • Loading branch information
mpolitzer committed Jan 8, 2025
1 parent e1ab682 commit e842961
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 6 deletions.
30 changes: 29 additions & 1 deletion rollup-http/rollup-http-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

use crate::rollup::{
AdvanceRequest, Exception, GIORequest, IndexResponse, InspectRequest, Notice, Report,
RollupRequest, RollupResponse, Voucher,
RollupRequest, RollupResponse, Voucher, DelegateCallVoucher,
};
use hyper::Response;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -59,6 +59,34 @@ pub async fn send_voucher(rollup_http_server_addr: &str, voucher: Voucher) {
}
}

pub async fn send_delegate_call_voucher(rollup_http_server_addr: &str, delegate_call_voucher: DelegateCallVoucher) {
log::debug!("sending delegate call voucher request to {}", rollup_http_server_addr);
let client = hyper::Client::new();
let req = hyper::Request::builder()
.method(hyper::Method::POST)
.header(hyper::header::CONTENT_TYPE, "application/json")
.uri(rollup_http_server_addr.to_string() + "/delegate-call-voucher")
.body(hyper::Body::from(serde_json::to_string(&delegate_call_voucher).unwrap()))
.expect("delegate call voucher request");
match client.request(req).await {
Ok(res) => {
let id_response = serde_json::from_slice::<IndexResponse>(
&hyper::body::to_bytes(res)
.await
.expect("error in voucher in response handling")
.to_vec(),
);
log::debug!("voucher generated: {:?}", &id_response);
}
Err(e) => {
log::error!(
"failed to send delegate call voucher request to rollup http server: {}",
e
);
}
}
}

pub async fn send_notice(rollup_http_server_addr: &str, notice: Notice) {
log::debug!("sending notice request to {}", rollup_http_server_addr);
let client = hyper::Client::new();
Expand Down
6 changes: 6 additions & 0 deletions rollup-http/rollup-http-client/src/rollup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ pub struct Voucher {
pub payload: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DelegateCallVoucher {
pub destination: String,
pub payload: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Report {
pub payload: String,
Expand Down
57 changes: 54 additions & 3 deletions rollup-http/rollup-http-server/src/http_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

use std::sync::Arc;

use actix_web::{middleware::Logger, web::Data, App, HttpResponse, HttpServer, http::header::CONTENT_TYPE};
use actix_web::{
http::header::CONTENT_TYPE, middleware::Logger, web::Data, App, HttpResponse, HttpServer,
};
use actix_web_validator::{Json, JsonConfig};
use async_mutex::Mutex;
use serde::{Deserialize, Serialize};
Expand All @@ -26,8 +28,8 @@ use tokio::sync::Notify;
use crate::config::Config;
use crate::rollup::{self, GIORequest, RollupFd};
use crate::rollup::{
AdvanceRequest, Exception, FinishRequest, InspectRequest, Notice, Report, RollupRequest,
Voucher,
AdvanceRequest, DelegateCallVoucher, Exception, FinishRequest, InspectRequest, Notice, Report,
RollupRequest, Voucher,
};

#[derive(Debug, Serialize, Deserialize)]
Expand All @@ -54,6 +56,7 @@ pub fn create_server(
.app_data(json_cfg)
.wrap(Logger::default())
.service(voucher)
.service(delegate_call_voucher)
.service(notice)
.service(report)
.service(gio)
Expand Down Expand Up @@ -116,6 +119,54 @@ async fn voucher(mut voucher: Json<Voucher>, data: Data<Mutex<Context>>) -> Http
};
}

/// Process voucher request from DApp, write voucher to rollup device
#[actix_web::post("/delegate-call-voucher")]
async fn delegate_call_voucher(
mut delegate_call_voucher: Json<DelegateCallVoucher>,
data: Data<Mutex<Context>>,
) -> HttpResponse {
log::debug!("received voucher request");
// Check if address is valid
if delegate_call_voucher.destination.len()
!= (rollup::CARTESI_ROLLUP_ADDRESS_SIZE * 2 + 2) as usize
|| (!delegate_call_voucher.destination.starts_with("0x"))
{
log::error!(
"address not valid: '{}' len: {}",
delegate_call_voucher.destination,
delegate_call_voucher.destination.len()
);
return HttpResponse::BadRequest()
.append_header((CONTENT_TYPE, "text/plain"))
.body("address not valid");
}
let context = data.lock().await;
// Write voucher to linux rollup device
return match rollup::rollup_write_delegate_call_voucher(
&*context.rollup_fd.lock().await,
&mut delegate_call_voucher.0,
) {
Ok(voucher_index) => {
log::debug!(
"delegate call voucher successfully inserted {:#?}",
delegate_call_voucher
);
HttpResponse::Created().json(IndexResponse {
index: voucher_index,
})
}
Err(e) => {
log::error!(
"unable to insert voucher, error details: '{}'",
e.to_string()
);
HttpResponse::BadRequest()
.append_header((CONTENT_TYPE, "text/plain"))
.body(format!("unable to insert voucher, error details: '{}'", e))
}
};
}

/// Process notice request from DApp, write notice to rollup device
#[actix_web::post("/notice")]
async fn notice(mut notice: Json<Notice>, data: Data<Mutex<Context>>) -> HttpResponse {
Expand Down
64 changes: 63 additions & 1 deletion rollup-http/rollup-http-server/src/rollup/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,13 @@ pub struct Voucher {
pub payload: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct DelegateCallVoucher {
#[validate(regex(path = "*ETH_ADDR_REGEXP"))]
pub destination: String,
pub payload: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct Report {
pub payload: String,
Expand Down Expand Up @@ -455,7 +462,7 @@ pub fn rollup_write_voucher(

if res != 0 {
return Err(Box::new(RollupError::new(&format!(
"IOCTL_ROLLUP_WRITE_VOUCHER returned error {}",
"IOCTL_ROLLUP_WRITE_OUTPUT returned error {}",
res
))));
} else {
Expand All @@ -465,6 +472,46 @@ pub fn rollup_write_voucher(
Ok(voucher_index as u64)
}

pub fn rollup_write_delegate_call_voucher(
fd: &RollupFd,
delegate_call_voucher: &mut DelegateCallVoucher,
) -> Result<u64, Box<dyn std::error::Error>> {
print_delegate_call_voucher(delegate_call_voucher);

let mut binary_payload = match hex::decode(&delegate_call_voucher.payload[2..]) {
Ok(payload) => payload,
Err(_err) => {
return Err(Box::new(RollupError::new(&format!(
"Error decoding voucher payload, it must be in Ethereum hex binary format"
))));
}
};
let address = cmt_abi_address_t::from_hex(&delegate_call_voucher.destination[2..])?;
let payload = cmt_abi_bytes_t {
data: binary_payload.as_mut_ptr() as *mut c_void,
length: binary_payload.len(),
};

let mut voucher_index: std::os::raw::c_ulong = 0;
let res = unsafe {
cmt_rollup_emit_delegate_call_voucher(fd.0, &address, &payload, &mut voucher_index)
};

if res != 0 {
return Err(Box::new(RollupError::new(&format!(
"IOCTL_ROLLUP_WRITE_OUTPUT returned error {}",
res
))));
} else {
log::debug!(
"delegate call voucher with id {} successfully written!",
voucher_index
);
}

Ok(voucher_index as u64)
}

pub fn rollup_write_report(
fd: &RollupFd,
report: &Report,
Expand Down Expand Up @@ -714,6 +761,21 @@ pub fn print_voucher(voucher: &Voucher) {
log::debug!("{}", &voucher_request_printout);
}

pub fn print_delegate_call_voucher(delegate_call_voucher: &DelegateCallVoucher) {
let mut voucher_request_printout = String::new();
voucher_request_printout.push_str("voucher: {{ destination: ");
format_address_printout(
&delegate_call_voucher.destination,
&mut voucher_request_printout,
);
voucher_request_printout.push_str(&format!(
" length: {} payload: {} }}",
delegate_call_voucher.payload.len(),
delegate_call_voucher.payload
));
log::debug!("{}", &voucher_request_printout);
}

pub fn print_report(report: &Report) {
log::debug!(
"report: {{ length: {} payload: {}}}",
Expand Down
66 changes: 65 additions & 1 deletion rollup-http/rollup-http-server/tests/rollup-http-server-tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ use actix_server::ServerHandle;
use async_mutex::Mutex;
use rand::Rng;
use rollup_http_client::rollup::{
Exception, GIORequest, Notice, Report, RollupRequest, RollupResponse, Voucher,
DelegateCallVoucher, Exception, GIORequest, Notice, Report, RollupRequest, RollupResponse,
Voucher,
};
use rollup_http_server::config::Config;
use rollup_http_server::rollup::RollupFd;
Expand Down Expand Up @@ -283,6 +284,69 @@ async fn test_write_voucher(
Ok(())
}

fn check_delegate_call_voucher_or_fail(
original_delegate_call_voucher: DelegateCallVoucher,
output_filename: &str,
) {
// we try to decode the produced voucher with a third-party lib to see if it matches
// the expected values
let data = std::fs::read(output_filename).expect("error reading voucher file");
let decoded_voucher = ethabi::decode(
&[ethabi::ParamType::Address, ethabi::ParamType::Bytes],
&data[4..], // skip the first 4 bytes that are the function signature
)
.ok()
.unwrap();

assert_eq!(
"0x".to_string() + &decoded_voucher[0].to_string(),
original_delegate_call_voucher.destination,
);
assert_eq!(
"0x".to_string() + &decoded_voucher[1].to_string(),
original_delegate_call_voucher.payload,
);
}

#[rstest]
#[tokio::test]
async fn test_write_delegate_call_voucher(
context_future: impl Future<Output = Context>,
) -> Result<(), Box<dyn std::error::Error>> {
let context = context_future.await;
println!("Writing delegate call voucher");
let test_delegate_call_voucher_01 = DelegateCallVoucher {
destination: "0x1111111111111111111111111111111111111111".to_string(),
payload: "0x".to_string() + &hex::encode("delegate call voucher test payload 01"),
};
let test_delegate_call_voucher_02 = DelegateCallVoucher {
destination: "0x2222222222222222222222222222222222222222".to_string(),
payload: "0x".to_string() + &hex::encode("delegate call voucher test payload 02"),
};
rollup_http_client::client::send_delegate_call_voucher(
&context.address,
test_delegate_call_voucher_01.clone(),
)
.await;

check_delegate_call_voucher_or_fail(test_delegate_call_voucher_01, "none.output-0.bin");
std::fs::remove_file("none.output-0.bin")?;

println!("Writing second voucher!");

rollup_http_client::client::send_delegate_call_voucher(
&context.address,
test_delegate_call_voucher_02.clone(),
)
.await;
context.server_handle.stop(true).await;

check_delegate_call_voucher_or_fail(test_delegate_call_voucher_02, "none.output-1.bin");
std::fs::remove_file("none.output-1.bin")?;

Ok(())
}

#[rstest]
#[tokio::test]
async fn test_write_notice(
Expand Down

0 comments on commit e842961

Please sign in to comment.