integration test of upd handshake
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultNodeDiscoveryService.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultNodeDiscoveryService.kt
index 972429e..8575452 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultNodeDiscoveryService.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultNodeDiscoveryService.kt
@@ -22,7 +22,6 @@
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.apache.tuweni.bytes.Bytes
-import org.apache.tuweni.crypto.Hash
import org.apache.tuweni.crypto.SECP256K1
import org.apache.tuweni.devp2p.EthereumNodeRecord
import org.apache.tuweni.devp2p.v5.NodeDiscoveryService
@@ -47,8 +46,7 @@
null,
bindAddress.port
),
- private val nodeId: Bytes = Hash.sha2_256(selfENR),
- private val connector: UdpConnector = DefaultUdpConnector(nodeId, bindAddress, keyPair, selfENR),
+ private val connector: UdpConnector = DefaultUdpConnector(bindAddress, keyPair, selfENR),
override val coroutineContext: CoroutineContext = Dispatchers.Default
) : NodeDiscoveryService, CoroutineScope {
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultPacketCodec.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultPacketCodec.kt
index 868243a..6dbab0f 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultPacketCodec.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultPacketCodec.kt
@@ -17,6 +17,7 @@
package org.apache.tuweni.devp2p.v5.internal
import org.apache.tuweni.bytes.Bytes
+import org.apache.tuweni.crypto.Hash
import org.apache.tuweni.crypto.SECP256K1
import org.apache.tuweni.devp2p.v5.AuthenticationProvider
import org.apache.tuweni.devp2p.v5.PacketCodec
@@ -33,9 +34,9 @@
import kotlin.IllegalArgumentException
class DefaultPacketCodec(
- private val nodeId: Bytes,
private val keyPair: SECP256K1.KeyPair,
private val enr: Bytes,
+ private val nodeId: Bytes = Hash.sha2_256(enr),
private val authenticationProvider: AuthenticationProvider = DefaultAuthenticationProvider(keyPair, enr)
) : PacketCodec {
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultUdpConnector.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultUdpConnector.kt
index 3bd3e73..ebb4eb8 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultUdpConnector.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultUdpConnector.kt
@@ -21,6 +21,7 @@
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.apache.tuweni.bytes.Bytes
+import org.apache.tuweni.crypto.Hash
import org.apache.tuweni.crypto.SECP256K1
import org.apache.tuweni.devp2p.v5.MessageHandler
import org.apache.tuweni.devp2p.v5.PacketCodec
@@ -39,13 +40,13 @@
import kotlin.coroutines.CoroutineContext
class DefaultUdpConnector(
- private val nodeId: Bytes,
private val bindAddress: InetSocketAddress,
private val keyPair: SECP256K1.KeyPair,
private val selfEnr: Bytes,
+ private val nodeId: Bytes = Hash.sha2_256(selfEnr),
private val receiveChannel: CoroutineDatagramChannel = CoroutineDatagramChannel.open(),
private val sendChannel: CoroutineDatagramChannel = CoroutineDatagramChannel.open(),
- private val packetCodec: PacketCodec = DefaultPacketCodec(nodeId, keyPair, selfEnr),
+ private val packetCodec: PacketCodec = DefaultPacketCodec(keyPair, selfEnr),
override val coroutineContext: CoroutineContext = Dispatchers.IO
) : UdpConnector, CoroutineScope {
@@ -106,8 +107,12 @@
override fun getNodeKeyPair(): SECP256K1.KeyPair = keyPair
- override fun getPendingNodeIdByAddress(address: InetSocketAddress): Bytes = authenticatingPeers[address]
- ?: throw IllegalArgumentException("Authenticated peer not found with address ${address.hostName}:${address.port}")
+ override fun getPendingNodeIdByAddress(address: InetSocketAddress): Bytes {
+ val result = authenticatingPeers[address]
+ ?: throw IllegalArgumentException("Authenticated peer not found with address ${address.hostName}:${address.port}")
+ authenticatingPeers.remove(address)
+ return result
+ }
private fun processDatagram(datagram: ByteBuffer, address: InetSocketAddress) {
val messageBytes = Bytes.wrapByteBuffer(datagram)
@@ -116,9 +121,8 @@
when (message) {
is RandomMessage -> randomMessageHandler.handle(message, address, decodeResult.srcNodeId, this)
is WhoAreYouMessage -> whoAreYouMessageHandler.handle(message, address, decodeResult.srcNodeId, this)
- is FindNodeMessage -> { } //TODO: response with NODES message
+ is FindNodeMessage -> { } //TODO: response with NODES message
else -> throw IllegalArgumentException("Unexpected message has been received - ${message::class.java.simpleName}")
}
}
-
}
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/handler/WhoAreYouMessageHandler.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/handler/WhoAreYouMessageHandler.kt
index 17e28e8..754ceae 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/handler/WhoAreYouMessageHandler.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/handler/WhoAreYouMessageHandler.kt
@@ -17,6 +17,7 @@
package org.apache.tuweni.devp2p.v5.internal.handler
import org.apache.tuweni.bytes.Bytes
+import org.apache.tuweni.crypto.Hash
import org.apache.tuweni.devp2p.v5.MessageHandler
import org.apache.tuweni.devp2p.v5.UdpConnector
import org.apache.tuweni.devp2p.v5.packet.FindNodeMessage
@@ -37,8 +38,9 @@
// Retrieve enr
val destRlp = connector.getPendingNodeIdByAddress(address)
val handshakeParams = HandshakeInitParameters(message.idNonce, message.authTag, destRlp)
+ val destNodeId = Hash.sha2_256(destRlp)
val findNodeMessage = FindNodeMessage()
- connector.send(address, findNodeMessage, srcNodeId, handshakeParams)
+ connector.send(address, findNodeMessage, destNodeId, handshakeParams)
}
}
diff --git a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/HandshakeIntegrationTest.kt b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/HandshakeIntegrationTest.kt
new file mode 100644
index 0000000..ebbad34
--- /dev/null
+++ b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/HandshakeIntegrationTest.kt
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+package org.apache.tuweni.devp2p.v5
+
+import kotlinx.coroutines.runBlocking
+import org.apache.tuweni.bytes.Bytes
+import org.apache.tuweni.crypto.Hash
+import org.apache.tuweni.crypto.SECP256K1
+import org.apache.tuweni.devp2p.EthereumNodeRecord
+import org.apache.tuweni.devp2p.v5.internal.DefaultAuthenticationProvider
+import org.apache.tuweni.devp2p.v5.internal.DefaultNodeDiscoveryService
+import org.apache.tuweni.devp2p.v5.internal.DefaultPacketCodec
+import org.apache.tuweni.devp2p.v5.internal.DefaultUdpConnector
+import org.apache.tuweni.devp2p.v5.packet.FindNodeMessage
+import org.apache.tuweni.devp2p.v5.packet.RandomMessage
+import org.apache.tuweni.devp2p.v5.packet.UdpMessage
+import org.apache.tuweni.devp2p.v5.packet.WhoAreYouMessage
+import org.apache.tuweni.io.Base64URLSafe
+import org.apache.tuweni.junit.BouncyCastleExtension
+import org.apache.tuweni.net.coroutines.CoroutineDatagramChannel
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.ExtendWith
+import java.net.InetAddress
+import java.net.InetSocketAddress
+import java.nio.ByteBuffer
+
+@ExtendWith(BouncyCastleExtension::class)
+class HandshakeIntegrationTest {
+
+ private val keyPair: SECP256K1.KeyPair = SECP256K1.KeyPair.random()
+ private val enr: Bytes = EthereumNodeRecord.toRLP(keyPair, ip = InetAddress.getLocalHost(), udp = SERVICE_PORT)
+ private val address: InetSocketAddress = InetSocketAddress(InetAddress.getLocalHost(), SERVICE_PORT)
+ private val connector: UdpConnector = DefaultUdpConnector(address, keyPair, enr)
+
+ private val clientKeyPair = SECP256K1.KeyPair.random()
+ private val clientEnr = EthereumNodeRecord.toRLP(clientKeyPair, ip = InetAddress.getLocalHost(), udp = CLIENT_PORT)
+ private val authProvider = DefaultAuthenticationProvider(clientKeyPair, clientEnr)
+ private val clientCodec = DefaultPacketCodec(clientKeyPair, clientEnr, authenticationProvider = authProvider)
+ private val socket = CoroutineDatagramChannel.open()
+
+ private val clientNodeId: Bytes = Hash.sha2_256(clientEnr)
+
+ private val bootList = listOf("enr:${Base64URLSafe.encode(clientEnr)}")
+ private val service: NodeDiscoveryService =
+ DefaultNodeDiscoveryService(keyPair, SERVICE_PORT, bootstrapENRList = bootList, connector = connector)
+
+ @BeforeEach
+ fun init() {
+ socket.bind(InetSocketAddress(9091))
+ service.start()
+ }
+
+ @Test
+ fun discv5HandshakeTest() {
+ runBlocking {
+ val buffer = ByteBuffer.allocate(UdpMessage.MAX_UDP_MESSAGE_SIZE)
+ socket.receive(buffer)
+ buffer.flip()
+
+ var content = Bytes.wrapByteBuffer(buffer)
+ var decodingResult = clientCodec.decode(content)
+ assert(decodingResult.message is RandomMessage)
+ buffer.clear()
+
+ sendWhoAreYou()
+
+ socket.receive(buffer)
+ buffer.flip()
+ content = Bytes.wrapByteBuffer(buffer)
+ decodingResult = clientCodec.decode(content)
+ assert(decodingResult.message is FindNodeMessage)
+ assert(null != authProvider.findSessionKey(Hash.sha2_256(enr).toHexString()))
+
+ val message = decodingResult.message as FindNodeMessage
+
+ assert(message.distance == 0L)
+ assert(message.requestId.size() == UdpMessage.REQUEST_ID_LENGTH)
+ }
+ }
+
+ @AfterEach
+ fun tearDown() {
+ service.terminate(true)
+ socket.close()
+ }
+
+ private suspend fun sendWhoAreYou() {
+ val message = WhoAreYouMessage()
+ val bytes = clientCodec.encode(message, clientNodeId)
+ val buffer = ByteBuffer.wrap(bytes.toArray())
+ socket.send(buffer, address)
+ }
+
+ companion object {
+ private const val SERVICE_PORT: Int = 9090
+ private const val CLIENT_PORT: Int = 9091
+ }
+}
diff --git a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/encrypt/AES128GCMTest.kt b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/encrypt/AES128GCMTest.kt
index f91ad02..4146d05 100644
--- a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/encrypt/AES128GCMTest.kt
+++ b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/encrypt/AES128GCMTest.kt
@@ -1,3 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
package org.apache.tuweni.devp2p.v5.encrypt
import org.apache.tuweni.bytes.Bytes
@@ -31,5 +47,4 @@
assert(result == expectedResult)
}
-
}
diff --git a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/encrypt/SessionKeyGeneratorTest.kt b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/encrypt/SessionKeyGeneratorTest.kt
index 530b73f..f517ed1 100644
--- a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/encrypt/SessionKeyGeneratorTest.kt
+++ b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/encrypt/SessionKeyGeneratorTest.kt
@@ -1,3 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
package org.apache.tuweni.devp2p.v5.encrypt
import org.apache.tuweni.bytes.Bytes
@@ -22,5 +38,4 @@
assert(result.initiatorKey == expectedInitiatorKey)
assert(result.recipientKey == expectedRecipientKey)
}
-
}
diff --git a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultAuthenticationProviderTest.kt b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultAuthenticationProviderTest.kt
index 357e9e5..cebe167 100644
--- a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultAuthenticationProviderTest.kt
+++ b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultAuthenticationProviderTest.kt
@@ -91,5 +91,4 @@
assert(result != null)
}
-
}
diff --git a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultNodeDiscoveryServiceTest.kt b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultNodeDiscoveryServiceTest.kt
index 9c65d90..895db0b 100644
--- a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultNodeDiscoveryServiceTest.kt
+++ b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultNodeDiscoveryServiceTest.kt
@@ -18,7 +18,6 @@
import kotlinx.coroutines.runBlocking
import org.apache.tuweni.bytes.Bytes
-import org.apache.tuweni.crypto.Hash
import org.apache.tuweni.crypto.SECP256K1
import org.apache.tuweni.devp2p.EthereumNodeRecord
import org.apache.tuweni.devp2p.v5.NodeDiscoveryService
@@ -56,11 +55,10 @@
null,
bindAddress.port
)
- private val nodeId: Bytes = Hash.sha2_256(selfENR)
- private val connector: UdpConnector = DefaultUdpConnector(nodeId, bindAddress, keyPair, selfENR)
+ private val connector: UdpConnector = DefaultUdpConnector(bindAddress, keyPair, selfENR)
private val nodeDiscoveryService: NodeDiscoveryService =
- DefaultNodeDiscoveryService(keyPair, localPort, bindAddress, bootstrapENRList, enrSeq, selfENR, nodeId, connector)
+ DefaultNodeDiscoveryService(keyPair, localPort, bindAddress, bootstrapENRList, enrSeq, selfENR, connector)
@Test
fun startInitializesConnectorAndBootstraps() {
@@ -96,5 +94,4 @@
assert(!connector.available())
}
-
}
diff --git a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultPacketCodecTest.kt b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultPacketCodecTest.kt
index ba03bb3..85a08dd 100644
--- a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultPacketCodecTest.kt
+++ b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultPacketCodecTest.kt
@@ -42,7 +42,7 @@
private val nodeId: Bytes = Hash.sha2_256(enr)
private val authenticationProvider: AuthenticationProvider = DefaultAuthenticationProvider(keyPair, enr)
- private val codec: PacketCodec = DefaultPacketCodec(nodeId, keyPair, enr, authenticationProvider)
+ private val codec: PacketCodec = DefaultPacketCodec(keyPair, enr, nodeId, authenticationProvider)
private val destNodeId: Bytes = Bytes.random(32)
@@ -144,5 +144,4 @@
assert(result!!.requestId == message.requestId)
assert(result.distance == message.distance)
}
-
}
diff --git a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultUdpConnectorTest.kt b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultUdpConnectorTest.kt
index 002af30..33f84eb 100644
--- a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultUdpConnectorTest.kt
+++ b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultUdpConnectorTest.kt
@@ -44,11 +44,11 @@
private val data: Bytes = UdpMessage.randomData()
private val message: RandomMessage = RandomMessage(data)
- private var connector: UdpConnector = DefaultUdpConnector(nodeId, address, keyPair, selfEnr)
+ private var connector: UdpConnector = DefaultUdpConnector(address, keyPair, selfEnr, nodeId)
@BeforeEach
fun setUp() {
- connector = DefaultUdpConnector(nodeId, address, keyPair, selfEnr)
+ connector = DefaultUdpConnector(address, keyPair, selfEnr, nodeId)
}
@AfterEach