user132147: I am trying to recreate the bucketing algorithm of bitcoin using python, but I am stuck at this particular line because I am unable to recreate it using a simple double sha256.
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash();

I know that the hash1 value is the last 64 bits of the hash value converted into an int.
How could I recreate the following part in python?(I know the individual values)
(CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetCheapHash()


user136416: CHashWriter does serialisation differently for different types of objects. src/serialize.h describes this different behaviour in detail.
Here's a simple version for the new table bucketing algorithm in python. get_group() assumes normal ipv4 addresses as input here.
ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP = 64
ADDRMAN_NEW_BUCKET_COUNT = 1024

def get_group(ip):
    ip_as_bytes = bytes(map(int, ip.split('.')))
    return bytes([1]) + ip_as_bytes[:2]

def double_hash(bytes):
    return sha256(sha256(bytes).digest()).digest()

def get_new_bucket(key, addr, src):
    addr_group = get_group(addr)
    src_group = get_group(src)
    hash1 =  int.from_bytes(double_hash(key + bytes([len(addr_group)]) + addr_group
                                            + bytes([len(src_group)]) + src_group)[:8], 'little')
    hash1 = hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP
    hash2 = int.from_bytes(double_hash(key + bytes([len(src_group)]) + src_group
                                           + hash1.to_bytes(8, 'little'))[:8], 'little')
    return hash2 % ADDRMAN_NEW_BUCKET_COUNT

key = bytes.fromhex("41f758f2e5cc078d3795b4fc0cb60c2d735fa92cc020572bdc982dd2d564d11b")
addr = "250.1.2.1"
src = "250.1.2.1"
bucket = get_new_bucket(key, addr, src)
print("bucket is", bucket) # 786


132147: <p>I am trying to recreate the bucketing algorithm of bitcoin using python, but I am stuck at this particular line because I am unable to recreate it using a simple double sha256.</p>
<pre><code>uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) &lt;&lt; nKey &lt;&lt; GetKey()).GetCheapHash();
</code></pre>
<p>I know that the hash1 value is the last 64 bits of the hash value converted into an int.</p>
<p>How could I recreate the following part in python?(I know the individual values)</p>
<pre><code>(CHashWriter(SER_GETHASH, 0) &lt;&lt; nKey &lt;&lt; GetKey()).GetCheapHash()
</code></pre>
 136416: <p><code>CHashWriter</code> does <a href="https://github.com/bitcoin/bitcoin/blob/e1bf5470f919cf212703466411968916db8ae61f/src/hash.h#L144" rel="nofollow noreferrer">serialisation</a> differently for different types of objects. <a href="https://github.com/bitcoin/bitcoin/blob/master/src/serialize.h" rel="nofollow noreferrer"><code>src/serialize.h</code></a> describes this different behaviour in detail.</p>
<p>Here's a simple version for the new table bucketing algorithm in python. <code>get_group()</code> assumes normal ipv4 addresses as input here.</p>
<pre><code>ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP = 64
ADDRMAN_NEW_BUCKET_COUNT = 1024

def get_group(ip):
    ip_as_bytes = bytes(map(int, ip.split('.')))
    return bytes([1]) + ip_as_bytes[:2]

def double_hash(bytes):
    return sha256(sha256(bytes).digest()).digest()

def get_new_bucket(key, addr, src):
    addr_group = get_group(addr)
    src_group = get_group(src)
    hash1 =  int.from_bytes(double_hash(key + bytes([len(addr_group)]) + addr_group
                                            + bytes([len(src_group)]) + src_group)[:8], 'little')
    hash1 = hash1 % ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP
    hash2 = int.from_bytes(double_hash(key + bytes([len(src_group)]) + src_group
                                           + hash1.to_bytes(8, 'little'))[:8], 'little')
    return hash2 % ADDRMAN_NEW_BUCKET_COUNT

key = bytes.fromhex(&quot;41f758f2e5cc078d3795b4fc0cb60c2d735fa92cc020572bdc982dd2d564d11b&quot;)
addr = &quot;250.1.2.1&quot;
src = &quot;250.1.2.1&quot;
bucket = get_new_bucket(key, addr, src)
print(&quot;bucket is&quot;, bucket) # 786
</code></pre>
