1

I am trying to decode chainstate db for a specific out index for a transaction in python just for learning. Transaction ID: 4d4a4c6ca4f3c91e69563199943336d3279fad71c9e8d9c1708ef9dc6ac16000 out index = 1822

chainstate_db = plyvel.DB(os.path.join(os.getenv('HOME'),".bitcoin/chainstate"), compression=None)
def getObfuscationKey():
    value = chainstate_db.get(b'\x0e\x00' + b'obfuscate_key')
    print('obfuscation key = %s' % value)
    obfuscation_key = value[1:]
    return obfuscation_key

def applyObfuscationKey(data: bytes):
    obfuscation_key = getObfuscationKey()
    new_val = bytes(data[index] ^ obfuscation_key[index % len(obfuscation_key)] for index in range(len(data)))
    return new_val

def b128_varint_decode(value: bytes, pos = 0):
    n = 0
    while True:
        data = value[pos]
        pos += 1
        n = (n << 7) | (data & 0x7f) # 1111111
        if data & 0x80 == 0:
            return (n, pos)
        n += 1

def txout_decompress(x):
    # x = 0  OR  x = 1+10*(9*n + d - 1) + e  OR  x = 1+10*(n - 1) + 9
    if x == 0:
        return 0
    x -=1
    # x = 10*(9*n + d - 1) + e
    e = x % 10
    x /= 10
    n = 0
    if e < 9:
        # x = 9*n + d - 1
        d = (x % 9) + 1
        x /= 9
        # x = n
        n = x*10 + d
    else:
        n = x+1
    while e:
        n *= 10
        e -= 1
    return n
...
def getChainstateData(txn_hash_big_endian: bytes, out_index: int):
    key = b'C' + txn_hash_big_endian + b128_varint_encode(out_index)
    value = chainstate_db.get(key)
    value = applyObfuscationKey(value)
    code, pos = b128_varint_decode(value)
    height = code >> 1
    coinbase = code & 0x01
    print('height = %d, coinbase = %r' % (height, coinbase))
    decoded_varint_amount, pos = b128_varint_decode(value, pos)
    amount = txout_decompress(decoded_varint_amount)
    print('amount = %d' % amount)
if __name__ == '__main__':
    getChainstateData(binascii.unhexlify('0060c16adcf98e70c1d9e8c971ad9f27d3363394993156691ec9f3a46c4c4a4d'), 1822)

I get below result: height = 355833, coinbase = 0 amount = 12353

When I do getrawtransaction in bitcoin core daemon I get amount as 12200.

./bitcoin-cli getrawtransaction 4d4a4c6ca4f3c91e69563199943336d3279fad71c9e8d9c1708ef9dc6ac16000 true

For out index 1822 I get:

{
      "value": 0.00012200,
      "n": 1822,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 c40c4870c3874cafb3385dca3731d637ac51110d OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a914c40c4870c3874cafb3385dca3731d637ac51110d88ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "1JscA3193KByPvFv4X6nNEV2SGjdXVcVq6"
        ]
      }
    },

So there must be problem with code which I am not able to figure out. I think problem is in

txout_decompress(x)

method. But this is strange because I have directly used method in bitcoin core

uint64_t DecompressAmount(uint64_t x)

in

src/compressor.cpp

after converting this to python. Please help me solve this issue.

1

After investigating I found the x in txout_decompress(x) was not an integer which was causing the difference in answer so during division I typecast it to int and it worked. So the corrected code:

def amount_decompress(x: int):
    # x = 0  OR  x = 1+10*(9*n + d - 1) + e  OR  x = 1+10*(n - 1) + 9
    if x == 0:
        return 0
    x -=1
    # x = 10*(9*n + d - 1) + e
    e = x % 10
    x = int(x / 10)
    n = 0
    if e < 9:
        # x = 9*n + d - 1
        d = (x % 9) + 1
        x = int(x / 9)
        # x = n
        n = x*10 + d
    else:
        n = x+1
    while e:
        n *= 10
        e -= 1
    return n

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.