杰瑞科技汇

pyethereum怎么用Python实现智能合约?

Of course! Here's a comprehensive guide to using pyethereum, the original Python library for interacting with the Ethereum blockchain.

What is PyEthereum?

PyEthereum is one of the oldest and most foundational Python libraries for the Ethereum ecosystem. It was the original library used to create the Ethereum Genesis Block and was central to the early development of the network.

It provides low-level access to the core components of Ethereum, including:

  • Transactions: Creating, signing, and sending raw transactions.
  • Accounts: Managing private keys and addresses.
  • The Ethereum Virtual Machine (EVM): Executing smart contracts and opcodes.
  • The Blockchain: Reading and interacting with the state of the blockchain.

⚠️ Important Note: PyEthereum is considered a legacy library. While it's fantastic for learning the fundamentals of how Ethereum works under the hood, it is not recommended for new production applications. For modern development, you should use higher-level libraries like Web3.py or Web3.py.


Key Differences: PyEthereum vs. Modern Web3.py

Feature PyEthereum Web3.py (Modern)
Philosophy Low-level, "batteries-included" toolkit. High-level, user-friendly wrapper.
Abstraction Exposes raw Ethereum concepts (RLP, Keccak, raw transactions). Hides complexity (e.g., eth.accounts.send_transaction()).
Dependencies Can have complex, older dependencies. Uses standard, modern libraries (requests, eth-account, etc.).
Active Development Largely unmaintained. Actively developed and widely used.
Use Case Learning, research, building from scratch. Building dApps, DeFi protocols, production tools.

Installation

First, you need to install PyEthereum. It's best to do this in a virtual environment.

# Create and activate a virtual environment
python3 -m venv pyeth_env
source pyeth_env/bin/activate
# Install pyethereum
pip install pyethereum

Core Concepts and Examples

Let's dive into the core functionalities of PyEthereum.

Accounts and Keys

PyEthereum uses its own key format, which is different from the standard Account object in Web3.py. You typically work with privkey and address objects.

from ethereum import utils
# 1. Generate a new private key
# This generates a random 32-byte private key
privkey_bytes = utils.sha3(b'') # Using empty bytes for a random key
privkey = utils.decode_hex(privkey_bytes.hex())
# 2. Derive the public key from the private key
pubkey = privtopub(privkey)
# 3. Derive the Ethereum address from the public key
# The address is the last 20 bytes of the Keccak-256 hash of the public key
address = utils.checksum_encode(addr(pubkey))
print(f"Private Key: {privkey.hex()}")
print(f"Public Key:  {pubkey.hex()}")
print(f"Address:     {address}")

Creating and Signing a Raw Transaction

This is where PyEthereum really shows its low-level nature. You construct a transaction dictionary and then sign it.

from ethereum.transactions import Transaction
from ethereum import utils
# Assume you have a sender's private key and address
# For this example, let's use the one from the previous step
# NOTE: In a real app, NEVER hardcode private keys!
SENDER_PRIVKEY = privkey # From the previous example
SENDER_ADDRESS = address # From the previous example
# --- Transaction Details ---
# The recipient's address
RECIPIENT_ADDRESS = '0x742d35Cc6634C0532925a3b844Bc454e4438f44e' # Example address
# The amount to send in Wei (1 ETH = 10^18 Wei)
VALUE = 10 * 10**18
# The gas limit
GAS = 21000
# The gas price in Gwei (1 Gwei = 10^9 Wei)
GAS_PRICE = 20 * 10**9
# The nonce (the number of transactions sent from this address)
# You need to get this from the blockchain!
# For this example, we'll assume it's 0.
NONCE = 0
# --- Create the Transaction Object ---
# The transaction constructor takes: nonce, gasprice, startgas, to, value, data, v, r, s
# v, r, s are for the signature, which are initially 0.
tx = Transaction(
    nonce=NONCE,
    gasprice=GAS_PRICE,
    startgas=GAS,
    to=utils.decode_hex(RECIPIENT_ADDRESS[2:]), # Remove '0x'
    value=VALUE,
    data=b''
)
# --- Sign the Transaction ---
# The `sign` method modifies the transaction in-place, adding the v, r, s signature components.
tx.sign(SENDER_PRIVKEY)
# The transaction object now contains the signature
print(f"Signed Raw Transaction: {tx.hex()}")
# You can now send this raw transaction hex string to an Ethereum node.

Interacting with the EVM (Smart Contracts)

PyEthereum allows you to execute smart contract code directly. This is great for testing or understanding how contract calls work.

from ethereum import abi
from ethereum import utils
# --- Smart Contract ABI (Application Binary Interface) ---
# This defines how to encode and decode calls to the contract.
# This is a simplified ABI for a basic storage contract.
contract_abi = [
    {
        'name': 'get',
        'outputs': [{'name': 'ret_val', 'type': 'uint256'}],
        'inputs': [],
        'type': 'function',
        'constant': True
    },
    {
        'name': 'set',
        'outputs': [],
        'inputs': [{'name': 'x', 'type': 'uint256'}],
        'type': 'function',
        'constant': False
    }
]
# --- Contract Bytecode ---
# This is the compiled EVM bytecode of the contract.
# Example: A simple contract that stores a number.
contract_bytecode = "6060604052341561000f57600080fd5b6040516101238061001d6000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114610046575b600080fd5b341561005157600080fd5b61005960043561007d565b60405190815260200160405180910390f35b600080549050905600a165627a7a72305820f9d5e8d1a1c3e5e7e5a5c5d5e5f5a5b5c5d5e5f5a5b5c5d5e5f5a5b5c5d5e5f6027"
# --- Create a Contract Object ---
# This object knows how to encode/decode calls based on the ABI.
contract = abi.Contract(contract_abi, contract_bytecode)
# --- Encoding a Transaction ---
# Let's call the 'set' function with the value 42.
# 1. Encode the data for the 'set' function call
# The first 4 bytes are the function selector (keccak256('set(uint256)')[:4])
# The rest is the ABI-encoded argument (42).
data_to_send = contract.set.build_transaction([42])
print(f"Encoded 'set(42)' call data: {data_to_send.hex()}")
# --- Executing the Call ---
# To actually execute this, you would need to send it as part of a transaction
# to the contract's address on the blockchain. PyEthereum can help you
# simulate this if you provide the state.
# This is a simplified example. Real execution requires a full blockchain state.
# You would create a Transaction object with `data=data_to_send` and send it.

When to Use PyEthereum (and When Not To)

Use PyEthereum for:

  • Education: To deeply understand the mechanics of Ethereum transactions, signatures, and the EVM.
  • Legacy Projects: If you are maintaining an old application that was built with it.
  • Research: For projects that require fine-grained, low-level control over Ethereum data structures.
  • Building Tools: For creating custom tools that need to interact with Ethereum at a fundamental level (e.g., a custom RPC node, an analysis tool).

Do NOT Use PyEthereum for:

  • New DApps: Use Web3.py or ethers.js. They are more secure, easier to use, and actively maintained.
  • Production Systems: The lack of maintenance and potential for security vulnerabilities in old dependencies makes it unsuitable for production.
  • Simple Interactions: If you just want to send ETH or call a contract, Web3.py is far simpler and less error-prone.

Modern Alternative: Web3.py

For comparison, here is how you would perform the same tasks with Web3.py, the modern standard.

pip install web3 eth-account

Creating an Account (Web3.py)

from web3 import Web3
from eth_account import Account
# Generate a new account
account = Account.create()
print(f"Address: {account.address}")
print(f"Private Key: {account.key.hex()}")
# Or import from a private key
# privkey = "0x..."
# account = Account.from_key(privkey)

Sending a Transaction (Web3.py)

from web3 import Web3
# Connect to a node (e.g., Infura or your own Geth node)
w3 = Web3(Web3.HTTPProvider('https://mainnet.infura.io/v3/YOUR_INFURA_KEY'))
# Build and send a transaction
tx = {
    'nonce': w3.eth.get_transaction_count(account.address),
    'to': '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
    'value': w3.to_wei(0.01, 'ether'),
    'gas': 21000,
    'gasPrice': w3.eth.gas_price,
    'chainId': 1, # Mainnet
}
# Sign the transaction
signed_tx = w3.eth.account.sign_transaction(tx, account.key)
# Send it
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
print(f"Transaction sent! Hash: {w3.to_hex(tx_hash)}")

As you can see, Web3.py abstracts away the low-level details like RLP encoding and manual signing, making it much safer and more efficient for most use cases.

分享:
扫描分享到社交APP
上一篇
下一篇