Skip to content
This repository was archived by the owner on Feb 28, 2025. It is now read-only.

Commit bb2c7d6

Browse files
authored
add timestamp to ethr builder (#48)
* add timestamp to ethr builder * improve coverage * add `get_query_value` fn to did_url * clippy * use AsRef<str> * timestamp -> block_timestamp, always return error * store block timestamp in seconds * fix bugs w.r.t byte conversions * remove constant use std::time::Duration * fmt
1 parent c7f7452 commit bb2c7d6

File tree

12 files changed

+310
-135
lines changed

12 files changed

+310
-135
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ tokio-test = "0.4"
5050
futures = "0.3"
5151
ctor = "0.2.5"
5252
surf = "2.3"
53+
regex = "1.10"
5354

5455
[features]
5556
default = []

lib/src/error.rs

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use ethers::{
33
contract::ContractError,
44
providers::{Middleware, ProviderError},
55
signers::WalletError,
6+
types::U64,
67
};
78
use jsonrpsee::types::ErrorObjectOwned;
89
use thiserror::Error;
@@ -16,6 +17,12 @@ pub enum ResolverError<M: Middleware> {
1617
ContractError(#[from] ContractError<M>),
1718
#[error("{0}")]
1819
Middleware(String),
20+
#[error("Block {0} containing Registry event not found")]
21+
MissingBlock(U64),
22+
#[error(transparent)]
23+
Time(#[from] ethers::core::types::TimeError),
24+
#[error("Block {0} timestamp out of range")]
25+
TimestampOutOfRange(U64),
1926
}
2027

2128
/// Errors originating from the parsing of a did url identifier, [`Did`](crate::types::DidUrl)

lib/src/resolver.rs

+56-6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,32 @@ impl<M> From<DIDRegistry<M>> for Resolver<M> {
2828
}
2929
}
3030

31+
/// Extra context passed to the document builder from the [`Resolver`]
32+
#[derive(Debug, Clone, PartialEq, Eq)]
33+
pub struct EventContext {
34+
/// the timestamp in seconds in which the block from the document was built.
35+
pub block_timestamp: u64,
36+
}
37+
38+
impl EventContext {
39+
pub async fn new<M: Middleware>(
40+
meta: &LogMeta,
41+
signer: impl Middleware,
42+
) -> Result<Self, ResolverError<M>> {
43+
let block = signer
44+
.get_block(meta.block_number)
45+
.await
46+
.map_err(|e| ResolverError::Middleware(e.to_string()))?;
47+
48+
let block_timestamp: u64 = block
49+
.ok_or(ResolverError::MissingBlock(meta.block_number))?
50+
.timestamp
51+
.as_u64();
52+
53+
Ok(Self { block_timestamp })
54+
}
55+
}
56+
3157
impl<M: Middleware + 'static> Resolver<M> {
3258
/// Instantiate a new did:ethr resolver
3359
pub async fn new(middleware: M, registry: Address) -> Result<Self, ResolverError<M>> {
@@ -83,21 +109,22 @@ impl<M: Middleware + 'static> Resolver<M> {
83109
Ok(history)
84110
}
85111

86-
fn dispatch_event(
112+
async fn dispatch_event(
87113
&self,
88114
doc: &mut EthrBuilder,
89115
address: H160,
90116
event: DIDRegistryEvents,
91117
meta: LogMeta,
92-
) {
118+
) -> Result<(), ResolverError<M>> {
119+
let context = EventContext::new(&meta, self.signer()).await?;
93120
let res = match event {
94121
DIDRegistryEvents::DiddelegateChangedFilter(delegate_changed) => {
95122
log::trace!("Delegate Changed {:?}", delegate_changed);
96-
doc.delegate_event(delegate_changed)
123+
doc.delegate_event(delegate_changed, &context)
97124
}
98125
DIDRegistryEvents::DidattributeChangedFilter(attribute_event) => {
99126
log::trace!("Attribute Changed {:?}", attribute_event);
100-
doc.attribute_event(attribute_event)
127+
doc.attribute_event(attribute_event, &context)
101128
}
102129
DIDRegistryEvents::DidownerChangedFilter(owner_changed) => {
103130
log::trace!("Owner Changed {:?}", owner_changed);
@@ -116,6 +143,7 @@ impl<M: Middleware + 'static> Resolver<M> {
116143
address, meta.block_number, meta.log_index, e,
117144
);
118145
};
146+
Ok(())
119147
}
120148

121149
async fn wrap_did_resolution(
@@ -150,7 +178,8 @@ impl<M: Middleware + 'static> Resolver<M> {
150178
if version_id.unwrap_or_default() > U64::zero() {
151179
if meta.block_number <= version_id.unwrap_or_default() {
152180
// 1. delegate events
153-
Resolver::dispatch_event(self, &mut base_document, address, event, meta);
181+
Resolver::dispatch_event(self, &mut base_document, address, event, meta)
182+
.await?;
154183
// 2. set latest version
155184
if current_version_id < block_number {
156185
current_version_id = block_number;
@@ -162,7 +191,7 @@ impl<M: Middleware + 'static> Resolver<M> {
162191
}
163192
} else {
164193
// 1. delegate events
165-
Resolver::dispatch_event(self, &mut base_document, address, event, meta);
194+
Resolver::dispatch_event(self, &mut base_document, address, event, meta).await?;
166195
// 2. set latest version
167196
if current_version_id < block_number {
168197
current_version_id = block_number;
@@ -216,6 +245,8 @@ impl<M: Middleware + 'static> Resolver<M> {
216245

217246
#[cfg(test)]
218247
mod tests {
248+
use ethers::{prelude::Provider, providers::MockProvider, types::TxHash};
249+
219250
use super::*;
220251

221252
#[test]
@@ -225,4 +256,23 @@ mod tests {
225256
let resolver = Resolver::from(registry);
226257
assert_eq!(resolver.registry.address(), Address::zero());
227258
}
259+
260+
#[tokio::test]
261+
async fn test_context_constructor() {
262+
let (provider, mock) = Provider::mocked();
263+
mock.push(Block::<TxHash>::default()).unwrap();
264+
265+
let meta = LogMeta {
266+
address: Address::zero(),
267+
block_hash: H256::zero(),
268+
block_number: U64::zero(),
269+
log_index: U256::zero(),
270+
transaction_hash: H256::zero(),
271+
transaction_index: U64::zero(),
272+
};
273+
let context = EventContext::new::<Provider<MockProvider>>(&meta, Arc::new(provider))
274+
.await
275+
.unwrap();
276+
assert_eq!(context.block_timestamp, 0);
277+
}
228278
}

lib/src/rpc/methods.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ impl<M: Middleware + 'static> DidRegistryServer for DidRegistryMethods<M> {
3434
) -> Result<DidResolutionResult, ErrorObjectOwned> {
3535
log::debug!("did_resolveDid called");
3636

37+
log::trace!("Resolving for key {}", &address);
38+
3739
// parse the version_id
3840
let parsed_version_id = version_id.map(|str| U64::from(u64::from_str(&str).unwrap()));
3941

@@ -43,9 +45,10 @@ impl<M: Middleware + 'static> DidRegistryServer for DidRegistryMethods<M> {
4345
H160::from_str(&address).map_err(RpcError::from)?,
4446
parsed_version_id,
4547
)
46-
.await?;
48+
.await;
49+
log::debug!("Resolution Result {:?}", resolution_result);
4750

48-
Ok(resolution_result)
51+
Ok(resolution_result?)
4952
}
5053
}
5154

lib/src/types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ impl From<Attribute> for [u8; 32] {
272272

273273
// internal function to fill a [u8; 32] with bytes.
274274
// anything over 32 bytes will be cutoff.
275-
fn string_to_bytes32<S: AsRef<str>>(s: S) -> [u8; 32] {
275+
pub fn string_to_bytes32<S: AsRef<str>>(s: S) -> [u8; 32] {
276276
let s = s.as_ref();
277277
let mut attr_bytes: [u8; 32] = [b' '; 32];
278278
let length = std::cmp::min(s.as_bytes().len(), 32);

lib/src/types/did_url.rs

+19
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,15 @@ impl DidUrl {
300300
minion
301301
}
302302

303+
/// get a query value based on its `key`
304+
pub fn get_query_value<S: AsRef<str>>(&self, key: S) -> Option<String> {
305+
self.query.as_ref().and_then(|q| {
306+
q.iter()
307+
.find(|(k, _)| k == key.as_ref())
308+
.map(|(_, v)| v.to_string())
309+
})
310+
}
311+
303312
/// Immutable copy constructor to add a query parameter to the DID URL.
304313
/// # Examples
305314
/// ```rust
@@ -745,4 +754,14 @@ mod tests {
745754
assert_eq!(Network::Sepolia.to_string(), "sepolia");
746755
assert_eq!(Network::Other(0x1a1).to_string(), "417");
747756
}
757+
758+
#[test]
759+
fn test_get_query_value() {
760+
let did_url = DidUrl::parse("did:ethr:mainnet:0x0000000000000000000000000000000000000000?meta=hi&username=&password=hunter2").unwrap();
761+
762+
assert_eq!(did_url.get_query_value("meta"), Some("hi".into()));
763+
assert_eq!(did_url.get_query_value("username"), Some("".into()));
764+
assert_eq!(did_url.get_query_value("password"), Some("hunter2".into()));
765+
assert_eq!(did_url.get_query_value("does_not_exist"), None);
766+
}
748767
}

0 commit comments

Comments
 (0)