diff --git a/src/DagCid.cs b/src/DagCid.cs
index b1ade6de..2ed3ac5e 100644
--- a/src/DagCid.cs
+++ b/src/DagCid.cs
@@ -1,4 +1,5 @@
-using Newtonsoft.Json;
+using System;
+using Newtonsoft.Json;
namespace Ipfs
{
@@ -10,11 +11,32 @@ namespace Ipfs
///
public record DagCid
{
+ private Cid _value = null!;
+
///
/// The value of this DAG link.
///
+ ///
+ /// Thrown when attempting to set a CID with ContentType "libp2p-key",
+ /// as IPLD links must be immutable and libp2p-key CIDs represent mutable IPNS addresses.
+ ///
[JsonProperty("/")]
- public required Cid Value { get; set; }
+ public required Cid Value
+ {
+ get => _value;
+ set
+ {
+ if (value.ContentType == "libp2p-key")
+ {
+ throw new ArgumentException(
+ "Cannot store CID-encoded libp2p key as DagCid link. " +
+ "IPLD links must be immutable, but libp2p-key CIDs represent mutable IPNS addresses. " +
+ "Use the resolved content CID instead.",
+ nameof(value));
+ }
+ _value = value;
+ }
+ }
///
/// Implicit casting of a to a .
@@ -25,8 +47,23 @@ public record DagCid
///
/// Explicit casting of a to a .
///
- /// The to cast."
- public static explicit operator DagCid(Cid cid) => new DagCid { Value = cid, };
+ /// The to cast.
+ ///
+ /// Thrown when attempting to cast a CID with ContentType "libp2p-key",
+ /// as IPLD links must be immutable and libp2p-key CIDs represent mutable IPNS addresses.
+ ///
+ public static explicit operator DagCid(Cid cid)
+ {
+ if (cid.ContentType == "libp2p-key")
+ {
+ throw new ArgumentException(
+ "Cannot cast CID-encoded libp2p key to DagCid. " +
+ "IPLD links must be immutable, but libp2p-key CIDs represent mutable IPNS addresses. " +
+ "Use the resolved content CID instead.",
+ nameof(cid));
+ }
+ return new DagCid { Value = cid, };
+ }
///
/// Returns the string representation of the .
diff --git a/test/DagCidTest.cs b/test/DagCidTest.cs
new file mode 100644
index 00000000..44cf472e
--- /dev/null
+++ b/test/DagCidTest.cs
@@ -0,0 +1,112 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+
+namespace Ipfs
+{
+ [TestClass]
+ public class DagCidTest
+ {
+ [TestMethod]
+ public void Value_ValidCid_SetsSuccessfully()
+ {
+ // Arrange
+ Cid validCid = "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V";
+
+ // Act & Assert
+ var dagCid = new DagCid { Value = validCid };
+ Assert.AreEqual(validCid, dagCid.Value);
+ }
+
+ [TestMethod]
+ public void Value_LibP2pKeyCid_ThrowsArgumentException()
+ {
+ // Arrange - using real IPNS key CID that should have libp2p-key content type
+ Cid libp2pKeyCid = "k51qzi5uqu5dlvj2baxnqndepeb86cbk3ng7n3i46uzyxzyqj2xjonzllnv0v8";
+
+ // Verify this CID actually has libp2p-key content type
+ Assert.AreEqual("libp2p-key", libp2pKeyCid.ContentType);
+
+ // Act & Assert
+ var exception = Assert.ThrowsException(() =>
+ new DagCid { Value = libp2pKeyCid });
+
+ Assert.IsTrue(exception.Message.Contains("Cannot store CID-encoded libp2p key as DagCid link"));
+ Assert.IsTrue(exception.Message.Contains("IPLD links must be immutable"));
+ Assert.AreEqual("value", exception.ParamName);
+ }
+
+ [TestMethod]
+ public void Value_LibP2pKeyCid_SetAfterConstruction_ThrowsArgumentException()
+ {
+ // Arrange
+ Cid validCid = "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V";
+ // Using another real IPNS key CID
+ Cid libp2pKeyCid = "k51qzi5uqu5dlvj2baxnqndepeb86cbk3ng7n3i46uzyxzyqj2xjonzllnv0v8";
+
+ var dagCid = new DagCid { Value = validCid };
+
+ // Act & Assert
+ var exception = Assert.ThrowsException(() =>
+ dagCid.Value = libp2pKeyCid);
+
+ Assert.IsTrue(exception.Message.Contains("Cannot store CID-encoded libp2p key as DagCid link"));
+ Assert.AreEqual("value", exception.ParamName);
+ }
+
+ [TestMethod]
+ public void ExplicitCast_ValidCid_CastsSuccessfully()
+ {
+ // Arrange
+ Cid validCid = "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V";
+
+ // Act
+ var dagCid = (DagCid)validCid;
+
+ // Assert
+ Assert.AreEqual(validCid, dagCid.Value);
+ }
+
+ [TestMethod]
+ public void ExplicitCast_LibP2pKeyCid_ThrowsArgumentException()
+ {
+ // Arrange - using real IPNS key CID that should have libp2p-key content type
+ Cid libp2pKeyCid = "k51qzi5uqu5dlvj2baxnqndepeb86cbk3ng7n3i46uzyxzyqj2xjonzllnv0v8";
+
+ // Act & Assert
+ var exception = Assert.ThrowsException(() =>
+ (DagCid)libp2pKeyCid);
+
+ Assert.IsTrue(exception.Message.Contains("Cannot cast CID-encoded libp2p key to DagCid"));
+ Assert.IsTrue(exception.Message.Contains("IPLD links must be immutable"));
+ Assert.AreEqual("cid", exception.ParamName);
+ }
+
+ [TestMethod]
+ public void ImplicitCast_DagCidToCid_WorksCorrectly()
+ {
+ // Arrange
+ Cid originalCid = "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V";
+ var dagCid = new DagCid { Value = originalCid };
+
+ // Act
+ Cid convertedCid = dagCid;
+
+ // Assert
+ Assert.AreEqual(originalCid, convertedCid);
+ }
+
+ [TestMethod]
+ public void ToString_ReturnsValueToString()
+ {
+ // Arrange
+ Cid cid = "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V";
+ var dagCid = new DagCid { Value = cid };
+
+ // Act
+ var result = dagCid.ToString();
+
+ // Assert
+ Assert.AreEqual(cid.ToString(), result);
+ }
+ }
+}