Exemple #1
0
        /// <summary>
        /// Creates CAN IPNS record object to point to a CAN object of the given hash with the given sequence number.
        /// </summary>
        /// <param name="Hash">Hash of the CAN object to point IPNS record to.</param>
        /// <param name="SequenceNumber">Sequence number of the IPNS record.</param>
        /// <param name="ExpirationTimeSeconds">Expiration time of the newly created record in seconds.</param>
        /// <returns>Valid signed CAN IPNS record object, ready to be sent to CAN server.</returns>
        public static CanIpnsEntry CreateIpnsRecord(byte[] Hash, UInt64 SequenceNumber, int ExpirationTimeSeconds)
        {
            log.Trace("(Hash:'{0}',SequenceNumber:{1},ExpirationTimeSeconds:{2})", Hash.ToBase58(), SequenceNumber, ExpirationTimeSeconds);

            string validityString = DateTime.UtcNow.AddMonths(1).ToString(Rfc3339DateTimeFormat, DateTimeFormatInfo.InvariantInfo);

            byte[] validityBytes = Encoding.UTF8.GetBytes(validityString);

            UInt64 ttlNanoSec = (UInt64)(TimeSpan.FromSeconds(ExpirationTimeSeconds).TotalMilliseconds) * (UInt64)1000000;

            string valueString = CanApi.CreateIpfsPathFromHash(Hash);

            byte[] valueBytes = Encoding.UTF8.GetBytes(valueString);

            CanIpnsEntry res = new CanIpnsEntry()
            {
                Sequence     = SequenceNumber,
                ValidityType = CanIpnsEntry.Types.ValidityType.Eol,
                Ttl          = ttlNanoSec,
                Validity     = ProtocolHelper.ByteArrayToByteString(validityBytes),
                Value        = ProtocolHelper.ByteArrayToByteString(valueBytes)
            };

            res.Signature = ProtocolHelper.ByteArrayToByteString(CreateIpnsRecordSignature(res));

            log.Trace("(-):{0}", res);
            return(res);
        }
        /// <summary>
        /// Refreshes profile server's IPNS record.
        /// </summary>
        public async Task IpnsRecordRefreshAsync()
        {
            log.Trace("()");

            if (canContactInformationHash == null)
            {
                log.Debug("No CAN contact information hash, can't refresh IPNS record, will try later.");
                log.Trace("(-)");
                return;
            }

            canIpnsLastSequenceNumber++;
            canIpnsRecord = CanApi.CreateIpnsRecord(canContactInformationHash, canIpnsLastSequenceNumber, IpnsRecordExpirationTimeSeconds);
            CanRefreshIpnsResult cres = await api.RefreshIpnsRecord(canIpnsRecord, Config.Configuration.Keys.PublicKey);

            if (cres.Success)
            {
                using (UnitOfWork unitOfWork = new UnitOfWork())
                {
                    await unitOfWork.AcquireLockAsync(UnitOfWork.SettingsLock);

                    try
                    {
                        Setting setting = new Setting("CanIpnsLastSequenceNumber", canIpnsLastSequenceNumber.ToString());
                        await unitOfWork.SettingsRepository.AddOrUpdate(setting);

                        await unitOfWork.SaveThrowAsync();

                        log.Debug("CanIpnsLastSequenceNumber updated in database to new value {0}.", setting.Value);
                    }
                    catch (Exception e)
                    {
                        log.Error("Unable to update CanIpnsLastSequenceNumber in the database to new value {0}, exception: {1}", canIpnsLastSequenceNumber, e.ToString());
                    }

                    unitOfWork.ReleaseLock(UnitOfWork.SettingsLock);
                }
            }
            else if (cres.Message != "Shutdown")
            {
                log.Error("Failed to refresh profile server's IPNS record.");
            }

            log.Trace("(-)");
        }
Exemple #3
0
        /// <summary>
        /// Calculates a signature of IPNS record.
        /// </summary>
        /// <param name="Record">IPNS record to calculate signature for.</param>
        /// <returns>Signature of the IPNS record.</returns>
        public byte[] CreateIpnsRecordSignature(CanIpnsEntry Record)
        {
            string validityTypeString = Record.ValidityType.ToString().ToUpperInvariant();

            byte[] validityTypeBytes = Encoding.UTF8.GetBytes(validityTypeString);
            byte[] dataToSign        = new byte[Record.Value.Length + Record.Validity.Length + validityTypeBytes.Length];

            int offset = 0;

            Array.Copy(Record.Value.ToByteArray(), 0, dataToSign, offset, Record.Value.Length);
            offset += Record.Value.Length;

            Array.Copy(Record.Validity.ToByteArray(), 0, dataToSign, offset, Record.Validity.Length);
            offset += Record.Validity.Length;

            Array.Copy(validityTypeBytes, 0, dataToSign, offset, validityTypeBytes.Length);
            offset += validityTypeBytes.Length;

            byte[] res = Ed25519.Sign(dataToSign, Base.Configuration.Keys.ExpandedPrivateKey);

            return(res);
        }
Exemple #4
0
        /// <summary>
        /// Calculates a signature of IPNS record.
        /// </summary>
        /// <param name="Record">IPNS record to calculate signature for.</param>
        /// <returns>Signature of the IPNS record.</returns>
        public static byte[] CreateIpnsRecordSignature(CanIpnsEntry Record)
        {
            string validityTypeString = Record.ValidityType.ToString().ToUpperInvariant();

            byte[] validityTypeBytes = Encoding.UTF8.GetBytes(validityTypeString);
            byte[] dataToSign        = new byte[Record.Value.Length + Record.Validity.Length + validityTypeBytes.Length];

            int offset = 0;

            Array.Copy(Record.Value.ToByteArray(), 0, dataToSign, offset, Record.Value.Length);
            offset += Record.Value.Length;

            Array.Copy(Record.Validity.ToByteArray(), 0, dataToSign, offset, Record.Validity.Length);
            offset += Record.Validity.Length;

            Array.Copy(validityTypeBytes, 0, dataToSign, offset, validityTypeBytes.Length);
            offset += validityTypeBytes.Length;

            ConfigBase config = (ConfigBase)Base.ComponentDictionary[ConfigBase.ComponentName];

            byte[] res = Ed25519.Sign(dataToSign, ((KeysEd25519)config.Settings["Keys"]).ExpandedPrivateKey);

            return(res);
        }
        /// <summary>
        /// Refreshes profile server's IPNS record in CAN.
        /// </summary>
        /// <param name="IpnsRecord">IPNS record to refresh.</param>
        /// <param name="PublicKey">Public key of the IPNS record owner.</param>
        /// <returns>Structure describing whether the function succeeded and response provided by CAN server.</returns>
        public async Task <CanRefreshIpnsResult> RefreshIpnsRecord(CanIpnsEntry IpnsRecord, byte[] PublicKey)
        {
            log.Trace("(PublicKey:'{0}')", PublicKey.ToHex());

            string ipnsRecordEncoded = IpnsRecord.ToByteArray().ToBase64UrlPad(true);

            CanCryptoKey cryptoKey = new CanCryptoKey()
            {
                Type = CanCryptoKey.Types.KeyType.Ed25519,
                Data = ProtocolHelper.ByteArrayToByteString(PublicKey)
            };
            string keyEncoded = Base58Encoding.Encoder.Encode(cryptoKey.ToByteArray());

            log.Debug("Encoding public key: {0}", keyEncoded);

            NameValueCollection args = new NameValueCollection();

            args.Add("arg", ipnsRecordEncoded);
            args.Add("key", keyEncoded);

            CanApiResult apiResult = await SendRequest("name/upload", args);

            CanRefreshIpnsResult res = CanRefreshIpnsResult.FromApiResult(apiResult);

            if (res.Success)
            {
                res.IsCanError = false;

                // Check that the ID, path and sequence number match what we expect.
                string canId = CanApi.PublicKeyToId(PublicKey).ToBase58();
                if (res.Details.Peer == canId)
                {
                    string path = Encoding.UTF8.GetString(IpnsRecord.Value.ToByteArray());
                    if (res.Details.NewPath == path)
                    {
                        if (res.Details.NewSeq == IpnsRecord.Sequence)
                        {
                            // All OK.
                        }
                        else
                        {
                            log.Warn("CAN sequence is {0}, received {1}.", IpnsRecord.Sequence, res.Details.NewSeq);
                            res.Success = false;
                            res.Message = "CAN path in response does not match expected value.";
                        }
                    }
                    else
                    {
                        log.Warn("CAN path is '{0}', received '{1}'.", path, res.Details.NewPath);
                        res.Success = false;
                        res.Message = "CAN path in response does not match expected value.";
                    }
                }
                else
                {
                    log.Warn("CAN ID is '{0}', received '{1}'.", canId, res.Details.Peer);
                    res.Success = false;
                    res.Message = "CAN ID in response does not match expected value.";
                }
            }

            if (res.Success)
            {
                log.Trace("(-):*.Success={0}", res.Success);
            }
            else
            {
                log.Trace("(-):*.Success={0},*.IsCanError={1},*.Message='{2}'", res.Success, res.IsCanError, res.Message);
            }
            return(res);
        }
        /// <summary>
        /// Implementation of the test itself.
        /// </summary>
        /// <returns>true if the test passes, false otherwise.</returns>
        public override async Task <bool> RunAsync()
        {
            IPAddress ServerIp    = (IPAddress)ArgumentValues["Server IP"];
            int       PrimaryPort = (int)ArgumentValues["primary Port"];

            log.Trace("(ServerIp:'{0}',PrimaryPort:{1})", ServerIp, PrimaryPort);

            bool res = false;

            Passed = false;

            ProtocolClient client = new ProtocolClient();

            try
            {
                MessageBuilder mb = client.MessageBuilder;

                // Step 1
                log.Trace("Step 1");
                // Get port list.
                await client.ConnectAsync(ServerIp, PrimaryPort, false);

                Dictionary <ServerRoleType, uint> rolePorts = new Dictionary <ServerRoleType, uint>();
                bool listPortsOk = await client.ListServerPorts(rolePorts);

                client.CloseConnection();

                await client.ConnectAsync(ServerIp, (int)rolePorts[ServerRoleType.ClNonCustomer], true);

                bool hostingOk = await client.EstablishHostingAsync("Test");

                client.CloseConnection();

                await client.ConnectAsync(ServerIp, (int)rolePorts[ServerRoleType.ClCustomer], true);

                bool checkInOk = await client.CheckInAsync();

                bool step1Ok = listPortsOk && hostingOk && checkInOk;
                log.Trace("Step 1: {0}", step1Ok ? "PASSED" : "FAILED");



                // Step 2
                log.Trace("Step 2");

                string       validityString = DateTime.UtcNow.AddMonths(1).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK", DateTimeFormatInfo.InvariantInfo);
                CanIpnsEntry ipnsRecord     = new CanIpnsEntry()
                {
                    Value        = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes("/ipfs/QmaRvpLT4RgBDVY6cQKwqQGQNtbM31KSqh8TxvQgFoEUus")),
                    ValidityType = CanIpnsEntry.Types.ValidityType.Eol,
                    Validity     = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(validityString)),
                    Sequence     = 1,
                    Ttl          = 6000000000,
                };
                ipnsRecord.Signature = ProtocolHelper.ByteArrayToByteString(client.CreateIpnsRecordSignature(ipnsRecord));

                Message requestMessage = mb.CreateCanPublishIpnsRecordRequest(ipnsRecord);
                await client.SendMessageAsync(requestMessage);

                Message responseMessage = await client.ReceiveMessageAsync();

                bool idOk     = responseMessage.Id == requestMessage.Id;
                bool statusOk = (responseMessage.Response.Status == Status.ErrorNotFound) || ((responseMessage.Response.Status == Status.ErrorInvalidValue) && (responseMessage.Response.Details == "record.value"));
                bool canPublishIpnsRecordOk = idOk && statusOk;

                // Step 2 Acceptance
                bool step2Ok = canPublishIpnsRecordOk;

                log.Trace("Step 2: {0}", step2Ok ? "PASSED" : "FAILED");



                // Step 3
                log.Trace("Step 3");
                byte[]             serverId   = Crypto.Sha256(client.ServerKey);
                List <CanKeyValue> clientData = new List <CanKeyValue>()
                {
                    new CanKeyValue()
                    {
                        Key = "key1", StringValue = "value 1"
                    },
                    new CanKeyValue()
                    {
                        Key = "key2", Uint32Value = 2
                    },
                    new CanKeyValue()
                    {
                        Key = "key3", BoolValue = true
                    },
                    new CanKeyValue()
                    {
                        Key = "key4", BinaryValue = ProtocolHelper.ByteArrayToByteString(new byte[] { 1, 2, 3 })
                    },
                };

                CanIdentityData identityData1 = new CanIdentityData()
                {
                    HostingServerId = ProtocolHelper.ByteArrayToByteString(serverId)
                };
                identityData1.KeyValueList.AddRange(clientData);

                requestMessage = mb.CreateCanStoreDataRequest(identityData1);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk     = responseMessage.Id == requestMessage.Id;
                statusOk = responseMessage.Response.Status == Status.Ok;
                bool canStoreDataOk = idOk && statusOk;

                byte[] objectHash1 = responseMessage.Response.ConversationResponse.CanStoreData.Hash.ToByteArray();


                string objectPath1 = client.CreateIpfsPathFromHash(objectHash1);
                log.Trace("Object path 1 is '{0}'.", objectPath1);

                requestMessage = mb.CreateCanPublishIpnsRecordRequest(null);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk     = responseMessage.Id == requestMessage.Id;
                statusOk = responseMessage.Response.Status == Status.ErrorInvalidValue;
                bool detailsOk = responseMessage.Response.Details == "record";
                canPublishIpnsRecordOk = idOk && statusOk && detailsOk;


                // Step 3 Acceptance
                bool step3Ok = canStoreDataOk && canPublishIpnsRecordOk;

                log.Trace("Step 3: {0}", step3Ok ? "PASSED" : "FAILED");



                // Step 4
                log.Trace("Step 4");


                validityString = DateTime.UtcNow.AddMonths(1).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK", DateTimeFormatInfo.InvariantInfo);
                ipnsRecord     = new CanIpnsEntry()
                {
                    Value        = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes("ipfabc")),
                    ValidityType = CanIpnsEntry.Types.ValidityType.Eol,
                    Validity     = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(validityString)),
                    Sequence     = 1,
                    Ttl          = 6000000000,
                };
                ipnsRecord.Signature = ProtocolHelper.ByteArrayToByteString(client.CreateIpnsRecordSignature(ipnsRecord));

                requestMessage = mb.CreateCanPublishIpnsRecordRequest(ipnsRecord);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk      = responseMessage.Id == requestMessage.Id;
                statusOk  = responseMessage.Response.Status == Status.ErrorInvalidValue;
                detailsOk = responseMessage.Response.Details == "record.value";
                canPublishIpnsRecordOk = idOk && statusOk && detailsOk;

                // Step 4 Acceptance
                bool step4Ok = canPublishIpnsRecordOk;

                log.Trace("Step 4: {0}", step4Ok ? "PASSED" : "FAILED");


                // Step 5
                log.Trace("Step 5");

                validityString = DateTime.UtcNow.AddMonths(1).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK", DateTimeFormatInfo.InvariantInfo);
                ipnsRecord     = new CanIpnsEntry()
                {
                    Value        = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(objectPath1)),
                    ValidityType = CanIpnsEntry.Types.ValidityType.Eol,
                    Validity     = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(validityString)),
                    Sequence     = 1,
                    Ttl          = 6000000000,
                };
                ipnsRecord.Signature = ProtocolHelper.ByteArrayToByteString(client.CreateIpnsRecordSignature(ipnsRecord));

                requestMessage = mb.CreateCanPublishIpnsRecordRequest(ipnsRecord);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk     = responseMessage.Id == requestMessage.Id;
                statusOk = responseMessage.Response.Status == Status.Ok;
                canPublishIpnsRecordOk = idOk && statusOk;

                // Step 5 Acceptance
                bool step5Ok = canPublishIpnsRecordOk;

                log.Trace("Step 5: {0}", step5Ok ? "PASSED" : "FAILED");



                // Step 6
                log.Trace("Step 6");

                validityString = DateTime.UtcNow.AddMonths(1).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK", DateTimeFormatInfo.InvariantInfo);
                ipnsRecord     = new CanIpnsEntry()
                {
                    Value        = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(objectPath1)),
                    ValidityType = CanIpnsEntry.Types.ValidityType.Eol,
                    Validity     = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(validityString)),
                    Sequence     = 1,
                    Ttl          = 6000000000,
                };
                ipnsRecord.Signature = ProtocolHelper.ByteArrayToByteString(client.CreateIpnsRecordSignature(ipnsRecord));

                requestMessage = mb.CreateCanPublishIpnsRecordRequest(ipnsRecord);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk      = responseMessage.Id == requestMessage.Id;
                statusOk  = responseMessage.Response.Status == Status.ErrorRejected;
                detailsOk = !string.IsNullOrEmpty(responseMessage.Response.Details);
                canPublishIpnsRecordOk = idOk && statusOk && detailsOk;

                // Step 6 Acceptance
                bool step6Ok = canPublishIpnsRecordOk;

                log.Trace("Step 6: {0}", step6Ok ? "PASSED" : "FAILED");


                // Step 7
                log.Trace("Step 7");

                validityString = DateTime.UtcNow.AddMonths(1).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK", DateTimeFormatInfo.InvariantInfo);
                ipnsRecord     = new CanIpnsEntry()
                {
                    Value        = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(objectPath1)),
                    ValidityType = CanIpnsEntry.Types.ValidityType.Eol,
                    Validity     = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(validityString)),
                    Sequence     = 2,
                    Ttl          = 6000000000,
                };
                ipnsRecord.Signature = ProtocolHelper.ByteArrayToByteString(new byte[] { 0x40, 0x40, 0x40, 0x40, 0x40 });

                requestMessage = mb.CreateCanPublishIpnsRecordRequest(ipnsRecord);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk      = responseMessage.Id == requestMessage.Id;
                statusOk  = responseMessage.Response.Status == Status.ErrorRejected;
                detailsOk = !string.IsNullOrEmpty(responseMessage.Response.Details);
                canPublishIpnsRecordOk = idOk && statusOk && detailsOk;

                // Step 7 Acceptance
                bool step7Ok = canPublishIpnsRecordOk;

                log.Trace("Step 7: {0}", step7Ok ? "PASSED" : "FAILED");



                // Step 8
                log.Trace("Step 8");


                requestMessage = mb.CreateCanStoreDataRequest(null);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk           = responseMessage.Id == requestMessage.Id;
                statusOk       = responseMessage.Response.Status == Status.Ok;
                canStoreDataOk = idOk && statusOk;


                validityString = DateTime.UtcNow.AddMonths(1).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK", DateTimeFormatInfo.InvariantInfo);
                ipnsRecord     = new CanIpnsEntry()
                {
                    Value        = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(objectPath1)),
                    ValidityType = CanIpnsEntry.Types.ValidityType.Eol,
                    Validity     = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(validityString)),
                    Sequence     = 3,
                    Ttl          = 6000000000,
                };
                ipnsRecord.Signature = ProtocolHelper.ByteArrayToByteString(client.CreateIpnsRecordSignature(ipnsRecord));

                requestMessage = mb.CreateCanPublishIpnsRecordRequest(ipnsRecord);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk     = responseMessage.Id == requestMessage.Id;
                statusOk = responseMessage.Response.Status == Status.ErrorNotFound;
                canPublishIpnsRecordOk = idOk && statusOk;

                // Step 8 Acceptance
                bool step8Ok = canStoreDataOk && canPublishIpnsRecordOk;

                log.Trace("Step 8: {0}", step8Ok ? "PASSED" : "FAILED");



                Passed = step1Ok && step2Ok && step3Ok && step4Ok && step5Ok && step6Ok && step7Ok && step8Ok;

                res = true;
            }
            catch (Exception e)
            {
                log.Error("Exception occurred: {0}", e.ToString());
            }
            client.Dispose();


            log.Trace("(-):{0}", res);
            return(res);
        }
        /// <summary>
        /// Implementation of the test itself.
        /// </summary>
        /// <returns>true if the test passes, false otherwise.</returns>
        public override async Task <bool> RunAsync()
        {
            IPAddress ServerIp    = (IPAddress)ArgumentValues["Server IP"];
            int       PrimaryPort = (int)ArgumentValues["primary Port"];
            int       CanPort     = (int)ArgumentValues["CAN Port"];

            log.Trace("(ServerIp:'{0}',PrimaryPort:{1},CanPort:{2})", ServerIp, PrimaryPort, CanPort);

            bool res = false;

            Passed = false;

            ProtocolClient client = new ProtocolClient();

            try
            {
                MessageBuilder mb = client.MessageBuilder;

                // Step 1
                log.Trace("Step 1");
                // Get port list.
                await client.ConnectAsync(ServerIp, PrimaryPort, false);

                Dictionary <ServerRoleType, uint> rolePorts = new Dictionary <ServerRoleType, uint>();
                bool listPortsOk = await client.ListServerPorts(rolePorts);

                client.CloseConnection();

                await client.ConnectAsync(ServerIp, (int)rolePorts[ServerRoleType.ClNonCustomer], true);

                bool hostingOk = await client.EstablishHostingAsync("Test");

                client.CloseConnection();

                await client.ConnectAsync(ServerIp, (int)rolePorts[ServerRoleType.ClCustomer], true);

                bool checkInOk = await client.CheckInAsync();

                bool step1Ok = listPortsOk && hostingOk && checkInOk;
                log.Trace("Step 1: {0}", step1Ok ? "PASSED" : "FAILED");



                // Step 2
                log.Trace("Step 2");
                byte[]             serverId   = Crypto.Sha256(client.ServerKey);
                List <CanKeyValue> clientData = new List <CanKeyValue>()
                {
                    new CanKeyValue()
                    {
                        Key = "key1", StringValue = "value 1"
                    },
                    new CanKeyValue()
                    {
                        Key = "key2", Uint32Value = 2
                    },
                    new CanKeyValue()
                    {
                        Key = "key3", BoolValue = true
                    },
                    new CanKeyValue()
                    {
                        Key = "key4", BinaryValue = ProtocolHelper.ByteArrayToByteString(new byte[] { 1, 2, 3 })
                    },
                };

                CanIdentityData identityData1 = new CanIdentityData()
                {
                    HostingServerId = ProtocolHelper.ByteArrayToByteString(serverId)
                };
                identityData1.KeyValueList.AddRange(clientData);

                Message requestMessage = mb.CreateCanStoreDataRequest(identityData1);
                await client.SendMessageAsync(requestMessage);

                Message responseMessage = await client.ReceiveMessageAsync();

                bool idOk           = responseMessage.Id == requestMessage.Id;
                bool statusOk       = responseMessage.Response.Status == Status.Ok;
                bool canStoreDataOk = idOk && statusOk;

                byte[] objectHash1 = responseMessage.Response.ConversationResponse.CanStoreData.Hash.ToByteArray();


                string objectPath1 = client.CreateIpfsPathFromHash(objectHash1);
                log.Trace("Object path 1 is '{0}'.", objectPath1);

                string       validityString = DateTime.UtcNow.AddMonths(1).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK", DateTimeFormatInfo.InvariantInfo);
                CanIpnsEntry ipnsRecord     = new CanIpnsEntry()
                {
                    Value        = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(objectPath1)),
                    ValidityType = CanIpnsEntry.Types.ValidityType.Eol,
                    Validity     = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(validityString)),
                    Sequence     = 1,
                    Ttl          = 6000000000,
                };
                ipnsRecord.Signature = ProtocolHelper.ByteArrayToByteString(client.CreateIpnsRecordSignature(ipnsRecord));

                requestMessage = mb.CreateCanPublishIpnsRecordRequest(ipnsRecord);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk     = responseMessage.Id == requestMessage.Id;
                statusOk = responseMessage.Response.Status == Status.Ok;
                bool canPublishIpnsRecordOk = idOk && statusOk;



                // Step 2 Acceptance
                bool step2Ok = canStoreDataOk && canPublishIpnsRecordOk;

                log.Trace("Step 2: {0}", step2Ok ? "PASSED" : "FAILED");



                // Step 3
                log.Trace("Step 3");
                IPEndPoint canEndPoint = new IPEndPoint(ServerIp, CanPort);
                byte[]     clientCanId = client.CanPublicKeyToId(client.GetIdentityKeys().PublicKey);
                string     ipnsPath    = client.CreateIpnsPathFromHash(clientCanId);

                ProtocolClient.CanIpnsResolveResult canIpnsResolveResult = await client.CanIpnsResolve(canEndPoint, ipnsPath);

                string canObjectPath = canIpnsResolveResult.Path;
                bool   objectPathOk  = canObjectPath == objectPath1;
                bool   resolveOk     = canIpnsResolveResult.Success && objectPathOk;

                ProtocolClient.CanCatResult canCatResult = await client.CanGetObject(canEndPoint, canObjectPath);

                byte[] receivedData = canCatResult.Data;
                byte[] expectedData = identityData1.ToByteArray();
                bool   dataOk       = StructuralComparisons.StructuralComparer.Compare(receivedData, expectedData) == 0;
                bool   catOk        = canCatResult.Success && dataOk;

                // Step 3 Acceptance
                bool step3Ok = resolveOk && catOk;

                log.Trace("Step 3: {0}", step3Ok ? "PASSED" : "FAILED");



                // Step 4
                log.Trace("Step 4");

                ipnsRecord.Sequence  = 2;
                ipnsRecord.Signature = ProtocolHelper.ByteArrayToByteString(client.CreateIpnsRecordSignature(ipnsRecord));

                requestMessage = mb.CreateCanPublishIpnsRecordRequest(ipnsRecord);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk     = responseMessage.Id == requestMessage.Id;
                statusOk = responseMessage.Response.Status == Status.Ok;
                canPublishIpnsRecordOk = idOk && statusOk;


                canIpnsResolveResult = await client.CanIpnsResolve(canEndPoint, ipnsPath);

                canObjectPath = canIpnsResolveResult.Path;
                objectPathOk  = canObjectPath == objectPath1;
                resolveOk     = canIpnsResolveResult.Success && objectPathOk;

                // Step 4 Acceptance
                bool step4Ok = canPublishIpnsRecordOk && resolveOk;

                log.Trace("Step 4: {0}", step4Ok ? "PASSED" : "FAILED");


                // Step 5
                log.Trace("Step 5");

                byte[] valX = new byte[50000];
                for (int i = 0; i < valX.Length; i++)
                {
                    valX[i] = 0x30;
                }

                clientData = new List <CanKeyValue>()
                {
                    new CanKeyValue()
                    {
                        Key = "key1", StringValue = "value 1"
                    },
                    new CanKeyValue()
                    {
                        Key = "key2", Uint32Value = 3
                    },
                    new CanKeyValue()
                    {
                        Key = "key3", BoolValue = false
                    },
                    new CanKeyValue()
                    {
                        Key = "keyX", BinaryValue = ProtocolHelper.ByteArrayToByteString(valX)
                    },
                };

                CanIdentityData identityData2 = new CanIdentityData()
                {
                    HostingServerId = ProtocolHelper.ByteArrayToByteString(serverId)
                };
                identityData2.KeyValueList.AddRange(clientData);


                requestMessage = mb.CreateCanStoreDataRequest(identityData2);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk           = responseMessage.Id == requestMessage.Id;
                statusOk       = responseMessage.Response.Status == Status.Ok;
                canStoreDataOk = idOk && statusOk;

                byte[] objectHash2 = responseMessage.Response.ConversationResponse.CanStoreData.Hash.ToByteArray();


                string objectPath2 = client.CreateIpfsPathFromHash(objectHash2);
                log.Trace("Object path 2 is '{0}'.", objectPath2);

                ipnsRecord.Sequence  = 3;
                ipnsRecord.Value     = ProtocolHelper.ByteArrayToByteString(Encoding.UTF8.GetBytes(objectPath2));
                ipnsRecord.Signature = ProtocolHelper.ByteArrayToByteString(client.CreateIpnsRecordSignature(ipnsRecord));

                requestMessage = mb.CreateCanPublishIpnsRecordRequest(ipnsRecord);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk     = responseMessage.Id == requestMessage.Id;
                statusOk = responseMessage.Response.Status == Status.Ok;
                canPublishIpnsRecordOk = idOk && statusOk;


                // Step 5 Acceptance
                bool step5Ok = canStoreDataOk && canPublishIpnsRecordOk;

                log.Trace("Step 5: {0}", step5Ok ? "PASSED" : "FAILED");


                // Step 6
                log.Trace("Step 6");

                await Task.Delay(10000);

                canIpnsResolveResult = await client.CanIpnsResolve(canEndPoint, ipnsPath);

                canObjectPath = canIpnsResolveResult.Path;
                objectPathOk  = canObjectPath == objectPath2;
                resolveOk     = canIpnsResolveResult.Success && objectPathOk;

                canCatResult = await client.CanGetObject(canEndPoint, canObjectPath);

                receivedData = canCatResult.Data;
                expectedData = identityData2.ToByteArray();
                dataOk       = StructuralComparisons.StructuralComparer.Compare(receivedData, expectedData) == 0;
                catOk        = canCatResult.Success && dataOk;

                // Step 6 Acceptance
                bool step6Ok = resolveOk && catOk;

                log.Trace("Step 6: {0}", step6Ok ? "PASSED" : "FAILED");


                // Step 7
                log.Trace("Step 7");

                requestMessage = mb.CreateCanStoreDataRequest(null);
                await client.SendMessageAsync(requestMessage);

                responseMessage = await client.ReceiveMessageAsync();

                idOk           = responseMessage.Id == requestMessage.Id;
                statusOk       = responseMessage.Response.Status == Status.Ok;
                canStoreDataOk = idOk && statusOk;

                ProtocolClient.CanDeleteResult canDeleteResult = await client.CanDeleteObject(canEndPoint, canObjectPath);

                bool pinsOk   = (canDeleteResult.Pins == null) || (canDeleteResult.Pins.Length == 0);
                bool deleteOk = canDeleteResult.Success && pinsOk;

                // Step 7 Acceptance
                bool step7Ok = canStoreDataOk && deleteOk;

                log.Trace("Step 7: {0}", step7Ok ? "PASSED" : "FAILED");



                // Step 8
                log.Trace("Step 8");

                canDeleteResult = await client.CanDeleteObject(canEndPoint, objectPath1);

                pinsOk   = (canDeleteResult.Pins == null) || (canDeleteResult.Pins.Length == 0);
                deleteOk = canDeleteResult.Success && pinsOk;

                // Step 8 Acceptance
                bool step8Ok = deleteOk;

                log.Trace("Step 8: {0}", step8Ok ? "PASSED" : "FAILED");



                Passed = step1Ok && step2Ok && step3Ok && step4Ok && step5Ok && step6Ok && step7Ok && step8Ok;

                res = true;
            }
            catch (Exception e)
            {
                log.Error("Exception occurred: {0}", e.ToString());
            }
            client.Dispose();


            log.Trace("(-):{0}", res);
            return(res);
        }