1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use ::fixt::prelude::*;
use holo_hash::AgentPubKey;
use holo_hash::EntryHash;
use holo_hash::HeaderHash;
use holochain_types::activity::ChainItems;
use holochain_types::dht_op::DhtOp;
use holochain_types::dht_op::DhtOpHashed;

use holochain_zome_types::*;

#[derive(Debug)]
pub struct ActivityTestData {
    pub hash_ops: Vec<DhtOpHashed>,
    pub noise_ops: Vec<DhtOpHashed>,
    pub store_ops: Vec<DhtOpHashed>,
    pub agent: AgentPubKey,
    pub query_filter: ChainQueryFilter,
    pub valid_hashes: ChainItems<HeaderHash>,
    pub valid_elements: ChainItems<Element>,
    pub chain_head: ChainHead,
    pub highest_observed: HighestObserved,
}

impl ActivityTestData {
    pub fn valid_chain_scenario() -> Self {
        // The agent we are querying.
        let agent = fixt!(AgentPubKey);

        // An entry that all headers can use to make things simpler.
        let entry = Entry::App(fixt!(AppEntryBytes));
        let entry_hash = EntryHash::with_data_sync(&entry);

        let to_op =
            |h| DhtOpHashed::from_content_sync(DhtOp::RegisterAgentActivity(fixt!(Signature), h));

        let to_element_and_op = |h: Header| {
            let sig = fixt!(Signature);
            // let e = Entry::App(fixt!(AppEntryBytes));
            let op = DhtOpHashed::from_content_sync(DhtOp::StoreElement(
                sig.clone(),
                h.clone(),
                Some(Box::new(entry.clone())),
            ));
            let shh = SignedHeaderHashed::with_presigned(HeaderHashed::from_content_sync(h), sig);
            (Element::new(shh, Some(entry.clone())), op)
        };

        let to_element_dna_op = |h: Header| {
            let sig = fixt!(Signature);
            let op =
                DhtOpHashed::from_content_sync(DhtOp::StoreElement(sig.clone(), h.clone(), None));
            let shh = SignedHeaderHashed::with_presigned(HeaderHashed::from_content_sync(h), sig);
            (Element::new(shh, None), op)
        };

        // The hashes we are expecting to get returned by the below activity set.
        let mut valid_hashes = Vec::new();

        // The elements on the chain. Needs to match the activity set.
        let mut valid_elements = Vec::new();

        // The store element ops for the actual data on the chain which should
        // match the set of activity ops.
        let mut store_ops = Vec::new();

        // A set of activity ops:
        // - Must be on the above agents chain.
        // - Create a valid, unbroken chain.
        // - All headers are valid:
        //    - Prev hash actually match prev header's hash
        //    - Seq numbers are in order.
        //    - First header must be a Dna.
        let mut hash_ops = Vec::new();
        let mut dna = fixt!(Dna);
        dna.author = agent.clone();
        let dna = Header::Dna(dna);

        // Insert the dna
        let (el, op) = to_element_dna_op(dna.clone());
        valid_elements.push(el);
        store_ops.push(op);
        hash_ops.push(to_op(dna.clone()));

        let creates: Vec<_> = CreateFixturator::new(Unpredictable)
            .enumerate()
            .take(50)
            .collect();
        let mut prev_hash = HeaderHash::with_data_sync(&dna);
        valid_hashes.push((0, prev_hash.clone()));
        for (seq, mut create) in creates {
            let header_seq = (seq + 1) as u32;
            create.author = agent.clone();
            create.header_seq = header_seq;
            create.prev_header = prev_hash.clone();
            create.entry_hash = entry_hash.clone();
            let header = Header::Create(create);
            prev_hash = HeaderHash::with_data_sync(&header);
            hash_ops.push(to_op(header.clone()));

            valid_hashes.push((header_seq, prev_hash.clone()));

            let (el, op) = to_element_and_op(header);
            valid_elements.push(el);
            store_ops.push(op);
        }

        // The head of the chain is the last valid hash
        // because we are going to insert all ops as valid and integrated.
        let last = valid_hashes.last().unwrap();
        let chain_head = ChainHead {
            header_seq: last.0,
            hash: last.1.clone(),
        };

        // Highest Observed is the same as the chain head.
        let highest_observed = HighestObserved {
            header_seq: last.0,
            hash: vec![last.1.clone()],
        };

        // We just want a simple query filter to get back the full chain.
        let query_filter = QueryFilter::new();

        // Finally add some random noise so we know we are getting the correct items.
        let noise_ops = HeaderFixturator::new(Unpredictable)
            .take(50)
            .map(to_op)
            .collect();

        Self {
            hash_ops,
            agent,
            query_filter,
            valid_hashes: ChainItems::Hashes(valid_hashes),
            highest_observed,
            chain_head,
            noise_ops,
            store_ops,
            valid_elements: ChainItems::Full(valid_elements),
        }
    }
}