Serialization improvements step 6 (all except wallet/gui) #18317

pull sipa wants to merge 7 commits into bitcoin:master from sipa:202003_noncastserial_6 changing 22 files +156 −302
  1. sipa commented at 4:53 pm on March 11, 2020: member

    The next step of changes from #10785.

    This:

    • Adds support for enum serialization to CustomUintFormatter, used in CAddress for service flags.
    • Merges BigEndian into CustomUintFormatter, used in CNetAddr for port numbers.
    • Converts everything (except wallet and gui) to use the new serialization framework.
  2. DrahtBot added the label Consensus on Mar 11, 2020
  3. DrahtBot added the label P2P on Mar 11, 2020
  4. DrahtBot added the label RPC/REST/ZMQ on Mar 11, 2020
  5. DrahtBot added the label Tests on Mar 11, 2020
  6. DrahtBot added the label TX fees and policy on Mar 11, 2020
  7. DrahtBot added the label UTXO Db and Indexes on Mar 11, 2020
  8. sipa requested review from ryanofsky on Mar 11, 2020
  9. DrahtBot commented at 5:43 pm on March 11, 2020: member

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #16463 ([BIP 174] Implement serialization support for GLOBAL_XPUB field. by achow101)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  10. fanquake removed the label Consensus on Mar 11, 2020
  11. fanquake removed the label P2P on Mar 11, 2020
  12. fanquake removed the label RPC/REST/ZMQ on Mar 11, 2020
  13. fanquake removed the label TX fees and policy on Mar 11, 2020
  14. fanquake removed the label Tests on Mar 11, 2020
  15. fanquake removed the label UTXO Db and Indexes on Mar 11, 2020
  16. fanquake added the label Utils/log/libs on Mar 11, 2020
  17. laanwj added this to the "Blockers" column in a project

  18. sipa force-pushed on Mar 17, 2020
  19. in src/protocol.h:336 in 4a185971f4 outdated
    319-    template <typename Stream, typename Operation>
    320-    inline void SerializationOp(Stream& s, Operation ser_action)
    321+    SERIALIZE_METHODS(CAddress, obj)
    322     {
    323-        if (ser_action.ForRead())
    324-            Init();
    


    ryanofsky commented at 2:40 pm on March 26, 2020:

    In commit “Convert everything except wallet/qt to new serialization” (4a185971f495ab89d869a4744d36aa1a8c9aea3f)

    Is it safe to drop the Init call here? It seems needed to avoid leaving nTime uninitialized if READWRITE(obj.nTime) is skipped below.

    I was experimenting a little bit with how to be able to bring back if (ser_action.ForRead()) ability in the new framework now that the object type can vary and may be const.

    One option might be to have SER_READ / SER_WRITE macros that contain code (similar to WITH_LOCK) and only execute when reading or writing:

     0--- a/src/protocol.h
     1+++ b/src/protocol.h
     2@@ -316,6 +316,7 @@ public:
     3 
     4     SERIALIZE_METHODS(CAddress, obj)
     5     {
     6+        SER_READ(obj, obj.Init());
     7         int nVersion = s.GetVersion();
     8         if (s.GetType() & SER_DISK) {
     9             READWRITE(nVersion);
    10diff --git a/src/serialize.h b/src/serialize.h
    11index 43f35f7ebe6..ae6a028ce97 100644
    12--- a/src/serialize.h
    13+++ b/src/serialize.h
    14@@ -179,6 +179,7 @@ template<typename X> const X& ReadWriteAsHelper(const X& x) { return x; }
    15 
    16 #define READWRITE(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__))
    17 #define READWRITEAS(type, obj) (::SerReadWriteMany(s, ser_action, ReadWriteAsHelper<type>(obj)))
    18+#define SER_READ(obj, code) ::SerRead(s, ser_action, obj, [&](Stream& s, typename std::remove_const<Type>::type& obj) { code; })
    19 
    20 /**
    21  * Implement three methods for serializable objects. These are actually wrappers over
    22@@ -1089,6 +1090,17 @@ inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&&
    23     ::UnserializeMany(s, args...);
    24 }
    25 
    26+template<typename Stream, typename Type, typename Fn>
    27+inline void SerRead(Stream& s, CSerActionSerialize ser_action, Type&&, Fn&&)
    28+{
    29+}
    30+
    31+template<typename Stream, typename Type, typename Fn>
    32+inline void SerRead(Stream& s, CSerActionUnserialize ser_action, Type&& obj, Fn&& fn)
    33+{
    34+    fn(s, std::forward<Type>(obj));
    35+}
    36+
    37 template<typename I>
    38 inline void WriteVarInt(CSizeComputer &s, I n)
    39 {
    

    sipa commented at 11:13 pm on March 30, 2020:
    That’s great! I’ve turned this snippet into a separate commit (with you as author; please let me know if you prefer a different approach). It also adds the corresponding SER_WRITE, as it turns out to be useful further.

    MarcoFalke commented at 7:47 pm on May 19, 2020:
    Going forward, the Init should probably be removed and replaced with a slim and clean C++11 initializer

    sipa commented at 9:26 pm on May 19, 2020:
    What do you mean with “C++11 initializer” ?

    MarcoFalke commented at 9:45 pm on May 19, 2020:

    What do you mean with “C++11 initializer” ?

    #19020


  20. in src/serialize.h:544 in 7c5a0c7c53 outdated
    539@@ -540,6 +540,26 @@ struct CustomUintFormatter
    540     }
    541 };
    542 
    543+/** Formatter that (de)serializes a type as another type it's convertible to/from. */
    544+template<typename F> struct ConvertFormatter
    


    ryanofsky commented at 5:47 pm on March 26, 2020:

    In commit “Add ConvertFormatter” (7c5a0c7c53c7cec8f4f6d074d90c5e8988f61c15)

    I think it would be better not to have this class, or maybe expose it less widely:

    • It only seems to be used one place currently, and I think CustomUintFormatter could be used there instead.
    • It seems easy to confuse with READWRITEAS, and not obvious when you’d use READWRITEAS vs READWRITE with ConvertFormatter
    • Haven’t thought about it too much, but just based on how this is implemented, there could be cases where using it would do unexpected temporary creation or copying or derived-base truncation.

    sipa commented at 11:14 pm on March 30, 2020:
    I’ve taken your approach of merging it into CustomUintFormatter.
  21. in src/bloom.h:69 in 4a185971f4 outdated
    73-        READWRITE(vData);
    74-        READWRITE(nHashFuncs);
    75-        READWRITE(nTweak);
    76-        READWRITE(nFlags);
    77-    }
    78+    SERIALIZE_METHODS(CBloomFilter, obj) { READWRITE(obj.vData, obj.nHashFuncs, obj.nTweak, obj.nFlags); }
    


    ryanofsky commented at 6:57 pm on March 26, 2020:

    In commit “Convert everything except wallet/qt to new serialization” (4a185971f495ab89d869a4744d36aa1a8c9aea3f)

    Last commit is mostly repetitive changes of this form. Maybe a big regex in a scripted diff could be used to do the boilerplate subtitutions in a separate commit, so the more complicated changes here stand out.


    sipa commented at 11:15 pm on March 30, 2020:
    I think that would be pretty hard to do, especially the classname argument to SERIALIZE_METHODS is hard to figure out with a regexp. Do you have any concrete ideas?

    MarcoFalke commented at 7:46 pm on May 19, 2020:
    Clang has tooling to do these kind of refactors. Though, I haven’t figured out how to run them in a scripted-diff.
  22. in src/protocol.h:327 in 4a185971f4 outdated
    335-        nServices = static_cast<ServiceFlags>(nServicesInt);
    336-        READWRITEAS(CService, *this);
    337+            (nVersion >= CADDR_TIME_VERSION && !(s.GetType() & SER_GETHASH))) {
    338+            READWRITE(obj.nTime);
    339+        }
    340+        READWRITE(Using<ConvertFormatter<uint64_t>>(obj.nServices));
    


    ryanofsky commented at 7:04 pm on March 26, 2020:

    In commit “Convert everything except wallet/qt to new serialization” (4a185971f495ab89d869a4744d36aa1a8c9aea3f)

    I suggested dropping ConvertFormatter in another comment for a few reasons. CustomUintFormatter could be used instead here if extended to support enums:

     0diff --git a/src/protocol.h b/src/protocol.h
     1index c1a21264705..901471e110d 100644
     2--- a/src/protocol.h
     3+++ b/src/protocol.h
     4@@ -324,7 +324,7 @@ public:
     5             (nVersion >= CADDR_TIME_VERSION && !(s.GetType() & SER_GETHASH))) {
     6             READWRITE(obj.nTime);
     7         }
     8-        READWRITE(Using<ConvertFormatter<uint64_t>>(obj.nServices));
     9+        READWRITE(Using<CustomUintFormatter<8>>(obj.nServices));
    10         READWRITEAS(CService, obj);
    11     }
    12 
    13diff --git a/src/serialize.h b/src/serialize.h
    14index 51d270d7976..718bdea90a6 100644
    15--- a/src/serialize.h
    16+++ b/src/serialize.h
    17@@ -527,14 +527,15 @@ struct CustomUintFormatter
    18 
    19     template <typename Stream, typename I> void Unser(Stream& s, I& v)
    20     {
    21-        static_assert(std::numeric_limits<I>::max() >= MAX && std::numeric_limits<I>::min() <= 0, "CustomUintFormatter type too small");
    22+        using U = typename std::conditional<std::is_enum<I>::value, std::underlying_type<I>, std::common_type<I>>::type::type;
    23+        static_assert(std::numeric_limits<U>::max() >= MAX && std::numeric_limits<U>::min() <= 0, "Assigned type too small");
    24         uint64_t raw = 0;
    25         if (BigEndian) {
    26             s.read(((char*)&raw) + 8 - Bytes, Bytes);
    27-            v = be64toh(raw);
    28+            v = static_cast<I>(be64toh(raw));
    29         } else {
    30             s.read((char*)&raw, Bytes);
    31-            v = le64toh(raw);
    32+            v = static_cast<I>(le64toh(raw));
    33         }
    34     }
    35 };
    

    sipa commented at 11:15 pm on March 30, 2020:
    I’ve turned this into a separate commit with you as author.
  23. ryanofsky commented at 7:17 pm on March 26, 2020: member

    Reviewed most of this (maybe 80%). Just posting feedback so far. Only maybe-blocking thing is question about CAddress::Init below, everything else feel free to ignore.

    The last commit here is especially nice. New serialization code is much cleaner than the old code.

  24. in src/merkleblock.h:168 in 25bfbbeb63 outdated
    167-    inline void SerializationOp(Stream& s, Operation ser_action) {
    168-        READWRITE(header);
    169-        READWRITE(txn);
    170-    }
    171-
    172-private:
    


    ryanofsky commented at 8:21 pm on March 27, 2020:

    In commit “Convert merkleblock to new serialization” (25bfbbeb63eca1f1c8852a8a08844069d9e06776)

    Maybe better to keep constructor below private and just declare SERIALIZE_METHODS before it, assuming there’s a valid reason for the constructor to be private.


    sipa commented at 11:16 pm on March 30, 2020:
    I think this was a mistake; fixed.
  25. ryanofsky approved
  26. ryanofsky commented at 8:47 pm on March 27, 2020: member
    Code review ACK 4a185971f495ab89d869a4744d36aa1a8c9aea3f. Really nice improvements in this PR. Left some suggestions and comments, but feel free to ignore. Only thing I would to see answered is question about whether CAddress::Init call can be skipped in #18317 (review).
  27. Merge BigEndian functionality into CustomUintFormatter 769ee5fa00
  28. Extend CustomUintFormatter to support enums
    Extracted by Pieter Wuille from a comment by Russ Yanofsky, see
    https://github.com/bitcoin/bitcoin/pull/18317#discussion_r398821936.
    6f9a1e5ad0
  29. Add SER_READ and SER_WRITE for read/write-dependent statements
    Extracted and extended by Pieter Wuille from a comment by Russ
    Yanofsky (see
    https://github.com/bitcoin/bitcoin/pull/18317#discussion_r398625457).
    d06fedd1bc
  30. Convert merkleblock to new serialization 73747afbbe
  31. Convert blockencodings_tests to new serialization 2b1f85e8c5
  32. Convert everything except wallet/qt to new serialization 4eb5643e35
  33. sipa force-pushed on Mar 30, 2020
  34. sipa commented at 11:18 pm on March 30, 2020: member
    Addressed a number of comments, and included some of @ryanofsky’s code suggestions. I’ve also revamped the merkleblock serializers using the new FOR_READ/FOR_WRITE.
  35. ryanofsky approved
  36. ryanofsky commented at 3:30 pm on April 1, 2020: member
    Code review ACK 4eb5643e3538863c9d2ff261f49a9a1b248de243. Changes since last review: new SER_READ/SER_WRITE macros, CustomUintFormatter enum support, updating CPartialMerkleTree to use SER_READ/WRITE and keep constructor private, changing CAddress to call Init() and use CustomUintFormatter
  37. jonatack commented at 8:49 pm on April 25, 2020: member

    Cleanup and improvements look very good. Nice collaboration.

    ACK 4eb5643e3538863c9d2ff261f49a9a1b248de243

    Code review, gcc+clang builds+tests+ran bitcoind at 4eb5643 and rebased on master 65276c7

  38. sipa commented at 9:33 pm on May 18, 2020: member
    Anyone else feel like reviewing this? We’re getting close.
  39. practicalswift commented at 4:41 am on May 19, 2020: contributor

    Strong concept ACK

    New code is much easier to read and reason about.

  40. in src/serialize.h:548 in 769ee5fa00 outdated
    557-/** Serialization wrapper class for big-endian integers.
    558- *
    559- * Use this wrapper around integer types that are stored in memory in native
    560- * byte order, but serialized in big endian notation. This is only intended
    561- * to implement serializers that are compatible with existing formats, and
    562- * its use is not recommended for new data structures.
    


    MarcoFalke commented at 6:38 pm on May 19, 2020:

    in commit 769ee5fa0011ae658770586442715452a656559d:

    Any reason why you remove the comment? “This is only intended to implement serializers that are compatible with existing formats, and its use is not recommended for new data structures.”


    sipa commented at 9:31 pm on May 19, 2020:
    I suspect it was just lost in refactoring. Added a new commit that adds it back.
  41. MarcoFalke commented at 7:44 pm on May 19, 2020: member

    ACK 4eb5643e3538863c9d2ff261f49a9a1b248de243 🐜

    Signature:

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3ACK 4eb5643e3538863c9d2ff261f49a9a1b248de243 🐜
     4-----BEGIN PGP SIGNATURE-----
     5
     6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
     7pUiapgv5AV3Ayc3O2WW2CHMAP08zdDmwuS4qvzMAKT4kAgIdFrVr+iXUXZIwuwQ0
     8M/HnR17FSJ8FlQ5plt0pyKolQv1fjVugdzJUPd9RjdhXZ3SqYof5arr8ddBi+xJv
     9qd9XkI8Ur65zVRTOSqWOabWPwGsVxZsztYxwZI8n5yQwWeZ1ANr7O6D/8xEBwggS
    10tYpFxtTaQ2Wp+REbpgWMYf9t9U2KUW3XFbac2xUf9Ff3hVM4uC+siOGKTf6omaEK
    11gpO2HT0RzKua6FRgLoTjdczhvPh1RbgLwnMSS7LazgM1rnwTS/fRSsFnr1D+CHqi
    12fShwPe9+7lOYoC+AzuK4z1RVOfVcLeUFzKRaGQNLXZQJ3LlzIdwg/nhd1xO+qov2
    132BF9pbxei6fCfGKz5KCDbJJI9KPcL0K2gfrpldGdF1tZQ7/CbvusEPCIoUe5K6g3
    14oJ1ttbViqpIGNFRhG0h6JWmu7mOoQm1EuoAjwDz05wJ+H2IthrbRSCYP6BvV00A2
    15qx5QVuZ8
    16=A3ac
    17-----END PGP SIGNATURE-----
    

    Timestamp of file with hash dab97ed81bacef9fec86c29c2502d3a9220b4eae2601a1671bb80dc4cce9dd01 -

  42. Add comments to CustomUintFormatter f9ee0f37c2
  43. in src/serialize.h:530 in f9ee0f37c2
    525+ * It permits specifying the serialized size (1 to 8 bytes) and endianness.
    526+ *
    527+ * Use the big endian mode for values that are stored in memory in native
    528+ * byte order, but serialized in big endian notation. This is only intended
    529+ * to implement serializers that are compatible with existing formats, and
    530+ * its use is not recommended for new data structures.
    


    MarcoFalke commented at 9:48 pm on May 19, 2020:

    in commit f9ee0f37c28f604bc82dab502ce229c66ef5b3b9

    Not recommend for big endian or anything that can be serialized with this wrapper? For example, I am wondering if there is a recommended way to serialize enums or should new code rather not use enums instead?


    sipa commented at 9:50 pm on May 19, 2020:

    The comment is only intended to apply to big endian serialization. Any suggestions to make that clearer?

    If it’s confusing, I think it’s also fine to just drop the comment. When picking a serialization for a new structure I doubt anyone would intentionally complicate their code by using big endian serialization.


    MarcoFalke commented at 9:58 pm on May 19, 2020:

    I doubt anyone would intentionally complicate their code by using big endian serialization

    Makes sense


    ryanofsky commented at 11:42 pm on May 19, 2020:

    In commit “Add comments to CustomUintFormatter” (f9ee0f37c28f604bc82dab502ce229c66ef5b3b9)

    re: “not recommended for new data structures”, it’d be nice to say what preferred alternatives are. Compact ints, varints, little endian fixed width ints? I keep forgetting all the int types myself..


    sipa commented at 0:32 am on May 20, 2020:
    @ryanofsky Maybe the serialization code just shouldn’t contain protocol design advice.
  44. MarcoFalke commented at 10:00 pm on May 19, 2020: member

    re-ACK f9ee0f37c2, only change is new documentation commit for CustomUintFormatter 📂

    Signature:

     0-----BEGIN PGP SIGNED MESSAGE-----
     1Hash: SHA512
     2
     3re-ACK f9ee0f37c2, only change is new documentation commit for CustomUintFormatter 📂
     4-----BEGIN PGP SIGNATURE-----
     5
     6iQGzBAEBCgAdFiEE+rVPoUahrI9sLGYTzit1aX5ppUgFAlwqrYAACgkQzit1aX5p
     7pUh+HQv9EdvBDfmaDb6c9KM50spORaYYJlbuXGYi+pomY/sL9zDHQw5DlnO6CsKS
     8CZ98PFhMSYoTY0jHxLDcQNoJdKnpuS027pJ82pE0lWLzawtSQrCjLk04UkkZwf1h
     9BvSTfmLOq+071pwCFaSo60n07nIlAlSq7gIGGLq/9UfCM0eAk+ndOWzIxS+lglkR
    10sO0U6bBK6w8PdpfyrYIJln+db4t7k6FnVeOOJG4TKF3vysvenSN3kknPzch7T7sN
    11qnVPtist4j8vNAWRxo51BcO42AcGmJM8lK6gqrkXRnn+CqhygxUfQ8oM6Q5UQt6N
    12mDYRUwvAYTJDwNrPJV378Otgb3Q6ZYF0/+RtIXO44NyhQYZ2mce600UhrrJatXu1
    13Dbvck/LPkFOkrjucmW4pE0a9xCx+4UCQ7uzPhz51yCXw0fY9fPK7L3OF/XcFTvTT
    14qNDFffulWh3yjw+0TFbvHSB655J9nabJvIhs9pz8G4FE1+kHNwj0bdjkAaMXkR4y
    1537zK6NZj
    16=NdvU
    17-----END PGP SIGNATURE-----
    

    Timestamp of file with hash ab46775e38a58bfb2a237b81708371ffad21f2374a35d117be61bd7b9e0fd5cf -

  45. ryanofsky approved
  46. ryanofsky commented at 11:43 pm on May 19, 2020: member
    Code review ACK f9ee0f37c28f604bc82dab502ce229c66ef5b3b9. Just new commit adding comment since last review
  47. jonatack commented at 5:06 am on May 20, 2020: member
    Code review re-ACK f9ee0f37c28f604bc82dab502ce229c6 only change since last review is an additional commit adding Doxygen documentation for CustomUintFormatter.
  48. MarcoFalke merged this on May 20, 2020
  49. MarcoFalke closed this on May 20, 2020

  50. fanquake removed this from the "Blockers" column in a project

  51. sidhujag referenced this in commit 90eb169cc8 on May 20, 2020
  52. domob1812 referenced this in commit 1cd26b1e6d on May 25, 2020
  53. van-orton referenced this in commit c3bccffb3d on Oct 30, 2020
  54. van-orton referenced this in commit 82c6571221 on Oct 30, 2020
  55. deadalnix referenced this in commit aefb3d7122 on Feb 5, 2021
  56. UdjinM6 referenced this in commit 6a36c4e4b1 on May 28, 2021
  57. furszy referenced this in commit ed0780db49 on Jun 4, 2021
  58. furszy referenced this in commit d79c096f7e on Jun 4, 2021
  59. furszy referenced this in commit 6e2bdc1a62 on Jun 8, 2021
  60. furszy referenced this in commit bd32e386b1 on Jun 8, 2021
  61. furszy referenced this in commit 3733f02d0a on Jun 8, 2021
  62. furszy referenced this in commit 4d987d231d on Jun 8, 2021
  63. furszy referenced this in commit 774a1cd2c6 on Jun 9, 2021
  64. furszy referenced this in commit 1022ef8ecb on Jun 9, 2021
  65. furszy referenced this in commit 1476c9241e on Jun 10, 2021
  66. furszy referenced this in commit d9393bd05b on Jun 10, 2021
  67. furszy referenced this in commit 822d0d492a on Jun 12, 2021
  68. furszy referenced this in commit 4fd03fe258 on Jun 12, 2021
  69. furszy referenced this in commit 3586b66577 on Jun 12, 2021
  70. furszy referenced this in commit a32cf0db46 on Jun 12, 2021
  71. furszy referenced this in commit 0e76eca5b7 on Jun 14, 2021
  72. furszy referenced this in commit dde7a78289 on Jun 14, 2021
  73. furszy referenced this in commit d22ffe66ef on Jun 19, 2021
  74. furszy referenced this in commit 939a5a1e69 on Jun 19, 2021
  75. furszy referenced this in commit 0bec48f021 on Jun 22, 2021
  76. furszy referenced this in commit ad8732b8f3 on Jun 22, 2021
  77. furszy referenced this in commit 9a910c62f9 on Jun 24, 2021
  78. furszy referenced this in commit f30234314a on Jun 24, 2021
  79. furszy referenced this in commit 19a92baffb on Jun 28, 2021
  80. furszy referenced this in commit 848e35bdc9 on Jun 28, 2021
  81. furszy referenced this in commit 230c534319 on Jun 28, 2021
  82. furszy referenced this in commit abe6521863 on Jun 28, 2021
  83. furszy referenced this in commit 455f8824df on Jul 1, 2021
  84. furszy referenced this in commit b99c891c7f on Jul 1, 2021
  85. furszy referenced this in commit 7344c1ae5f on Jul 3, 2021
  86. furszy referenced this in commit 13577fb405 on Jul 3, 2021
  87. furszy referenced this in commit 5c93f159bc on Jul 5, 2021
  88. random-zebra referenced this in commit b4751e10ce on Aug 11, 2021
  89. AloeareV referenced this in commit 8f457167ed on Oct 5, 2021
  90. AloeareV referenced this in commit 7be79e4410 on Oct 5, 2021
  91. zancas referenced this in commit 0c3735bb0c on Oct 28, 2021
  92. zancas referenced this in commit c11c6c058c on Oct 28, 2021
  93. zancas referenced this in commit b9527bac0b on Dec 10, 2021
  94. zancas referenced this in commit a16fad9289 on Dec 10, 2021
  95. DeckerSU referenced this in commit eb3ca0556a on Feb 12, 2022
  96. DrahtBot locked this on Feb 15, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-07-03 10:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me