@@ -94,6 +94,114 @@ CAddrMan::CAddrMan(bool deterministic, int32_t consistency_check_ratio)
9494 }
9595}
9696
97+ template <typename Stream>
98+ void CAddrMan::Serialize (Stream& s_) const
99+ {
100+ LOCK (cs);
101+
102+ /* *
103+ * Serialized format.
104+ * * format version byte (@see `Format`)
105+ * * lowest compatible format version byte. This is used to help old software decide
106+ * whether to parse the file. For example:
107+ * * Bitcoin Core version N knows how to parse up to format=3. If a new format=4 is
108+ * introduced in version N+1 that is compatible with format=3 and it is known that
109+ * version N will be able to parse it, then version N+1 will write
110+ * (format=4, lowest_compatible=3) in the first two bytes of the file, and so
111+ * version N will still try to parse it.
112+ * * Bitcoin Core version N+2 introduces a new incompatible format=5. It will write
113+ * (format=5, lowest_compatible=5) and so any versions that do not know how to parse
114+ * format=5 will not try to read the file.
115+ * * nKey
116+ * * nNew
117+ * * nTried
118+ * * number of "new" buckets XOR 2**30
119+ * * all new addresses (total count: nNew)
120+ * * all tried addresses (total count: nTried)
121+ * * for each new bucket:
122+ * * number of elements
123+ * * for each element: index in the serialized "all new addresses"
124+ * * asmap checksum
125+ *
126+ * 2**30 is xorred with the number of buckets to make addrman deserializer v0 detect it
127+ * as incompatible. This is necessary because it did not check the version number on
128+ * deserialization.
129+ *
130+ * vvNew, vvTried, mapInfo, mapAddr and vRandom are never encoded explicitly;
131+ * they are instead reconstructed from the other information.
132+ *
133+ * This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
134+ * changes to the ADDRMAN_ parameters without breaking the on-disk structure.
135+ *
136+ * We don't use SERIALIZE_METHODS since the serialization and deserialization code has
137+ * very little in common.
138+ */
139+
140+ // Always serialize in the latest version (FILE_FORMAT).
141+
142+ OverrideStream<Stream> s (&s_, s_.GetType (), s_.GetVersion () | ADDRV2_FORMAT);
143+
144+ s << static_cast <uint8_t >(FILE_FORMAT);
145+
146+ // Increment `lowest_compatible` iff a newly introduced format is incompatible with
147+ // the previous one.
148+ static constexpr uint8_t lowest_compatible = Format::V3_BIP155;
149+ s << static_cast <uint8_t >(INCOMPATIBILITY_BASE + lowest_compatible);
150+
151+ s << nKey;
152+ s << nNew;
153+ s << nTried;
154+
155+ int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30 );
156+ s << nUBuckets;
157+ std::unordered_map<int , int > mapUnkIds;
158+ int nIds = 0 ;
159+ for (const auto & entry : mapInfo) {
160+ mapUnkIds[entry.first ] = nIds;
161+ const CAddrInfo &info = entry.second ;
162+ if (info.nRefCount ) {
163+ assert (nIds != nNew); // this means nNew was wrong, oh ow
164+ s << info;
165+ nIds++;
166+ }
167+ }
168+ nIds = 0 ;
169+ for (const auto & entry : mapInfo) {
170+ const CAddrInfo &info = entry.second ;
171+ if (info.fInTried ) {
172+ assert (nIds != nTried); // this means nTried was wrong, oh ow
173+ s << info;
174+ nIds++;
175+ }
176+ }
177+ for (int bucket = 0 ; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
178+ int nSize = 0 ;
179+ for (int i = 0 ; i < ADDRMAN_BUCKET_SIZE; i++) {
180+ if (vvNew[bucket][i] != -1 )
181+ nSize++;
182+ }
183+ s << nSize;
184+ for (int i = 0 ; i < ADDRMAN_BUCKET_SIZE; i++) {
185+ if (vvNew[bucket][i] != -1 ) {
186+ int nIndex = mapUnkIds[vvNew[bucket][i]];
187+ s << nIndex;
188+ }
189+ }
190+ }
191+ // Store asmap checksum after bucket entries so that it
192+ // can be ignored by older clients for backward compatibility.
193+ uint256 asmap_checksum;
194+ if (m_asmap.size () != 0 ) {
195+ asmap_checksum = SerializeHash (m_asmap);
196+ }
197+ s << asmap_checksum;
198+ }
199+
200+ // explicit instantiation
201+ template void CAddrMan::Serialize (CHashWriter& s) const ;
202+ template void CAddrMan::Serialize (CAutoFile& s) const ;
203+ template void CAddrMan::Serialize (CDataStream& s) const ;
204+
97205CAddrInfo* CAddrMan::Find (const CNetAddr& addr, int * pnId)
98206{
99207 AssertLockHeld (cs);
0 commit comments