This is an automated email from the ASF dual-hosted git repository.
toulmean pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-tuweni.git
The following commit(s) were added to refs/heads/master by this push:
new de49f47 Add support for list entries in ENRs
new 30a04f7 Merge pull request #115 from
atoulme/add_support_for_lists_in_enrs
de49f47 is described below
commit de49f47e57a4a908adc13e56ca447dd4d9396a91
Author: Antoine Toulme <[email protected]>
AuthorDate: Sun Jul 5 10:26:44 2020 -0700
Add support for list entries in ENRs
---
.../devp2p/v5/DefaultNodeDiscoveryServiceTest.kt | 1 +
.../org/apache/tuweni/devp2p/DiscoveryService.kt | 2 +-
.../org/apache/tuweni/devp2p/EthereumNodeRecord.kt | 38 +++++++++++++++++-----
.../tuweni/devp2p/v5/NodeDiscoveryService.kt | 1 +
.../tuweni/devp2p/v5/storage/RoutingTable.kt | 2 +-
.../apache/tuweni/devp2p/ENRResponsePacketTest.kt | 7 ++--
.../apache/tuweni/devp2p/EthereumNodeRecordTest.kt | 29 ++++++++++-------
.../tuweni/devp2p/v5/storage/RoutingTableTest.kt | 17 +++++++---
8 files changed, 69 insertions(+), 28 deletions(-)
diff --git
a/devp2p/src/integrationTest/kotlin/org/apache/tuweni/devp2p/v5/DefaultNodeDiscoveryServiceTest.kt
b/devp2p/src/integrationTest/kotlin/org/apache/tuweni/devp2p/v5/DefaultNodeDiscoveryServiceTest.kt
index e448415..92e3838 100644
---
a/devp2p/src/integrationTest/kotlin/org/apache/tuweni/devp2p/v5/DefaultNodeDiscoveryServiceTest.kt
+++
b/devp2p/src/integrationTest/kotlin/org/apache/tuweni/devp2p/v5/DefaultNodeDiscoveryServiceTest.kt
@@ -52,6 +52,7 @@ class DefaultNodeDiscoveryServiceTest {
keyPair,
enrSeq,
emptyMap(),
+ emptyMap(),
bindAddress.address,
null,
bindAddress.port
diff --git
a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/DiscoveryService.kt
b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/DiscoveryService.kt
index 24021b1..f5b9b73 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/DiscoveryService.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/DiscoveryService.kt
@@ -349,7 +349,7 @@ internal class CoroutineDiscoveryService(
)
enr = EthereumNodeRecord.toRLP(
- keyPair, seq, enrData, selfEndpoint.address, selfEndpoint.tcpPort,
+ keyPair, seq, enrData, null, selfEndpoint.address, selfEndpoint.tcpPort,
selfEndpoint.udpPort
)
diff --git
a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/EthereumNodeRecord.kt
b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/EthereumNodeRecord.kt
index cc6f7f7..abeea22 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/EthereumNodeRecord.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/EthereumNodeRecord.kt
@@ -31,7 +31,12 @@ import java.time.Instant
/**
* Ethereum Node Record (ENR) as described in
[EIP-778](https://eips.ethereum.org/EIPS/eip-778).
*/
-class EthereumNodeRecord(val signature: Bytes, val seq: Long, val data:
Map<String, Bytes>) {
+class EthereumNodeRecord(
+ val signature: Bytes,
+ val seq: Long,
+ val data: Map<String, Bytes>,
+ val listData: Map<String, List<Bytes>> = emptyMap()
+) {
companion object {
@@ -52,19 +57,26 @@ class EthereumNodeRecord(val signature: Bytes, val seq:
Long, val data: Map<Stri
val seq = it.readLong()
val data = mutableMapOf<String, Bytes>()
+ val listData = mutableMapOf<String, List<Bytes>>()
while (!it.isComplete) {
val key = it.readString()
if (it.nextIsList()) {
- it.skipNext()
- // TODO("not ready yet to read list values")
- // data[key] = it.readListContents { listreader ->
listreader.readValue()}
+ listData[key] = it.readListContents { listreader ->
+ if (listreader.nextIsList()) {
+ // TODO complex structures not supported
+ listreader.skipNext()
+ null
+ } else {
+ listreader.readValue()
+ }
+ }.filterNotNull()
} else {
val value = it.readValue()
data[key] = value
}
}
- EthereumNodeRecord(sig, seq, data)
+ EthereumNodeRecord(sig, seq, data, listData)
}
}
@@ -75,6 +87,7 @@ class EthereumNodeRecord(val signature: Bytes, val seq: Long,
val data: Map<Stri
tcp: Int? = null,
udp: Int? = null,
data: Map<String, Bytes>? = null,
+ listData: Map<String, List<Bytes>>? = null,
writer: RLPWriter
) {
writer.writeLong(seq)
@@ -92,11 +105,18 @@ class EthereumNodeRecord(val signature: Bytes, val seq:
Long, val data: Map<Stri
udp?.let {
mutableData["udp"] = Bytes.ofUnsignedShort(it)
}
- mutableData.keys.sorted().forEach { key ->
+ val keys = mutableListOf<String>()
+ keys.addAll(mutableData.keys)
+ listData?.let { keys.addAll(it.keys) }
+ keys.sorted().forEach { key ->
mutableData[key]?.let { value ->
writer.writeString(key)
writer.writeValue(value)
}
+ listData?.get(key)?.let { value ->
+ writer.writeString(key)
+ writer.writeList(value) { writer, v -> writer.writeValue(v) }
+ }
}
}
@@ -105,6 +125,7 @@ class EthereumNodeRecord(val signature: Bytes, val seq:
Long, val data: Map<Stri
* @param signatureKeyPair the key pair to use to sign the ENR
* @param seq the sequence number for the ENR. It should be higher than
the previous time the ENR was generated. It defaults to the current time since
epoch in milliseconds.
* @param data the key pairs to encode in the ENR
+ * @param listData the key pairs of list values to encode in the ENR
* @param ip the IP address of the host
* @param tcp an optional parameter to a TCP port used for the wire
protocol
* @param udp an optional parameter to a UDP port used for discovery
@@ -116,12 +137,13 @@ class EthereumNodeRecord(val signature: Bytes, val seq:
Long, val data: Map<Stri
signatureKeyPair: SECP256K1.KeyPair,
seq: Long = Instant.now().toEpochMilli(),
data: Map<String, Bytes>? = null,
+ listData: Map<String, List<Bytes>>? = null,
ip: InetAddress,
tcp: Int? = null,
udp: Int? = null
): Bytes {
val encoded = RLP.encode { writer ->
- encode(signatureKeyPair, seq, ip, tcp, udp, data, writer)
+ encode(signatureKeyPair, seq, ip, tcp, udp, data, listData, writer)
}
val signature = SECP256K1.sign(Hash.keccak256(encoded), signatureKeyPair)
val sigBytes = MutableBytes.create(64)
@@ -130,7 +152,7 @@ class EthereumNodeRecord(val signature: Bytes, val seq:
Long, val data: Map<Stri
val completeEncoding = RLP.encodeList { writer ->
writer.writeValue(sigBytes)
- encode(signatureKeyPair, seq, ip, tcp, udp, data, writer)
+ encode(signatureKeyPair, seq, ip, tcp, udp, data, listData, writer)
}
return completeEncoding
}
diff --git
a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/NodeDiscoveryService.kt
b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/NodeDiscoveryService.kt
index 2862ac1..653a392 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/NodeDiscoveryService.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/NodeDiscoveryService.kt
@@ -90,6 +90,7 @@ class DefaultNodeDiscoveryService(
keyPair,
enrSeq,
emptyMap(),
+ emptyMap(),
bindAddress.address,
null,
bindAddress.port
diff --git
a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/storage/RoutingTable.kt
b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/storage/RoutingTable.kt
index 6777272..252a382 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/storage/RoutingTable.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/storage/RoutingTable.kt
@@ -36,7 +36,7 @@ class RoutingTable(
nodeId = nodeIdCalculation,
distanceToSelf = {
val xorResult = key(it) xorDist selfNodeId
- IntMath.log2(xorResult, RoundingMode.FLOOR)
+ if (xorResult == 0) 0 else IntMath.log2(xorResult, RoundingMode.FLOOR)
})
val size: Int
diff --git
a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/ENRResponsePacketTest.kt
b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/ENRResponsePacketTest.kt
index df0f929..63f2b75 100644
--- a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/ENRResponsePacketTest.kt
+++ b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/ENRResponsePacketTest.kt
@@ -35,8 +35,11 @@ internal class ENRResponsePacketTest {
val keyPair = SECP256K1.KeyPair.random()
val requestHash = Bytes32.random()
- val enr = EthereumNodeRecord.toRLP(SECP256K1.KeyPair.random(), 2,
emptyMap(),
- InetAddress.getByName("localhost"), 3000, 12000)
+ val enr = EthereumNodeRecord.toRLP(
+ SECP256K1.KeyPair.random(), 2, emptyMap(),
+ emptyMap(),
+ InetAddress.getByName("localhost"), 3000, 12000
+ )
val now = System.currentTimeMillis()
val pong = ENRResponsePacket.create(keyPair, now, requestHash, enr)
diff --git
a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/EthereumNodeRecordTest.kt
b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/EthereumNodeRecordTest.kt
index eeb1552..87cc06b 100644
--- a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/EthereumNodeRecordTest.kt
+++ b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/EthereumNodeRecordTest.kt
@@ -23,7 +23,6 @@ import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.extension.ExtendWith
-import java.lang.IllegalArgumentException
import java.net.InetAddress
@ExtendWith(BouncyCastleExtension::class)
@@ -40,34 +39,42 @@ class EthereumNodeRecordTest {
@Test
fun readFromRLP() {
- val enr = EthereumNodeRecord.fromRLP(Bytes.fromHexString(
- "f884b8407098ad865b00a582051940cb9cf36836572411a4727878307701" +
- "1599ed5cd16b76f2635f4e234738f30813a89eb9137e3e3df5266e3a1f11" +
- "df72ecf1145ccb9c01826964827634826970847f00000189736563703235" +
- "366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1" +
- "400f3258cd31388375647082765f"))
+ val enr = EthereumNodeRecord.fromRLP(
+ Bytes.fromHexString(
+ "f884b8407098ad865b00a582051940cb9cf36836572411a4727878307701" +
+ "1599ed5cd16b76f2635f4e234738f30813a89eb9137e3e3df5266e3a1f11" +
+ "df72ecf1145ccb9c01826964827634826970847f00000189736563703235" +
+ "366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1" +
+ "400f3258cd31388375647082765f"
+ )
+ )
assertEquals(1L, enr.seq)
assertEquals(Bytes.wrap("v4".toByteArray()), enr.data["id"])
assertEquals(Bytes.fromHexString("7f000001"), enr.data["ip"])
assertEquals(
Bytes.fromHexString("03ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138"),
- enr.data["secp256k1"])
+ enr.data["secp256k1"]
+ )
assertEquals(Bytes.fromHexString("765f"), enr.data["udp"])
enr.validate()
- System.out.println(enr.publicKey().bytes())
}
@Test
fun toRLP() {
val keypair = SECP256K1.KeyPair.random()
- val rlp = EthereumNodeRecord.toRLP(keypair,
+ val rlp = EthereumNodeRecord.toRLP(
+ keypair,
seq = 1L,
data = mutableMapOf(Pair("key", Bytes.fromHexString("deadbeef"))),
- ip = InetAddress.getByName("127.0.0.1"))
+ listData = mutableMapOf(Pair("foo",
listOf(Bytes.fromHexString("deadbeef")))),
+ ip = InetAddress.getByName("127.0.0.1")
+ )
val record = EthereumNodeRecord.fromRLP(rlp)
assertEquals(1L, record.seq)
assertEquals(Bytes.wrap("v4".toByteArray()), record.data["id"])
assertEquals(Bytes.fromHexString("7f000001"), record.data["ip"])
assertEquals(keypair.publicKey(), record.publicKey())
+ assertEquals(Bytes.fromHexString("deadbeef"), record.data["key"])
+ assertEquals(Bytes.fromHexString("deadbeef"), (record.listData["foo"] ?:
error("None"))[0])
}
}
diff --git
a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/storage/RoutingTableTest.kt
b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/storage/RoutingTableTest.kt
index 9792645..7293590 100644
---
a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/storage/RoutingTableTest.kt
+++
b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/storage/RoutingTableTest.kt
@@ -21,6 +21,9 @@ import org.apache.tuweni.crypto.SECP256K1
import org.apache.tuweni.devp2p.EthereumNodeRecord
import org.apache.tuweni.junit.BouncyCastleExtension
import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertNotEquals
+import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import java.net.InetAddress
@@ -38,26 +41,30 @@ class RoutingTableTest {
@Test
fun addCreatesRecordInBucket() {
routingTable.add(newEnr)
-
- assert(!routingTable.isEmpty())
+ assertTrue(!routingTable.isEmpty())
}
@Test
fun evictRemovesRecord() {
routingTable.add(newEnr)
- assert(!routingTable.isEmpty())
+ assertTrue(!routingTable.isEmpty())
routingTable.evict(newEnr)
- assert(routingTable.isEmpty())
+ assertTrue(routingTable.isEmpty())
}
@Test
fun getSelfEnrGivesTableOwnerEnr() {
val result = routingTable.getSelfEnr()
+ assertEquals(enr, result)
+ }
- assert(result == enr)
+ @Test
+ fun distanceToSelf() {
+ assertEquals(0, routingTable.distanceToSelf(routingTable.getSelfEnr()))
+ assertNotEquals(0, routingTable.distanceToSelf(newEnr))
}
@AfterEach
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]