Light friendly dapps (#5634)

* move native_contracts ABIs to JSON files, add urlhint

* port hash-fetch to futures, fix tests

* fix dapps compilation, defer async port to later

* activate dapps server in the light client

* better formatting
This commit is contained in:
Robert Habermeier
2017-05-18 12:44:09 +02:00
committed by Gav Wood
parent 95d9706fe1
commit b1eab698d2
23 changed files with 347 additions and 240 deletions

View File

@@ -87,6 +87,28 @@ impl From<io::Error> for Error {
}
}
fn validate_hash(path: PathBuf, hash: H256, result: Result<Response, FetchError>) -> Result<PathBuf, Error> {
let response = result?;
if !response.is_success() {
return Err(Error::InvalidStatus);
}
// Read the response
let mut reader = io::BufReader::new(response);
let mut writer = io::BufWriter::new(fs::File::create(&path)?);
io::copy(&mut reader, &mut writer)?;
writer.flush()?;
// And validate the hash
let mut file_reader = io::BufReader::new(fs::File::open(&path)?);
let content_hash = sha3(&mut file_reader)?;
if content_hash != hash {
Err(Error::HashMismatch{ got: content_hash, expected: hash })
} else {
Ok(path)
}
}
/// Default Hash-fetching client using on-chain contract to resolve hashes to URLs.
pub struct Client<F: Fetch + 'static = FetchClient> {
contract: URLHintContract,
@@ -103,7 +125,6 @@ impl Client {
}
impl<F: Fetch + 'static> Client<F> {
/// Creates new instance of the `Client` given on-chain contract client, fetch service and task runner.
pub fn with_fetch(contract: Arc<ContractClient>, fetch: F, remote: Remote) -> Self {
Client {
@@ -119,44 +140,22 @@ impl<F: Fetch + 'static> HashFetch for Client<F> {
fn fetch(&self, hash: H256, on_done: Box<Fn(Result<PathBuf, Error>) + Send>) {
debug!(target: "fetch", "Fetching: {:?}", hash);
let url = self.contract.resolve(hash.to_vec()).map(|content| match content {
URLHintResult::Dapp(dapp) => {
dapp.url()
},
URLHintResult::Content(content) => {
content.url
},
}).ok_or_else(|| Error::NoResolution);
debug!(target: "fetch", "Resolved {:?} to {:?}. Fetching...", hash, url);
match url {
Err(err) => on_done(Err(err)),
Ok(url) => {
let random_path = self.random_path.clone();
let future = self.fetch.fetch(&url).then(move |result| {
fn validate_hash(path: PathBuf, hash: H256, result: Result<Response, FetchError>) -> Result<PathBuf, Error> {
let response = result?;
if !response.is_success() {
return Err(Error::InvalidStatus);
}
// Read the response
let mut reader = io::BufReader::new(response);
let mut writer = io::BufWriter::new(fs::File::create(&path)?);
io::copy(&mut reader, &mut writer)?;
writer.flush()?;
// And validate the hash
let mut file_reader = io::BufReader::new(fs::File::open(&path)?);
let content_hash = sha3(&mut file_reader)?;
if content_hash != hash {
Err(Error::HashMismatch{ got: content_hash, expected: hash })
} else {
Ok(path)
}
}
let random_path = self.random_path.clone();
let remote_fetch = self.fetch.clone();
let future = self.contract.resolve(hash.to_vec())
.map_err(|e| { warn!("Error resolving URL: {}", e); Error::NoResolution })
.and_then(|maybe_url| maybe_url.ok_or(Error::NoResolution))
.map(|content| match content {
URLHintResult::Dapp(dapp) => {
dapp.url()
},
URLHintResult::Content(content) => {
content.url
},
})
.and_then(move |url| {
debug!(target: "fetch", "Resolved {:?} to {:?}. Fetching...", hash, url);
let future = remote_fetch.fetch(&url).then(move |result| {
debug!(target: "fetch", "Content fetched, validating hash ({:?})", hash);
let path = random_path();
let res = validate_hash(path.clone(), hash, result);
@@ -165,13 +164,13 @@ impl<F: Fetch + 'static> HashFetch for Client<F> {
// Remove temporary file in case of error
let _ = fs::remove_file(&path);
}
on_done(res);
Ok(()) as Result<(), ()>
res
});
self.remote.spawn(self.fetch.process(future));
},
}
remote_fetch.process(future)
})
.then(move |res| { on_done(res); Ok(()) as Result<(), ()> });
self.remote.spawn(future);
}
}
@@ -225,7 +224,7 @@ mod tests {
let mut registrar = FakeRegistrar::new();
registrar.responses = Mutex::new(vec![
Ok(format!("000000000000000000000000{}", URLHINT).from_hex().unwrap()),
Ok("00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000deadcafebeefbeefcafedeaddeedfeedffffffff000000000000000000000000000000000000000000000000000000000000003d68747470733a2f2f657468636f72652e696f2f6173736574732f696d616765732f657468636f72652d626c61636b2d686f72697a6f6e74616c2e706e67000000".from_hex().unwrap()),
Ok("00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000deadcafebeefbeefcafedeaddeedfeedffffffff000000000000000000000000000000000000000000000000000000000000003c68747470733a2f2f7061726974792e696f2f6173736574732f696d616765732f657468636f72652d626c61636b2d686f72697a6f6e74616c2e706e6700000000".from_hex().unwrap()),
]);
registrar
}