Skip to content
This repository has been archived by the owner on Aug 1, 2022. It is now read-only.

Commit

Permalink
feat: implement one-way attestation (#105)
Browse files Browse the repository at this point in the history
* expand register_project with one-way attestation
  • Loading branch information
garbados authored and rudolfs committed Mar 4, 2020
1 parent 247114e commit d596216
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 22 deletions.
11 changes: 11 additions & 0 deletions proxy/Cargo.lock

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

1 change: 1 addition & 0 deletions proxy/Cargo.toml
Expand Up @@ -22,6 +22,7 @@ pico-args = "0.3"
pretty_env_logger = "0.3"
rand = "0.7"
serde = "1.0"
serde_cbor = "0.11.1"
serde_derive = "1.0"
serde_json = "1.0"
tempfile = "3.1"
Expand Down
6 changes: 3 additions & 3 deletions proxy/src/schema/git.rs
Expand Up @@ -162,7 +162,7 @@ pub fn local_branches(repo_path: &str) -> Result<Vec<Branch>, Error> {
Ok(branches)
}

/// Initialize a [`librad::Project`] in the location of the given `path`.
/// Initialize a [`librad::meta::Project`] in the location of the given `path`.
pub fn init_project(
librad_paths: &Paths,
path: &str,
Expand All @@ -187,7 +187,7 @@ pub fn init_project(
Ok((id, meta))
}

/// Initialize a [`git2::GitRepository`] at the given path.
/// Initialize a [`git2::Repository`] at the given path.
pub fn init_repo(path: String) -> Result<(), Error> {
let repo = git2::Repository::init(path)?;

Expand All @@ -209,7 +209,7 @@ pub fn init_repo(path: String) -> Result<(), Error> {
Ok(())
}

/// Creates a small set of projects in [`librad::Paths`].
/// Creates a small set of projects in [`librad::paths::Paths`].
pub fn setup_fixtures(librad_paths: &Paths, root: &str) -> Result<(), Error> {
let infos = vec![
(
Expand Down
11 changes: 10 additions & 1 deletion proxy/src/schema/mod.rs
Expand Up @@ -87,12 +87,21 @@ impl Mutation {
ctx: &Context,
domain: String,
name: String,
maybe_librad_id_input: Option<ID>,
) -> Result<registry::Transaction, Error> {
let maybe_librad_id = maybe_librad_id_input
.map(|id| ProjectId::from_str(&id.to_string()).expect("unable to parse project id"));

// TODO(xla): Get keypair from persistent storage.
let fake_pair = ed25519::Pair::from_legacy_string("//Robot", None);
// TODO(xla): Remove single-threaded executor once async/await lands in juniper:
// https://github.com/graphql-rust/juniper/pull/497
futures::executor::block_on(ctx.registry.register_project(&fake_pair, domain, name))
futures::executor::block_on(ctx.registry.register_project(
&fake_pair,
domain,
name,
maybe_librad_id,
))
}
}

Expand Down
80 changes: 62 additions & 18 deletions proxy/src/schema/registry.rs
Expand Up @@ -2,6 +2,8 @@ use radicle_registry_client::{
self as registry, ed25519, message, Client, ClientT, CryptoPair, String32, TransactionExtra,
H256,
};
use serde_cbor::to_vec;
use serde_derive::{Deserialize, Serialize};
use std::convert::TryFrom;

use crate::schema::error::{Error, ProjectValidation};
Expand All @@ -23,7 +25,7 @@ pub struct Transaction {
}

/// Required information to issue a new project registration on the [`Registry`].
#[derive(juniper::GraphQLObject)]
#[derive(GraphQLObject)]
pub struct ProjectRegistration {
// TODO(xla): Use String32 type.
/// The domain the project should be registered for.
Expand All @@ -33,6 +35,15 @@ pub struct ProjectRegistration {
pub name: String,
}

/// `ProjectID` wrapper for serde de/serialization
#[derive(Serialize, Deserialize)]
pub struct Metadata {
/// Librad project ID.
pub id: String,
/// Metadata version.
pub version: u8,
}

/// Possible messages a [`Transaction`] can carry.
pub enum Message {
/// Issue a new project registration. See [`ProjectRegistration`] for the shape of the data.
Expand Down Expand Up @@ -91,6 +102,7 @@ impl Registry {
author: &ed25519::Pair,
domain: String,
name: String,
maybe_pid: Option<librad::project::ProjectId>,
) -> Result<Transaction, Error> {
// Verify that inputs are valid.
let project_name =
Expand Down Expand Up @@ -118,11 +130,26 @@ impl Registry {
.await?
.result?;

let register_metadata_vec = if let Some(pid_string) = maybe_pid {
let pid_cbor = Metadata {
id: pid_string.to_string(),
version: 1,
};
// TODO(garbados): unpanic
to_vec(&pid_cbor).expect("unable to serialize project metadata")
} else {
vec![]
};

// TODO: remove .expect() call, see: https://github.com/radicle-dev/radicle-registry/issues/185
let register_metadata =
registry::Bytes128::from_vec(register_metadata_vec).expect("unable construct metadata");

// Prepare and submit project registration transaction.
let register_message = message::RegisterProject {
id: (project_name, project_domain),
checkpoint_id,
metadata: registry::Bytes128::from_vec(vec![]).expect("unable construct metadata"),
metadata: register_metadata,
};
let register_tx = registry::Transaction::new_signed(
author,
Expand All @@ -138,8 +165,8 @@ impl Registry {
Ok(Transaction {
id: juniper::ID::new(register_applied.tx_hash.to_string()),
messages: vec![Message::ProjectRegistration(ProjectRegistration {
domain: domain,
name: name,
domain,
name,
})],
state: TransactionState::Applied(Applied {
block: juniper::ID::new(register_applied.block.to_string()),
Expand All @@ -158,18 +185,35 @@ impl Registry {
}
}

#[test]
fn test_register_project() {
use radicle_registry_client::Client;

// Test that project registration submits valid transactions and they succeed.
let client = Client::new_emulator();
let registry = Registry::new(client);
let alice = ed25519::Pair::from_legacy_string("//Alice", None);
let result = futures::executor::block_on(registry.register_project(
&alice,
"hello".into(),
"world".into(),
));
assert!(result.is_ok());
#[cfg(test)]
mod tests {
use crate::schema::registry::{Metadata, Registry};
use radicle_registry_client::ed25519;
use radicle_registry_client::{Client, ClientT, String32};
use serde_cbor::from_reader;

#[test]
fn test_register_project() {
// Test that project registration submits valid transactions and they succeed.
let client = Client::new_emulator();
let registry = Registry::new(client.clone());
let alice = ed25519::Pair::from_legacy_string("//Alice", None);
let result = futures::executor::block_on(registry.register_project(
&alice,
"hello".into(),
"world".into(),
Some(librad::git::ProjectId::new(radicle_surf::git::git2::Oid::zero()).into()),
));
assert!(result.is_ok());
let project_domain = String32::from_string("hello".into()).unwrap();
let project_name = String32::from_string("world".into()).unwrap();
let pid = (project_name, project_domain);
let future_project = client.get_project(pid);
let maybe_project = futures::executor::block_on(future_project).unwrap();
assert_eq!(maybe_project.is_some(), true);
let project = maybe_project.unwrap();
let metadata_vec: Vec<u8> = project.metadata.into();
let metadata: Metadata = from_reader(&metadata_vec[..]).unwrap();
assert_eq!(metadata.version, 1);
}
}

0 comments on commit d596216

Please sign in to comment.