bitcoin chainstate database parsing in python giving wrong value

1

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.

Vizeet Srivastava

Posted 2018-05-05T06:40:05.163

Reputation: 51

Answers

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

Vizeet Srivastava

Posted 2018-05-05T06:40:05.163

Reputation: 51