language/diem-framework/modules/doc/NetworkIdentity.md
<a name="0x1_NetworkIdentity"></a>
0x1::NetworkIdentityModule managing Diemnet NetworkIdentity
NetworkIdentityNetworkIdentityEventHandleNetworkIdentityChangeNotificationinitialize_network_identity_event_handletc_network_identity_event_handle_existsinitialize_network_identitygetadd_identitiesremove_identitiesadd_members_internalremove_members_internal<a name="0x1_NetworkIdentity_NetworkIdentity"></a>
NetworkIdentityHolder for all <code><a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a></code> in an account
<pre><code><b>struct</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a> has key </code></pre> <details> <summary>Fields</summary> <dl> <dt> <code>identities: vector<vector<u8>></code> </dt> <dd> </dd> </dl> </details> <details> <summary>Specification</summary> <pre><code><b>include</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_UniqueMembers">UniqueMembers</a><vector<u8>> {members: identities}; </code></pre> </details><a name="0x1_NetworkIdentity_NetworkIdentityEventHandle"></a>
NetworkIdentityEventHandle<a name="0x1_NetworkIdentity_NetworkIdentityChangeNotification"></a>
NetworkIdentityChangeNotificationMessage sent when there are updates to the <code><a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a></code>.
<pre><code><b>struct</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_NetworkIdentityChangeNotification">NetworkIdentityChangeNotification</a> has drop, store </code></pre> <details> <summary>Fields</summary> <dl> <dt> <code>account: address</code> </dt> <dd> The address of the account that changed identities </dd> <dt> <code>identities: vector<vector<u8>></code> </dt> <dd> The new identities </dd> <dt> <code>time_rotated_seconds: u64</code> </dt> <dd> The time at which the <code>identities</code> was rotated </dd> </dl> </details><a name="@Constants_0"></a>
<a name="0x1_NetworkIdentity_ENETWORK_ID_DOESNT_EXIST"></a>
Network ID doesn't exist when trying to get it
<pre><code><b>const</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_ENETWORK_ID_DOESNT_EXIST">ENETWORK_ID_DOESNT_EXIST</a>: u64 = 0; </code></pre><a name="0x1_NetworkIdentity_ENETWORK_ID_EVENT_HANDLE_INVALID"></a>
Network identity event handle invalid
<pre><code><b>const</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_ENETWORK_ID_EVENT_HANDLE_INVALID">ENETWORK_ID_EVENT_HANDLE_INVALID</a>: u64 = 3; </code></pre><a name="0x1_NetworkIdentity_ENETWORK_ID_LIMIT_EXCEEDED"></a>
Limit exceeded on number of identities for an address
<pre><code><b>const</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_ENETWORK_ID_LIMIT_EXCEEDED">ENETWORK_ID_LIMIT_EXCEEDED</a>: u64 = 1; </code></pre><a name="0x1_NetworkIdentity_ENETWORK_ID_NO_INPUT"></a>
No identities provided for changes
<pre><code><b>const</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_ENETWORK_ID_NO_INPUT">ENETWORK_ID_NO_INPUT</a>: u64 = 2; </code></pre><a name="0x1_NetworkIdentity_MAX_ADDR_IDENTITIES"></a>
<pre><code><b>const</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_MAX_ADDR_IDENTITIES">MAX_ADDR_IDENTITIES</a>: u64 = 100; </code></pre><a name="0x1_NetworkIdentity_initialize_network_identity_event_handle"></a>
initialize_network_identity_event_handle<a name="0x1_NetworkIdentity_tc_network_identity_event_handle_exists"></a>
tc_network_identity_event_handle_exists<a name="0x1_NetworkIdentity_initialize_network_identity"></a>
initialize_network_identityInitialize <code><a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a></code> with an empty list
<pre><code><b>fun</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_initialize_network_identity">initialize_network_identity</a>(account: &signer) </code></pre> <details> <summary>Implementation</summary> <pre><code><b>fun</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_initialize_network_identity">initialize_network_identity</a>(account: &signer) { <b>let</b> identities = <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_empty">Vector::empty</a><vector<u8>>(); move_to(account, <a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a> { identities }); } </code></pre> </details> <details> <summary>Specification</summary> <pre><code><b>let</b> account_addr = <a href="../../../../../../move-stdlib/docs/Signer.md#0x1_Signer_spec_address_of">Signer::spec_address_of</a>(account); <b>modifies</b> <b>global</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr); </code></pre> </details><a name="0x1_NetworkIdentity_get"></a>
getReturn the underlying <code><a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a></code> bytes
<pre><code><b>public</b> <b>fun</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_get">get</a>(account_addr: address): vector<vector<u8>> </code></pre> <details> <summary>Implementation</summary> <pre><code><b>public</b> <b>fun</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_get">get</a>(account_addr: address): vector<vector<u8>> <b>acquires</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a> { <b>assert</b>( <b>exists</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr), <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_not_published">Errors::not_published</a>(<a href="NetworkIdentity.md#0x1_NetworkIdentity_ENETWORK_ID_DOESNT_EXIST">ENETWORK_ID_DOESNT_EXIST</a>) ); *&borrow_global<<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr).identities } </code></pre> </details> <details> <summary>Specification</summary> <pre><code><b>aborts_if</b> !<b>exists</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr) <b>with</b> <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_NOT_PUBLISHED">Errors::NOT_PUBLISHED</a>; <b>ensures</b> result == <b>global</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr).identities; </code></pre> </details><a name="0x1_NetworkIdentity_add_identities"></a>
add_identitiesUpdate and create if not exist <code><a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a></code>
<pre><code><b>public</b> <b>fun</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_add_identities">add_identities</a>(account: &signer, to_add: vector<vector<u8>>) </code></pre> <details> <summary>Implementation</summary> <pre><code><b>public</b> <b>fun</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_add_identities">add_identities</a>(account: &signer, to_add: vector<vector<u8>>) <b>acquires</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>, <a href="NetworkIdentity.md#0x1_NetworkIdentity_NetworkIdentityEventHandle">NetworkIdentityEventHandle</a> { <b>assert</b>(<a href="NetworkIdentity.md#0x1_NetworkIdentity_tc_network_identity_event_handle_exists">tc_network_identity_event_handle_exists</a>(), <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_not_published">Errors::not_published</a>(<a href="NetworkIdentity.md#0x1_NetworkIdentity_ENETWORK_ID_EVENT_HANDLE_INVALID">ENETWORK_ID_EVENT_HANDLE_INVALID</a>)); <b>let</b> num_to_add = <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_length">Vector::length</a>(&to_add); <b>assert</b>(num_to_add > 0, <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_invalid_argument">Errors::invalid_argument</a>(<a href="NetworkIdentity.md#0x1_NetworkIdentity_ENETWORK_ID_NO_INPUT">ENETWORK_ID_NO_INPUT</a>)); <b>if</b> (!<b>exists</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(<a href="../../../../../../move-stdlib/docs/Signer.md#0x1_Signer_address_of">Signer::address_of</a>(account))) { <a href="NetworkIdentity.md#0x1_NetworkIdentity_initialize_network_identity">initialize_network_identity</a>(account); }; <b>let</b> account_addr = <a href="../../../../../../move-stdlib/docs/Signer.md#0x1_Signer_address_of">Signer::address_of</a>(account); <b>let</b> identity = borrow_global_mut<<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr); <b>let</b> identities = &<b>mut</b> identity.identities; <b>assert</b>( <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_length">Vector::length</a>(identities) + num_to_add <= <a href="NetworkIdentity.md#0x1_NetworkIdentity_MAX_ADDR_IDENTITIES">MAX_ADDR_IDENTITIES</a>, <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_limit_exceeded">Errors::limit_exceeded</a>(<a href="NetworkIdentity.md#0x1_NetworkIdentity_ENETWORK_ID_LIMIT_EXCEEDED">ENETWORK_ID_LIMIT_EXCEEDED</a>) ); <b>let</b> has_change = <a href="NetworkIdentity.md#0x1_NetworkIdentity_add_members_internal">add_members_internal</a>(identities, &to_add); <b>if</b> (has_change) { <a href="../../../../../../move-stdlib/docs/Event.md#0x1_Event_emit_event">Event::emit_event</a>( &<b>mut</b> borrow_global_mut<<a href="NetworkIdentity.md#0x1_NetworkIdentity_NetworkIdentityEventHandle">NetworkIdentityEventHandle</a>>(@TreasuryCompliance).identity_change_events, <a href="NetworkIdentity.md#0x1_NetworkIdentity_NetworkIdentityChangeNotification">NetworkIdentityChangeNotification</a> { account: account_addr, identities: *&identity.identities, time_rotated_seconds: <a href="DiemTimestamp.md#0x1_DiemTimestamp_now_seconds">DiemTimestamp::now_seconds</a>(), } ); } } </code></pre> </details> <details> <summary>Specification</summary> <pre><code><b>pragma</b> verify=<b>false</b>; <b>let</b> account_addr = <a href="../../../../../../move-stdlib/docs/Signer.md#0x1_Signer_spec_address_of">Signer::spec_address_of</a>(account); <b>let</b> prior_identities = <b>if</b> (<b>exists</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr)) { <b>global</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr).identities } <b>else</b> { vec() }; <b>let</b> has_change = (<b>exists</b> e in to_add: !contains(prior_identities, e)); <b>let</b> post handle = <b>global</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity_NetworkIdentityEventHandle">NetworkIdentityEventHandle</a>>(@TreasuryCompliance).identity_change_events; <b>let</b> post msg = <a href="NetworkIdentity.md#0x1_NetworkIdentity_NetworkIdentityChangeNotification">NetworkIdentityChangeNotification</a> { account: account_addr, identities: <b>global</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr).identities, time_rotated_seconds: <a href="DiemTimestamp.md#0x1_DiemTimestamp_spec_now_seconds">DiemTimestamp::spec_now_seconds</a>(), }; <b>aborts_if</b> !<a href="NetworkIdentity.md#0x1_NetworkIdentity_tc_network_identity_event_handle_exists">tc_network_identity_event_handle_exists</a>() <b>with</b> <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_NOT_PUBLISHED">Errors::NOT_PUBLISHED</a>; <b>aborts_if</b> len(to_add) == 0 <b>with</b> <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_INVALID_ARGUMENT">Errors::INVALID_ARGUMENT</a>; <b>aborts_if</b> len(prior_identities) + len(to_add) > MAX_U64; <b>aborts_if</b> len(prior_identities) + len(to_add) > <a href="NetworkIdentity.md#0x1_NetworkIdentity_MAX_ADDR_IDENTITIES">MAX_ADDR_IDENTITIES</a> <b>with</b> <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_LIMIT_EXCEEDED">Errors::LIMIT_EXCEEDED</a>; <b>include</b> has_change ==> <a href="DiemTimestamp.md#0x1_DiemTimestamp_AbortsIfNotOperating">DiemTimestamp::AbortsIfNotOperating</a>; <b>include</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_AddMembersInternalEnsures">AddMembersInternalEnsures</a><vector<u8>> { old_members: prior_identities, new_members: <b>global</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr).identities, }; <b>modifies</b> <b>global</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr); emits msg <b>to</b> handle <b>if</b> has_change; </code></pre> </details><a name="0x1_NetworkIdentity_remove_identities"></a>
remove_identitiesRemove <code><a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a></code>, skipping if it doesn't exist
<pre><code><b>public</b> <b>fun</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_remove_identities">remove_identities</a>(account: &signer, to_remove: vector<vector<u8>>) </code></pre> <details> <summary>Implementation</summary> <pre><code><b>public</b> <b>fun</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_remove_identities">remove_identities</a>(account: &signer, to_remove: vector<vector<u8>>) <b>acquires</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>, <a href="NetworkIdentity.md#0x1_NetworkIdentity_NetworkIdentityEventHandle">NetworkIdentityEventHandle</a> { <b>assert</b>(<a href="NetworkIdentity.md#0x1_NetworkIdentity_tc_network_identity_event_handle_exists">tc_network_identity_event_handle_exists</a>(), <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_not_published">Errors::not_published</a>(<a href="NetworkIdentity.md#0x1_NetworkIdentity_ENETWORK_ID_EVENT_HANDLE_INVALID">ENETWORK_ID_EVENT_HANDLE_INVALID</a>)); <b>let</b> num_to_remove = <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_length">Vector::length</a>(&to_remove); <b>assert</b>(num_to_remove > 0, <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_invalid_argument">Errors::invalid_argument</a>(<a href="NetworkIdentity.md#0x1_NetworkIdentity_ENETWORK_ID_NO_INPUT">ENETWORK_ID_NO_INPUT</a>)); <b>assert</b>( num_to_remove <= <a href="NetworkIdentity.md#0x1_NetworkIdentity_MAX_ADDR_IDENTITIES">MAX_ADDR_IDENTITIES</a>, <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_limit_exceeded">Errors::limit_exceeded</a>(<a href="NetworkIdentity.md#0x1_NetworkIdentity_ENETWORK_ID_LIMIT_EXCEEDED">ENETWORK_ID_LIMIT_EXCEEDED</a>) ); <b>let</b> account_addr = <a href="../../../../../../move-stdlib/docs/Signer.md#0x1_Signer_address_of">Signer::address_of</a>(account); <b>assert</b>( <b>exists</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr), <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_not_published">Errors::not_published</a>(<a href="NetworkIdentity.md#0x1_NetworkIdentity_ENETWORK_ID_DOESNT_EXIST">ENETWORK_ID_DOESNT_EXIST</a>) ); <b>let</b> identity = borrow_global_mut<<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr); <b>let</b> identities = &<b>mut</b> identity.identities; <b>let</b> has_change = <a href="NetworkIdentity.md#0x1_NetworkIdentity_remove_members_internal">remove_members_internal</a>(identities, &to_remove); <b>if</b> (has_change) { <a href="../../../../../../move-stdlib/docs/Event.md#0x1_Event_emit_event">Event::emit_event</a>( &<b>mut</b> borrow_global_mut<<a href="NetworkIdentity.md#0x1_NetworkIdentity_NetworkIdentityEventHandle">NetworkIdentityEventHandle</a>>(@TreasuryCompliance).identity_change_events, <a href="NetworkIdentity.md#0x1_NetworkIdentity_NetworkIdentityChangeNotification">NetworkIdentityChangeNotification</a> { account: account_addr, identities: *&identity.identities, time_rotated_seconds: <a href="DiemTimestamp.md#0x1_DiemTimestamp_now_seconds">DiemTimestamp::now_seconds</a>(), } ); }; } </code></pre> </details> <details> <summary>Specification</summary> <pre><code><b>let</b> account_addr = <a href="../../../../../../move-stdlib/docs/Signer.md#0x1_Signer_spec_address_of">Signer::spec_address_of</a>(account); <b>let</b> prior_identities = <b>global</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr).identities; <b>let</b> has_change = (<b>exists</b> e in to_remove: contains(prior_identities, e)); <b>let</b> post handle = <b>global</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity_NetworkIdentityEventHandle">NetworkIdentityEventHandle</a>>(@TreasuryCompliance).identity_change_events; <b>let</b> post msg = <a href="NetworkIdentity.md#0x1_NetworkIdentity_NetworkIdentityChangeNotification">NetworkIdentityChangeNotification</a> { account: account_addr, identities: <b>global</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr).identities, time_rotated_seconds: <a href="DiemTimestamp.md#0x1_DiemTimestamp_spec_now_seconds">DiemTimestamp::spec_now_seconds</a>(), }; <b>aborts_if</b> !<a href="NetworkIdentity.md#0x1_NetworkIdentity_tc_network_identity_event_handle_exists">tc_network_identity_event_handle_exists</a>() <b>with</b> <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_NOT_PUBLISHED">Errors::NOT_PUBLISHED</a>; <b>aborts_if</b> len(to_remove) == 0 <b>with</b> <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_INVALID_ARGUMENT">Errors::INVALID_ARGUMENT</a>; <b>aborts_if</b> len(to_remove) > <a href="NetworkIdentity.md#0x1_NetworkIdentity_MAX_ADDR_IDENTITIES">MAX_ADDR_IDENTITIES</a> <b>with</b> <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_LIMIT_EXCEEDED">Errors::LIMIT_EXCEEDED</a>; <b>aborts_if</b> !<b>exists</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr) <b>with</b> <a href="../../../../../../move-stdlib/docs/Errors.md#0x1_Errors_NOT_PUBLISHED">Errors::NOT_PUBLISHED</a>; <b>include</b> has_change ==> <a href="DiemTimestamp.md#0x1_DiemTimestamp_AbortsIfNotOperating">DiemTimestamp::AbortsIfNotOperating</a>; <b>include</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_RemoveMembersInternalEnsures">RemoveMembersInternalEnsures</a><vector<u8>> { old_members: prior_identities, new_members: <b>global</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr).identities, }; <b>modifies</b> <b>global</b><<a href="NetworkIdentity.md#0x1_NetworkIdentity">NetworkIdentity</a>>(account_addr); emits msg <b>to</b> handle <b>if</b> has_change; </code></pre> </details><a name="0x1_NetworkIdentity_add_members_internal"></a>
add_members_internalAdd all elements that appear in <code>to_add</code> into <code>members</code>.
The <code>members</code> argument is essentially a set simulated by a vector, hence the uniqueness of its elements are guaranteed, before and after the bulk insertion. The <code>to_add</code> argument, on the other hand, does not guarantee to be a set and hence can have duplicated elements.
<pre><code><b>fun</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_add_members_internal">add_members_internal</a><T: <b>copy</b>>(members: &<b>mut</b> vector<T>, to_add: &vector<T>): bool </code></pre> <details> <summary>Implementation</summary> <pre><code><b>fun</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_add_members_internal">add_members_internal</a><T: <b>copy</b>>( members: &<b>mut</b> vector<T>, to_add: &vector<T>, ): bool { <b>let</b> num_to_add = <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_length">Vector::length</a>(to_add); <b>let</b> num_existing = <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_length">Vector::length</a>(members); <b>let</b> i = 0; <b>while</b> ({ <b>spec</b> { <b>invariant</b> i <= num_to_add; // the set can never reduce in size <b>invariant</b> len(members) >= len(<b>old</b>(members)); // the current set maintains the uniqueness of the elements <b>invariant</b> <b>forall</b> j in 0..len(members), k in 0..len(members): members[j] == members[k] ==> j == k; // the left-split of the current set is exactly the same <b>as</b> the original set <b>invariant</b> <b>forall</b> j in 0..len(<b>old</b>(members)): members[j] == <b>old</b>(members)[j]; // all elements in the the right-split of the current set is from the `to_add` vector <b>invariant</b> <b>forall</b> j in len(<b>old</b>(members))..len(members): contains(to_add[0..i], members[j]); // the current set includes everything in `to_add` we have seen so far <b>invariant</b> <b>forall</b> j in 0..i: contains(members, to_add[j]); // having no new members means that all elements in the `to_add` vector we have seen so far are already // in the existing set, and vice versa. <b>invariant</b> len(members) == len(<b>old</b>(members)) <==> (<b>forall</b> j in 0..i: contains(<b>old</b>(members), to_add[j])); }; (i < num_to_add) }) { <b>let</b> entry = <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_borrow">Vector::borrow</a>(to_add, i); <b>if</b> (!<a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_contains">Vector::contains</a>(members, entry)) { <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_push_back">Vector::push_back</a>(members, *entry); }; i = i + 1; }; <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_length">Vector::length</a>(members) > num_existing } </code></pre> </details> <details> <summary>Specification</summary> <pre><code><b>pragma</b> opaque; <b>ensures</b> [concrete] <b>true</b>; <b>aborts_if</b> <b>false</b>; <b>include</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_AddMembersInternalEnsures">AddMembersInternalEnsures</a><T> { old_members: <b>old</b>(members), new_members: members, }; <b>include</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_UniqueMembers">UniqueMembers</a><T>; <b>ensures</b> result == (<b>exists</b> e in to_add: !contains(<b>old</b>(members), e)); </code></pre><a name="0x1_NetworkIdentity_AddMembersInternalEnsures"></a>
<pre><code><b>schema</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_AddMembersInternalEnsures">AddMembersInternalEnsures</a><T> { old_members: vector<T>; new_members: vector<T>; to_add: vector<T>; <b>ensures</b> <b>forall</b> e in to_add: contains(new_members, e); <b>ensures</b> <b>forall</b> e in old_members: contains(new_members, e); <b>ensures</b> <b>forall</b> e in new_members: (contains(old_members, e) || contains(to_add, e)); } </code></pre> </details><a name="0x1_NetworkIdentity_remove_members_internal"></a>
remove_members_internalRemove all elements that appear in <code>to_remove</code> from <code>members</code>.
The <code>members</code> argument is essentially a set simulated by a vector, hence the uniqueness of its elements are guaranteed, before and after the bulk removal. The <code>to_remove</code> argument, on the other hand, does not guarantee to be a set and hence can have duplicated elements.
<pre><code><b>fun</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_remove_members_internal">remove_members_internal</a><T: drop>(members: &<b>mut</b> vector<T>, to_remove: &vector<T>): bool </code></pre> <details> <summary>Implementation</summary> <pre><code><b>fun</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_remove_members_internal">remove_members_internal</a><T: drop>( members: &<b>mut</b> vector<T>, to_remove: &vector<T>, ): bool { <b>let</b> num_existing = <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_length">Vector::length</a>(members); <b>let</b> num_to_remove = <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_length">Vector::length</a>(to_remove); <b>let</b> i = 0; <b>while</b> ({ <b>spec</b> { <b>invariant</b> i <= num_to_remove; // the set can never grow in size <b>invariant</b> len(members) <= len(<b>old</b>(members)); // the current set maintains the uniqueness of the elements <b>invariant</b> <b>forall</b> j in 0..len(members), k in 0..len(members): members[j] == members[k] ==> j == k; // all elements in the the current set come from the original set <b>invariant</b> <b>forall</b> j in 0..len(members): contains(<b>old</b>(members), members[j]); // the current set never contains anything from the `to_remove` vector <b>invariant</b> <b>forall</b> j in 0..i: !contains(members, to_remove[j]); // the current set should never remove an element from the original set which is not in `to_remove` <b>invariant</b> <b>forall</b> j in 0..len(<b>old</b>(members)): (contains(to_remove[0..i], <b>old</b>(members)[j]) || contains(members, <b>old</b>(members)[j])); // having the same member means that all elements in the `to_remove` vector we have seen so far are not // in the existing set, and vice versa. <b>invariant</b> len(members) == len(<b>old</b>(members)) <==> (<b>forall</b> j in 0..i: !contains(<b>old</b>(members), to_remove[j])); }; (i < num_to_remove) }) { <b>let</b> entry = <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_borrow">Vector::borrow</a>(to_remove, i); <b>let</b> (exist, index) = <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_index_of">Vector::index_of</a>(members, entry); <b>if</b> (exist) { <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_swap_remove">Vector::swap_remove</a>(members, index); }; i = i + 1; }; <a href="../../../../../../move-stdlib/docs/Vector.md#0x1_Vector_length">Vector::length</a>(members) < num_existing } </code></pre> </details> <details> <summary>Specification</summary> <pre><code><b>pragma</b> verify = <b>false</b>; <b>pragma</b> opaque; <b>ensures</b> [concrete] <b>true</b>; <b>aborts_if</b> <b>false</b>; <b>include</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_RemoveMembersInternalEnsures">RemoveMembersInternalEnsures</a><T> { old_members: <b>old</b>(members), new_members: members, }; <b>include</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_UniqueMembers">UniqueMembers</a><T>; <b>ensures</b> result == (<b>exists</b> e in to_remove: contains(<b>old</b>(members), e)); </code></pre><a name="0x1_NetworkIdentity_RemoveMembersInternalEnsures"></a>
<pre><code><b>schema</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_RemoveMembersInternalEnsures">RemoveMembersInternalEnsures</a><T> { old_members: vector<T>; new_members: vector<T>; to_remove: vector<T>; <b>ensures</b> <b>forall</b> e in to_remove: !contains(new_members, e); <b>ensures</b> <b>forall</b> e in new_members: contains(old_members, e); <b>ensures</b> <b>forall</b> e in old_members: (contains(to_remove, e) || contains(new_members, e)); } </code></pre><a name="0x1_NetworkIdentity_UniqueMembers"></a>
<pre><code><b>schema</b> <a href="NetworkIdentity.md#0x1_NetworkIdentity_UniqueMembers">UniqueMembers</a><T> { members: vector<T>; <b>invariant</b> <b>forall</b> i in 0..len(members), j in 0..len(members): members[i] == members[j] ==> i == j; } </code></pre> </details>