Created
February 21, 2025 16:27
-
-
Save k26dr/3205f7a615ead3df28dcd969e814cf07 to your computer and use it in GitHub Desktop.
How to Upload Books to Ethereum L1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Calldata on Ethereum has gotten so cheap that you can upload entire books in text format directly to Layer 1. | |
| I'll use Meditations by Marcus Aurelius as an example because it's short enough to upload easily. | |
| This book is available for free, so the first thing I did is to download a TXT copy of the book from the internet. | |
| $ wget http://classics.mit.edu/Antoninus/meditations.mb.txt | |
| Ethereum has a limit on how much data you can upload in a single transaction, | |
| so I use a bash script to split the file up into 1000 line segments. | |
| First determine how many lines the file has. | |
| $ wc -l | |
| 4328 meditations.mb.txt | |
| This means the file has 4328 lines. The following script will create the first 4 parts. | |
| Since the last part will have 328 lines, I need to do that custom. | |
| $ for i in $(seq 1 4); do head meditations.mb.txt -n $((i * 1000)) | tail -n 1000 > med_p$((i)).txt; done | |
| Now do the last part with a custom line count. | |
| $ tail meditations.mb.txt -n 328 > med_p5.txt | |
| Now you have the book split into 5 parts which you can upload to the chain individually. | |
| I wrote a Python script to make this part easier. | |
| ``` | |
| from web3 import Web3, AsyncWeb3 | |
| # Mainnet | |
| address = "MY_ETHEREUM_ADDRESS" # TODO | |
| pkey = bytes.fromhex("MY_PRIVATE_KEY") #TODO | |
| w3 = Web3(Web3.HTTPProvider('ETHEREUM_RPC_URL')) #TODO | |
| chainId = 1 | |
| contract_address = "0xc0a9c5BA3076fa7eE600A9f0E659DDa6382B2701" | |
| maxFeePerGas = 0.8 | |
| maxPriorityFeePerGas = 0.8 | |
| abi = [{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"text","type":"string"}],"name":"book","outputs":[],"stateMutability":"nonpayable","type":"function"}] | |
| book = w3.eth.contract(address=contract_address, abi=abi) | |
| # TODO: Replace this with the next nonce on your Ethereum address | |
| nonce = 0 | |
| for i in range(1,6): | |
| print(nonce + i - 1) | |
| filename = "med_p" + str(i) + ".txt" | |
| with open(filename) as f: | |
| content = f.read() | |
| book_txn = book.functions.book("Meditations: Part " + str(i), content).build_transaction({ | |
| 'chainId': chainId, | |
| 'gas': 1407106, | |
| 'maxFeePerGas': w3.to_wei(maxFeePerGas, 'gwei'), | |
| 'maxPriorityFeePerGas': w3.to_wei(maxPriorityFeePerGas, 'gwei'), | |
| 'nonce': nonce + i - 1, | |
| }) | |
| signed_txn = w3.eth.account.sign_transaction(book_txn, private_key=pkey) | |
| w3.eth.send_raw_transaction(signed_txn.raw_transaction) | |
| print(signed_txn.hash.hex()) | |
| ``` | |
| You need to replace MY_ETHEREUM_ADDRESS, MY_PRIVATE_KEY, ETHEREUM_RPC_URL, | |
| and add in your account's current nonce to make the script work. If you're | |
| uploading a different book, you will want to update the title in the book_txn | |
| field as well. | |
| I would also recommend updating maxFeePerGas and maxPriorityFeePerGas | |
| as needed toget the transaction to go through. I set it low so that I spend as little | |
| money as possible, but that means it can take a few hours to clear. | |
| If you do, the script will spit out a series of transaction hashes for submitted | |
| transactions that you can look up on Etherscan. If you look those up, you will see | |
| that the data has been uploaded. | |
| Congrats! You've just uploaded a book to Ethereum L1. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment