<jupyter_start><jupyter_text>Exercise 1 Make [this test](/edit/session5/tx.py) pass: `tx.py:TxTest:test_verify_p2pkh`<jupyter_code># Exercise 1

reload(tx)
run(tx.TxTest('test_verify_p2pkh'))
# Transaction Construction Example
from ecc import PrivateKey # needed to sign the tx
from helper import decode_base58, SIGHASH_ALL # decode base converts address to hash needed P2PKH
from script import p2pkh_script, Script # calculates z P2PH
from tx import Tx, TxIn, TxOut

# Step 1
tx_ins = []
prev_tx = bytes.fromhex('8be2f69037de71e3bc856a6627ed3e222a7a2d0ce81daeeb54a3aea8db274149')
prev_index = 4
tx_ins.append(TxIn(prev_tx, prev_index))

# Step 2
tx_outs = []

    # CHANGE BACK TO MYSELF
h160 = decode_base58('mzx5YhAH9kNHtcN481u6WkjeHjYtVeKVh2')
tx_outs.append(TxOut(
    amount=int(0.38*100000000),
    script_pubkey=p2pkh_script(h160),
))
    # TO RECIPIENT
h160 = decode_base58('mnrVtF8DWjMu839VW3rBfgYaAfKk8983Xf')
tx_outs.append(TxOut(
    amount=int(0.1*100000000),
    script_pubkey=p2pkh_script(h160),
))

    # version, tx_ins, tx_outs, index, testnet
tx_obj = Tx(1, tx_ins, tx_outs, 0, testnet=True)

# Step 3
z = tx_obj.sig_hash(0)
# print(z) 39632174008676238049387290821569513652244231797557994875840378150192119985579
pk = PrivateKey(secret=8675309)
# print(pk) <ecc.PrivateKey object at 0x000001BC5ACC7D00>
der = pk.sign(z).der()
# print(der) b'0E\x02!\x00\xfa02`{P\xe8\xcb\x05\xbe\xdc\x9dC\xf9\x86\xf1\x9d\xed\xc2.a2\x0b\x97e\x06\x1c\\\xd9\xc6iF\x02 r\xd5\x14\xefcy\x88Q[\xfaY\xa6`Yb\x06\xdeh\xf0\xed@\x90\xd0\xa3\x98\xe7\x0fM\x817\r\xfb'
sig = der + SIGHASH_ALL.to_bytes(1, 'big')
# print(sig) b'0E\x02!\x00\xfa02`{P\xe8\xcb\x05\xbe\xdc\x9dC\xf9\x86\xf1\x9d\xed\xc2.a2\x0b\x97e\x06\x1c\\\xd9\xc6iF\x02 r\xd5\x14\xefcy\x88Q[\xfaY\xa6`Yb\x06\xdeh\xf0\xed@\x90\xd0\xa3\x98\xe7\x0fM\x817\r\xfb\x01'
sec = pk.point.sec()
# print(sec) b'\x03\x93U\x81\xe5,5L\xd2\xf4\x84\xfe\x8e\xd8:\xf7\xa3\tp\x05\xb2\xf9\xc6\x0b\xffq\xd3[\xd7\x95\xf5Kg'
tx_obj.tx_ins[0].script_sig = Script([sig, sec]) # unlocks tx to be spent
# print(tx_obj) tx: 3b998df74ac249d3f787cae4d43f29ab6ea6dd70f48d53d8f941aa0524d8d6cb
# version: 1
# tx_ins:
# 8be2f69037de71e3bc856a6627ed3e222a7a2d0ce81daeeb54a3aea8db274149:4
# tx_outs:
# 38000000:OP_DUP OP_HASH160 d52ad7ca9b3d096a38e752c2018e6fbc40cdf26f OP_EQUALVERIFY # OP_CHECKSIG 10000000:OP_DUP OP_HASH160 507b27411ccf7f16f10297de6cef3f291623eddf OP_EQUALVERIFY OP_CHECKSIG
# locktime: 0

print(tx_obj.serialize().hex())

# FULL TX:
# 0100000001494127dba8aea354ebae1de80c2d7a2a223eed27666a85bce371de3790f6e28b040000006b483045022100fa3032607b50e8cb05bedc9d43f986f19dedc22e61320b9765061c5cd9c66946022072d514ef637988515bfa59a660596206de68f0ed4090d0a398e70f4d81370dfb012103935581e52c354cd2f484fe8ed83af7a3097005b2f9c60bff71d35bd795f54b67ffffffff0280d54302000000001976a914d52ad7ca9b3d096a38e752c2018e6fbc40cdf26f88ac80969800000000001976a914507b27411ccf7f16f10297de6cef3f291623eddf88ac00000000

# VERSION: 01000000
# NUM OF INPUTS: 01
# PREV HASH: 494127dba8aea354ebae1de80c2d7a2a223eed27666a85bce371de3790f6e28b040000006b483045022100fa3032607b50e8cb05bedc9d43f986f19dedc22e61320b9765061c5cd9c66946022072d514ef637988515bfa59a660596206de68f0ed4090d0a398e70f4d81370dfb012103935581e52c354cd2f484fe8ed83af7a3097005b2f9c60bff71d35bd795f54b67ffffffff0280d54302000000001976a914d52ad7ca9b3d096a38e752c2018e6fbc40cdf26f88ac
# VALUE OF OUTPUT: 8096980000000000
# SCRIPT PUB KEY: 1976a914507b27411ccf7f16f10297de6cef3f291623eddf88ac
# LOCKTIME: 00000000<jupyter_output>0100000001494127dba8aea354ebae1de80c2d7a2a223eed27666a85bce371de3790f6e28b040000006b483045022100fa3032607b50e8cb05bedc9d43f986f19dedc22e61320b9765061c5cd9c66946022072d514ef637988515bfa59a660596206de68f0ed4090d0a398e70f4d81370dfb012103935581e52c354cd2f484fe8ed83af7a3097005b2f9c60bff71d35bd795f54b67ffffffff0280d54302000000001976a914d52ad7ca9b3d096a38e752c2018e6fbc40cdf26f88ac80969800000000001976a914507b27411ccf7f16f10297de6cef3f291623eddf88ac00000000<jupyter_text>Exercise 2 Make [this test](/edit/session5/tx.py) pass: `tx.py:TxTest:test_sign_input`<jupyter_code># Exercise 2

reload(tx)
run(tx.TxTest('test_sign_input'))<jupyter_output>.
----------------------------------------------------------------------
Ran 1 test in 0.477s

OK<jupyter_text>Exercise 3Send 0.04 TBTC to this address`mqYz6JpuKukHzPg94y4XNDdPCEJrNkLQcv` Go here to send your transaction: https://blockstream.info/testnet/tx/push<jupyter_code># Exercise 3

from tx import Tx, TxIn, TxOut
from helper import decode_base58, hash256, little_endian_to_int
from script import p2pkh_script
prev_tx = bytes.fromhex('8f5a634245870352c88dbd39073ccc8024cb2a155d6398b1d8e0542f616e657c')  # CHANGE
prev_index = 1  # CHANGE
target_address = 'mqYz6JpuKukHzPg94y4XNDdPCEJrNkLQcv'
target_amount = 0.04
fee = 50000
passphrase = b'<PASSWORD>divingaroundthe<PASSWORD>whichwasgoingaboutahundred<PASSWORD>anhourwiththetopdowntolasvegasandavoicewasscreamingholyjesuswhatarethesegoddamnanimalsthenitwasquietagainmyattorneyhadtakenhisshirtoffandwaspouringbeeronhischesttofacilitatethetanningprocesswhatthehellareyouyellingabouthemutteredstaringupatthesunwithhiseyesclosedandcoveredwithwraparoundspanishsunglassesnevermindisaidItsyourturntodriveihitthebrakesandaimedthegreatredsharktowardtheshoulderofthehighwaynopointmentioningthosebatsithoughtthepoorbastardwillseethemsoonenough'

secret = little_endian_to_int(hash256(passphrase))
private_key = PrivateKey(secret=secret)
change_address = private_key.point.address(testnet=True)

# initialize inputs
tx_ins = []

# create a new tx input with prev_tx, prev_index
tx_ins.append(TxIn(prev_tx, prev_index))

# initialize outputs
tx_outs = []

# decode the hash160 from the target address
target_h160 = decode_base58(target_address)

# convert hash160 to p2pkh script
target_script_pubkey = p2pkh_script(target_h160)

# convert target amount to satoshis (multiply by 100 million)
target_satoshis = int(target_amount*100000000)

# create a new tx output for target with amount and script_pubkey
tx_outs.append(TxOut(target_satoshis, target_script_pubkey)) 

# decode the hash160 from the change address
change_h160 = decode_base58(change_address)

# convert hash160 to p2pkh script
change_script_pubkey = p2pkh_script(change_h160)

# get the value for the transaction input (remember testnet=True)
prev_amount = tx_ins[0].value(testnet=True)

# calculate change_satoshis based on previous amount, target_satoshis & fee
change_satoshis = prev_amount - target_satoshis - fee

# create a new tx output for target with amount and script_pubkey
tx_outs.append(TxOut(change_satoshis, change_script_pubkey))

# create the transaction (name it tx_obj and set testnet=True)
tx_obj = Tx(1, tx_ins, tx_outs, 0, testnet=True)

# now sign the 0th input with the private_key using sign_input
tx_obj.sign_input(0, private_key)

# SANITY CHECK: change address corresponds to private key
if private_key.point.address(testnet=True) != change_address:
    raise RuntimeError('Private Key does not correspond to Change Address, check priv_key and change_address')

# SANITY CHECK: output's script_pubkey is the same one as your address
if tx_ins[0].script_pubkey(testnet=True).commands[2] != decode_base58(change_address):
    raise RuntimeError('Output is not something you can spend with this private key. Check that the prev_tx and prev_index are correct')

# SANITY CHECK: fee is reasonable
if tx_obj.fee() > 0.05*100000000 or tx_obj.fee() <= 0:
    raise RuntimeError(f'Check that the change amount is reasonable. Fee is {tx_obj.fee()}')

# serialize and hex()
print(tx_obj.serialize().hex())<jupyter_output>01000000017c656e612f54e0d8b198635d152acb2480cc3c0739bd8dc85203874542635a8f010000006b483045022100cfad521e7dd2ad2aabf515bb3bc8e2f9b4b6233a882d420d7ac889f5f0a2ef3a02205442b3aa7e3918033e00a64bdca2f21291e385cf6e9a64950aa7622c7fc7d71e0121020ed2cf0fbc53d3485416abfe82630c5a8f5f0e70a8279253fdb638d4a0d73c37ffffffff0200093d00000000001976a9146e13971913b9aa89659a9f53d327baa8826f2d7588ac30ca5a00000000001976a914350bc6220a4cc18cc52f665a04cbeb7fe2a3450c88ac00000000<jupyter_text>Exercise 4 Bonus Question. Only attempt if you've finished Exercise 3 and have time to try it.Get some testnet coins and spend both outputs (one from your change address and one from the testnet faucet) to`mqYz6JpuKukHzPg94y4XNDdPCEJrNkLQcv` You can get some free testnet coins at: https://testnet.coinfaucet.eu/en/<jupyter_code># Exercise 4

# Bonus
from tx import Tx, TxIn, TxOut
from helper import decode_base58, hash256, little_endian_to_int
from script import p2pkh_script
prev_tx = bytes.fromhex('cd83c251c33411ba04f67dcd86c62eaf0d3e6b46043e7a2ec6120d197635e0e7')  # CHANGE
prev_index = 17  # CHANGE
target_address = 'mqYz6JpuKukHzPg94y4XNDdPCEJrNkLQcv'
target_amount = 0.05
fee = 50000
passphrase = b'<PASSWORD>'


secret = little_endian_to_int(hash256(passphrase))
private_key = PrivateKey(secret=secret)
change_address = private_key.point.address(testnet=True)

# initialize inputs
tx_ins = []

# create a new tx input with prev_tx, prev_index
tx_ins.append(TxIn(prev_tx, prev_index))

# initialize outputs
tx_outs = []

# decode the hash160 from the target address
target_h160 = decode_base58(target_address)

# convert hash160 to p2pkh script
target_script_pubkey = p2pkh_script(target_h160)

# convert target amount to satoshis (multiply by 100 million)
target_satoshis = int(target_amount*100000000)

# create a new tx output for target with amount and script_pubkey
tx_outs.append(TxOut(target_satoshis, target_script_pubkey)) 

# decode the hash160 from the change address
change_h160 = decode_base58(change_address)

# convert hash160 to p2pkh script
change_script_pubkey = p2pkh_script(change_h160)

# get the value for the transaction input (remember testnet=True)
prev_amount = tx_ins[0].value(testnet=True)

# calculate change_satoshis based on previous amount, target_satoshis & fee
change_satoshis = prev_amount - target_satoshis - fee

# create a new tx output for target with amount and script_pubkey
tx_outs.append(TxOut(change_satoshis, change_script_pubkey))

# create the transaction (name it tx_obj and set testnet=True)
tx_obj = Tx(1, tx_ins, tx_outs, 0, testnet=True)

# now sign the 0th input with the private_key using sign_input
tx_obj.sign_input(0, private_key)

# SANITY CHECK: change address corresponds to private key
if private_key.point.address(testnet=True) != change_address:
    raise RuntimeError('Private Key does not correspond to Change Address, check priv_key and change_address')

# SANITY CHECK: output's script_pubkey is the same one as your address
if tx_ins[0].script_pubkey(testnet=True).commands[2] != decode_base58(change_address):
    raise RuntimeError('Output is not something you can spend with this private key. Check that the prev_tx and prev_index are correct')

# SANITY CHECK: fee is reasonable
if tx_obj.fee() > 0.05*100000000 or tx_obj.fee() <= 0:
    raise RuntimeError(f'Check that the change amount is reasonable. Fee is {tx_obj.fee()}')

# serialize and hex()
# change_satoshis = prev_amount - target_satoshis - fee
print("prev_amount: " + str(prev_amount / 100000000))
print("sent to: " + str(target_satoshis / 100000000))
print("fee: " + str(fee / 100000000))
print("change: " + str(change_satoshis / 100000000))
print(tx_obj.serialize().hex())

# op_checkmultisig
def op_checkmultisig(stack, z):
    if len(stack) < 1:
        return False
    n = decode_num(stack.pop())
    if len(stack) < n + 1:
        return False
    sec_pubkeys = []
    for _ in range(n):
        sec_pubkeys.append(stack.pop())
    m = decode_num(stack.pop())
    if len(stack) < m + 1:
        return False
    der_signatures = []
    for _ in range(m):
        # signature is assumed to be using SIGHASH_ALL
        der_signatures.append(stack.pop()[:-1])
    # OP_CHECKMULTISIG bug
    stack.pop()
    try:
        raise NotImplementedError
    except (ValueError, SyntaxError):
        return False
    return True<jupyter_output><empty_output><jupyter_text>Exercise 5 Make [this test](/edit/session5/op.py) pass: `op.py:OpTest:test_op_checkmultisig`<jupyter_code># Exercise 5

reload(op)
reload(script)
run(op.OpTest('test_op_checkmultisig'))<jupyter_output>.
----------------------------------------------------------------------
Ran 1 test in 0.546s

OK<jupyter_text>Exercise 6Find the hash160 of the RedeemScript```5221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152ae```<jupyter_code># Exercise 6

# P2SH

# 52 OP_2
# Length of Key: 21 
# Key: <KEY>
# Length of Key: 21
# Key: 03b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb71
# 52 OP_2
# ae OP_CHECKMULTISIG

from helper import hash160
hex_redeem_script = '5221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152ae'
# bytes.fromhex script
redeem_script = bytes.fromhex(hex_redeem_script)
# hash160 result
h160 = hash160(redeem_script)
# hex() to display
print(h160.hex())
# 74d691da1574e6b3c192ecfb52cc8984ee7b6c56
# P2SH address construction example
from helper import encode_base58_checksum
# \x05  = mainnet
print(encode_base58_checksum(b'\x05'+bytes.fromhex('74d691da1574e6b3c192ecfb52cc8984ee7b6c56')))<jupyter_output>3CLoMMyuoDQTPRD3XYZtCvgvkadrAdvdXh<jupyter_text>Exercise 7 Make [this test](/edit/session5/helper.py) pass: `helper.py:HelperTest:test_p2pkh_address`<jupyter_code># Exercise 7

reload(helper)
run(helper.HelperTest('test_p2pkh_address'))<jupyter_output>.
----------------------------------------------------------------------
Ran 1 test in 0.002s

OK<jupyter_text>Exercise 8 Make [this test](/edit/session5/helper.py) pass: `helper.py:HelperTest:test_p2sh_address`<jupyter_code># Exercise 8

reload(helper)
run(helper.HelperTest('test_p2sh_address'))<jupyter_output>.
----------------------------------------------------------------------
Ran 1 test in 0.003s

OK<jupyter_text>Exercise 9 Make [this test](/edit/session5/script.py) pass: `script.py:ScriptTest:test_address`<jupyter_code># Exercise 9

reload(script)
run(script.ScriptTest('test_address'))
# z for p2sh example
from helper import hash256
h256 = hash256(bytes.fromhex('0100000001868278ed6ddfb6c1ed3ad5f8181eb0c7a385aa0836f01d5e4789e6bd304d87221a000000475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152aeffffffff04d3b11400000000001976a914904a49878c0adfc3aa05de7afad2cc15f483a56a88ac7f400900000000001976a914418327e3f3dda4cf5b9089325a4b95abdfa0334088ac722c0c00000000001976a914ba35042cfe9fc66fd35ac2224eebdafd1028ad2788acdc4ace020000000017a91474d691da1574e6b3c192ecfb52cc8984ee7b6c56870000000001000000'))
z = int.from_bytes(h256, 'big')
print(hex(z))
# p2sh verification example
from ecc import S256Point, Signature
from helper import hash256
h256 = hash256(bytes.fromhex('0100000001868278ed6ddfb6c1ed3ad5f8181eb0c7a385aa0836f01d5e4789e6bd304d87221a000000475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152aeffffffff04d3b11400000000001976a914904a49878c0adfc3aa05de7afad2cc15f483a56a88ac7f400900000000001976a914418327e3f3dda4cf5b9089325a4b95abdfa0334088ac722c0c00000000001976a914ba35042cfe9fc66fd35ac2224eebdafd1028ad2788acdc4ace020000000017a91474d691da1574e6b3c192ecfb52cc8984ee7b6c56870000000001000000'))
z = int.from_bytes(h256, 'big')
point = S256Point.parse(bytes.fromhex('022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb70'))
sig = Signature.parse(bytes.fromhex('3045022100dc92655fe37036f47756db8102e0d7d5e28b3beb83a8fef4f5dc0559bddfb94e02205a36d4e4e6c7fcd16658c50783e00c341609977aed3ad00937bf4ee942a89937'))
print(point.verify(z, sig))<jupyter_output>True<jupyter_text>Exercise 10Validate the second signature of the first input```0100000001868278ed6ddfb6c1ed3ad5f8181eb0c7a385aa0836f01d5e4789e6bd304d87221a000000db00483045022100dc92655fe37036f47756db8102e0d7d5e28b3beb83a8fef4f5dc0559bddfb94e02205a36d4e4e6c7fcd16658c50783e00c341609977aed3ad00937bf4ee942a8993701483045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e75402201475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152aeffffffff04d3b11400000000001976a914904a49878c0adfc3aa05de7afad2cc15f483a56a88ac7f400900000000001976a914418327e3f3dda4cf5b9089325a4b95abdfa0334088ac722c0c00000000001976a914ba35042cfe9fc66fd35ac2224eebdafd1028ad2788acdc4ace020000000017a91474d691da1574e6b3c192ecfb52cc8984ee7b6c568700000000```The sec pubkey of the second signature is:```03b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb71```The der signature of the second signature is:```3045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e75402201475221022```The redeemScript is:```475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152ae```<jupyter_code># Exercise 10

from io import BytesIO
from ecc import S256Point, Signature
from helper import int_to_little_endian, SIGHASH_ALL
from script import Script
from tx import Tx
hex_sec = '03b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb71'
hex_der = '3045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e754022'
hex_redeem_script = '475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152ae'
sec = bytes.fromhex(hex_sec)
der = bytes.fromhex(hex_der)
redeem_script_stream = BytesIO(bytes.fromhex(hex_redeem_script))
redeem_script = Script.parse(redeem_script_stream)
hex_tx = '0100000001868278ed6ddfb6c1ed3ad5f8181eb0c7a385aa0836f01d5e4789e6bd304d87221a000000db00483045022100dc92655fe37036f47756db8102e0d7d5e28b3beb83a8fef4f5dc0559bddfb94e02205a36d4e4e6c7fcd16658c50783e00c341609977aed3ad00937bf4ee942a8993701483045022100da6bee3c93766232079a01639d07fa869598749729ae323eab8eef53577d611b02207bef15429dcadce2121ea07f233115c6f09034c0be68db99980b9a6c5e75402201475221022626e955ea6ea6d98850c994f9107b036b1334f18ca8830bfff1295d21cfdb702103b287eaf122eea69030a0e9feed096bed8045c8b98bec453e1ffac7fbdbd4bb7152aeffffffff04d3b11400000000001976a914904a49878c0adfc3aa05de7afad2cc15f483a56a88ac7f400900000000001976a914418327e3f3dda4cf5b9089325a4b95abdfa0334088ac722c0c00000000001976a914ba35042cfe9fc66fd35ac2224eebdafd1028ad2788acdc4ace020000000017a91474d691da1574e6b3c192ecfb52cc8984ee7b6c568700000000'
stream = BytesIO(bytes.fromhex(hex_tx))
# parse the S256Point and Signature
point = S256Point.parse(sec) 
sig = Signature.parse(der) 
# parse the Tx
t = Tx.parse(stream) 
# change the first input's ScriptSig to RedeemScript
t.tx_ins[0].script_sig = redeem_script
# get the serialization
ser = t.serialize() 
# add the sighash (4 bytes, little-endian of SIGHASH_ALL)
ser += int_to_little_endian(SIGHASH_ALL, 4) 
# hash256 the result
h256 = hash256(ser) 
# your z is the hash256 as a big-endian number: use int.from_bytes(x, 'big')
z = int.from_bytes(h256, 'big') 
# now verify the signature using point.verify
print(point.verify(z, sig))<jupyter_output>True
{'fraction_non_alphanumeric': 0.0826586912803589, 'fraction_numerical': 0.24477904398494302, 'mean_word_length': 7.978703703703704, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 40, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 58, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '471251', 'license': 'BSD-2-Clause', 'n_tokens_mistral': 10810, 'n_tokens_neox': 8137, 'n_words': 1115, 'path': 'session5/session5.ipynb', 'repo_name': 'willwooten/pb-exercises', 'size': '19715'}