1use std::str::FromStr;
8
9use crate::action::NewEntryAction;
10use crate::prelude::*;
11use crate::record::RecordGroup;
12use crate::warrant::WarrantOp;
13use holo_hash::*;
14use holochain_sqlite::rusqlite::types::FromSql;
15use holochain_sqlite::rusqlite::ToSql;
16use holochain_zome_types::action;
17use holochain_zome_types::prelude::*;
18use serde::Deserialize;
19use serde::Serialize;
20
21mod error;
22pub use error::*;
23
24#[cfg(test)]
25mod tests;
26
27#[derive(
30 Clone, Debug, Serialize, Deserialize, SerializedBytes, Eq, PartialEq, Hash, derive_more::From,
31)]
32pub enum DhtOp {
33 ChainOp(Box<ChainOp>),
35 WarrantOp(Box<WarrantOp>),
37}
38
39#[derive(
41 Clone, Debug, Serialize, Deserialize, SerializedBytes, Eq, PartialEq, Hash, derive_more::Display,
42)]
43pub enum ChainOp {
44 #[display(fmt = "StoreRecord")]
45 StoreRecord(Signature, Action, RecordEntry),
55
56 #[display(fmt = "StoreEntry")]
57 StoreEntry(Signature, NewEntryAction, Entry),
72
73 #[display(fmt = "RegisterAgentActivity")]
74 RegisterAgentActivity(Signature, Action),
88
89 #[display(fmt = "RegisterUpdatedContent")]
90 RegisterUpdatedContent(Signature, action::Update, RecordEntry),
96
97 #[display(fmt = "RegisterUpdatedRecord")]
98 RegisterUpdatedRecord(Signature, action::Update, RecordEntry),
101
102 #[display(fmt = "RegisterDeletedBy")]
103 RegisterDeletedBy(Signature, action::Delete),
105
106 #[display(fmt = "RegisterDeletedEntryAction")]
107 RegisterDeletedEntryAction(Signature, action::Delete),
110
111 #[display(fmt = "RegisterAddLink")]
112 RegisterAddLink(Signature, action::CreateLink),
114
115 #[display(fmt = "RegisterRemoveLink")]
116 RegisterRemoveLink(Signature, action::DeleteLink),
118}
119
120impl From<ChainOp> for DhtOp {
121 fn from(op: ChainOp) -> Self {
122 DhtOp::ChainOp(Box::new(op))
123 }
124}
125
126impl From<WarrantOp> for DhtOp {
127 fn from(op: WarrantOp) -> Self {
128 DhtOp::WarrantOp(Box::new(op))
129 }
130}
131
132impl From<SignedWarrant> for DhtOp {
133 fn from(op: SignedWarrant) -> Self {
134 DhtOp::WarrantOp(Box::new(WarrantOp::from(op)))
135 }
136}
137
138#[allow(missing_docs)]
141#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, derive_more::From)]
142pub enum DhtOpLite {
143 Chain(Box<ChainOpLite>),
144 Warrant(Box<WarrantOp>),
146}
147
148#[allow(missing_docs)]
151#[derive(Clone, Debug, Serialize, Deserialize, derive_more::Display)]
152pub enum ChainOpLite {
153 #[display(fmt = "StoreRecord")]
154 StoreRecord(ActionHash, Option<EntryHash>, OpBasis),
155 #[display(fmt = "StoreEntry")]
156 StoreEntry(ActionHash, EntryHash, OpBasis),
157 #[display(fmt = "RegisterAgentActivity")]
158 RegisterAgentActivity(ActionHash, OpBasis),
159 #[display(fmt = "RegisterUpdatedContent")]
160 RegisterUpdatedContent(ActionHash, EntryHash, OpBasis),
161 #[display(fmt = "RegisterUpdatedRecord")]
162 RegisterUpdatedRecord(ActionHash, EntryHash, OpBasis),
163 #[display(fmt = "RegisterDeletedBy")]
164 RegisterDeletedBy(ActionHash, OpBasis),
165 #[display(fmt = "RegisterDeletedEntryAction")]
166 RegisterDeletedEntryAction(ActionHash, OpBasis),
167 #[display(fmt = "RegisterAddLink")]
168 RegisterAddLink(ActionHash, OpBasis),
169 #[display(fmt = "RegisterRemoveLink")]
170 RegisterRemoveLink(ActionHash, OpBasis),
171}
172
173impl From<ChainOpLite> for DhtOpLite {
174 fn from(op: ChainOpLite) -> Self {
175 DhtOpLite::Chain(Box::new(op))
176 }
177}
178
179impl From<WarrantOp> for DhtOpLite {
180 fn from(op: WarrantOp) -> Self {
181 DhtOpLite::Warrant(Box::new(op))
182 }
183}
184
185impl From<SignedWarrant> for DhtOpLite {
186 fn from(warrant: SignedWarrant) -> Self {
187 DhtOpLite::Warrant(Box::new(warrant.into()))
188 }
189}
190
191impl PartialEq for ChainOpLite {
192 fn eq(&self, other: &Self) -> bool {
193 self.get_type() == other.get_type() && self.action_hash() == other.action_hash()
197 }
198}
199
200impl Eq for ChainOpLite {}
201
202impl std::hash::Hash for ChainOpLite {
203 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
204 self.get_type().hash(state);
205 self.action_hash().hash(state);
206 }
207}
208
209#[allow(missing_docs)]
211#[derive(Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, derive_more::From)]
212pub enum DhtOpType {
213 Chain(ChainOpType),
214 Warrant(WarrantOpType),
215}
216
217impl ToSql for DhtOpType {
218 fn to_sql(
219 &self,
220 ) -> holochain_sqlite::rusqlite::Result<holochain_sqlite::rusqlite::types::ToSqlOutput> {
221 match self {
222 DhtOpType::Chain(op) => op.to_sql(),
223 DhtOpType::Warrant(op) => op.to_sql(),
224 }
225 }
226}
227
228impl FromSql for DhtOpType {
229 fn column_result(
230 value: holochain_sqlite::rusqlite::types::ValueRef<'_>,
231 ) -> holochain_sqlite::rusqlite::types::FromSqlResult<Self> {
232 String::column_result(value)
233 .and_then(|string| {
234 ChainOpType::from_str(&string)
235 .map(DhtOpType::from)
236 .or_else(|_| WarrantOpType::from_str(&string).map(DhtOpType::from))
237 .map_err(|_| holochain_sqlite::rusqlite::types::FromSqlError::InvalidType)
238 })
239 .map(Into::into)
240 }
241}
242
243pub type SysValDeps = Vec<ActionHash>;
245
246#[allow(missing_docs)]
248#[derive(
249 Clone,
250 Copy,
251 Debug,
252 Serialize,
253 Deserialize,
254 Eq,
255 PartialEq,
256 Hash,
257 derive_more::Display,
258 strum_macros::EnumString,
259)]
260pub enum ChainOpType {
261 #[display(fmt = "StoreRecord")]
262 StoreRecord,
263 #[display(fmt = "StoreEntry")]
264 StoreEntry,
265 #[display(fmt = "RegisterAgentActivity")]
266 RegisterAgentActivity,
267 #[display(fmt = "RegisterUpdatedContent")]
268 RegisterUpdatedContent,
269 #[display(fmt = "RegisterUpdatedRecord")]
270 RegisterUpdatedRecord,
271 #[display(fmt = "RegisterDeletedBy")]
272 RegisterDeletedBy,
273 #[display(fmt = "RegisterDeletedEntryAction")]
274 RegisterDeletedEntryAction,
275 #[display(fmt = "RegisterAddLink")]
276 RegisterAddLink,
277 #[display(fmt = "RegisterRemoveLink")]
278 RegisterRemoveLink,
279}
280impl ChainOpType {
281 pub fn sys_validation_dependencies(&self, action: &Action) -> SysValDeps {
283 match self {
284 ChainOpType::StoreRecord | ChainOpType::StoreEntry => vec![],
285 ChainOpType::RegisterAgentActivity => action
286 .prev_action()
287 .map(|p| vec![p.clone()])
288 .unwrap_or_default(),
289 ChainOpType::RegisterUpdatedContent | ChainOpType::RegisterUpdatedRecord => {
290 match action {
291 Action::Update(update) => vec![update.original_action_address.clone()],
292 _ => vec![],
293 }
294 }
295 ChainOpType::RegisterDeletedBy | ChainOpType::RegisterDeletedEntryAction => {
296 match action {
297 Action::Delete(delete) => vec![delete.deletes_address.clone()],
298 _ => vec![],
299 }
300 }
301 ChainOpType::RegisterAddLink => vec![],
302 ChainOpType::RegisterRemoveLink => match action {
303 Action::DeleteLink(delete_link) => vec![delete_link.link_add_address.clone()],
304 _ => vec![],
305 },
306 }
307 }
308}
309
310impl rusqlite::ToSql for ChainOpType {
311 fn to_sql(
312 &self,
313 ) -> holochain_sqlite::rusqlite::Result<holochain_sqlite::rusqlite::types::ToSqlOutput> {
314 Ok(holochain_sqlite::rusqlite::types::ToSqlOutput::Owned(
315 format!("{}", self).into(),
316 ))
317 }
318}
319
320impl rusqlite::types::FromSql for ChainOpType {
321 fn column_result(
322 value: holochain_sqlite::rusqlite::types::ValueRef<'_>,
323 ) -> holochain_sqlite::rusqlite::types::FromSqlResult<Self> {
324 String::column_result(value).and_then(|string| {
325 ChainOpType::from_str(&string)
326 .map_err(|_| holochain_sqlite::rusqlite::types::FromSqlError::InvalidType)
327 })
328 }
329}
330
331impl DhtOp {
332 pub fn as_chain_op(&self) -> Option<&ChainOp> {
334 match self {
335 Self::ChainOp(op) => Some(op),
336 _ => None,
337 }
338 }
339
340 pub fn get_type(&self) -> DhtOpType {
342 match self {
343 Self::ChainOp(op) => DhtOpType::Chain(op.get_type()),
344 Self::WarrantOp(op) => DhtOpType::Warrant(op.get_type()),
345 }
346 }
347
348 pub fn dht_basis(&self) -> OpBasis {
350 match self {
351 Self::ChainOp(op) => op.as_unique_form().basis(),
352 Self::WarrantOp(op) => op.dht_basis(),
353 }
354 }
355
356 pub fn signature(&self) -> &Signature {
358 match self {
359 Self::ChainOp(op) => op.signature(),
360 Self::WarrantOp(op) => op.signature(),
361 }
362 }
363
364 fn to_order(&self) -> OpOrder {
365 match self {
366 Self::ChainOp(op) => OpOrder::new(op.get_type(), op.timestamp()),
367 Self::WarrantOp(op) => OpOrder::new(op.get_type(), op.timestamp()),
368 }
369 }
370
371 pub fn author(&self) -> AgentPubKey {
373 match self {
374 Self::ChainOp(op) => op.action().author().clone(),
375 Self::WarrantOp(op) => op.author.clone(),
376 }
377 }
378
379 pub fn timestamp(&self) -> Timestamp {
381 match self {
382 Self::ChainOp(op) => op.timestamp(),
383 Self::WarrantOp(op) => op.timestamp(),
384 }
385 }
386
387 pub fn to_lite(&self) -> DhtOpLite {
389 match self {
390 Self::ChainOp(op) => DhtOpLite::Chain(op.to_lite().into()),
391 Self::WarrantOp(op) => DhtOpLite::Warrant(op.clone()),
392 }
393 }
394
395 pub fn sys_validation_dependencies(&self) -> SysValDeps {
397 match self {
398 Self::ChainOp(op) => op.get_type().sys_validation_dependencies(&op.action()),
399 Self::WarrantOp(op) => match &op.proof {
400 WarrantProof::ChainIntegrity(w) => match w {
401 ChainIntegrityWarrant::InvalidChainOp {
402 action: action_hash,
403 ..
404 } => vec![action_hash.0.clone()],
405 ChainIntegrityWarrant::ChainFork { action_pair, .. } => {
406 vec![action_pair.0 .0.clone()]
407 }
408 },
409 },
410 }
411 }
412}
413
414impl PartialOrd for DhtOp {
415 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
416 Some(self.cmp(other))
417 }
418}
419
420impl Ord for DhtOp {
421 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
422 match self.to_order().cmp(&other.to_order()) {
423 std::cmp::Ordering::Equal => self.signature().cmp(other.signature()),
425 ordering => ordering,
426 }
427 }
428}
429
430impl ChainOp {
431 fn as_unique_form(&self) -> ChainOpUniqueForm<'_> {
432 match self {
433 Self::StoreRecord(_, action, _) => ChainOpUniqueForm::StoreRecord(action),
434 Self::StoreEntry(_, action, _) => ChainOpUniqueForm::StoreEntry(action),
435 Self::RegisterAgentActivity(_, action) => {
436 ChainOpUniqueForm::RegisterAgentActivity(action)
437 }
438 Self::RegisterUpdatedContent(_, action, _) => {
439 ChainOpUniqueForm::RegisterUpdatedContent(action)
440 }
441 Self::RegisterUpdatedRecord(_, action, _) => {
442 ChainOpUniqueForm::RegisterUpdatedRecord(action)
443 }
444 Self::RegisterDeletedBy(_, action) => ChainOpUniqueForm::RegisterDeletedBy(action),
445 Self::RegisterDeletedEntryAction(_, action) => {
446 ChainOpUniqueForm::RegisterDeletedEntryAction(action)
447 }
448 Self::RegisterAddLink(_, action) => ChainOpUniqueForm::RegisterAddLink(action),
449 Self::RegisterRemoveLink(_, action) => ChainOpUniqueForm::RegisterRemoveLink(action),
450 }
451 }
452
453 pub fn dht_basis(&self) -> OpBasis {
455 self.as_unique_form().basis()
456 }
457
458 pub fn signature(&self) -> &Signature {
460 match self {
461 Self::StoreRecord(s, _, _)
462 | Self::StoreEntry(s, _, _)
463 | Self::RegisterAgentActivity(s, _)
464 | Self::RegisterUpdatedContent(s, _, _)
465 | Self::RegisterUpdatedRecord(s, _, _)
466 | Self::RegisterDeletedBy(s, _)
467 | Self::RegisterDeletedEntryAction(s, _)
468 | Self::RegisterAddLink(s, _)
469 | Self::RegisterRemoveLink(s, _) => s,
470 }
471 }
472
473 pub fn to_lite(&self) -> ChainOpLite {
475 let basis = self.dht_basis();
476 match self {
477 Self::StoreRecord(_, a, _) => {
478 let e = a.entry_data().map(|(e, _)| e.clone());
479 let h = ActionHash::with_data_sync(a);
480 ChainOpLite::StoreRecord(h, e, basis)
481 }
482 Self::StoreEntry(_, a, _) => {
483 let e = a.entry().clone();
484 let h = ActionHash::with_data_sync(&Action::from(a.clone()));
485 ChainOpLite::StoreEntry(h, e, basis)
486 }
487 Self::RegisterAgentActivity(_, a) => {
488 let h = ActionHash::with_data_sync(a);
489 ChainOpLite::RegisterAgentActivity(h, basis)
490 }
491 Self::RegisterUpdatedContent(_, a, _) => {
492 let e = a.entry_hash.clone();
493 let h = ActionHash::with_data_sync(&Action::from(a.clone()));
494 ChainOpLite::RegisterUpdatedContent(h, e, basis)
495 }
496 Self::RegisterUpdatedRecord(_, a, _) => {
497 let e = a.entry_hash.clone();
498 let h = ActionHash::with_data_sync(&Action::from(a.clone()));
499 ChainOpLite::RegisterUpdatedRecord(h, e, basis)
500 }
501 Self::RegisterDeletedBy(_, a) => {
502 let h = ActionHash::with_data_sync(&Action::from(a.clone()));
503 ChainOpLite::RegisterDeletedBy(h, basis)
504 }
505 Self::RegisterDeletedEntryAction(_, a) => {
506 let h = ActionHash::with_data_sync(&Action::from(a.clone()));
507 ChainOpLite::RegisterDeletedEntryAction(h, basis)
508 }
509 Self::RegisterAddLink(_, a) => {
510 let h = ActionHash::with_data_sync(&Action::from(a.clone()));
511 ChainOpLite::RegisterAddLink(h, basis)
512 }
513 Self::RegisterRemoveLink(_, a) => {
514 let h = ActionHash::with_data_sync(&Action::from(a.clone()));
515 ChainOpLite::RegisterRemoveLink(h, basis)
516 }
517 }
518 }
519
520 pub fn action(&self) -> Action {
524 match self {
525 Self::StoreRecord(_, a, _) => a.clone(),
526 Self::StoreEntry(_, a, _) => a.clone().into(),
527 Self::RegisterAgentActivity(_, a) => a.clone(),
528 Self::RegisterUpdatedContent(_, a, _) => a.clone().into(),
529 Self::RegisterUpdatedRecord(_, a, _) => a.clone().into(),
530 Self::RegisterDeletedBy(_, a) => a.clone().into(),
531 Self::RegisterDeletedEntryAction(_, a) => a.clone().into(),
532 Self::RegisterAddLink(_, a) => a.clone().into(),
533 Self::RegisterRemoveLink(_, a) => a.clone().into(),
534 }
535 }
536
537 pub fn signed_action(&self) -> SignedAction {
539 match self {
540 Self::StoreRecord(s, a, _) => SignedAction::new(a.clone(), s.clone()),
541 Self::StoreEntry(s, a, _) => SignedAction::new(a.clone().into(), s.clone()),
542 Self::RegisterAgentActivity(s, a) => SignedAction::new(a.clone(), s.clone()),
543 Self::RegisterUpdatedContent(s, a, _) => SignedAction::new(a.clone().into(), s.clone()),
544 Self::RegisterUpdatedRecord(s, a, _) => SignedAction::new(a.clone().into(), s.clone()),
545 Self::RegisterDeletedBy(s, a) => SignedAction::new(a.clone().into(), s.clone()),
546 Self::RegisterDeletedEntryAction(s, a) => {
547 SignedAction::new(a.clone().into(), s.clone())
548 }
549 Self::RegisterAddLink(s, a) => SignedAction::new(a.clone().into(), s.clone()),
550 Self::RegisterRemoveLink(s, a) => SignedAction::new(a.clone().into(), s.clone()),
551 }
552 }
553
554 pub fn is_genesis(&self) -> bool {
556 match self {
559 ChainOp::StoreRecord(_, a, _) => a.is_genesis(),
560 ChainOp::StoreEntry(_, a, _) => a.action_seq() < POST_GENESIS_SEQ_THRESHOLD,
561 ChainOp::RegisterAgentActivity(_, a) => a.is_genesis(),
562 ChainOp::RegisterUpdatedContent(_, a, _) => a.action_seq < POST_GENESIS_SEQ_THRESHOLD,
563 ChainOp::RegisterUpdatedRecord(_, a, _) => a.action_seq < POST_GENESIS_SEQ_THRESHOLD,
564 ChainOp::RegisterDeletedBy(_, a) => a.action_seq < POST_GENESIS_SEQ_THRESHOLD,
565 ChainOp::RegisterDeletedEntryAction(_, a) => a.action_seq < POST_GENESIS_SEQ_THRESHOLD,
566 ChainOp::RegisterAddLink(_, a) => a.action_seq < POST_GENESIS_SEQ_THRESHOLD,
567 ChainOp::RegisterRemoveLink(_, a) => a.action_seq < POST_GENESIS_SEQ_THRESHOLD,
568 }
569 }
570
571 pub fn entry(&self) -> RecordEntryRef {
573 match self {
574 Self::StoreRecord(_, _, e) => e.as_ref(),
575 Self::StoreEntry(_, _, e) => RecordEntry::Present(e),
576 Self::RegisterUpdatedContent(_, _, e) => e.as_ref(),
577 Self::RegisterUpdatedRecord(_, _, e) => e.as_ref(),
578 Self::RegisterAgentActivity(_, a) => RecordEntry::new(a.entry_visibility(), None),
579 Self::RegisterDeletedBy(_, _) => RecordEntry::NA,
580 Self::RegisterDeletedEntryAction(_, _) => RecordEntry::NA,
581 Self::RegisterAddLink(_, _) => RecordEntry::NA,
582 Self::RegisterRemoveLink(_, _) => RecordEntry::NA,
583 }
584 }
585
586 pub fn get_type(&self) -> ChainOpType {
588 match self {
589 Self::StoreRecord(_, _, _) => ChainOpType::StoreRecord,
590 Self::StoreEntry(_, _, _) => ChainOpType::StoreEntry,
591 Self::RegisterUpdatedContent(_, _, _) => ChainOpType::RegisterUpdatedContent,
592 Self::RegisterUpdatedRecord(_, _, _) => ChainOpType::RegisterUpdatedRecord,
593 Self::RegisterAgentActivity(_, _) => ChainOpType::RegisterAgentActivity,
594 Self::RegisterDeletedBy(_, _) => ChainOpType::RegisterDeletedBy,
595 Self::RegisterDeletedEntryAction(_, _) => ChainOpType::RegisterDeletedEntryAction,
596 Self::RegisterAddLink(_, _) => ChainOpType::RegisterAddLink,
597 Self::RegisterRemoveLink(_, _) => ChainOpType::RegisterRemoveLink,
598 }
599 }
600
601 pub fn from_type(
603 op_type: ChainOpType,
604 action: SignedAction,
605 entry: Option<Entry>,
606 ) -> DhtOpResult<Self> {
607 let (action, signature) = action.into();
608 let entry = RecordEntry::new(action.entry_visibility(), entry);
609 let r = match op_type {
610 ChainOpType::StoreRecord => Self::StoreRecord(signature, action, entry),
611 ChainOpType::StoreEntry => {
612 let entry = entry
613 .into_option()
614 .ok_or_else(|| DhtOpError::ActionWithoutEntry(action.clone()))?;
615 let action = match action {
616 Action::Create(c) => NewEntryAction::Create(c),
617 Action::Update(c) => NewEntryAction::Update(c),
618 _ => return Err(DhtOpError::OpActionMismatch(op_type, action.action_type())),
619 };
620 Self::StoreEntry(signature, action, entry)
621 }
622 ChainOpType::RegisterAgentActivity => Self::RegisterAgentActivity(signature, action),
623 ChainOpType::RegisterUpdatedContent => {
624 Self::RegisterUpdatedContent(signature, action.try_into()?, entry)
625 }
626 ChainOpType::RegisterUpdatedRecord => {
627 Self::RegisterUpdatedRecord(signature, action.try_into()?, entry)
628 }
629 ChainOpType::RegisterDeletedBy => {
630 Self::RegisterDeletedBy(signature, action.try_into()?)
631 }
632 ChainOpType::RegisterDeletedEntryAction => {
633 Self::RegisterDeletedEntryAction(signature, action.try_into()?)
634 }
635 ChainOpType::RegisterAddLink => Self::RegisterAddLink(signature, action.try_into()?),
636 ChainOpType::RegisterRemoveLink => {
637 Self::RegisterRemoveLink(signature, action.try_into()?)
638 }
639 };
640 Ok(r)
641 }
642
643 #[cfg(feature = "test_utils")]
651 pub fn normalized(self) -> DhtOpResult<Self> {
652 let action = self.signed_action();
653 let entry = if action.entry_hash().is_none() {
654 None
655 } else {
656 self.entry().into_option().cloned()
657 };
658 Self::from_type(self.get_type(), action, entry)
659 }
660
661 pub fn enzymatic_countersigning_enzyme(&self) -> Option<&AgentPubKey> {
666 if let Some(Entry::CounterSign(session_data, _)) = self.entry().into_option() {
667 if session_data.preflight_request().enzymatic {
668 session_data
669 .preflight_request()
670 .signing_agents
671 .first()
672 .map(|(pubkey, _)| pubkey)
673 } else {
674 None
675 }
676 } else {
677 None
678 }
679 }
680
681 pub fn timestamp(&self) -> Timestamp {
683 match self {
684 ChainOp::StoreRecord(_, a, _) => a.timestamp(),
685 ChainOp::StoreEntry(_, a, _) => a.timestamp(),
686 ChainOp::RegisterAgentActivity(_, a) => a.timestamp(),
687 ChainOp::RegisterUpdatedContent(_, a, _) => a.timestamp,
688 ChainOp::RegisterUpdatedRecord(_, a, _) => a.timestamp,
689 ChainOp::RegisterDeletedBy(_, a) => a.timestamp,
690 ChainOp::RegisterDeletedEntryAction(_, a) => a.timestamp,
691 ChainOp::RegisterAddLink(_, a) => a.timestamp,
692 ChainOp::RegisterRemoveLink(_, a) => a.timestamp,
693 }
694 }
695
696 pub fn author(&self) -> &AgentPubKey {
698 match self {
699 ChainOp::StoreRecord(_, a, _) => a.author(),
700 ChainOp::StoreEntry(_, a, _) => a.author(),
701 ChainOp::RegisterAgentActivity(_, a) => a.author(),
702 ChainOp::RegisterUpdatedContent(_, a, _) => &a.author,
703 ChainOp::RegisterUpdatedRecord(_, a, _) => &a.author,
704 ChainOp::RegisterDeletedBy(_, a) => &a.author,
705 ChainOp::RegisterDeletedEntryAction(_, a) => &a.author,
706 ChainOp::RegisterAddLink(_, a) => &a.author,
707 ChainOp::RegisterRemoveLink(_, a) => &a.author,
708 }
709 }
710
711 pub fn sys_validation_dependencies(&self) -> SysValDeps {
713 self.get_type().sys_validation_dependencies(&self.action())
714 }
715
716 pub fn map_entry(self, f: impl FnOnce(RecordEntry) -> RecordEntry) -> Self {
718 match self {
719 Self::StoreRecord(signature, action, entry) => {
720 Self::StoreRecord(signature, action, f(entry))
721 }
722 Self::RegisterUpdatedContent(signature, action, entry) => {
723 Self::RegisterUpdatedContent(signature, action, f(entry))
724 }
725 Self::RegisterUpdatedRecord(signature, action, entry) => {
726 Self::RegisterUpdatedRecord(signature, action, f(entry))
727 }
728 _ => self,
729 }
730 }
731}
732
733impl DhtOpLite {
734 pub fn dht_basis(&self) -> OpBasis {
736 match self {
737 Self::Chain(op) => op.dht_basis().clone(),
738 Self::Warrant(op) => op.dht_basis(),
739 }
740 }
741
742 pub fn as_chain_op(&self) -> Option<&ChainOpLite> {
744 match self {
745 Self::Chain(op) => Some(op),
746 _ => None,
747 }
748 }
749
750 pub fn get_type(&self) -> DhtOpType {
752 match self {
753 Self::Chain(op) => op.get_type().into(),
754 Self::Warrant(op) => op.get_type().into(),
755 }
756 }
757
758 pub fn fetch_dependency_hashes(&self) -> Vec<AnyDhtHash> {
764 match self {
765 Self::Chain(op) => match &**op {
766 ChainOpLite::StoreEntry(_, entry_hash, _) => vec![entry_hash.clone().into()],
767 other => vec![other.action_hash().clone().into()],
768 },
769 Self::Warrant(op) => match &op.proof {
770 WarrantProof::ChainIntegrity(w) => match w {
771 ChainIntegrityWarrant::InvalidChainOp {
772 action: action_hash,
773 ..
774 } => vec![action_hash.0.clone().into()],
775 ChainIntegrityWarrant::ChainFork { action_pair, .. } => {
776 vec![
777 action_pair.0 .0.clone().into(),
778 action_pair.1 .0.clone().into(),
779 ]
780 }
781 },
782 },
783 }
784 }
785}
786
787impl ChainOpLite {
788 pub fn dht_basis(&self) -> &OpBasis {
790 match self {
791 ChainOpLite::StoreRecord(_, _, b)
792 | ChainOpLite::StoreEntry(_, _, b)
793 | ChainOpLite::RegisterAgentActivity(_, b)
794 | ChainOpLite::RegisterUpdatedContent(_, _, b)
795 | ChainOpLite::RegisterUpdatedRecord(_, _, b)
796 | ChainOpLite::RegisterDeletedBy(_, b)
797 | ChainOpLite::RegisterDeletedEntryAction(_, b)
798 | ChainOpLite::RegisterAddLink(_, b)
799 | ChainOpLite::RegisterRemoveLink(_, b) => b,
800 }
801 }
802
803 pub fn action_hash(&self) -> &ActionHash {
805 match self {
806 Self::StoreRecord(h, _, _)
807 | Self::StoreEntry(h, _, _)
808 | Self::RegisterAgentActivity(h, _)
809 | Self::RegisterUpdatedContent(h, _, _)
810 | Self::RegisterUpdatedRecord(h, _, _)
811 | Self::RegisterDeletedBy(h, _)
812 | Self::RegisterDeletedEntryAction(h, _)
813 | Self::RegisterAddLink(h, _)
814 | Self::RegisterRemoveLink(h, _) => h,
815 }
816 }
817
818 pub fn get_type(&self) -> ChainOpType {
820 match self {
821 Self::StoreRecord(_, _, _) => ChainOpType::StoreRecord,
822 Self::StoreEntry(_, _, _) => ChainOpType::StoreEntry,
823 Self::RegisterUpdatedContent(_, _, _) => ChainOpType::RegisterUpdatedContent,
824 Self::RegisterUpdatedRecord(_, _, _) => ChainOpType::RegisterUpdatedRecord,
825 Self::RegisterAgentActivity(_, _) => ChainOpType::RegisterAgentActivity,
826 Self::RegisterDeletedBy(_, _) => ChainOpType::RegisterDeletedBy,
827 Self::RegisterDeletedEntryAction(_, _) => ChainOpType::RegisterDeletedEntryAction,
828 Self::RegisterAddLink(_, _) => ChainOpType::RegisterAddLink,
829 Self::RegisterRemoveLink(_, _) => ChainOpType::RegisterRemoveLink,
830 }
831 }
832
833 pub fn from_type(
835 op_type: ChainOpType,
836 action_hash: ActionHash,
837 action: &Action,
838 ) -> DhtOpResult<Self> {
839 let op = match op_type {
840 ChainOpType::StoreRecord => {
841 let entry_hash = action.entry_hash().cloned();
842 Self::StoreRecord(action_hash.clone(), entry_hash, action_hash.into())
843 }
844 ChainOpType::StoreEntry => {
845 let entry_hash = action
846 .entry_hash()
847 .cloned()
848 .ok_or_else(|| DhtOpError::ActionWithoutEntry(action.clone()))?;
849 Self::StoreEntry(action_hash, entry_hash.clone(), entry_hash.into())
850 }
851 ChainOpType::RegisterAgentActivity => {
852 Self::RegisterAgentActivity(action_hash, action.author().clone().into())
853 }
854 ChainOpType::RegisterUpdatedContent => {
855 let entry_hash = action
856 .entry_hash()
857 .cloned()
858 .ok_or_else(|| DhtOpError::ActionWithoutEntry(action.clone()))?;
859 let basis = match action {
860 Action::Update(update) => update.original_entry_address.clone(),
861 _ => return Err(DhtOpError::OpActionMismatch(op_type, action.action_type())),
862 };
863 Self::RegisterUpdatedContent(action_hash, entry_hash, basis.into())
864 }
865 ChainOpType::RegisterUpdatedRecord => {
866 let entry_hash = action
867 .entry_hash()
868 .cloned()
869 .ok_or_else(|| DhtOpError::ActionWithoutEntry(action.clone()))?;
870 let basis = match action {
871 Action::Update(update) => update.original_entry_address.clone(),
872 _ => return Err(DhtOpError::OpActionMismatch(op_type, action.action_type())),
873 };
874 Self::RegisterUpdatedRecord(action_hash, entry_hash, basis.into())
875 }
876 ChainOpType::RegisterDeletedBy => {
877 let basis = match action {
878 Action::Delete(delete) => delete.deletes_address.clone(),
879 _ => return Err(DhtOpError::OpActionMismatch(op_type, action.action_type())),
880 };
881 Self::RegisterDeletedBy(action_hash, basis.into())
882 }
883 ChainOpType::RegisterDeletedEntryAction => {
884 let basis = match action {
885 Action::Delete(delete) => delete.deletes_entry_address.clone(),
886 _ => return Err(DhtOpError::OpActionMismatch(op_type, action.action_type())),
887 };
888 Self::RegisterDeletedEntryAction(action_hash, basis.into())
889 }
890 ChainOpType::RegisterAddLink => {
891 let basis = match action {
892 Action::CreateLink(create_link) => create_link.base_address.clone(),
893 _ => return Err(DhtOpError::OpActionMismatch(op_type, action.action_type())),
894 };
895 Self::RegisterAddLink(action_hash, basis)
896 }
897 ChainOpType::RegisterRemoveLink => {
898 let basis = match action {
899 Action::DeleteLink(delete_link) => delete_link.base_address.clone(),
900 _ => return Err(DhtOpError::OpActionMismatch(op_type, action.action_type())),
901 };
902 Self::RegisterRemoveLink(action_hash, basis)
903 }
904 };
905 Ok(op)
906 }
907}
908
909#[allow(missing_docs)]
910#[derive(Serialize, Debug)]
911pub enum ChainOpUniqueForm<'a> {
912 StoreRecord(&'a Action),
915 StoreEntry(&'a NewEntryAction),
916 RegisterAgentActivity(&'a Action),
917 RegisterUpdatedContent(&'a action::Update),
918 RegisterUpdatedRecord(&'a action::Update),
919 RegisterDeletedBy(&'a action::Delete),
920 RegisterDeletedEntryAction(&'a action::Delete),
921 RegisterAddLink(&'a action::CreateLink),
922 RegisterRemoveLink(&'a action::DeleteLink),
923}
924
925impl<'a> ChainOpUniqueForm<'a> {
926 fn basis(&'a self) -> OpBasis {
927 match self {
928 ChainOpUniqueForm::StoreRecord(action) => ActionHash::with_data_sync(*action).into(),
929 ChainOpUniqueForm::StoreEntry(action) => action.entry().clone().into(),
930 ChainOpUniqueForm::RegisterAgentActivity(action) => action.author().clone().into(),
931 ChainOpUniqueForm::RegisterUpdatedContent(action) => {
932 action.original_entry_address.clone().into()
933 }
934 ChainOpUniqueForm::RegisterUpdatedRecord(action) => {
935 action.original_action_address.clone().into()
936 }
937 ChainOpUniqueForm::RegisterDeletedBy(action) => action.deletes_address.clone().into(),
938 ChainOpUniqueForm::RegisterDeletedEntryAction(action) => {
939 action.deletes_entry_address.clone().into()
940 }
941 ChainOpUniqueForm::RegisterAddLink(action) => action.base_address.clone(),
942 ChainOpUniqueForm::RegisterRemoveLink(action) => action.base_address.clone(),
943 }
944 }
945
946 pub fn op_hash(op_type: ChainOpType, action: Action) -> DhtOpResult<(Action, DhtOpHash)> {
948 match op_type {
949 ChainOpType::StoreRecord => {
950 let hash = DhtOpHash::with_data_sync(&ChainOpUniqueForm::StoreRecord(&action));
951 Ok((action, hash))
952 }
953 ChainOpType::StoreEntry => {
954 let action = action.try_into()?;
955 let hash = DhtOpHash::with_data_sync(&ChainOpUniqueForm::StoreEntry(&action));
956 Ok((action.into(), hash))
957 }
958 ChainOpType::RegisterAgentActivity => {
959 let hash =
960 DhtOpHash::with_data_sync(&ChainOpUniqueForm::RegisterAgentActivity(&action));
961 Ok((action, hash))
962 }
963 ChainOpType::RegisterUpdatedContent => {
964 let action = action.try_into()?;
965 let hash =
966 DhtOpHash::with_data_sync(&ChainOpUniqueForm::RegisterUpdatedContent(&action));
967 Ok((action.into(), hash))
968 }
969 ChainOpType::RegisterUpdatedRecord => {
970 let action = action.try_into()?;
971 let hash =
972 DhtOpHash::with_data_sync(&ChainOpUniqueForm::RegisterUpdatedRecord(&action));
973 Ok((action.into(), hash))
974 }
975 ChainOpType::RegisterDeletedBy => {
976 let action = action.try_into()?;
977 let hash =
978 DhtOpHash::with_data_sync(&ChainOpUniqueForm::RegisterDeletedBy(&action));
979 Ok((action.into(), hash))
980 }
981 ChainOpType::RegisterDeletedEntryAction => {
982 let action = action.try_into()?;
983 let hash = DhtOpHash::with_data_sync(
984 &ChainOpUniqueForm::RegisterDeletedEntryAction(&action),
985 );
986 Ok((action.into(), hash))
987 }
988 ChainOpType::RegisterAddLink => {
989 let action = action.try_into()?;
990 let hash = DhtOpHash::with_data_sync(&ChainOpUniqueForm::RegisterAddLink(&action));
991 Ok((action.into(), hash))
992 }
993 ChainOpType::RegisterRemoveLink => {
994 let action = action.try_into()?;
995 let hash =
996 DhtOpHash::with_data_sync(&ChainOpUniqueForm::RegisterRemoveLink(&action));
997 Ok((action.into(), hash))
998 }
999 }
1000 }
1001}
1002
1003pub fn produce_ops_from_record(record: &Record) -> DhtOpResult<Vec<ChainOp>> {
1005 let op_lites = produce_op_lites_from_records(vec![record])?;
1006 let (shh, entry) = record.clone().into_inner();
1007 let SignedActionHashed {
1008 hashed: ActionHashed {
1009 content: action, ..
1010 },
1011 signature,
1012 } = shh;
1013
1014 let mut ops = Vec::with_capacity(op_lites.len());
1015
1016 for op_light in op_lites {
1017 let signature = signature.clone();
1018 let action = action.clone();
1019 let op = match op_light {
1020 ChainOpLite::StoreRecord(_, _, _) => {
1021 ChainOp::StoreRecord(signature, action, entry.clone())
1022 }
1023 ChainOpLite::StoreEntry(_, _, _) => {
1024 let new_entry_action = action.clone().try_into()?;
1025 let e = match entry.clone().into_option() {
1026 Some(e) => e,
1027 None => {
1028 continue;
1030 }
1031 };
1032 ChainOp::StoreEntry(signature, new_entry_action, e)
1033 }
1034 ChainOpLite::RegisterAgentActivity(_, _) => {
1035 ChainOp::RegisterAgentActivity(signature, action)
1036 }
1037 ChainOpLite::RegisterUpdatedContent(_, _, _) => {
1038 let entry_update = action.try_into()?;
1039 ChainOp::RegisterUpdatedContent(signature, entry_update, entry.clone())
1040 }
1041 ChainOpLite::RegisterUpdatedRecord(_, _, _) => {
1042 let entry_update = action.try_into()?;
1043 ChainOp::RegisterUpdatedRecord(signature, entry_update, entry.clone())
1044 }
1045 ChainOpLite::RegisterDeletedEntryAction(_, _) => {
1046 let record_delete = action.try_into()?;
1047 ChainOp::RegisterDeletedEntryAction(signature, record_delete)
1048 }
1049 ChainOpLite::RegisterDeletedBy(_, _) => {
1050 let record_delete = action.try_into()?;
1051 ChainOp::RegisterDeletedBy(signature, record_delete)
1052 }
1053 ChainOpLite::RegisterAddLink(_, _) => {
1054 let link_add = action.try_into()?;
1055 ChainOp::RegisterAddLink(signature, link_add)
1056 }
1057 ChainOpLite::RegisterRemoveLink(_, _) => {
1058 let link_remove = action.try_into()?;
1059 ChainOp::RegisterRemoveLink(signature, link_remove)
1060 }
1061 };
1062 ops.push(op);
1063 }
1064 Ok(ops)
1065}
1066
1067pub fn produce_op_lites_from_records(actions: Vec<&Record>) -> DhtOpResult<Vec<ChainOpLite>> {
1069 let actions_and_hashes = actions.into_iter().map(|e| {
1070 (
1071 e.action_address(),
1072 e.action(),
1073 e.action().entry_data().map(|(h, _)| h.clone()),
1074 )
1075 });
1076 produce_op_lites_from_iter(actions_and_hashes)
1077}
1078
1079pub fn produce_op_lites_from_record_group(
1082 records: &RecordGroup<'_>,
1083) -> DhtOpResult<Vec<ChainOpLite>> {
1084 let actions_and_hashes = records.actions_and_hashes();
1085 let maybe_entry_hash = Some(records.entry_hash());
1086 produce_op_lites_from_parts(actions_and_hashes, maybe_entry_hash)
1087}
1088
1089fn produce_op_lites_from_parts<'a>(
1091 actions_and_hashes: impl Iterator<Item = (&'a ActionHash, &'a Action)>,
1092 maybe_entry_hash: Option<&EntryHash>,
1093) -> DhtOpResult<Vec<ChainOpLite>> {
1094 let iter = actions_and_hashes.map(|(head, hash)| (head, hash, maybe_entry_hash.cloned()));
1095 produce_op_lites_from_iter(iter)
1096}
1097
1098pub fn produce_op_lites_from_iter<'a>(
1100 iter: impl Iterator<Item = (&'a ActionHash, &'a Action, Option<EntryHash>)>,
1101) -> DhtOpResult<Vec<ChainOpLite>> {
1102 let mut ops = Vec::new();
1103
1104 for (action_hash, action, maybe_entry_hash) in iter {
1105 let op_lites = action_to_op_types(action)
1106 .into_iter()
1107 .filter_map(|op_type| {
1108 let op_light = match (op_type, action) {
1109 (ChainOpType::StoreRecord, _) => {
1110 let store_record_basis = ChainOpUniqueForm::StoreRecord(action).basis();
1111 ChainOpLite::StoreRecord(
1112 action_hash.clone(),
1113 maybe_entry_hash.clone(),
1114 store_record_basis,
1115 )
1116 }
1117 (ChainOpType::RegisterAgentActivity, _) => {
1118 let register_activity_basis =
1119 ChainOpUniqueForm::RegisterAgentActivity(action).basis();
1120 ChainOpLite::RegisterAgentActivity(
1121 action_hash.clone(),
1122 register_activity_basis,
1123 )
1124 }
1125 (ChainOpType::StoreEntry, Action::Create(create)) => ChainOpLite::StoreEntry(
1126 action_hash.clone(),
1127 maybe_entry_hash.clone()?,
1128 ChainOpUniqueForm::StoreEntry(&NewEntryAction::Create(create.clone()))
1129 .basis(),
1130 ),
1131 (ChainOpType::StoreEntry, Action::Update(update)) => ChainOpLite::StoreEntry(
1132 action_hash.clone(),
1133 maybe_entry_hash.clone()?,
1134 ChainOpUniqueForm::StoreEntry(&NewEntryAction::Update(update.clone()))
1135 .basis(),
1136 ),
1137 (ChainOpType::RegisterUpdatedContent, Action::Update(update)) => {
1138 ChainOpLite::RegisterUpdatedContent(
1139 action_hash.clone(),
1140 maybe_entry_hash.clone()?,
1141 ChainOpUniqueForm::RegisterUpdatedContent(update).basis(),
1142 )
1143 }
1144 (ChainOpType::RegisterUpdatedRecord, Action::Update(update)) => {
1145 ChainOpLite::RegisterUpdatedRecord(
1146 action_hash.clone(),
1147 maybe_entry_hash.clone()?,
1148 ChainOpUniqueForm::RegisterUpdatedRecord(update).basis(),
1149 )
1150 }
1151 (ChainOpType::RegisterDeletedBy, Action::Delete(delete)) => {
1152 ChainOpLite::RegisterDeletedBy(
1153 action_hash.clone(),
1154 ChainOpUniqueForm::RegisterDeletedBy(delete).basis(),
1155 )
1156 }
1157 (ChainOpType::RegisterDeletedEntryAction, Action::Delete(delete)) => {
1158 ChainOpLite::RegisterDeletedEntryAction(
1159 action_hash.clone(),
1160 ChainOpUniqueForm::RegisterDeletedEntryAction(delete).basis(),
1161 )
1162 }
1163 (ChainOpType::RegisterAddLink, Action::CreateLink(create_link)) => {
1164 ChainOpLite::RegisterAddLink(
1165 action_hash.clone(),
1166 ChainOpUniqueForm::RegisterAddLink(create_link).basis(),
1167 )
1168 }
1169 (ChainOpType::RegisterRemoveLink, Action::DeleteLink(delete_link)) => {
1170 ChainOpLite::RegisterRemoveLink(
1171 action_hash.clone(),
1172 ChainOpUniqueForm::RegisterRemoveLink(delete_link).basis(),
1173 )
1174 }
1175 _ => return None,
1176 };
1177 Some(op_light)
1178 });
1179 ops.extend(op_lites);
1180 }
1181 Ok(ops)
1182}
1183
1184pub fn action_to_op_types(action: &Action) -> Vec<ChainOpType> {
1186 match action {
1187 Action::Dna(_)
1188 | Action::OpenChain(_)
1189 | Action::CloseChain(_)
1190 | Action::AgentValidationPkg(_)
1191 | Action::InitZomesComplete(_) => {
1192 vec![ChainOpType::StoreRecord, ChainOpType::RegisterAgentActivity]
1193 }
1194 Action::CreateLink(_) => vec![
1195 ChainOpType::StoreRecord,
1196 ChainOpType::RegisterAgentActivity,
1197 ChainOpType::RegisterAddLink,
1198 ],
1199
1200 Action::DeleteLink(_) => vec![
1201 ChainOpType::StoreRecord,
1202 ChainOpType::RegisterAgentActivity,
1203 ChainOpType::RegisterRemoveLink,
1204 ],
1205 Action::Create(_) => vec![
1206 ChainOpType::StoreRecord,
1207 ChainOpType::RegisterAgentActivity,
1208 ChainOpType::StoreEntry,
1209 ],
1210 Action::Update(_) => vec![
1211 ChainOpType::StoreRecord,
1212 ChainOpType::RegisterAgentActivity,
1213 ChainOpType::StoreEntry,
1214 ChainOpType::RegisterUpdatedContent,
1215 ChainOpType::RegisterUpdatedRecord,
1216 ],
1217 Action::Delete(_) => vec![
1218 ChainOpType::StoreRecord,
1219 ChainOpType::RegisterAgentActivity,
1220 ChainOpType::RegisterDeletedBy,
1221 ChainOpType::RegisterDeletedEntryAction,
1222 ],
1223 }
1224}
1225
1226impl<'a> TryFrom<&ChainOpUniqueForm<'a>> for SerializedBytes {
1230 type Error = SerializedBytesError;
1231 fn try_from(u: &ChainOpUniqueForm<'a>) -> Result<Self, Self::Error> {
1232 match holochain_serialized_bytes::encode(u) {
1233 Ok(v) => Ok(SerializedBytes::from(
1234 holochain_serialized_bytes::UnsafeBytes::from(v),
1235 )),
1236 Err(e) => Err(SerializedBytesError::Serialize(e.to_string())),
1237 }
1238 }
1239}
1240
1241pub type DhtOpHashed = HoloHashed<DhtOp>;
1243
1244pub type ChainOpHashed = HoloHashed<ChainOp>;
1246
1247impl HashableContent for DhtOp {
1248 type HashType = hash_type::DhtOp;
1249
1250 fn hash_type(&self) -> Self::HashType {
1251 hash_type::DhtOp
1252 }
1253
1254 fn hashable_content(&self) -> HashableContentBytes {
1255 match self {
1256 DhtOp::ChainOp(op) => op.hashable_content(),
1257 DhtOp::WarrantOp(op) => op.hashable_content(),
1258 }
1259 }
1260}
1261
1262impl HashableContent for ChainOp {
1263 type HashType = hash_type::DhtOp;
1264
1265 fn hash_type(&self) -> Self::HashType {
1266 hash_type::DhtOp
1267 }
1268
1269 fn hashable_content(&self) -> HashableContentBytes {
1270 HashableContentBytes::Content(
1271 (&self.as_unique_form())
1272 .try_into()
1273 .expect("Could not serialize HashableContent"),
1274 )
1275 }
1276}
1277
1278impl HashableContent for ChainOpUniqueForm<'_> {
1279 type HashType = hash_type::DhtOp;
1280
1281 fn hash_type(&self) -> Self::HashType {
1282 hash_type::DhtOp
1283 }
1284
1285 fn hashable_content(&self) -> HashableContentBytes {
1286 HashableContentBytes::Content(
1287 UnsafeBytes::from(
1288 holochain_serialized_bytes::encode(self)
1289 .expect("Could not serialize HashableContent"),
1290 )
1291 .into(),
1292 )
1293 }
1294}
1295
1296#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, SerializedBytes)]
1297pub enum WireOps {
1299 Entry(WireEntryOps),
1301 Record(WireRecordOps),
1303 Warrant(Box<WarrantOp>),
1306}
1307
1308impl WireOps {
1309 pub fn render(self) -> DhtOpResult<RenderedOps> {
1311 match self {
1312 WireOps::Entry(o) => o.render(),
1313 WireOps::Record(o) => o.render(),
1314 WireOps::Warrant(warrant) => Ok(RenderedOps {
1315 entry: Default::default(),
1316 ops: Default::default(),
1317 warrant: Some(*warrant),
1318 }),
1319 }
1320 }
1321}
1322
1323#[derive(Debug, PartialEq, Eq, Clone)]
1324pub struct RenderedOp {
1326 pub action: SignedActionHashed,
1328 pub op_light: DhtOpLite,
1330 pub op_hash: DhtOpHash,
1332 pub validation_status: Option<ValidationStatus>,
1334}
1335
1336impl RenderedOp {
1337 pub fn new(
1341 action: Action,
1342 signature: Signature,
1343 validation_status: Option<ValidationStatus>,
1344 op_type: ChainOpType,
1345 ) -> DhtOpResult<Self> {
1346 let (action, op_hash) = ChainOpUniqueForm::op_hash(op_type, action)?;
1347 let action_hashed = ActionHashed::from_content_sync(action);
1348 let action = SignedActionHashed::with_presigned(action_hashed, signature);
1350 let op_light =
1351 ChainOpLite::from_type(op_type, action.as_hash().clone(), action.action())?.into();
1352 Ok(Self {
1353 action,
1354 op_light,
1355 op_hash,
1356 validation_status,
1357 })
1358 }
1359}
1360
1361#[derive(Debug, PartialEq, Eq, Clone, Default)]
1362pub struct RenderedOps {
1366 pub entry: Option<EntryHashed>,
1368 pub ops: Vec<RenderedOp>,
1370 pub warrant: Option<WarrantOp>,
1374}
1375
1376#[allow(missing_docs)]
1380#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
1381pub enum OpNumericalOrder {
1382 RegisterAgentActivity = 0,
1383 StoreEntry,
1384 StoreRecord,
1385 RegisterUpdatedContent,
1386 RegisterUpdatedRecord,
1387 RegisterDeletedBy,
1388 RegisterDeletedEntryAction,
1389 RegisterAddLink,
1390 RegisterRemoveLink,
1391 ChainIntegrityWarrant,
1392}
1393
1394#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
1398pub struct OpOrder {
1399 order: OpNumericalOrder,
1400 timestamp: holochain_zome_types::timestamp::Timestamp,
1401}
1402
1403impl std::fmt::Display for OpOrder {
1404 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1405 write!(
1406 f,
1407 "{}{:019}",
1408 self.order as u8,
1409 i64::max(0, self.timestamp.as_micros())
1411 )
1412 }
1413}
1414
1415impl OpOrder {
1416 pub fn new(
1418 op_type: impl Into<DhtOpType>,
1419 timestamp: holochain_zome_types::timestamp::Timestamp,
1420 ) -> Self {
1421 let order = match op_type.into() {
1422 DhtOpType::Chain(ChainOpType::StoreRecord) => OpNumericalOrder::StoreRecord,
1423 DhtOpType::Chain(ChainOpType::StoreEntry) => OpNumericalOrder::StoreEntry,
1424 DhtOpType::Chain(ChainOpType::RegisterAgentActivity) => {
1425 OpNumericalOrder::RegisterAgentActivity
1426 }
1427 DhtOpType::Chain(ChainOpType::RegisterUpdatedContent) => {
1428 OpNumericalOrder::RegisterUpdatedContent
1429 }
1430 DhtOpType::Chain(ChainOpType::RegisterUpdatedRecord) => {
1431 OpNumericalOrder::RegisterUpdatedRecord
1432 }
1433 DhtOpType::Chain(ChainOpType::RegisterDeletedBy) => OpNumericalOrder::RegisterDeletedBy,
1434 DhtOpType::Chain(ChainOpType::RegisterDeletedEntryAction) => {
1435 OpNumericalOrder::RegisterDeletedEntryAction
1436 }
1437 DhtOpType::Chain(ChainOpType::RegisterAddLink) => OpNumericalOrder::RegisterAddLink,
1438 DhtOpType::Chain(ChainOpType::RegisterRemoveLink) => {
1439 OpNumericalOrder::RegisterRemoveLink
1440 }
1441 DhtOpType::Warrant(WarrantOpType::ChainIntegrityWarrant) => {
1442 OpNumericalOrder::ChainIntegrityWarrant
1443 }
1444 };
1445 Self { order, timestamp }
1446 }
1447}
1448
1449impl holochain_sqlite::rusqlite::ToSql for OpOrder {
1450 fn to_sql(
1451 &self,
1452 ) -> holochain_sqlite::rusqlite::Result<holochain_sqlite::rusqlite::types::ToSqlOutput> {
1453 Ok(holochain_sqlite::rusqlite::types::ToSqlOutput::Owned(
1454 self.to_string().into(),
1455 ))
1456 }
1457}