Skip to content
This repository has been archived by the owner on Feb 3, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1932 from holochain/fallback-build-validation-pac…
Browse files Browse the repository at this point in the history
…kages-dht-with-smart-validation

Add ability to validate entries with full chain validation when author is offline
  • Loading branch information
zippy authored Dec 9, 2019
2 parents bf9a155 + b9f3100 commit 70ed96c
Show file tree
Hide file tree
Showing 20 changed files with 624 additions and 63 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG-UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Added

- Adds smarter ordering of pending validation. Builds a dependency graph and only will try to validate entries that do not have dependencies also awaiting validation as this will always fail. [#1924](https://github.com/holochain/holochain-rust/pull/1924)
- Adds support for [hApp-bundles](https://github.com/holochain/holoscape/tree/master/example-bundles) to `hc run`. This enables complex hApp setups with multiple DNAs and bridges to be easily run during development without having to write/maintain a conductor config file. [#1939](https://github.com/holochain/holochain-rust/pull/1939)
- Adds ability to validate entries with full chain validation when author is offline [#1932](https://github.com/holochain/holochain-rust/pull/1932)

### Changed

Expand Down
44 changes: 22 additions & 22 deletions Cargo.lock

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

101 changes: 101 additions & 0 deletions app_spec/test/files/offline-validation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
const { one } = require('../config')

const delay = ms => new Promise(resolve => setTimeout(resolve, ms))

module.exports = scenario => {

scenario('Can retrieve header entries using get_entry', async (s, t) => {
const { alice, bob } = await s.players({ alice: one, bob: one })
await alice.spawn()
await bob.spawn()

await s.consistency()

// alice publishes a memo. This is private but should still publish a header
const create_result = await alice.call('app', "blog", "create_memo", { content: "private memo" })
t.comment(JSON.stringify(create_result))
t.equal(create_result.Ok.length, 46)
await s.consistency()

// get all the chain header hashes and check if they are retrievable
const maybe_chain_header_hashes = await alice.call('app', "blog", "get_chain_header_hashes", {})
t.ok(maybe_chain_header_hashes.Ok)
let chain_header_hashes = maybe_chain_header_hashes.Ok
t.equal(chain_header_hashes.length, 4) // dna, agentId, cap grant, memo

t.comment(JSON.stringify(chain_header_hashes))
let chain_headers = []

await s.consistency()

for (let i=0; i< chain_header_hashes.length; i++) {
// can use get_post because it just returns a raw entry given a hash
let header_hash = chain_header_hashes[i]
t.comment(header_hash)

// check bob can retrieve alices header entries
let header_bob = await bob.call('app', "blog", "get_post", { post_address: header_hash })
t.ok(header_bob.Ok)

chain_headers.push(header_bob.Ok)
}
t.comment(JSON.stringify(chain_headers))
})

scenario('Can perform validation of an entry while the author is offline', async (s, t) => {

const { alice, bob, carol } = await s.players({alice: one, bob: one, carol: one})
// alice and bob start online
await alice.spawn()
await s.consistency()
await bob.spawn()
await s.consistency()

// alice publishes the original entry. !This is an entry that requires full chain validation!
const initialContent = "Holo world y'all"
const params = { content: initialContent, in_reply_to: null }
const create_result = await alice.call('app', "blog", "create_post", params)
t.comment(JSON.stringify(create_result))
t.equal(create_result.Ok.length, 46)
await s.consistency()

t.comment('waiting for consistency between Alice and Bob')
// bob will receive the entry and hold it
await s.consistency()
t.comment('consistency has been reached')

// check bob got the content Ok
const bob_result = await bob.call('app', "blog", "get_post", { post_address: create_result.Ok })
t.ok(bob_result.Ok)
t.equal(JSON.parse(bob_result.Ok.App[1]).content, initialContent)

// alice then goes offline
t.comment('waiting for alice to go offline')
await alice.kill()
t.comment('alice has gone offline')

// carol then comes online, will receive the entry via gossip from bob and need to validate
// Since alice is offline the validation package cannot come direct and must
// be regenerated from the published headers (which bob should hold)
t.comment('waiting for Carol to come online')
await carol.spawn()
t.comment('Carol is online')

t.comment('Waiting for Carol to get all data via gossip')
await s.consistency()
t.comment('consistency has been reached')

await delay(50000) // keep this until consistency works with dynamic starting agents

// Bob now go offline to ensure the following get_post uses carols local store only
t.comment('waiting for Bob to go offline')
await bob.kill()
t.comment('Bob has gone offline')

t.comment('Waiting for Carol to get post')
const carol_result = await carol.call('app', "blog", "get_post", { post_address: create_result.Ok })
t.ok(carol_result.Ok, 'Carol get_post does not have truth Ok field')
t.equal(JSON.parse(carol_result.Ok.App[1]).content, initialContent)
})

}
3 changes: 2 additions & 1 deletion app_spec/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { Orchestrator, tapeExecutor, singleConductor, localOnly, combine, callSyn
// This constant serves as a check that we haven't accidentally disabled scenario tests.
// Try to keep this number as close as possible to the actual number of scenario tests.
// (But never over)
const MIN_EXPECTED_SCENARIOS = 30
const MIN_EXPECTED_SCENARIOS = 32

process.on('unhandledRejection', error => {
console.error('got unhandledRejection:', error);
Expand Down Expand Up @@ -41,6 +41,7 @@ require('./files/entry')(orchestrator.registerScenario)
require('./files/links')(orchestrator.registerScenario)
require('./files/memo')(orchestrator.registerScenario)
require('./files/crypto')(orchestrator.registerScenario)
require('./files/offline-validation')(orchestrator.registerScenario)
require('./multi-dna')(orchestrator.registerScenario)
// require('./validate-agent-test')(orchestrator.registerScenario)

Expand Down
11 changes: 11 additions & 0 deletions app_spec/zomes/blog/code/src/blog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,17 @@ pub fn handle_get_post_bridged(post_address: Address) -> ZomeApiResult<Option<En
entry
}

pub fn handle_get_chain_header_hashes() -> ZomeApiResult<Vec<Address>> {
match hdk::query_result("**".into(), QueryArgsOptions{ headers: true, ..Default::default()})? {
QueryResult::Headers(headers) => {
Ok(headers.iter().map(|header| {
header.address()
}).collect())
}
_ => unreachable!()
}
}

#[cfg(test)]
pub mod tests {

Expand Down
Loading

0 comments on commit 70ed96c

Please sign in to comment.