add limits to schemas. first stab at dht transactions

This commit is contained in:
Christien Rioux 2025-09-22 22:29:53 -04:00
parent bcb6e8b549
commit f39c4b5c57
4 changed files with 77 additions and 9 deletions

View file

@ -328,9 +328,10 @@ struct OperationGetValueA @0xf97edb86a914d093 {
struct OperationSetValueQ @0xb315a71cd3f555b3 {
key @0 :OpaqueRecordKey; # DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ]
subkey @1 :Subkey; # the index of the subkey
value @2 :SignedValueData; # value or subvalue contents (older or equal seq number gets dropped)
descriptor @3 :SignedValueDescriptor; # optional: the descriptor if needed
transactionId @1 :UInt64; # optional: transaction id if inside a transaction
subkey @2 :Subkey; # the index of the subkey
value @3 :SignedValueData; # value or subvalue contents (older or equal seq number gets dropped)
descriptor @4 :SignedValueDescriptor; # optional: the descriptor if needed
}
struct OperationSetValueA @0xb5ff5b18c0d7b918 {
@ -376,6 +377,42 @@ struct OperationValueChanged @0xbf9d00e88fd96623 {
value @4 :SignedValueData; # Optional: first value that changed (the rest can be gotten with getvalue)
}
enum TransactCommand @0xa841a757a9a7f946 {
begin @0; # start a new transaction
commit @1; # commit all operations
rollback @2; # roll back all operations
}
struct OperationTransactValueQ @0xf8629eff87ac729d {
key @0 :OpaqueRecordKey; # key for record to transact on
command @1 :TransactCommand; # transaction command to execute
transactionId @2 :UInt64; # optional: transaction id if committing or rolling back
writer @3 :PublicKey; # the writer performing the transaction, can be the owner or a schema member
signature @4 :Signature; # signature of the writer, signature covers: key, writer, signature, count, watchId
}
struct OperationTransactValueA @0xd2b5a46f55268aa4 {
accepted @0 :Bool; # true if the transaction was close enough to be accepted
transactionId @1 :UInt64; # optional: transaction id if successful, missing if operation failed
peers @2 :List(PeerInfo); # returned 'closer peer' information on either success or failure
}
struct OperationSyncValueQ @0xee28e7a72302fef7 {
key @0 :OpaqueRecordKey; # key for record to sync
transactionId @1 :UInt64; # optional: transaction id if inside a transaction
seqs @2 :List(ValueSeqNum); # the list of subkey value sequence numbers in ascending order for each subkey
subkey @3 :Subkey; # optional: the index of the subkey
value @4 :SignedValueData; # optional: value or subvalue contents (older or equal seq number gets dropped)
descriptor @5 :SignedValueDescriptor; # optional: the descriptor if needed
}
struct OperationSyncValueA @0xe42e5bb79e2f9009 {
seqs @0 :List(ValueSeqNum); # the list of subkey value sequence numbers in ascending order for each subkey
subkey @1 :Subkey; # optional: the index of the subkey
value @2 :SignedValueData; # optional: value or subvalue contents (older or equal seq number gets dropped)
}
struct OperationSupplyBlockQ @0xe0d00fd8091dd2e0 {
blockId @0 :BlockId; # hash of the block we can supply
routeId @1 :RouteId; # the private route endpoint for this block supplier

View file

@ -29,6 +29,10 @@ impl DHTSchemaDFLT {
if self.o_cnt == 0 {
apibail_invalid_argument!("must have at least one subkey", "o_cnt", self.o_cnt);
}
if self.o_cnt > DHTSchema::MAX_SUBKEY_COUNT {
apibail_invalid_argument!("too many subkeys", "o_cnt", self.o_cnt);
}
Ok(())
}

View file

@ -21,6 +21,9 @@ pub enum DHTSchema {
}
impl DHTSchema {
pub const MAX_WRITER_COUNT: usize = 256;
pub const MAX_SUBKEY_COUNT: usize = 1024;
pub fn dflt(o_cnt: u16) -> VeilidAPIResult<DHTSchema> {
Ok(DHTSchema::DFLT(DHTSchemaDFLT::new(o_cnt)?))
}

View file

@ -35,6 +35,7 @@ pub struct DHTSchemaSMPL {
impl DHTSchemaSMPL {
pub const FCC: [u8; 4] = *b"SMPL";
pub const FIXED_SIZE: usize = 6;
pub const MAX_MEMBER_COUNT: usize = 256;
/// Make a schema
pub fn new(o_cnt: u16, members: Vec<DHTSchemaSMPLMember>) -> VeilidAPIResult<Self> {
@ -45,7 +46,13 @@ impl DHTSchemaSMPL {
/// Validate the data representation
pub fn validate(&self) -> VeilidAPIResult<()> {
let mut keycount = self.o_cnt as usize;
let mut subkey_count = self.o_cnt as usize;
let mut writer_count = 0;
if self.o_cnt > 0 {
writer_count += 1;
}
let mut writers = HashSet::<MemberId>::new();
for m in &self.members {
if m.m_key.len() != MEMBER_ID_LENGTH {
apibail_invalid_argument!(
@ -54,14 +61,31 @@ impl DHTSchemaSMPL {
m.m_key.len()
);
}
keycount += m.m_cnt as usize;
if m.m_cnt > 0 {
writers.insert(m.m_key);
}
subkey_count += m.m_cnt as usize;
}
if keycount == 0 {
apibail_invalid_argument!("must have at least one subkey", "keycount", keycount);
let member_count = self.members.len();
if member_count > MAX_MEMBER_COUNT {
apibail_invalid_argument!("too many members", "member_count", writercount);
}
if keycount > 65535 {
apibail_invalid_argument!("too many subkeys", "keycount", keycount);
writer_count += writers.len();
if writer_count > DHTSchema::MAX_WRITER_COUNT {
apibail_invalid_argument!("too many writers", "writer_count", writercount);
}
if subkey_count == 0 {
apibail_invalid_argument!(
"must have at least one subkey",
"subkey_count",
subkey_count
);
}
if subkey_count > DHTSchema::MAX_SUBKEY_COUNT {
apibail_invalid_argument!("too many subkeys", "subkey_count", subkey_count);
}
Ok(())
}