Package: pythereum
pythereum(formerly eth_rpc)A lightweight Ethereum RPC library for PythonOver four times faster than Web3.py, with more functionality!Features include:Ability to initiate remote procedure calls on a wide variety of ethereum functionsWebsocket pooling for high performance callsSupport for RPC batching, allowing multiple calls to the same function at once"eth_subscribe" functionalityCurrency conversion, with support for esoteric denomination names (e.g. lovelace)Private transaction and Bundle support for communication directly with block buildersAutomatic nonce and gas management for transactionsEarly-stage support for L2 chain specific functionality (Optimism P2P implemented for now)Automatic ABI decodingTyped function outputs for intuitive library useImplemented RPC methodsAll methods listed in theEthereum JSON RPC API specificationare completed as of version1.0.5,
alongside methods for subscriptions, and support for calling custom function names with custom parameters.Supported BuildersWith theBuilderRPCclass, pythereum supports submitting bundles and private transactions directly to block builders.
Each builder class that can be passed into BuilderRPC instances automatically manages communication with the given builder.The following builder classes are currently implemented:Titan BuilderRsync BuilderBuilder0x69Flashbots BuilderLoki BuilderBeaver BuilderTitan Builder and Flashbots now have support formevboostbundles.Getting startedPoetryThis project and its dependencies are managed by python poetry,
which will automatically manage the versions of each library / python version
upon which this project depends.Install poetry with the instructionshere.DocumentationBrief documentation available onreadthedocs.More information and guides will be added to documentation over time.InstallationPoetry InstallationThe library currently requires python versions>=3.11.If you want to include this library for use in another project via Poetry
you must simply add the following to yourpyproject.tomlfile under[tool.poetry.dependencies]pythereum={git="https://github.com/gabedonnan/pythereum.git"}orpythereum="^1.2.1"If you would like to install the library via pypi instead of via this git repository.
This git repository will always be the most up to date but the releases on pypi should
be more thoroughly tested.Pip / PyPi installationThe library is now available via pip!! (I had to change the whole project name to get it there)It can be installed with the following command, or downloadedhere:python3 -m pip install pythereumExample usageBasic single function call# Example simple functionimportasynciofrompythereumimportEthRPCTEST_URL="ws://127.0.0.1:8545"asyncdeftest_transaction_count():asyncwithEthRPC(TEST_URL,pool_size=1)aserpc:# Gets the number of transactions sent from a given EOA addressr=awaiterpc.get_transaction_count("0x5fC2E691E520bbd3499f409bb9602DBA94184672")print(r)if__name__=="__main__":asyncio.run(test_transaction_count())Example subscription# Example subscriptionimportasynciofrompythereumimportEthRPC,SubscriptionTypeTEST_URL="ws://127.0.0.1:8545"asyncdeftest_subscription(subscription_type:SubscriptionType):"""Creates a subscription to receive data about all new headsPrints each new subscription result as it is received"""asyncwithEthRPC(TEST_URL,pool_size=1)aserpc:asyncwitherpc.subscribe(subscription_type)assc:# The following will iterate as each item is gotten by sc.recv()asyncforiteminsc.recv():# 'item' is formatted into the appropriate form for its subscription type# this is done by the sc.recv() automaticallyprint(item)if__name__=="__main__":asyncio.run(test_subscription(SubscriptionType.new_heads))Example batch call# Example batch callimportasynciofrompythereumimportEthRPCTEST_URL="ws://127.0.0.1:8545"asyncdeftest_batching():# Batch calls can be applied to any parameterised method# Each parameter must be passed in as a list# With list length k where k is the batch sizeasyncwithEthRPC(TEST_URL,pool_size=1)aserpc:r=awaiterpc.get_block_by_number(block_specifier=[iforiinrange(40000,40010)],full_object=[Truefor_inrange(10)])print(r)if__name__=="__main__":asyncio.run(test_batching())Example utility functions>>>frompythereumimportEthDenomination,convert_eth>>>convert_eth(1_000_000,convert_from=EthDenomination.wei,convert_to=EthDenomination.ether)1e-12>>>convert_eth(1_000,EthDenomination.babbage,EthDenomination.finney)1e-09>>>convert_eth(1e18,"wei","eth")# We can now use strings to represent denominations1.0>>>frompythereumimportto_checksum_address>>>to_checksum_address("0x5050f69a9786f081509234f1a7f4684b5e5b76c9")HexStr('0x5050F69a9786F081509234F1a7F4684b5E5b76C9')Example builder submission# Example builder submissionimportasynciofrometh_accountimportAccountfrompythereumimportBuilderRPC,TitanBuilder,HexStr,Transactionasyncdeftest_builder_submission():# Create new arbitrary account walletacct=Account.create()# Create an arbitrary EIP-1559 transaction# This transaction is an equivalence to a dictionary,# it simply provides a convenient constructortx=Transaction(from_address=acct.address,to_address="0x5fC2E691E520bbd3499f409bb9602DBA94184672",value=1,max_priority_fee_per_gas=1,max_fee_per_gas=1,gas=1,chain_id=1,nonce=0)# Sign your transaction with your account's keysigned_tx=Account.sign_transaction(tx,acct.key).rawTransaction# BuilderRPC sends to TitanBuilder, private key used for creating a signed headerasyncwithBuilderRPC(TitanBuilder(),private_key=acct.key)asbrpc:msg=awaitbrpc.send_private_transaction(HexStr(signed_tx))print(msg)if__name__=="__main__":asyncio.run(test_builder_submission())Example Gas and Nonce managementimportasynciofrometh_accountimportAccountfrompythereumimportGasManager,NonceManager,Transaction,EthRPCTEST_URL="ws://127.0.0.1:8545"asyncdeftest_management():acct=Account.create()tx=Transaction(from_address=acct.address,to_address="0x5fC2E691E520bbd3499f409bb9602DBA94184672",value=1,chain_id=1)manager_rpc=EthRPC(TEST_URL,pool_size=2)awaitmanager_rpc.start_pool()gm=GasManager(manager_rpc)asyncwithgm.informed_manager()asim:im.fill_transaction(tx)asyncwithNonceManager(manager_rpc)asnm:awaitnm.fill_transaction(tx)signed_tx=Account.sign_transaction(tx,acct.key).rawTransactiontx_result=awaitmanager_rpc.send_raw_transaction(signed_tx)print(tx_result)# Wait some time for transaction to be executed so we can get its receiptawaitasyncio.sleep(3)tx_receipt=awaitmanager_rpc.get_transaction_receipt(tx_result)# This means the next time gm.informed_manager() fills a tx, its price will update# An execution success will mean the maxPriorityFeePerGas value of tx will# be modified by im.success_multiplier, else it will be modified by im.fail_multiplierasyncwithgm.informed_manager()asim:iftx_receiptisnotNone:iftx_receipt.status==1:# Tell the gas manager that the transaction succeededim.execution_success()else:# Tell the gas manager that the transaction failedim.execution_failure()# Fill the next transaction with updated valuesim.fill_transaction(tx)print(tx)awaitmanager_rpc.close_pool()if__name__=="__main__":asyncio.run(test_management())More examples available in thedemofolder, including performance comparisons to Web3.py.Testing your programsTesting a program built with this library can be done with actual ethereum
nodes, though they may rate limit you or cost eth to run.
As such using testing programs such as Anvil from the Foundry suite of products
allows for faster and more productive testing.Install foundryInstructions available atthis link.Run anvilAnvil is a blockchain testing application included with foundry.The following command will run an instance of anvil representing
the blockchain's status at block numberEXAMPLE_BLOCK_NUMvia urlEXAMPLE_RPC_URL.anvilrpc-urlEXAMPLE_RPC_URL@EXAMPLE_BLOCK_NUMThis is helpful for ensuring consistency in tests, or to simply have a simulated RPC client, run:anvilAcknowledgementsSpecial thanks to@totlsotaas a more experienced blockchain developer than I, for giving me pointers when I needed them and
generally assisting in the development of this project.