From 6f1f5962348e8356f2968d9a64a54d0edf8d82ef Mon Sep 17 00:00:00 2001 From: Arnab Ghose Date: Thu, 20 Apr 2023 10:03:32 +0530 Subject: [PATCH 1/3] Update LICENSE --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index e27fa52..957d296 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2022 Hypermine Limited + Copyright 2023 Hypermine Limited Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -198,4 +198,4 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file + limitations under the License. From 16ca1109c8c4c779c30a7014ab7457c21f04b9f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 May 2023 09:36:15 +0000 Subject: [PATCH 2/3] build(deps): bump golang.org/x/net from 0.6.0 to 0.7.0 Bumps [golang.org/x/net](https://github.com/golang/net) from 0.6.0 to 0.7.0. - [Release notes](https://github.com/golang/net/releases) - [Commits](https://github.com/golang/net/compare/v0.6.0...v0.7.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-type: indirect ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5282b90..5365d01 100644 --- a/go.mod +++ b/go.mod @@ -133,7 +133,7 @@ require ( github.com/golang/protobuf v1.5.2 github.com/multiformats/go-multibase v0.0.3 github.com/spf13/viper v1.13.0 - golang.org/x/net v0.6.0 // indirect + golang.org/x/net v0.7.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 536422a..2bd932c 100644 --- a/go.sum +++ b/go.sum @@ -1442,8 +1442,8 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= From 30e065f2b216e941f174ee36f98c154b63f83b68 Mon Sep 17 00:00:00 2001 From: Arnab Ghose Date: Tue, 27 Jun 2023 10:21:36 +0530 Subject: [PATCH 3/3] feat: verification methods with blockchainAccountId field populated cannot be added in a DID Document if it already exists in some registered DID Document --- tests/e2e/ssi_tests/e2e_tests.py | 173 +++++++++++++--------- tests/e2e/ssi_tests/run.py | 3 +- x/ssi/keeper/did.go | 18 +++ x/ssi/keeper/msg_server_create_did.go | 23 +++ x/ssi/keeper/msg_server_deactivate_did.go | 7 + x/ssi/keeper/msg_server_update_did.go | 67 +++++++++ x/ssi/types/chain_namespace_validation.go | 2 +- x/ssi/types/keys.go | 2 + 8 files changed, 226 insertions(+), 69 deletions(-) diff --git a/tests/e2e/ssi_tests/e2e_tests.py b/tests/e2e/ssi_tests/e2e_tests.py index 968e87a..20d5ffb 100644 --- a/tests/e2e/ssi_tests/e2e_tests.py +++ b/tests/e2e/ssi_tests/e2e_tests.py @@ -9,6 +9,104 @@ query_did, form_create_schema_tx, form_did_deactivate_tx_multisig, form_create_cred_status_tx from constants import DEFAULT_BLOCKCHAIN_ACCOUNT_NAME +def unique_wallet_address_test(): + print("\n---1. FAIL: Alice Creates a DID Doc. Bob attempts to create a DID Document by adding one of Alice's VM.---\n") + + kp_alice = generate_key_pair("recover-eth") + signers = [] + did_doc_string = generate_did_document(kp_alice, "recover-eth") + did_doc_alice = did_doc_string["id"] + did_doc_alice_vm = did_doc_string["verificationMethod"][0] + signPair_alice = { + "kp": kp_alice, + "verificationMethodId": did_doc_string["verificationMethod"][0]["id"], + "signing_algo": "recover-eth" + } + signers.append(signPair_alice) + create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) + run_blockchain_command(create_tx_cmd, f"Registering Alice's DID with Id: {did_doc_alice}") + + # Create Bob's DID with Alice's VM + kp_bob = generate_key_pair("recover-eth") + signers = [] + did_doc_string = generate_did_document(kp_bob, "recover-eth") + did_doc_bob = did_doc_string["id"] + did_doc_string["controller"] = [did_doc_alice] + did_doc_string["verificationMethod"] = [did_doc_alice_vm] + signers.append(signPair_alice) + create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) + run_blockchain_command(create_tx_cmd, f"Registering Bob's DID with Id: {did_doc_bob}", True) + + print("\n---2. FAIL: Charlie creates a DID Document. After that, Charlie attempts to update its DID Document by adding one of Alice's VM for which valid signature is passed.---\n") + + kp_charlie = generate_key_pair("recover-eth") + signers = [] + did_doc_string_charlie = generate_did_document(kp_charlie, "recover-eth") + did_doc_charlie_id = did_doc_string_charlie["id"] + did_doc_charlie_vm = did_doc_string_charlie["verificationMethod"][0] + signPair_charlie = { + "kp": kp_charlie, + "verificationMethodId": did_doc_string_charlie["verificationMethod"][0]["id"], + "signing_algo": "recover-eth" + } + signers.append(signPair_charlie) + create_tx_cmd = form_did_create_tx_multisig(did_doc_string_charlie, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) + run_blockchain_command(create_tx_cmd, f"Registering Charlie's DID with Id: {did_doc_charlie_id}") + + signers = [] + did_doc_string_charlie["verificationMethod"] = [did_doc_charlie_vm, did_doc_alice_vm] + signers.append(signPair_charlie) + signers.append(signPair_alice) + update_tx_cmd = form_did_update_tx_multisig(did_doc_string_charlie, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) + run_blockchain_command(update_tx_cmd, f"Charlie (controller) attempts to add Alice's VM in its DID Id: {did_doc_charlie_id}", True) + + print("\n---3. PASS: Alice deactivates her DID Document. Charlie attempts to update its DID Document by adding one of Alice's VM for which valid signature is passed.---\n") + + # Alice Deactivates their DID Document + signers = [] + signers.append(signPair_alice) + deactivate_tx_cmd = form_did_deactivate_tx_multisig(did_doc_alice, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) + run_blockchain_command(deactivate_tx_cmd, f"Deactivation of Org's DID with Id: {did_doc_alice}") + + # Charlie attempts to add the VM again + signers = [] + signers.append(signPair_charlie) + signers.append(signPair_alice) + run_blockchain_command(update_tx_cmd, f"Charlie (controller) attempts to add Alice's VM in DID Id: {did_doc_charlie_id}") + + print("\n---4. PASS: Charlie removes one of its Verification Methods. George creates a didDoc for himself. He then proceed to update his DID Document by adding the Verification method removed by Charlie---\n") + + # Create George's DIDDoc + kp_george = generate_key_pair("recover-eth") + signers = [] + did_doc_string_george = generate_did_document(kp_george, "recover-eth") + did_doc_george_id = did_doc_string_george["id"] + did_doc_george_vm = did_doc_string_george["verificationMethod"][0] + signPair_george = { + "kp": kp_george, + "verificationMethodId": did_doc_string_george["verificationMethod"][0]["id"], + "signing_algo": "recover-eth" + } + signers.append(signPair_george) + create_tx_cmd = form_did_create_tx_multisig(did_doc_string_george, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) + run_blockchain_command(create_tx_cmd, f"Registering George's DID with Id: {did_doc_george_id}") + + # Charlie Removes one of their DIDDoc + signers = [] + charlie_vm_to_be_removed = did_doc_string_charlie["verificationMethod"][0] # Controller is Charlie + signers.append(signPair_charlie) + did_doc_string_charlie["verificationMethod"] = [did_doc_string_charlie["verificationMethod"][1]] # Controller for this VM is alice + update_tx_cmd = form_did_update_tx_multisig(did_doc_string_charlie, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) + run_blockchain_command(update_tx_cmd, f"Charlie (controller) attempts to remove one of its VM from its DID: {did_doc_charlie_id}") + + # George updates it DID Document by adding the VM that Charlie Removed + signers = [] + did_doc_string_george["verificationMethod"] = [charlie_vm_to_be_removed, did_doc_george_vm] + signers.append(signPair_charlie) + signers.append(signPair_george) + update_tx_cmd = form_did_update_tx_multisig(did_doc_string_george, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) + run_blockchain_command(update_tx_cmd, f"George attempts add the VM removed by Charlie: {did_doc_george_id}") + # TC - I : Create DID scenarios def create_did_test(): print("\n--- Create DID Test ---\n") @@ -109,15 +207,15 @@ def create_did_test(): # Alice creates a DID where they keep the VM of their friend Eve in the verificationMethod list of the document print("6. FAIL: Alice creates an Org DID where Alice is the controller, and she adds a verification method of her friend Eve. Only Alice sends the singature.\n") - kp_eve = generate_key_pair("secp256k1") - did_doc_string = generate_did_document(kp_eve, algo="secp256k1") + kp_eve = generate_key_pair("ed25519") + did_doc_string = generate_did_document(kp_eve, algo="ed25519") did_doc_eve = did_doc_string["id"] did_doc_eve_vms = did_doc_string["verificationMethod"] signers = [] signPair_eve = { "kp": kp_eve, "verificationMethodId": did_doc_string["verificationMethod"][0]["id"], - "signing_algo": "secp256k1" + "signing_algo": "ed25519" } signers.append(signPair_eve) create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) @@ -280,7 +378,6 @@ def update_did_test(): update_tx_cmd = form_did_update_tx_multisig(did_doc_string_org, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) run_blockchain_command(update_tx_cmd, f"Removal of George's controller by Alice's signature") - # Addition of George's controller and removal of Alice's controller at same time print("7. PASS: Addition of George as a controller and simultaneous removal of Alice as a controller. Both alice's and george's signature are passed.\n") signers = [] @@ -290,65 +387,7 @@ def update_did_test(): update_tx_cmd = form_did_update_tx_multisig(did_doc_string_org, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) run_blockchain_command(update_tx_cmd, f"Removal of Alice's controller and addition of Bob's controller") - #Alice creates a DID where the controller only has Alice's DID and the verfication method has two ETH wallets added. Signature of all hot wallets are passed - print("8. FAIL: Alice has already created two didDocs, each representing a wallet. Now, she creates a DID where she is the controller, and the VMs from two DIDDocs are just added in the VM List. Each of these VMs have different controllers. One of the VMs attempts to update DIDDoc.\n") - kp_hot_wallet_1 = generate_key_pair("recover-eth") - signers = [] - did_doc_string = generate_did_document(kp_hot_wallet_1, algo="recover-eth") - did_doc_hw1 = did_doc_string["id"] - did_doc_hw1_vm = did_doc_string["verificationMethod"][0] - signPair_hw1 = { - "kp": kp_hot_wallet_1, - "verificationMethodId": did_doc_hw1_vm["id"], - "signing_algo": "recover-eth" - } - signers.append(signPair_hw1) - create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) - run_blockchain_command(create_tx_cmd, f"Registering Hot Wallet 1 with Id: {did_doc_hw1}") - - kp_hot_wallet_2 = generate_key_pair("recover-eth") - signers = [] - did_doc_string = generate_did_document(kp_hot_wallet_2, algo="recover-eth") - did_doc_hw2 = did_doc_string["id"] - did_doc_hw2_vm = did_doc_string["verificationMethod"][0] - signPair_hw2 = { - "kp": kp_hot_wallet_2, - "verificationMethodId": did_doc_hw2_vm["id"], - "signing_algo": "recover-eth" - } - signers.append(signPair_hw2) - create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) - run_blockchain_command(create_tx_cmd, f"Registering Hot Wallet 2 with Id: {did_doc_hw2}") - - kp_org = generate_key_pair() - signers = [] - did_doc_string = generate_did_document(kp_org) - did_doc_org = did_doc_string["id"] - did_doc_string["controller"] = [did_doc_alice] - did_doc_string["verificationMethod"] = [ - did_doc_hw1_vm, - did_doc_hw2_vm - ] - signers.append(signPair_alice) - signers.append(signPair_hw1) - signers.append(signPair_hw2) - create_tx_cmd = form_did_create_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) - run_blockchain_command(create_tx_cmd, f"Registering of Org DID with Id: {did_doc_org}") - - print("Hot-Wallet 1 attemps to update Org DID. It is expected to fail") - did_doc_string["context"] = ["exempler.org"] - signers = [] - signers.append(signPair_hw1) - update_tx_cmd = form_did_update_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) - run_blockchain_command(update_tx_cmd, f"Hot Wallet 1 attempts to update Tx", True) - - print("9. PASS: Alice has already created two didDocs, each representing a wallet. Now, she creates a DID where she is the controller, and the VMs from two DIDDocs are just added in the VM List. Each of these VMs have different controllers. Alice attempts to update DIDDoc.\n") - signers = [] - signers.append(signPair_alice) - update_tx_cmd = form_did_update_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) - run_blockchain_command(update_tx_cmd, f"Alice (controller) attempts to update Tx") - - print("10. FAIL: Alice tries to update her DID Document without changing anything\n") + print("8. FAIL: Alice tries to update her DID Document without changing anything\n") did_doc_string = query_did(did_doc_alice)["didDocument"] signers = [] signers.append(signPair_alice) @@ -356,7 +395,7 @@ def update_did_test(): run_blockchain_command(update_tx_cmd, f"Alice attempts update without any change Tx", True) # Register Alice's DID - print("11. PASS: Jenny creates herself a DID with empty Controller list. She then attempts to update the DIDDoc by changing the context field and passes her signature only.\n") + print("9. PASS: Jenny creates herself a DID with empty Controller list. She then attempts to update the DIDDoc by changing the context field and passes her signature only.\n") kp_jenny = generate_key_pair() signers = [] did_doc_string = generate_did_document(kp_jenny) @@ -378,7 +417,7 @@ def update_did_test(): update_tx_cmd = form_did_update_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) run_blockchain_command(update_tx_cmd, f"Jenny (controller) attempts to update Tx") - print("12. FAIL: Jenny creates a DID. She then attempts to update the DIDDoc by adding a new Verification method. She passes signature only for old VM\n") + print("10. FAIL: Jenny creates a DID. She then attempts to update the DIDDoc by adding a new Verification method. She passes signature only for old VM\n") kp_jenny = generate_key_pair() kp_jenny_2 = generate_key_pair() @@ -420,7 +459,7 @@ def update_did_test(): update_tx_cmd = form_did_update_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) run_blockchain_command(update_tx_cmd, f"Jenny attempts to update the DIDDoc with only old VM's signature", True) - print("13. PASS: Jenny attempts to update the same didDoc by passing signatures for both old and new verification methods\n") + print("11. PASS: Jenny attempts to update the same didDoc by passing signatures for both old and new verification methods\n") signers = [] signers.append(signPair_jenny_1) @@ -428,7 +467,7 @@ def update_did_test(): update_tx_cmd = form_did_update_tx_multisig(did_doc_string, signers, DEFAULT_BLOCKCHAIN_ACCOUNT_NAME) run_blockchain_command(update_tx_cmd, f"Jenny attempts to update the DIDDoc with both new and old VM's signature") - print("14. PASS: Jenny removes the inital verification method she had added. She passes only one signature corresponding to the lastest VM") + print("12. PASS: Jenny removes the inital verification method she had added. She passes only one signature corresponding to the lastest VM") did_doc_string["verificationMethod"] = [ new_vm, diff --git a/tests/e2e/ssi_tests/run.py b/tests/e2e/ssi_tests/run.py index 8ebe69e..0667f32 100644 --- a/tests/e2e/ssi_tests/run.py +++ b/tests/e2e/ssi_tests/run.py @@ -33,7 +33,8 @@ def run_all_tests(): caip10_cosmos_support_test() vm_type_test() method_specific_id_test() - + unique_wallet_address_test() + print("============= 😃️ All test cases completed successfully ============== \n") if __name__=='__main__': diff --git a/x/ssi/keeper/did.go b/x/ssi/keeper/did.go index b47ccb3..7ceb89b 100644 --- a/x/ssi/keeper/did.go +++ b/x/ssi/keeper/did.go @@ -89,3 +89,21 @@ func (k Keeper) RegisterDidDocumentInStore(ctx sdk.Context, didDoc *types.DidDoc k.SetDidCount(ctx, didCount+1) return didCount } + +// Set the BlockchainAccountId in Store +func (k Keeper) SetBlockchainAddressInStore(ctx *sdk.Context, blockchainAccountId string, didId string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.BlockchainAccountIdStoreKey)) + store.Set([]byte(blockchainAccountId), []byte(didId)) +} + +// Get the BlockchainAccountId from Store +func (k Keeper) GetBlockchainAddressFromStore(ctx *sdk.Context, blockchainAccountId string) []byte { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.BlockchainAccountIdStoreKey)) + return store.Get([]byte(blockchainAccountId)) +} + +// Remove the BlockchainAccountId from Store +func (k Keeper) RemoveBlockchainAddressInStore(ctx *sdk.Context, blockchainAccountId string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.BlockchainAccountIdStoreKey)) + store.Delete([]byte(blockchainAccountId)) +} diff --git a/x/ssi/keeper/msg_server_create_did.go b/x/ssi/keeper/msg_server_create_did.go index 93be00f..96cbc76 100644 --- a/x/ssi/keeper/msg_server_create_did.go +++ b/x/ssi/keeper/msg_server_create_did.go @@ -40,6 +40,21 @@ func (k msgServer) CreateDID(goCtx context.Context, msg *types.MsgCreateDID) (*t return nil, sdkerrors.Wrap(types.ErrDidDocExists, msgDidDocument.Id) } + // Check if any of the blockchainAccountId is present in any registered DID Document. If so, throw error + for _, vm := range msgDidDocument.VerificationMethod { + if vm.BlockchainAccountId != "" { + if existingDidDocId := k.GetBlockchainAddressFromStore(&ctx, vm.BlockchainAccountId); len(existingDidDocId) != 0 { + return nil, sdkerrors.Wrapf( + types.ErrInvalidDidDoc, + "blockchainAccountId %v of verification method %v is already part of DID Document %v", + vm.BlockchainAccountId, + vm.Id, + string(existingDidDocId), + ) + } + } + } + // Get the list of controllers and check the non-subject controller's existance in the state controllerList := getControllersForCreateDID(msgDidDocument) @@ -79,6 +94,14 @@ func (k msgServer) CreateDID(goCtx context.Context, msg *types.MsgCreateDID) (*t // Register DID Document in Store once all validation checks are passed id := k.RegisterDidDocumentInStore(ctx, &didDocumentState) + // After successful registration of the DID Document, every blockchainAccountIds + // can be added to the store + for _, vm := range didDocumentState.DidDocument.VerificationMethod { + if vm.BlockchainAccountId != "" { + k.SetBlockchainAddressInStore(&ctx, vm.BlockchainAccountId, vm.Controller) + } + } + return &types.MsgCreateDIDResponse{Id: id}, nil } diff --git a/x/ssi/keeper/msg_server_deactivate_did.go b/x/ssi/keeper/msg_server_deactivate_did.go index f5df62e..ed3c664 100644 --- a/x/ssi/keeper/msg_server_deactivate_did.go +++ b/x/ssi/keeper/msg_server_deactivate_did.go @@ -85,6 +85,13 @@ func (k msgServer) DeactivateDID(goCtx context.Context, msg *types.MsgDeactivate return nil, err } + // Remove the BlockchainAccountId from BlockchainAddressStore + for _, vm := range didDocumentState.DidDocument.VerificationMethod { + if vm.BlockchainAccountId != "" { + k.RemoveBlockchainAddressInStore(&ctx, vm.BlockchainAccountId) + } + } + return &types.MsgDeactivateDIDResponse{Id: 1}, nil } diff --git a/x/ssi/keeper/msg_server_update_did.go b/x/ssi/keeper/msg_server_update_did.go index 73c185a..1a68bf7 100644 --- a/x/ssi/keeper/msg_server_update_did.go +++ b/x/ssi/keeper/msg_server_update_did.go @@ -81,6 +81,9 @@ func (k msgServer) UpdateDID(goCtx context.Context, msg *types.MsgUpdateDID) (*t incomingDidDocumentControllers = append(incomingDidDocumentControllers, msgDidDocument.Id) } + vmsToBeRemoved := []*types.VerificationMethod{} + vmsToBeAdded := []*types.VerificationMethod{} + // check if both controller arrays are equal if reflect.DeepEqual(existingDidDocumentControllers, incomingDidDocumentControllers) { commonController := existingDidDocumentControllers @@ -95,6 +98,13 @@ func (k msgServer) UpdateDID(goCtx context.Context, msg *types.MsgUpdateDID) (*t return nil, sdkerrors.Wrap(types.ErrInvalidDidDoc, vmMapErr.Error()) } } else { + // Get a list of Verification Methods having a populated `blockchainAccountId` field, which are being newly added + // and/or removed from the DID Document + vmsToBeAdded, vmsToBeRemoved, err = processBlockchainAccountIdForUpdateDID(k, ctx, existingDidDocument.VerificationMethod, msgDidDocument.VerificationMethod) + if err != nil { + return nil, err + } + // if Vms are not similar // Get the distinct VMs (new) updatedVms := getVerificationMethodsForUpdateDID(existingDidDocument.VerificationMethod, msgDidDocument.VerificationMethod) @@ -169,6 +179,18 @@ func (k msgServer) UpdateDID(goCtx context.Context, msg *types.MsgUpdateDID) (*t return nil, err } + // Iterate through the removed Verification Methods having `blockchainAccountId` populated + // and remove them from store + for _, vm := range vmsToBeRemoved { + k.RemoveBlockchainAddressInStore(&ctx, vm.BlockchainAccountId) + } + + // Iterate through the added Verification Methods having `blockchainAccountId` populated + // and add them to store + for _, vm := range vmsToBeAdded { + k.SetBlockchainAddressInStore(&ctx, vm.BlockchainAccountId, vm.Controller) + } + return &types.MsgUpdateDIDResponse{UpdateId: msgDidDocument.Id}, nil } @@ -268,3 +290,48 @@ func getVerificationMethodsForUpdateDID(existingVMs []*types.VerificationMethod, return updatedVms } + +func processBlockchainAccountIdForUpdateDID(k msgServer, ctx sdk.Context, existingVMs []*types.VerificationMethod, incomingVMs []*types.VerificationMethod) ([]*types.VerificationMethod, []*types.VerificationMethod, error) { + newVms := []*types.VerificationMethod{} + deletedVms := []*types.VerificationMethod{} + + // Make map of existing VMs + existingVmMap := map[string]*types.VerificationMethod{} + for _, vm := range existingVMs { + existingVmMap[vm.Id] = vm + } + + // Make map of incoming VMs + incomingVmMap := map[string]*types.VerificationMethod{} + for _, vm := range incomingVMs { + incomingVmMap[vm.Id] = vm + // Check if VM is present in existing VM map. + // If it's not present, the VM is being added to existing Did Document. + // Add the VM to "required" group + if _, present := existingVmMap[vm.Id]; !present { + if vm.BlockchainAccountId != "" { + if didIdBytes := k.GetBlockchainAddressFromStore(&ctx, vm.BlockchainAccountId); len(didIdBytes) != 0 { + return nil, nil, fmt.Errorf( + "blockchainAccountId %v of verification method %v is already part of DID Document %v", + vm.BlockchainAccountId, + vm.Id, + string(didIdBytes), + ) + } else { + newVms = append(newVms, vm) + } + } + } + } + + // Get the list of VMs that are being removed + for _, vm := range existingVMs { + if _, present := incomingVmMap[vm.Id]; !present { + if vm.BlockchainAccountId != "" { + deletedVms = append(deletedVms, vm) + } + } + } + + return newVms, deletedVms, nil +} diff --git a/x/ssi/types/chain_namespace_validation.go b/x/ssi/types/chain_namespace_validation.go index bac87ea..97dfedb 100644 --- a/x/ssi/types/chain_namespace_validation.go +++ b/x/ssi/types/chain_namespace_validation.go @@ -59,4 +59,4 @@ func DidChainNamespaceValidation(didDoc *Did, validChainNamespace string) error } return nil -} \ No newline at end of file +} diff --git a/x/ssi/types/keys.go b/x/ssi/types/keys.go index ad07701..203d3d8 100644 --- a/x/ssi/types/keys.go +++ b/x/ssi/types/keys.go @@ -28,6 +28,8 @@ const ( CredKey = "Cred-value-" CredCountKey = "Cred-count-" + + BlockchainAccountIdStoreKey = "blockchainaddrstorekey" ) func KeyPrefix(p string) []byte {