Bitcoin has revolutionized society. It offers an almost miraculous alternative to the FIAT hellhole we've been led into by the powers that be. To many, this alone translates into a potential scenario where the economy isn't regulated by a handful of nameless oligarchs but by the collective computational power of cyberspace. The secret to bitcoin's power? The blockchain.

I wrote a blog post covering some technical details as well as the motivations behind this script, make sure to check it out for more background info. As for the script itself, it decodes the output (receiving) addresses of a given bitcoin transaction in the original order in an attempt to reveal a hidden message. The transaction data is taken from the transaction explorer, removing the need for a local copy of the bitcoin blockchain, all it needs is a valid TX hash.

import sys
import urllib3
import base58

def findSubStr(ogStr, subStr):
    hits = [i for i in range(len(ogStr)) if ogStr.startswith(subStr, i)]
    return hits

def decodeTX(txNum):
    http = urllib3.PoolManager()
    txData = http.request(
        "GET", "" + txNum + "?show_adv=true")

    # Decode the raw bytes received
    dataStr ='utf-8')

    atOutput = False
    if (dataStr.find("output scripts")):
        dataStr = dataStr[dataStr.find("output scripts"):]
        # Remove the trailing CSS style code
        if (dataStr.find("<style")):
            dataStr = dataStr[: dataStr.find("<style ")]

        # Trim the unnecessary content
        dataStr = dataStr[dataStr.find('"outputs":'):dataStr.find('"config":')]
        addrSubStr = findSubStr(dataStr, "address")
        if (len(addrSubStr) < 1):
            print("Invalid transaction hash!")
        print("Total output addresses found: " + str(len(addrSubStr)))
        # print(addrSubStr)
        counter = 0
        totalData = b""
        for i in addrSubStr:
            counter += 1
            # Isolate the address
            addr = dataStr[i+10:i+46]
            addr = addr[:addr.find('"')]
            # Check for invalid / empty adresses
            if (':' in addr or ',' in addr):
            addrDecoded = base58.b58decode_check(addr)
            totalData += addrDecoded
            print("["+str(counter)+"]" + addr + "d: " + str(addrDecoded))

        print("Total bytes extracted: " + str(len(totalData)))
        print("Saving data to "+txNum)

        # Save the decoded data into a file with the transaction hash as name
        # Not all the decoded bytes have an ASCII equivalent or even proper alignement / syntax
        # so decoding it with python's .decode('ascii') usually fails
        # Running cat on the file does a much better job printing the data
        saveFileBinary = open(txNum, "wb")

if __name__ == "__main__":
    print("TX Hash: " + str(sys.argv[1]))


As an example, we decode a well-known hidden message in transaction 930a2114cdaa86e1fac46d15c74e81c09eee1d4150ff9d48e76cb0697d8e1d72. The extracted, decoded output is also stored in a file named after it's transaction hash.

Left: Encoded output addresses | Right: Decoded ASCII

It's worth pointing out that this is one of a handful of ways a user can sneak data into the blockchain!