|
4 | 4 |
|
5 | 5 | package org.ethereum.beacon.discovery; |
6 | 6 |
|
| 7 | +import java.net.Inet6Address; |
7 | 8 | import java.net.InetAddress; |
8 | 9 | import java.net.InetSocketAddress; |
9 | 10 | import java.net.UnknownHostException; |
@@ -35,12 +36,30 @@ public static NodeRecord createNodeRecord(final int nodeId) { |
35 | 36 |
|
36 | 37 | public static NodeRecord createNodeRecord( |
37 | 38 | final Bytes nodeId, final InetSocketAddress udpAddress) { |
| 39 | + if (udpAddress.getAddress() instanceof Inet6Address) { |
| 40 | + return createNodeRecord( |
| 41 | + nodeId, |
| 42 | + new EnrField(EnrField.IP_V6, Bytes.wrap(udpAddress.getAddress().getAddress())), |
| 43 | + new EnrField(EnrField.UDP_V6, udpAddress.getPort())); |
| 44 | + } |
38 | 45 | return createNodeRecord( |
39 | 46 | nodeId, |
40 | 47 | new EnrField(EnrField.IP_V4, Bytes.wrap(udpAddress.getAddress().getAddress())), |
41 | 48 | new EnrField(EnrField.UDP, udpAddress.getPort())); |
42 | 49 | } |
43 | 50 |
|
| 51 | + public static NodeRecord createDualStackNodeRecord( |
| 52 | + final Bytes nodeId, |
| 53 | + final InetSocketAddress ipv4Address, |
| 54 | + final InetSocketAddress ipv6Address) { |
| 55 | + return createNodeRecord( |
| 56 | + nodeId, |
| 57 | + new EnrField(EnrField.IP_V4, Bytes.wrap(ipv4Address.getAddress().getAddress())), |
| 58 | + new EnrField(EnrField.UDP, ipv4Address.getPort()), |
| 59 | + new EnrField(EnrField.IP_V6, Bytes.wrap(ipv6Address.getAddress().getAddress())), |
| 60 | + new EnrField(EnrField.UDP_V6, ipv6Address.getPort())); |
| 61 | + } |
| 62 | + |
44 | 63 | public static NodeRecord createNodeRecord(final Bytes nodeId, final EnrField... extraFields) { |
45 | 64 | final List<EnrField> fields = new ArrayList<>(List.of(extraFields)); |
46 | 65 | fields.add(new EnrField(EnrField.ID, IdentitySchema.V4)); |
@@ -86,8 +105,18 @@ public Optional<InetSocketAddress> getUdpAddress(final NodeRecord nodeRecord) { |
86 | 105 | } |
87 | 106 |
|
88 | 107 | @Override |
89 | | - public Optional<InetSocketAddress> getUdp6Address(NodeRecord nodeRecord) { |
90 | | - return Optional.empty(); |
| 108 | + public Optional<InetSocketAddress> getUdp6Address(final NodeRecord nodeRecord) { |
| 109 | + try { |
| 110 | + final Bytes ipBytes = (Bytes) nodeRecord.get(EnrField.IP_V6); |
| 111 | + if (ipBytes == null) { |
| 112 | + return Optional.empty(); |
| 113 | + } |
| 114 | + final InetAddress ipAddress = InetAddress.getByAddress(ipBytes.toArrayUnsafe()); |
| 115 | + final int port = (int) nodeRecord.get(EnrField.UDP_V6); |
| 116 | + return Optional.of(new InetSocketAddress(ipAddress, port)); |
| 117 | + } catch (UnknownHostException e) { |
| 118 | + return Optional.empty(); |
| 119 | + } |
91 | 120 | } |
92 | 121 |
|
93 | 122 | @Override |
@@ -117,7 +146,31 @@ public NodeRecord createWithNewAddress( |
117 | 146 | final Optional<Integer> newTcpPort, |
118 | 147 | final Optional<Integer> newQuicPort, |
119 | 148 | final Signer signer) { |
120 | | - final NodeRecord newRecord = createNodeRecord(getNodeId(nodeRecord), newAddress); |
| 149 | + final List<EnrField> fields = new ArrayList<>(); |
| 150 | + // Preserve fields from the other IP family |
| 151 | + if (newAddress.getAddress() instanceof Inet6Address) { |
| 152 | + // Updating IPv6 — preserve IPv4 fields if present |
| 153 | + if (nodeRecord.get(EnrField.IP_V4) != null) { |
| 154 | + fields.add(new EnrField(EnrField.IP_V4, nodeRecord.get(EnrField.IP_V4))); |
| 155 | + fields.add(new EnrField(EnrField.UDP, nodeRecord.get(EnrField.UDP))); |
| 156 | + } |
| 157 | + fields.add( |
| 158 | + new EnrField(EnrField.IP_V6, Bytes.wrap(newAddress.getAddress().getAddress()))); |
| 159 | + fields.add(new EnrField(EnrField.UDP_V6, newAddress.getPort())); |
| 160 | + } else { |
| 161 | + // Updating IPv4 — preserve IPv6 fields if present |
| 162 | + fields.add( |
| 163 | + new EnrField(EnrField.IP_V4, Bytes.wrap(newAddress.getAddress().getAddress()))); |
| 164 | + fields.add(new EnrField(EnrField.UDP, newAddress.getPort())); |
| 165 | + if (nodeRecord.get(EnrField.IP_V6) != null) { |
| 166 | + fields.add(new EnrField(EnrField.IP_V6, nodeRecord.get(EnrField.IP_V6))); |
| 167 | + fields.add(new EnrField(EnrField.UDP_V6, nodeRecord.get(EnrField.UDP_V6))); |
| 168 | + } |
| 169 | + } |
| 170 | + fields.add(new EnrField(EnrField.ID, IdentitySchema.V4)); |
| 171 | + fields.add(new EnrField(EnrField.PKEY_SECP256K1, getNodeId(nodeRecord))); |
| 172 | + final NodeRecord newRecord = |
| 173 | + NodeRecord.fromValues(this, nodeRecord.getSeq().add(1), fields); |
121 | 174 | sign(newRecord, signer); |
122 | 175 | return newRecord; |
123 | 176 | } |
|
0 commit comments