work in progress
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/ENRStorage.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/ENRStorage.kt
index 8224a27..3388444 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/ENRStorage.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/ENRStorage.kt
@@ -1,11 +1,41 @@
+/*
+ * 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 org.apache.tuweni.bytes.Bytes
 
+/**
+ * In-memory storage of node records
+ */
 interface ENRStorage {
 
+  /**
+   * Persist node record into storage
+   *
+   * @param enr node record
+   */
   fun set(enr: Bytes)
 
+  /**
+   * Find node record into storage
+   *
+   * @param nodeId node identifier
+   *
+   * @return node record
+   */
   fun find(nodeId: Bytes): Bytes?
-
 }
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/MessageObserver.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/MessageObserver.kt
index 2d926ca..843378b 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/MessageObserver.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/MessageObserver.kt
@@ -1,9 +1,32 @@
+/*
+ * 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 org.apache.tuweni.devp2p.v5.packet.UdpMessage
 
+/**
+ * Udp message listener for message observance, generally for test purposes
+ */
 interface MessageObserver {
 
+  /**
+   * Perform message observation
+   *
+   * @param incoming processed message
+   */
   fun observe(message: UdpMessage)
-
 }
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 cbe8a3d..b146209 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
@@ -26,8 +26,6 @@
 import org.apache.tuweni.crypto.SECP256K1
 import org.apache.tuweni.devp2p.EthereumNodeRecord
 import org.apache.tuweni.devp2p.v5.internal.DefaultUdpConnector
-import org.apache.tuweni.devp2p.v5.packet.FindNodeMessage
-import org.apache.tuweni.devp2p.v5.packet.PingMessage
 import org.apache.tuweni.devp2p.v5.packet.RandomMessage
 import org.apache.tuweni.devp2p.v5.storage.DefaultENRStorage
 import org.apache.tuweni.io.Base64URLSafe
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/UdpConnector.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/UdpConnector.kt
index 47b3caf..8fef7cf 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/UdpConnector.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/UdpConnector.kt
@@ -71,23 +71,6 @@
   fun started(): Boolean
 
   /**
-   * Add node identifier which awaits for authentication
-   *
-   * @param address socket address
-   * @param nodeId node identifier
-   */
-  fun addPendingNodeId(address: InetSocketAddress, nodeId: Bytes)
-
-  /**
-   * Get node identifier which awaits for authentication
-   *
-   * @param address socket address
-   *
-   * @return node identifier
-   */
-  fun findPendingNodeId(address: InetSocketAddress): Bytes
-
-  /**
    * Provides node's key pair
    *
    * @return node's key pair
@@ -108,15 +91,49 @@
    */
   fun getEnr(): EthereumNodeRecord
 
+  /**
+   * Attach observer for listening processed messages
+   *
+   * @param observer instance, proceeding observation
+   */
   fun attachObserver(observer: MessageObserver)
 
+  /**
+   * Remove observer for listening processed message
+   *
+   * @param observer observer for removal
+   */
   fun detachObserver(observer: MessageObserver)
 
+  /**
+   * Get kademlia routing table
+   *
+   * @return kademlia table
+   */
   fun getNodesTable(): RoutingTable
 
+  /**
+   * Retrieve enr of pinging node
+   *
+   * @param node identifier
+   *
+   * @return node record
+   */
   fun getAwaitingPongRecord(nodeId: Bytes): Bytes?
 
+  /**
+   * Retrieve last sent message, in case if it unauthorized and node can resend with authentication header
+   *
+   * @param authTag message's authentication tag
+   *
+   * @return message, including node identifier
+   */
   fun getPendingMessage(authTag: Bytes): TrackingMessage
 
+  /**
+   * Provides enr storage of known nodes
+   *
+   * @return nodes storage
+   */
   fun getNodeRecords(): ENRStorage
 }
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultAuthenticationProvider.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultAuthenticationProvider.kt
index 06ce1c4..79783c3 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultAuthenticationProvider.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/DefaultAuthenticationProvider.kt
@@ -43,6 +43,7 @@
     .build()
   private val nodeId: Bytes = Hash.sha2_256(routingTable.getSelfEnr())
 
+  @Synchronized
   override fun authenticate(handshakeParams: HandshakeInitParameters): AuthHeader {
     // Generate ephemeral key pair
     val ephemeralKeyPair = SECP256K1.KeyPair.random()
@@ -57,7 +58,7 @@
     // Derive keys
     val sessionKey = SessionKeyGenerator.generate(nodeId, destNodeId, secret, handshakeParams.idNonce)
 
-    setSessionKey(destNodeId.toHexString(), sessionKey)
+    sessionKeys.put(destNodeId.toHexString(), sessionKey)
 
     val signature = sign(keyPair, handshakeParams)
 
@@ -70,14 +71,17 @@
     )
   }
 
+  @Synchronized
   override fun findSessionKey(nodeId: String): SessionKey? {
     return sessionKeys.getIfPresent(nodeId)
   }
 
+  @Synchronized
   override fun setSessionKey(nodeId: String, sessionKey: SessionKey) {
     sessionKeys.put(nodeId, sessionKey)
   }
 
+  @Synchronized
   override fun finalizeHandshake(senderNodeId: Bytes, authHeader: AuthHeader) {
     val ephemeralPublicKey = SECP256K1.PublicKey.fromBytes(authHeader.ephemeralPublicKey)
     val secret = SECP256K1.calculateKeyAgreement(keyPair.secretKey(), ephemeralPublicKey)
@@ -95,7 +99,7 @@
       if (!signatureVerified) {
         throw IllegalArgumentException("Signature is not verified")
       }
-      setSessionKey(senderNodeId.toHexString(), sessionKey)
+      sessionKeys.put(senderNodeId.toHexString(), sessionKey)
       routingTable.add(enrRLP)
     }
   }
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 9f45a04..51374c1 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
@@ -23,7 +23,6 @@
 import org.apache.tuweni.devp2p.v5.PacketCodec
 import org.apache.tuweni.devp2p.v5.storage.RoutingTable
 import org.apache.tuweni.devp2p.v5.encrypt.AES128GCM
-import org.apache.tuweni.devp2p.v5.encrypt.SessionKeyGenerator
 import org.apache.tuweni.devp2p.v5.packet.FindNodeMessage
 import org.apache.tuweni.devp2p.v5.packet.RandomMessage
 import org.apache.tuweni.devp2p.v5.packet.UdpMessage
@@ -60,21 +59,27 @@
 
     val tag = UdpMessage.tag(nodeId, destNodeId)
     if (message is RandomMessage) {
-      val rlpAuthTag = RLP.encodeValue(message.authTag)
-      val content = message.encode()
-      return EncodeResult(message.authTag, Bytes.wrap(tag, rlpAuthTag, content))
+      return encodeRandomMessage(tag, message)
     }
 
-    val authHeader = handshakeParams?.let { authenticationProvider.authenticate(handshakeParams) }
+    val sessionKey = authenticationProvider.findSessionKey(destNodeId.toHexString())
+    val authHeader = handshakeParams?.let {
+      if (null == sessionKey) {
+        authenticationProvider.authenticate(handshakeParams)
+      } else null
+    }
 
     val initiatorKey = authenticationProvider.findSessionKey(destNodeId.toHexString())?.initiatorKey
-      ?: Bytes.random(SessionKeyGenerator.DERIVED_KEY_SIZE) // encrypt with random key, to initiate handshake
+      ?: return encodeRandomMessage(tag, RandomMessage())
     val messagePlain = Bytes.wrap(message.getMessageType(), message.encode())
     return if (null != authHeader) {
       val encodedHeader = authHeader.asRlp()
       val authTag = authHeader.authTag
       val encryptionMeta = Bytes.wrap(tag, encodedHeader)
       val encryptionResult = AES128GCM.encrypt(initiatorKey, authTag, messagePlain, encryptionMeta)
+      if (message is NodesMessage) {
+        println(encryptionResult)
+      }
       EncodeResult(authTag, Bytes.wrap(tag, encodedHeader, encryptionResult))
     } else {
       val authTag = UdpMessage.authTag()
@@ -138,6 +143,12 @@
     }
   }
 
+  private fun encodeRandomMessage(tag: Bytes, message: RandomMessage): EncodeResult {
+    val rlpAuthTag = RLP.encodeValue(message.authTag)
+    val content = message.encode()
+    return EncodeResult(message.authTag, Bytes.wrap(tag, rlpAuthTag, content))
+  }
+
   companion object {
     private const val WHO_ARE_YOU_MESSAGE_LENGTH = 48
   }
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 41ed9cb..9a517a0 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
@@ -18,6 +18,7 @@
 
 import com.google.common.cache.Cache
 import com.google.common.cache.CacheBuilder
+import com.google.common.cache.RemovalCause
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.Job
@@ -50,11 +51,10 @@
 import org.apache.tuweni.devp2p.v5.packet.PongMessage
 import org.apache.tuweni.devp2p.v5.storage.DefaultENRStorage
 import org.apache.tuweni.net.coroutines.CoroutineDatagramChannel
-import org.logl.Logger
-import org.logl.LoggerProvider
 import java.net.InetSocketAddress
 import java.nio.ByteBuffer
 import java.time.Duration
+import java.util.logging.Logger
 import kotlin.coroutines.CoroutineContext
 
 class DefaultUdpConnector(
@@ -65,13 +65,12 @@
   private val receiveChannel: CoroutineDatagramChannel = CoroutineDatagramChannel.open(),
   private val nodesTable: RoutingTable = RoutingTable(selfEnr),
   private val packetCodec: PacketCodec = DefaultPacketCodec(keyPair, nodesTable),
-  private val authenticatingPeers: MutableMap<InetSocketAddress, Bytes> = mutableMapOf(),
   private val selfNodeRecord: EthereumNodeRecord = EthereumNodeRecord.fromRLP(selfEnr),
   private val messageListeners: MutableList<MessageObserver> = mutableListOf(),
   override val coroutineContext: CoroutineContext = Dispatchers.IO
 ) : UdpConnector, CoroutineScope {
 
-  private val log: Logger = LoggerProvider.nullProvider().getLogger(DefaultUdpConnector::class.java)
+  private val log: Logger = Logger.getLogger(DefaultUdpConnector::class.java.simpleName)
 
   private val randomMessageHandler: MessageHandler<RandomMessage> = RandomMessageHandler()
   private val whoAreYouMessageHandler: MessageHandler<WhoAreYouMessage> = WhoAreYouMessageHandler()
@@ -88,7 +87,7 @@
   private val pings: Cache<String, Bytes> = CacheBuilder.newBuilder()
     .expireAfterWrite(Duration.ofMillis(REQUEST_TIMEOUT + PING_TIMEOUT))
     .removalListener<String, Bytes> {
-      if (it.wasEvicted()) {
+      if (RemovalCause.EXPIRED == it.cause) {
         getNodesTable().evict(it.value)
       }
     }.build()
@@ -112,8 +111,7 @@
   override fun getNodeKeyPair(): SECP256K1.KeyPair = keyPair
 
   override fun getPendingMessage(authTag: Bytes): TrackingMessage = pendingMessages.getIfPresent(authTag.toHexString())
-      ?: throw IllegalArgumentException("Pending message not found")
-
+    ?: throw IllegalArgumentException("Pending message not found")
 
   override fun start() {
     receiveChannel.bind(bindAddress)
@@ -152,17 +150,6 @@
     messageListeners.remove(observer)
   }
 
-  override fun addPendingNodeId(address: InetSocketAddress, nodeId: Bytes) {
-    authenticatingPeers[address] = nodeId
-  }
-
-  override fun findPendingNodeId(address: InetSocketAddress): Bytes {
-    val result = authenticatingPeers[address]
-      ?: throw IllegalArgumentException("Authenticated peer not found with address ${address.hostName}:${address.port}")
-    authenticatingPeers.remove(address)
-    return result
-  }
-
   override fun getAwaitingPongRecord(nodeId: Bytes): Bytes? {
     val nodeIdHex = nodeId.toHexString()
     val result = pings.getIfPresent(nodeIdHex)
@@ -187,7 +174,7 @@
     val nonAskedNodes = nearest - askedNodes
     val targetNode = if (nonAskedNodes.isNotEmpty()) nonAskedNodes.random() else Bytes.random(32)
     val distance = getNodesTable().distanceToSelf(targetNode)
-    for(target in nearest.take(LOOKUP_MAX_REQUESTED_NODES)) {
+    for (target in nearest.take(LOOKUP_MAX_REQUESTED_NODES)) {
       val enr = EthereumNodeRecord.fromRLP(target)
       val message = FindNodeMessage(distance = distance)
       val address = InetSocketAddress(enr.ip(), enr.udp())
@@ -198,20 +185,24 @@
 
   // Process packets
   private fun receiveDatagram() = launch {
-    val datagram = ByteBuffer.allocate(UdpMessage.MAX_UDP_MESSAGE_SIZE)
     while (receiveChannel.isOpen) {
-      datagram.clear()
+      val datagram = ByteBuffer.allocate(UdpMessage.MAX_UDP_MESSAGE_SIZE)
       val address = receiveChannel.receive(datagram) as InetSocketAddress
       datagram.flip()
-      try {
-        processDatagram(datagram, address)
-      } catch (ex: Exception) {
-        log.error(ex.message)
+      launch {
+        try {
+          processDatagram(datagram, address)
+        } catch (ex: Exception) {
+          log.warning("${ex.message}")
+        }
       }
     }
   }
 
   private fun processDatagram(datagram: ByteBuffer, address: InetSocketAddress) {
+    if (datagram.limit() > UdpMessage.MAX_UDP_MESSAGE_SIZE) {
+      return
+    }
     val messageBytes = Bytes.wrapByteBuffer(datagram)
     val decodeResult = packetCodec.decode(messageBytes)
     val message = decodeResult.message
@@ -233,12 +224,14 @@
       if (!getNodesTable().isEmpty()) {
         val enrBytes = getNodesTable().random()
         val nodeId = Hash.sha2_256(enrBytes)
-        val enr = EthereumNodeRecord.fromRLP(enrBytes)
-        val address = InetSocketAddress(enr.ip(), enr.udp())
-        val message = PingMessage(enrSeq = enr.seq)
+        if (null == pings.getIfPresent(nodeId.toHexString())) {
+          val enr = EthereumNodeRecord.fromRLP(enrBytes)
+          val address = InetSocketAddress(enr.ip(), enr.udp())
+          val message = PingMessage(enrSeq = enr.seq)
 
-        send(address, message, nodeId)
-        pings.put(nodeId.toHexString(), enrBytes)
+          send(address, message, nodeId)
+          pings.put(nodeId.toHexString(), enrBytes)
+        }
       }
       delay(TABLE_REFRESH_RATE)
     }
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/handler/FindNodeMessageHandler.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/handler/FindNodeMessageHandler.kt
index 13548f2..4e7c354 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/handler/FindNodeMessageHandler.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/internal/handler/FindNodeMessageHandler.kt
@@ -41,6 +41,6 @@
   }
 
   companion object {
-    private const val MAX_NODES_IN_RESPONSE: Int = 16
+    private const val MAX_NODES_IN_RESPONSE: Int = 4
   }
 }
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/misc/EncodeResult.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/misc/EncodeResult.kt
index 5100329..5a482ea 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/misc/EncodeResult.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/misc/EncodeResult.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.misc
 
 import org.apache.tuweni.bytes.Bytes
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/misc/TrackingMessage.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/misc/TrackingMessage.kt
index 66987c1..c0d724b 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/misc/TrackingMessage.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/misc/TrackingMessage.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.misc
 
 import org.apache.tuweni.bytes.Bytes
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/packet/RandomMessage.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/packet/RandomMessage.kt
index 99dfb51..faaf210 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/packet/RandomMessage.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/packet/RandomMessage.kt
@@ -28,7 +28,7 @@
   }
 
   companion object {
-    fun create(authTag: Bytes, content: Bytes): RandomMessage {
+    fun create(authTag: Bytes, content: Bytes = randomData()): RandomMessage {
       return RandomMessage(authTag, content)
     }
   }
diff --git a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/storage/DefaultENRStorage.kt b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/storage/DefaultENRStorage.kt
index 80e9d5b..26ff813 100644
--- a/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/storage/DefaultENRStorage.kt
+++ b/devp2p/src/main/kotlin/org/apache/tuweni/devp2p/v5/storage/DefaultENRStorage.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.storage
 
 import org.apache.tuweni.bytes.Bytes
@@ -5,7 +21,7 @@
 import org.apache.tuweni.devp2p.v5.ENRStorage
 import java.util.concurrent.ConcurrentHashMap
 
-class DefaultENRStorage: ENRStorage {
+class DefaultENRStorage : ENRStorage {
 
   private val storage: MutableMap<String, Bytes> = ConcurrentHashMap()
 
@@ -15,5 +31,4 @@
     val nodeId = Hash.sha2_256(enr)
     storage[nodeId.toHexString()] = enr
   }
-
 }
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 0e3131c..6777272 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
@@ -69,5 +69,4 @@
   companion object {
     private const val BUCKET_SIZE: Int = 16
   }
-
 }
diff --git a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/AbstractIntegrationTest.kt b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/AbstractIntegrationTest.kt
index c797b3b..8344c3a 100644
--- a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/AbstractIntegrationTest.kt
+++ b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/AbstractIntegrationTest.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
 
 import kotlinx.coroutines.channels.Channel
@@ -18,7 +34,6 @@
 import org.junit.jupiter.api.extension.ExtendWith
 import java.net.InetAddress
 import java.net.InetSocketAddress
-import kotlin.random.Random
 
 @ExtendWith(BouncyCastleExtension::class)
 abstract class AbstractIntegrationTest {
@@ -89,7 +104,11 @@
     initiator.connector.send(recipient.address, message, recipient.nodeId)
   }
 
-  protected inline fun <reified T: UdpMessage>sendAndAwait(initiator: TestNode, recipient: TestNode, message: UdpMessage): T {
+  protected inline fun <reified T : UdpMessage> sendAndAwait(
+    initiator: TestNode,
+    recipient: TestNode,
+    message: UdpMessage
+  ): T {
     val listener = object : MessageObserver {
       var result: Channel<T> = Channel()
 
diff --git a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/HandshakeTest.kt b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/IntegrationTest.kt
similarity index 77%
rename from devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/HandshakeTest.kt
rename to devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/IntegrationTest.kt
index bbdc7f7..47c82c4 100644
--- a/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/HandshakeTest.kt
+++ b/devp2p/src/test/kotlin/org/apache/tuweni/devp2p/v5/IntegrationTest.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
 
 import kotlinx.coroutines.delay
@@ -7,7 +23,7 @@
 import org.junit.jupiter.api.Disabled
 import org.junit.jupiter.api.Test
 
-class HandshakeTest: AbstractIntegrationTest() {
+class IntegrationTest : AbstractIntegrationTest() {
 
   @Test
   fun testHandshake() {
@@ -47,7 +63,7 @@
 
       node2.service.terminate( true)
 
-      delay(3000)
+      delay(5000)
 
       assert(node1.routingTable.isEmpty())
 
@@ -97,13 +113,9 @@
     handshake(targetNode, node1)
     handshake(targetNode, node4)
     handshake(targetNode, node7)
-    handshake(targetNode, node10)
-    handshake(targetNode, node13)
-    handshake(targetNode, node14)
-    handshake(targetNode, node17)
 
     var size = targetNode.routingTable.size
-    while(size < 16) {
+    while (size < 8) {
       val newSize = targetNode.routingTable.size
       if (size < newSize) {
         size = newSize
@@ -131,5 +143,4 @@
 
     targetNode.service.terminate(true)
   }
-
 }
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 7629d80..4b6d188 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
@@ -22,7 +22,6 @@
 import org.apache.tuweni.devp2p.EthereumNodeRecord
 import org.apache.tuweni.devp2p.v5.storage.RoutingTable
 import org.apache.tuweni.devp2p.v5.misc.HandshakeInitParameters
-import org.apache.tuweni.devp2p.v5.misc.SessionKey
 import org.apache.tuweni.junit.BouncyCastleExtension
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.extension.ExtendWith
@@ -81,17 +80,4 @@
 
     assert(result == null)
   }
-
-  @Test
-  fun setSessionKeyPersistsSessionKeyIfExists() {
-    val nodeId = Bytes.random(32).toHexString()
-    val bytes = Bytes.random(32)
-    val sessionKey = SessionKey(bytes, bytes, bytes)
-
-    authenticationProvider.setSessionKey(nodeId, sessionKey)
-
-    val result = authenticationProvider.findSessionKey(nodeId)
-
-    assert(result != null)
-  }
 }
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 50a677d..e04771f 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
@@ -31,7 +31,6 @@
 import org.apache.tuweni.devp2p.v5.packet.WhoAreYouMessage
 import org.apache.tuweni.junit.BouncyCastleExtension
 import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
 import org.junit.jupiter.api.extension.ExtendWith
 import java.net.InetAddress
 
@@ -49,7 +48,7 @@
   private val destNodeId: Bytes = Bytes.random(32)
 
   @Test
-  fun encodePerformsValidEncodingOfRandomMessasge() {
+  fun encodePerformsValidEncodingOfRandomMessage() {
     val message = RandomMessage()
 
     val encodedResult = codec.encode(message, destNodeId)