[Fix] Connection Management
This commit is contained in:
parent
9e9e3597da
commit
3f2ac18333
122 changed files with 19970 additions and 5263 deletions
132
iota-storage/tests/descriptor_lifecycle.rs
Normal file
132
iota-storage/tests/descriptor_lifecycle.rs
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
use iota_identity::{
|
||||
AuthorityKind, LocalNodeIdentity, LocalUserDescriptor, LocalUserId, PrincipalHome, PrincipalId,
|
||||
PrincipalStore, VerifiedPrincipalDescriptor,
|
||||
};
|
||||
use iota_storage::identity::SqlitePrincipalStore;
|
||||
use mtp::crypto::Keyring;
|
||||
|
||||
#[test]
|
||||
fn local_descriptor_revision_persists_changes_and_retirement() {
|
||||
let storage = tempfile::tempdir().unwrap();
|
||||
iota_util::file_util::configure_storage_directory(storage.path().to_owned());
|
||||
iota_storage::util::db::initialize_database().unwrap();
|
||||
|
||||
let identity = LocalNodeIdentity::from_keyring(Keyring::generate()).unwrap();
|
||||
let user_key = Keyring::generate();
|
||||
let mut user = LocalUserDescriptor {
|
||||
id: LocalUserId(9),
|
||||
username: "alice".into(),
|
||||
display_name: None,
|
||||
public_key: user_key.public_key_bundle().try_to_base64().unwrap(),
|
||||
};
|
||||
iota_storage::util::db::with_db(|connection| {
|
||||
connection.execute(
|
||||
"INSERT INTO users (user_id, username, public_key, created_at) VALUES (?1, ?2, ?3, ?4)",
|
||||
rusqlite::params![user.id.0, user.username, user.public_key, 1_i64],
|
||||
)?;
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let store = SqlitePrincipalStore;
|
||||
let home = PrincipalHome::Iota(identity.node_id().clone());
|
||||
store
|
||||
.ensure_local_principal(
|
||||
identity.authority_id(),
|
||||
AuthorityKind::Iota,
|
||||
&user,
|
||||
home.clone(),
|
||||
1_000,
|
||||
)
|
||||
.unwrap();
|
||||
let first = store.local_principal_descriptor(user.id).unwrap();
|
||||
assert_eq!(first.revision, 0);
|
||||
|
||||
store
|
||||
.ensure_local_principal(
|
||||
identity.authority_id(),
|
||||
AuthorityKind::Iota,
|
||||
&user,
|
||||
home.clone(),
|
||||
1_001,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
store.local_principal_descriptor(user.id).unwrap().revision,
|
||||
0
|
||||
);
|
||||
|
||||
user.display_name = Some("Alice".into());
|
||||
store
|
||||
.ensure_local_principal(
|
||||
identity.authority_id(),
|
||||
AuthorityKind::Iota,
|
||||
&user,
|
||||
home.clone(),
|
||||
1_002,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
store.local_principal_descriptor(user.id).unwrap().revision,
|
||||
1
|
||||
);
|
||||
|
||||
let replacement_key = Keyring::generate().public_key_bundle();
|
||||
user.public_key = replacement_key.try_to_base64().unwrap();
|
||||
store
|
||||
.ensure_local_principal(
|
||||
identity.authority_id(),
|
||||
AuthorityKind::Iota,
|
||||
&user,
|
||||
home.clone(),
|
||||
1_003,
|
||||
)
|
||||
.unwrap();
|
||||
let rotated = store.local_principal_descriptor(user.id).unwrap();
|
||||
assert_eq!(rotated.revision, 2);
|
||||
assert_eq!(rotated.public_keys.len(), 1);
|
||||
assert_eq!(
|
||||
rotated.public_keys[0].try_to_base64().unwrap(),
|
||||
replacement_key.try_to_base64().unwrap()
|
||||
);
|
||||
|
||||
let renewal_at = rotated.valid_until.unwrap() - 1;
|
||||
store
|
||||
.ensure_local_principal(
|
||||
identity.authority_id(),
|
||||
AuthorityKind::Iota,
|
||||
&user,
|
||||
home,
|
||||
renewal_at,
|
||||
)
|
||||
.unwrap();
|
||||
let renewed = store.local_principal_descriptor(user.id).unwrap();
|
||||
assert_eq!(renewed.revision, 3);
|
||||
let mut conflicting = renewed.clone();
|
||||
conflicting.display_name = Some("Changed without revision".into());
|
||||
assert!(
|
||||
store
|
||||
.upsert_remote_descriptor(
|
||||
&VerifiedPrincipalDescriptor::from_trusted_authority(conflicting).unwrap()
|
||||
)
|
||||
.is_err()
|
||||
);
|
||||
|
||||
store
|
||||
.retire_local_principal(user.id, renewal_at + 1)
|
||||
.unwrap();
|
||||
assert!(store.local_principal_descriptor(user.id).is_err());
|
||||
let principal = PrincipalId {
|
||||
authority: identity.authority_id().clone(),
|
||||
user_id: 9,
|
||||
};
|
||||
let retired = store.get_by_canonical_id(&principal).unwrap().unwrap();
|
||||
assert_eq!(retired.descriptor_revision, 4);
|
||||
assert!(
|
||||
store
|
||||
.upsert_remote_descriptor(
|
||||
&VerifiedPrincipalDescriptor::from_trusted_authority(first).unwrap()
|
||||
)
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
111
iota-storage/tests/node_directory.rs
Normal file
111
iota-storage/tests/node_directory.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
use iota_identity::{
|
||||
AuthorityLocator, LocalNodeIdentity, NodeDescriptor, NodeDirectory, NodeIdentityResolver,
|
||||
SignedNodeDescriptor,
|
||||
};
|
||||
use iota_storage::node_directory::SqliteNodeDirectory;
|
||||
use mtp::crypto::Keyring;
|
||||
|
||||
#[tokio::test]
|
||||
async fn node_directory_persists_identity_revision_endpoints_and_pins() {
|
||||
let storage = tempfile::tempdir().unwrap();
|
||||
iota_util::file_util::configure_storage_directory(storage.path().to_owned());
|
||||
iota_storage::util::db::initialize_database().unwrap();
|
||||
|
||||
let identity = LocalNodeIdentity::from_keyring(Keyring::generate()).unwrap();
|
||||
let endpoint = AuthorityLocator::new("iota.example.org:443").unwrap();
|
||||
let relay = AuthorityLocator::new("relay.example.org:443").unwrap();
|
||||
let now = iota_storage::util::sync::now_millis();
|
||||
let signed = SignedNodeDescriptor::sign(
|
||||
NodeDescriptor {
|
||||
node: identity.node_id().clone(),
|
||||
public_keys: identity.public_keys(),
|
||||
direct_endpoints: vec![endpoint.clone()],
|
||||
relay_hints: vec![relay.clone()],
|
||||
revision: 1,
|
||||
valid_until: Some(now + 60_000),
|
||||
},
|
||||
&identity,
|
||||
)
|
||||
.unwrap();
|
||||
let verified = signed.verify(None, now).unwrap();
|
||||
SqliteNodeDirectory
|
||||
.upsert_node_descriptor(&verified)
|
||||
.unwrap();
|
||||
SqliteNodeDirectory
|
||||
.pin_endpoint(&endpoint, identity.node_id(), now)
|
||||
.unwrap();
|
||||
let certificate = b"test certificate";
|
||||
SqliteNodeDirectory
|
||||
.pin_endpoint_certificate(&endpoint, certificate)
|
||||
.unwrap();
|
||||
SqliteNodeDirectory
|
||||
.record_successful_endpoint(identity.node_id(), &endpoint)
|
||||
.unwrap();
|
||||
|
||||
let resolved = SqliteNodeDirectory
|
||||
.resolve_node(identity.node_id())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(resolved.descriptor_revision, 1);
|
||||
assert_eq!(resolved.direct_endpoints, vec![endpoint.clone()]);
|
||||
assert_eq!(resolved.relay_hints, vec![relay]);
|
||||
assert_eq!(resolved.last_successful_endpoint, Some(endpoint.clone()));
|
||||
assert_eq!(
|
||||
SqliteNodeDirectory.pinned_node(&endpoint).unwrap(),
|
||||
Some(identity.node_id().clone())
|
||||
);
|
||||
assert_eq!(
|
||||
SqliteNodeDirectory
|
||||
.pinned_endpoint_certificate(&endpoint)
|
||||
.unwrap(),
|
||||
Some(certificate.to_vec())
|
||||
);
|
||||
assert!(
|
||||
SqliteNodeDirectory
|
||||
.pin_endpoint_certificate(&endpoint, b"changed certificate")
|
||||
.is_err()
|
||||
);
|
||||
|
||||
let stale = SignedNodeDescriptor::sign(
|
||||
NodeDescriptor {
|
||||
node: identity.node_id().clone(),
|
||||
public_keys: identity.public_keys(),
|
||||
direct_endpoints: Vec::new(),
|
||||
relay_hints: Vec::new(),
|
||||
revision: 0,
|
||||
valid_until: Some(now + 60_000),
|
||||
},
|
||||
&identity,
|
||||
)
|
||||
.unwrap()
|
||||
.verify(None, now)
|
||||
.unwrap();
|
||||
assert!(SqliteNodeDirectory.upsert_node_descriptor(&stale).is_err());
|
||||
|
||||
let conflicting = SignedNodeDescriptor::sign(
|
||||
NodeDescriptor {
|
||||
node: identity.node_id().clone(),
|
||||
public_keys: identity.public_keys(),
|
||||
direct_endpoints: Vec::new(),
|
||||
relay_hints: Vec::new(),
|
||||
revision: 1,
|
||||
valid_until: Some(now + 60_000),
|
||||
},
|
||||
&identity,
|
||||
)
|
||||
.unwrap()
|
||||
.verify(None, now)
|
||||
.unwrap();
|
||||
assert!(
|
||||
SqliteNodeDirectory
|
||||
.upsert_node_descriptor(&conflicting)
|
||||
.is_err()
|
||||
);
|
||||
|
||||
let other = LocalNodeIdentity::from_keyring(Keyring::generate()).unwrap();
|
||||
assert!(
|
||||
SqliteNodeDirectory
|
||||
.pin_endpoint(&endpoint, other.node_id(), now + 1)
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
60
iota-storage/tests/pending_retry.rs
Normal file
60
iota-storage/tests/pending_retry.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
use iota_identity::{IotaNodeId, PrincipalHandle};
|
||||
use iota_storage::util::relay_queue::{
|
||||
self, PendingRelayDeliveryState, RelayIdentity, RelayTarget,
|
||||
};
|
||||
use mtp::crypto::Keyring;
|
||||
|
||||
#[test]
|
||||
fn pending_iota_relay_uses_bounded_backoff_and_quarantine() {
|
||||
let storage = tempfile::tempdir().unwrap();
|
||||
iota_util::file_util::configure_storage_directory(storage.path().to_owned());
|
||||
iota_storage::util::db::initialize_database().unwrap();
|
||||
let (signer, recipient) = iota_storage::util::db::with_db(|connection| {
|
||||
connection.execute(
|
||||
"INSERT INTO principals (authority_kind, authority_id, remote_user_id, descriptor_revision, last_resolved_at) VALUES ('iota', 'iota:first', 1, 1, 1)",
|
||||
[],
|
||||
)?;
|
||||
let signer = connection.last_insert_rowid();
|
||||
connection.execute(
|
||||
"INSERT INTO principals (authority_kind, authority_id, remote_user_id, descriptor_revision, last_resolved_at) VALUES ('iota', 'iota:second', 1, 1, 1)",
|
||||
[],
|
||||
)?;
|
||||
Ok((signer, connection.last_insert_rowid()))
|
||||
})
|
||||
.unwrap();
|
||||
let node = IotaNodeId::from_public_keys(&Keyring::generate().public_key_bundle()).unwrap();
|
||||
relay_queue::enqueue(
|
||||
RelayTarget::Iota(node),
|
||||
&RelayIdentity {
|
||||
signer: PrincipalHandle(signer),
|
||||
recipient: PrincipalHandle(recipient),
|
||||
message_id: "retry".into(),
|
||||
legacy_signer_id: Some(1),
|
||||
legacy_recipient_id: Some(1),
|
||||
},
|
||||
&[1, 2, 3],
|
||||
1,
|
||||
7,
|
||||
"1.0",
|
||||
)
|
||||
.unwrap();
|
||||
let id = relay_queue::list(1).unwrap()[0].id;
|
||||
let now = iota_storage::util::sync::now_millis();
|
||||
|
||||
for attempt in 0..8 {
|
||||
relay_queue::record_retry(id, now, "offline").unwrap();
|
||||
let relay = relay_queue::list(1).unwrap().remove(0);
|
||||
let exponent = attempt.min(6);
|
||||
let expected_delay = (5_000_i64 * (1_i64 << exponent)).min(300_000);
|
||||
assert_eq!(relay.attempt_count, attempt + 1);
|
||||
assert_eq!(relay.last_attempt_at, Some(now));
|
||||
assert_eq!(relay.next_attempt_at, now + expected_delay);
|
||||
assert_eq!(relay.last_error.as_deref(), Some("offline"));
|
||||
}
|
||||
assert!(relay_queue::list_active(1).unwrap().is_empty());
|
||||
|
||||
relay_queue::quarantine_for_frame(7, "wrong acknowledgement").unwrap();
|
||||
let relay = relay_queue::list(1).unwrap().remove(0);
|
||||
assert_eq!(relay.delivery_state, PendingRelayDeliveryState::Quarantined);
|
||||
assert_eq!(relay.last_error.as_deref(), Some("wrong acknowledgement"));
|
||||
}
|
||||
Loading…
Reference in a new issue