mirror of
https://gitlab.com/veilid/veilid.git
synced 2025-03-12 00:46:29 -04:00
adding the ability to create dht records with a specified owner keypair
This commit is contained in:
parent
95d61855a8
commit
abfa5b12e8
@ -229,12 +229,26 @@ impl StorageManager {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a local record from scratch with a new owner key, open it, and return the opened descriptor
|
/// Builds the record key for a given schema and owner
|
||||||
#[instrument(level = "trace", target = "stor", skip_all)]
|
#[instrument(level = "trace", target = "stor", skip_all)]
|
||||||
|
pub async fn get_record_key(
|
||||||
|
&self,
|
||||||
|
kind: CryptoKind,
|
||||||
|
schema: DHTSchema,
|
||||||
|
owner_key: &PublicKey,
|
||||||
|
) -> VeilidAPIResult<TypedKey> {
|
||||||
|
let inner = self.lock().await?;
|
||||||
|
schema.validate()?;
|
||||||
|
|
||||||
|
inner.get_record_key(kind, owner_key, schema).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a local record from scratch with a new owner key, open it, and return the opened descriptor
|
||||||
pub async fn create_record(
|
pub async fn create_record(
|
||||||
&self,
|
&self,
|
||||||
kind: CryptoKind,
|
kind: CryptoKind,
|
||||||
schema: DHTSchema,
|
schema: DHTSchema,
|
||||||
|
owner: Option<KeyPair>,
|
||||||
safety_selection: SafetySelection,
|
safety_selection: SafetySelection,
|
||||||
) -> VeilidAPIResult<DHTRecordDescriptor> {
|
) -> VeilidAPIResult<DHTRecordDescriptor> {
|
||||||
let mut inner = self.lock().await?;
|
let mut inner = self.lock().await?;
|
||||||
@ -242,7 +256,7 @@ impl StorageManager {
|
|||||||
|
|
||||||
// Create a new owned local record from scratch
|
// Create a new owned local record from scratch
|
||||||
let (key, owner) = inner
|
let (key, owner) = inner
|
||||||
.create_new_owned_local_record(kind, schema, safety_selection)
|
.create_new_owned_local_record(kind, schema, owner, safety_selection)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// Now that the record is made we should always succeed to open the existing record
|
// Now that the record is made we should always succeed to open the existing record
|
||||||
|
@ -219,6 +219,7 @@ impl StorageManagerInner {
|
|||||||
&mut self,
|
&mut self,
|
||||||
kind: CryptoKind,
|
kind: CryptoKind,
|
||||||
schema: DHTSchema,
|
schema: DHTSchema,
|
||||||
|
owner: Option<KeyPair>,
|
||||||
safety_selection: SafetySelection,
|
safety_selection: SafetySelection,
|
||||||
) -> VeilidAPIResult<(TypedKey, KeyPair)> {
|
) -> VeilidAPIResult<(TypedKey, KeyPair)> {
|
||||||
// Get cryptosystem
|
// Get cryptosystem
|
||||||
@ -248,8 +249,11 @@ impl StorageManagerInner {
|
|||||||
// Compile the dht schema
|
// Compile the dht schema
|
||||||
let schema_data = schema.compile();
|
let schema_data = schema.compile();
|
||||||
|
|
||||||
// New values require a new owner key
|
// New values require a new owner key if not given
|
||||||
let owner = vcrypto.generate_keypair();
|
let owner = owner.unwrap_or_else(|| vcrypto.generate_keypair());
|
||||||
|
|
||||||
|
// Calculate dht key
|
||||||
|
let dht_key = Self::get_key(vcrypto.clone(), &owner.key, &schema_data);
|
||||||
|
|
||||||
// Make a signed value descriptor for this dht value
|
// Make a signed value descriptor for this dht value
|
||||||
let signed_value_descriptor = Arc::new(SignedValueDescriptor::make_signature(
|
let signed_value_descriptor = Arc::new(SignedValueDescriptor::make_signature(
|
||||||
@ -258,14 +262,12 @@ impl StorageManagerInner {
|
|||||||
vcrypto.clone(),
|
vcrypto.clone(),
|
||||||
owner.secret,
|
owner.secret,
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
// Add new local value record
|
// Add new local value record
|
||||||
let cur_ts = Timestamp::now();
|
let cur_ts = Timestamp::now();
|
||||||
let local_record_detail = LocalRecordDetail::new(safety_selection);
|
let local_record_detail = LocalRecordDetail::new(safety_selection);
|
||||||
let record =
|
let record =
|
||||||
Record::<LocalRecordDetail>::new(cur_ts, signed_value_descriptor, local_record_detail)?;
|
Record::<LocalRecordDetail>::new(cur_ts, signed_value_descriptor, local_record_detail)?;
|
||||||
|
|
||||||
let dht_key = Self::get_key(vcrypto.clone(), &record);
|
|
||||||
local_record_store.new_record(dht_key, record).await?;
|
local_record_store.new_record(dht_key, record).await?;
|
||||||
|
|
||||||
Ok((dht_key, owner))
|
Ok((dht_key, owner))
|
||||||
@ -702,18 +704,29 @@ impl StorageManagerInner {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ]
|
pub async fn get_record_key(
|
||||||
#[instrument(level = "trace", target = "stor", skip_all)]
|
&self,
|
||||||
fn get_key<D>(vcrypto: CryptoSystemVersion, record: &Record<D>) -> TypedKey
|
kind: CryptoKind,
|
||||||
where
|
owner_key: &PublicKey,
|
||||||
D: fmt::Debug + Clone + Serialize,
|
schema: DHTSchema,
|
||||||
{
|
) -> VeilidAPIResult<TypedKey> {
|
||||||
let descriptor = record.descriptor();
|
// Get cryptosystem
|
||||||
let compiled = descriptor.schema_data();
|
let Some(vcrypto) = self.unlocked_inner.crypto.get(kind) else {
|
||||||
let mut hash_data = Vec::<u8>::with_capacity(PUBLIC_KEY_LENGTH + 4 + compiled.len());
|
apibail_generic!("unsupported cryptosystem");
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self::get_key(vcrypto, owner_key, &schema.compile()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(
|
||||||
|
vcrypto: CryptoSystemVersion,
|
||||||
|
owner_key: &PublicKey,
|
||||||
|
schema_data: &[u8],
|
||||||
|
) -> TypedKey {
|
||||||
|
let mut hash_data = Vec::<u8>::with_capacity(PUBLIC_KEY_LENGTH + 4 + schema_data.len());
|
||||||
hash_data.extend_from_slice(&vcrypto.kind().0);
|
hash_data.extend_from_slice(&vcrypto.kind().0);
|
||||||
hash_data.extend_from_slice(&record.owner().bytes);
|
hash_data.extend_from_slice(&owner_key.bytes);
|
||||||
hash_data.extend_from_slice(compiled);
|
hash_data.extend_from_slice(schema_data);
|
||||||
let hash = vcrypto.generate_hash(&hash_data);
|
let hash = vcrypto.generate_hash(&hash_data);
|
||||||
TypedKey::new(vcrypto.kind(), hash)
|
TypedKey::new(vcrypto.kind(), hash)
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ pub async fn test_create_delete_dht_record_simple(api: VeilidAPI) {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let rec = rc
|
let rec = rc
|
||||||
.create_dht_record(DHTSchema::dflt(1).unwrap(), Some(CRYPTO_KIND_VLD0))
|
.create_dht_record(DHTSchema::dflt(1).unwrap(), None, Some(CRYPTO_KIND_VLD0))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -71,6 +71,63 @@ pub async fn test_create_delete_dht_record_simple(api: VeilidAPI) {
|
|||||||
rc.delete_dht_record(dht_key).await.unwrap();
|
rc.delete_dht_record(dht_key).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn test_create_dht_record_with_owner(api: VeilidAPI) {
|
||||||
|
let rc = api
|
||||||
|
.routing_context()
|
||||||
|
.unwrap()
|
||||||
|
.with_safety(SafetySelection::Unsafe(Sequencing::EnsureOrdered))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let cs = api.crypto().unwrap().get(CRYPTO_KIND_VLD0).unwrap();
|
||||||
|
let owner_keypair = cs.generate_keypair();
|
||||||
|
|
||||||
|
let rec = rc
|
||||||
|
.create_dht_record(
|
||||||
|
DHTSchema::dflt(1).unwrap(),
|
||||||
|
Some(owner_keypair),
|
||||||
|
Some(CRYPTO_KIND_VLD0),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(rec.owner(), &owner_keypair.key);
|
||||||
|
|
||||||
|
let dht_key = *rec.key();
|
||||||
|
rc.close_dht_record(dht_key).await.unwrap();
|
||||||
|
rc.delete_dht_record(dht_key).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn test_get_dht_record_key(api: VeilidAPI) {
|
||||||
|
let rc = api
|
||||||
|
.routing_context()
|
||||||
|
.unwrap()
|
||||||
|
.with_safety(SafetySelection::Unsafe(Sequencing::EnsureOrdered))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let cs = api.crypto().unwrap().get(CRYPTO_KIND_VLD0).unwrap();
|
||||||
|
let owner_keypair = cs.generate_keypair();
|
||||||
|
let schema = DHTSchema::dflt(1).unwrap();
|
||||||
|
|
||||||
|
// create the record normally
|
||||||
|
let rec = rc
|
||||||
|
.create_dht_record(schema.clone(), Some(owner_keypair), Some(CRYPTO_KIND_VLD0))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// recreate the record key from the metadata alone
|
||||||
|
let key = rc
|
||||||
|
.get_dht_record_key(schema.clone(), &owner_keypair.key, Some(CRYPTO_KIND_VLD0))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// keys should be the same
|
||||||
|
assert_eq!(key, *rec.key());
|
||||||
|
|
||||||
|
let dht_key = *rec.key();
|
||||||
|
rc.close_dht_record(dht_key).await.unwrap();
|
||||||
|
rc.delete_dht_record(dht_key).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn test_get_dht_value_nonexistent(api: VeilidAPI) {
|
pub async fn test_get_dht_value_nonexistent(api: VeilidAPI) {
|
||||||
let rc = api
|
let rc = api
|
||||||
.routing_context()
|
.routing_context()
|
||||||
@ -79,7 +136,7 @@ pub async fn test_get_dht_value_nonexistent(api: VeilidAPI) {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let rec = rc
|
let rec = rc
|
||||||
.create_dht_record(DHTSchema::dflt(1).unwrap(), Some(CRYPTO_KIND_VLD0))
|
.create_dht_record(DHTSchema::dflt(1).unwrap(), None, Some(CRYPTO_KIND_VLD0))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let dht_key = *rec.key();
|
let dht_key = *rec.key();
|
||||||
@ -98,7 +155,7 @@ pub async fn test_set_get_dht_value(api: VeilidAPI) {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let rec = rc
|
let rec = rc
|
||||||
.create_dht_record(DHTSchema::dflt(2).unwrap(), Some(CRYPTO_KIND_VLD0))
|
.create_dht_record(DHTSchema::dflt(2).unwrap(), None, Some(CRYPTO_KIND_VLD0))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let dht_key = *rec.key();
|
let dht_key = *rec.key();
|
||||||
@ -150,7 +207,7 @@ pub async fn test_open_writer_dht_value(api: VeilidAPI) {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let rec = rc
|
let rec = rc
|
||||||
.create_dht_record(DHTSchema::dflt(2).unwrap(), Some(CRYPTO_KIND_VLD0))
|
.create_dht_record(DHTSchema::dflt(2).unwrap(), None, Some(CRYPTO_KIND_VLD0))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let key = *rec.key();
|
let key = *rec.key();
|
||||||
@ -340,6 +397,7 @@ pub async fn test_all() {
|
|||||||
test_delete_dht_record_nonexistent(api.clone()).await;
|
test_delete_dht_record_nonexistent(api.clone()).await;
|
||||||
test_get_dht_value_nonexistent(api.clone()).await;
|
test_get_dht_value_nonexistent(api.clone()).await;
|
||||||
test_create_delete_dht_record_simple(api.clone()).await;
|
test_create_delete_dht_record_simple(api.clone()).await;
|
||||||
|
test_create_dht_record_with_owner(api.clone()).await;
|
||||||
test_set_get_dht_value(api.clone()).await;
|
test_set_get_dht_value(api.clone()).await;
|
||||||
test_open_writer_dht_value(api.clone()).await;
|
test_open_writer_dht_value(api.clone()).await;
|
||||||
|
|
||||||
|
@ -1478,7 +1478,7 @@ impl VeilidAPI {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Do a record create
|
// Do a record create
|
||||||
let record = match rc.create_dht_record(schema, Some(csv.kind())).await {
|
let record = match rc.create_dht_record(schema, None, Some(csv.kind())).await {
|
||||||
Err(e) => return Ok(format!("Can't open DHT record: {}", e)),
|
Err(e) => return Ok(format!("Can't open DHT record: {}", e)),
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
};
|
};
|
||||||
|
@ -296,7 +296,7 @@ impl JsonRequestProcessor {
|
|||||||
RoutingContextResponseOp::CreateDhtRecord {
|
RoutingContextResponseOp::CreateDhtRecord {
|
||||||
result: to_json_api_result(
|
result: to_json_api_result(
|
||||||
routing_context
|
routing_context
|
||||||
.create_dht_record(schema, kind)
|
.create_dht_record(schema, None, kind)
|
||||||
.await
|
.await
|
||||||
.map(Box::new),
|
.map(Box::new),
|
||||||
),
|
),
|
||||||
|
@ -225,27 +225,51 @@ impl RoutingContext {
|
|||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
/// DHT Records
|
/// DHT Records
|
||||||
|
|
||||||
/// Creates a new DHT record
|
/// Builds the record key for a given schema and owner public key
|
||||||
///
|
|
||||||
/// The record is considered 'open' after the create operation succeeds.
|
|
||||||
/// * 'schema' - the schema to use when creating the DHT record
|
|
||||||
/// * 'kind' - specify a cryptosystem kind to use. Normally you will leave this as None to choose the 'best' cryptosystem available.
|
|
||||||
/// Returns the newly allocated DHT record's key if successful.
|
|
||||||
#[instrument(target = "veilid_api", level = "debug", ret, err)]
|
#[instrument(target = "veilid_api", level = "debug", ret, err)]
|
||||||
pub async fn create_dht_record(
|
pub async fn get_dht_record_key(
|
||||||
&self,
|
&self,
|
||||||
schema: DHTSchema,
|
schema: DHTSchema,
|
||||||
|
owner_key: &PublicKey,
|
||||||
kind: Option<CryptoKind>,
|
kind: Option<CryptoKind>,
|
||||||
) -> VeilidAPIResult<DHTRecordDescriptor> {
|
) -> VeilidAPIResult<TypedKey> {
|
||||||
event!(target: "veilid_api", Level::DEBUG,
|
event!(target: "veilid_api", Level::DEBUG,
|
||||||
"RoutingContext::create_dht_record(self: {:?}, schema: {:?}, kind: {:?})", self, schema, kind);
|
"RoutingContext::get_dht_record_key(self: {:?}, schema: {:?}, owner_key: {:?}, kind: {:?})", self, schema, owner_key, kind);
|
||||||
schema.validate()?;
|
schema.validate()?;
|
||||||
|
|
||||||
let kind = kind.unwrap_or(best_crypto_kind());
|
let kind = kind.unwrap_or(best_crypto_kind());
|
||||||
Crypto::validate_crypto_kind(kind)?;
|
Crypto::validate_crypto_kind(kind)?;
|
||||||
let storage_manager = self.api.storage_manager()?;
|
let storage_manager = self.api.storage_manager()?;
|
||||||
storage_manager
|
storage_manager
|
||||||
.create_record(kind, schema, self.unlocked_inner.safety_selection)
|
.get_record_key(kind, schema, owner_key)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new DHT record
|
||||||
|
///
|
||||||
|
/// The record is considered 'open' after the create operation succeeds.
|
||||||
|
/// * 'schema' - the schema to use when creating the DHT record
|
||||||
|
/// * 'owner' - optionally specify an owner keypair to use. If you leave this as None then a random one will be generated
|
||||||
|
/// * 'kind' - specify a cryptosystem kind to use. Normally you will leave this as None to choose the 'best' cryptosystem available.
|
||||||
|
/// Returns the newly allocated DHT record's key if successful.
|
||||||
|
///
|
||||||
|
/// Note: if you pass in an owner keypair this call is a deterministic! This means that if you try to create a new record for a given owner and schema that already exists it *will* fail.
|
||||||
|
#[instrument(target = "veilid_api", level = "debug", ret, err)]
|
||||||
|
pub async fn create_dht_record(
|
||||||
|
&self,
|
||||||
|
schema: DHTSchema,
|
||||||
|
owner: Option<KeyPair>,
|
||||||
|
kind: Option<CryptoKind>,
|
||||||
|
) -> VeilidAPIResult<DHTRecordDescriptor> {
|
||||||
|
event!(target: "veilid_api", Level::DEBUG,
|
||||||
|
"RoutingContext::create_dht_record(self: {:?}, schema: {:?}, owner: {:?}, kind: {:?})", self, schema, owner, kind);
|
||||||
|
schema.validate()?;
|
||||||
|
|
||||||
|
let kind = kind.unwrap_or(best_crypto_kind());
|
||||||
|
Crypto::validate_crypto_kind(kind)?;
|
||||||
|
let storage_manager = self.api.storage_manager()?;
|
||||||
|
storage_manager
|
||||||
|
.create_record(kind, schema, owner, self.unlocked_inner.safety_selection)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,7 +671,7 @@ pub extern "C" fn routing_context_create_dht_record(port: i64, id: u32, schema:
|
|||||||
let routing_context = get_routing_context(id, "routing_context_create_dht_record")?;
|
let routing_context = get_routing_context(id, "routing_context_create_dht_record")?;
|
||||||
|
|
||||||
let dht_record_descriptor = routing_context
|
let dht_record_descriptor = routing_context
|
||||||
.create_dht_record(schema, crypto_kind)
|
.create_dht_record(schema, None, crypto_kind)
|
||||||
.await?;
|
.await?;
|
||||||
APIResult::Ok(dht_record_descriptor)
|
APIResult::Ok(dht_record_descriptor)
|
||||||
}
|
}
|
||||||
|
@ -494,7 +494,7 @@ pub fn routing_context_create_dht_record(id: u32, schema: String, kind: u32) ->
|
|||||||
let routing_context = get_routing_context(id, "routing_context_create_dht_record")?;
|
let routing_context = get_routing_context(id, "routing_context_create_dht_record")?;
|
||||||
|
|
||||||
let dht_record_descriptor = routing_context
|
let dht_record_descriptor = routing_context
|
||||||
.create_dht_record(schema, crypto_kind)
|
.create_dht_record(schema, None, crypto_kind)
|
||||||
.await?;
|
.await?;
|
||||||
APIResult::Ok(dht_record_descriptor)
|
APIResult::Ok(dht_record_descriptor)
|
||||||
})
|
})
|
||||||
|
@ -207,7 +207,7 @@ impl VeilidRoutingContext {
|
|||||||
let routing_context = self.getRoutingContext()?;
|
let routing_context = self.getRoutingContext()?;
|
||||||
|
|
||||||
let dht_record_descriptor = routing_context
|
let dht_record_descriptor = routing_context
|
||||||
.create_dht_record(schema, crypto_kind)
|
.create_dht_record(schema, None, crypto_kind)
|
||||||
.await?;
|
.await?;
|
||||||
APIResult::Ok(dht_record_descriptor)
|
APIResult::Ok(dht_record_descriptor)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user