Skip to content

Commit

Permalink
Allow to publish extra data in ipns
Browse files Browse the repository at this point in the history
This is because the value cannot be arbitrary data
  • Loading branch information
ianopolous committed Jan 30, 2025
1 parent 55297dd commit 5f6960b
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 15 deletions.
5 changes: 3 additions & 2 deletions src/main/java/org/peergos/EmbeddedIpfs.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.peergos.blockstore.metadatadb.sql.H2BlockMetadataCommands;
import org.peergos.blockstore.metadatadb.sql.UncloseableConnection;
import org.peergos.blockstore.s3.S3Blockstore;
import org.peergos.cbor.Cborable;
import org.peergos.config.*;
import org.peergos.net.ConnectionException;
import org.peergos.protocol.*;
Expand Down Expand Up @@ -110,11 +111,11 @@ public List<HashedBlock> getBlocks(List<Want> wants, Set<PeerId> peers, boolean
.collect(Collectors.toList());
}

public CompletableFuture<Integer> publishValue(PrivKey priv, byte[] value, long sequence, int hoursTtl) {
public CompletableFuture<Integer> publishValue(PrivKey priv, byte[] value, Optional<String> extraDataKeySuffix, Optional<Cborable> extraData, long sequence, int hoursTtl) {
Multihash pub = Multihash.deserialize(PeerId.fromPubKey(priv.publicKey()).getBytes());
LocalDateTime expiry = LocalDateTime.now().plusHours(hoursTtl);
long ttlNanos = hoursTtl * 3600_000_000_000L;
byte[] signedRecord = IPNS.createSignedRecord(value, expiry, sequence, ttlNanos, priv);
byte[] signedRecord = IPNS.createSignedRecord(value, expiry, sequence, ttlNanos, extraDataKeySuffix, extraData, priv);
return dht.publishValue(pub, signedRecord, node);
}

Expand Down
17 changes: 12 additions & 5 deletions src/main/java/org/peergos/IpnsPublisher.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package org.peergos;

import io.ipfs.cid.Cid;
import io.ipfs.multiaddr.*;
import io.ipfs.multihash.*;
import io.libp2p.core.*;
import io.libp2p.core.crypto.*;
import io.libp2p.crypto.keys.*;
import org.peergos.blockstore.*;
import org.peergos.cbor.CborObject;
import org.peergos.cbor.Cborable;
import org.peergos.config.*;
import org.peergos.protocol.dht.*;
import org.peergos.protocol.ipns.*;
Expand Down Expand Up @@ -62,10 +65,12 @@ public static void main(String[] a) throws Exception {
List<PrivKey> keys = IntStream.range(0, keycount)
.mapToObj(i -> Ed25519Kt.generateEd25519KeyPair().getFirst())
.collect(Collectors.toList());
byte[] value = new byte[1024];
new Random(28).nextBytes(value);
byte[] extraData = new byte[1024];
new Random(28).nextBytes(extraData);
Cid staticValue = new Cid(1, Cid.Codec.Raw, Multihash.Type.id, new byte[0]);
byte[] value = staticValue.toBytes();
long t0 = System.currentTimeMillis();
List<CompletableFuture<PublishResult>> futs = publish(keys, value, publisher, publishFile)
List<CompletableFuture<PublishResult>> futs = publish(keys, value, new CborObject.CborByteArray(extraData), publisher, publishFile)
.collect(Collectors.toList());
int done = 0;
for (CompletableFuture<PublishResult> fut : futs) {
Expand Down Expand Up @@ -103,14 +108,15 @@ public String toString() {

public static Stream<CompletableFuture<PublishResult>> publish(List<PrivKey> publishers,
byte[] value,
Cborable extraData,
EmbeddedIpfs ipfs,
Path publishFile) throws IOException {
LocalDateTime expiry = LocalDateTime.now().plusDays(7);
long ttlNanos = 7L * 24 * 3600 * 1000_000_000;
List<PublishResult> signed = publishers.stream()
.map(p -> {
Multihash pub = Multihash.deserialize(PeerId.fromPubKey(p.publicKey()).getBytes());
byte[] record = IPNS.createSignedRecord(value, expiry, 1, ttlNanos, p);
byte[] record = IPNS.createSignedRecord(value, expiry, 1, ttlNanos, Optional.of("peergos_rr"), Optional.of(extraData), p);
return new PublishResult(p, pub, record, 0);
}).collect(Collectors.toList());
for (PublishResult rec : signed) {
Expand Down Expand Up @@ -142,7 +148,8 @@ public static List<Integer> resolveAndRepublish(List<PublishResult> publishers,
List<CompletableFuture<Integer>> futs = publishers.stream().map(pub -> CompletableFuture.supplyAsync(() -> {
try {
List<IpnsRecord> records = resolver.resolveRecords(pub.pub, 30);
int success = records.isEmpty() ? successes.get() : successes.incrementAndGet();
List<IpnsRecord> correct = records.stream().filter(r -> Arrays.equals(r.raw, pub.record)).collect(Collectors.toList());
int success = correct.isEmpty() ? successes.get() : successes.incrementAndGet();
int total = done.incrementAndGet();
if (total % 10 == 0)
System.out.println("resolved " + success + " / " + done);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/peergos/protocol/dht/Kademlia.java
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ public CompletableFuture<Integer> publishIpnsValue(PrivKey priv,
LocalDateTime expiry = LocalDateTime.now().plusHours(hours);
long ttlNanos = hours * 3600_000_000_000L;
byte[] publishValue = ("/ipfs/" + value).getBytes();
byte[] signedRecord = IPNS.createSignedRecord(publishValue, expiry, sequence, ttlNanos, priv);
byte[] signedRecord = IPNS.createSignedRecord(publishValue, expiry, sequence, ttlNanos, Optional.empty(), Optional.empty(), priv);
return publishValue(publisher, signedRecord, us);
}

Expand Down
9 changes: 7 additions & 2 deletions src/main/java/org/peergos/protocol/ipns/IPNS.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ public static byte[] createSignedRecord(byte[] value,
LocalDateTime expiry,
long sequence,
long ttlNanos,
Optional<String> extraDataKeySuffix,
Optional<Cborable> extraData,
PrivKey ourKey) {
byte[] cborEntryData = IPNS.createCborDataForIpnsEntry(value, expiry,
Ipns.IpnsEntry.ValidityType.EOL_VALUE, sequence, ttlNanos);
Ipns.IpnsEntry.ValidityType.EOL_VALUE, sequence, ttlNanos, extraDataKeySuffix, extraData);
String expiryString = IPNS.formatExpiry(expiry);
byte[] signature = ourKey.sign(IPNS.createSigV2Data(cborEntryData));
PubKey pubKey = ourKey.publicKey();
Expand Down Expand Up @@ -73,14 +75,17 @@ public static byte[] createCborDataForIpnsEntry(byte[] value,
LocalDateTime expiry,
long validityType,
long sequence,
long ttl) {
long ttl,
Optional<String> extraDataKeySuffix,
Optional<Cborable> extraData) {
SortedMap<String, Cborable> state = new TreeMap<>();
state.put("TTL", new CborObject.CborLong(ttl));
state.put("Value", new CborObject.CborByteArray(value));
state.put("Sequence", new CborObject.CborLong(sequence));
String expiryString = formatExpiry(expiry);
state.put("Validity", new CborObject.CborByteArray(expiryString.getBytes(StandardCharsets.UTF_8)));
state.put("ValidityType", new CborObject.CborLong(validityType));
extraData.ifPresent(e -> state.put("_" + extraDataKeySuffix.get(), e));
return CborObject.CborMap.build(state).serialize();
}

Expand Down
8 changes: 4 additions & 4 deletions src/test/java/org/peergos/EmbeddedIpfsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public void publishValue() throws Exception {

PrivKey publisher = Ed25519Kt.generateEd25519KeyPair().getFirst();
byte[] value = "This is a test".getBytes();
node1.publishValue(publisher, value, 1, 24).join();
node1.publishValue(publisher, value, Optional.empty(), Optional.empty(), 1, 24).join();
byte[] res = node1.resolveValue(publisher.publicKey(), 5).join();
Assert.assertTrue(Arrays.equals(res, value));

Expand All @@ -145,7 +145,7 @@ public void publishPresignedValue() throws Exception {
long hoursTtl = 24*365;
LocalDateTime expiry = LocalDateTime.now().plusHours(hoursTtl);
long ttlNanos = hoursTtl * 3600_000_000_000L;
byte[] signedRecord = IPNS.createSignedRecord(value, expiry, 1, ttlNanos, publisher);
byte[] signedRecord = IPNS.createSignedRecord(value, expiry, 1, ttlNanos, Optional.empty(), Optional.empty(), publisher);
node1.publishPresignedRecord(pub, signedRecord).join();
node1.publishPresignedRecord(pub, signedRecord).join();
node1.publishPresignedRecord(pub, signedRecord).join();
Expand All @@ -155,7 +155,7 @@ public void publishPresignedValue() throws Exception {

// publish an updated value with same expiry
byte[] value2 = "Updated value".getBytes();
byte[] signedRecord2 = IPNS.createSignedRecord(value2, expiry, 2, ttlNanos, publisher);
byte[] signedRecord2 = IPNS.createSignedRecord(value2, expiry, 2, ttlNanos, Optional.empty(), Optional.empty(), publisher);
node1.publishPresignedRecord(pub, signedRecord2).join();
node1.publishPresignedRecord(pub, signedRecord2).join();
node1.publishPresignedRecord(pub, signedRecord2).join();
Expand All @@ -165,7 +165,7 @@ public void publishPresignedValue() throws Exception {

// publish an updated value with earlier expiry
byte[] value3 = "3rd value to put in IPNS".getBytes();
byte[] signedRecord3 = IPNS.createSignedRecord(value3, expiry.minusDays(1), 3, ttlNanos, publisher);
byte[] signedRecord3 = IPNS.createSignedRecord(value3, expiry.minusDays(1), 3, ttlNanos, Optional.empty(), Optional.empty(), publisher);
node1.publishPresignedRecord(pub, signedRecord3).join();
node1.publishPresignedRecord(pub, signedRecord3).join();
node1.publishPresignedRecord(pub, signedRecord3).join();
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/org/peergos/IpnsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void publishIPNSRecordToKubo() throws IOException {

for (int i = 0; i < 10; i++) {
try {
byte[] value = IPNS.createSignedRecord(pathToPublish.getBytes(), expiry, sequence, ttl, node1.getPrivKey());
byte[] value = IPNS.createSignedRecord(pathToPublish.getBytes(), expiry, sequence, ttl, Optional.empty(), Optional.empty(), node1.getPrivKey());
success = dht.dial(node1, address2).getController().join()
.putValue(node1Id, value)
.orTimeout(2, TimeUnit.SECONDS).join();
Expand Down

0 comments on commit 5f6960b

Please sign in to comment.