Before we start, let’s briefly understand the basic concepts. I can roughly summarize them into the following points What is Web3.0 and what does it have to do with blockchain? (The article last time will come in handy)
Requirements: Develop a Python-based Web 3.0 image uploading system. This system will allow users to upload images and store them on a decentralized network, while recording transaction information on the blockchain. I originally wrote it for fun, but I thought about writing it into a user authentication file operation that integrates a full set of management, so that it “will eventually become the ultimate solution for image upload services.” But in practice, I found that it was not very practical, so I gave up. However, I have always been so obsessed with pictures.
Step Overview
- Environment Settings: Use Python to develop and install the necessary Python libraries.
- IPFS integration: Upload the image to IPFS and obtain the CID (Content Identifier) of the image.
- Blockchain Integration: Record IPFS CID on the blockchain.
- Web Interface: Use Flask to create a Web interface that allows users to upload images.
Detailed steps
1. Environment settings
Install the required Python libraries:
pip install flask web3 ipfshttpclient
2. IPFS integration
IPFS (InterPlanetary File System) is a peer-to-peer file storage protocol. We can use the ipfshttpclient library to interact with the IPFS network.
First, make sure you have an IPFS node installed and running. If IPFS has not been installed yet, you can find the installation guide at IPFS official website.
The following is a code example for uploading images to IPFS:
importipfshttpclient
def upload_to_ipfs(file_path):
client = ipfshttpclient.connect('/ip4/127.0.0.1/tcp/5001')
res = client.add(file_path)
return res['Hash']
3. Blockchain integration
Use the web3.py library to record the IPFS CID to the blockchain. We will use Ethereum as an example blockchain.
Here is a simple smart contract example for storing IPFS CID:
pragma solidity ^0.8.0;
contract IPFSStorage {
mapping(address => string[]) public userCIDs;
function storeCID(string memory cid) public {
userCIDs[msg.sender].push(cid);
}
function getCIDs() public view returns (string[] memory) {
return userCIDs[msg.sender];
}
}
After compiling and deploying the contract, use the following Python code to interact with the smart contract:
from web3 import Web3
# Connect to Ethereum node
w3 = Web3(Web3.HTTPProvider('http://localhost:8545'))
# Contract address and ABI (obtained after deploying the contract)
contract_address = 'YOUR_CONTRACT_ADDRESS'
contract_abi = 'YOUR_CONTRACT_ABI'
contract = w3.eth.contract(address=contract_address, abi=contract_abi)
def store_cid_on_blockchain(cid, account, private_key):
txn = contract.functions.storeCID(cid).buildTransaction({
'from': account,
'nonce': w3.eth.getTransactionCount(account),
'gas': 2000000,
'gasPrice': w3.toWei('50', 'gwei')
})
signed_txn = w3.eth.account.sign_transaction(txn, private_key=private_key)
txn_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction)
return txn_hash.hex()
4. Web interface
Use Flask to create a web interface to upload images.
from flask import Flask, request, jsonify
import os
app = Flask(__name__)
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return jsonify({'error': 'No file part'})
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'})
if file:
file_path = os.path.join('/path/to/save/uploads', file.filename)
file.save(file_path)
# Upload to IPFS
cid = upload_to_ipfs(file_path)
# Store to blockchain
account = 'YOUR_ETHEREUM_ACCOUNT'
private_key = 'YOUR_PRIVATE_KEY'
txn_hash = store_cid_on_blockchain(cid, account, private_key)
return jsonify({'cid': cid, 'transaction_hash': txn_hash})
if __name__ == '__main__':
app.run(debug=True)
After the upload is successful, a HASH value will be returned, which is the ID of the image on ipfs. Local gateway access: ipfs://QmVJGX3FJPZsAgGMtJZoTt14XBj8QKhPwaaP4UfCcvYaN2, ipfs://QmRF9mejyfq89vAJ5yfsBbmVY3RUcLqfSsVTAmAbS8U2xD External network gateway: https://ipfs.crossbell.io/ipfs/QmVJGX3FJPZsAgGMtJZoTt14XBj8QKhPwaaP4UfCcvYa N2 .
Smart Contract
We will use Solidity to write smart contracts, compile the contracts with the solc compiler, and deploy the contracts to the Ethereum network using the web3.py library.
1. Write smart contract code
First, create a Solidity file (such as IPFSStorage.sol) and write your smart contract code:
//IPFSStorage.sol
pragma solidity ^0.8.0;
contract IPFSStorage {
mapping(address => string[]) public userCIDs;
function storeCID(string memory cid) public {
userCIDs[msg.sender].push(cid);
}
function getCIDs() public view returns (string[] memory) {
return userCIDs[msg.sender];
}
}
2. Compile smart contract
To compile Solidity smart contracts, we can use the solc compiler. You can install the Solidity compiler with the following command:
npm install -g solc
Then, compile the smart contract using the following command:
solc --abi --bin IPFSStorage.sol -o build/
This will generate two files: IPFStorage.abi (the contract’s ABI) and IPFStorage.bin (the contract’s bytecode).
3. Deploy smart contract
Use the web3.py library to deploy the contract. Make sure you have an Ethereum node running (such as using Ganache local development environment).
First, install web3.py:
pip install web3
Then, write and run the following Python script to deploy the contract:
from web3 import Web3
# Connect to the Ethereum node (use Ganache local node as an example)
w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:7545'))
# Read the ABI and bytecode of the contract
with open('build/IPFSStorage.abi', 'r') as abi_file:
contract_abi = abi_file.read()
with open('build/IPFSStorage.bin', 'r') as bin_file:
contract_bytecode = bin_file.read()
#Set the deployment account and private key (use the account provided by Ganache)
deployer_account = '0xYourAccountAddress'
private_key = 'YourPrivateKey'
#Create contract object
IPFSStorage = w3.eth.contract(abi=contract_abi, bytecode=contract_bytecode)
# Build transaction
transaction = IPFSStorage.constructor().buildTransaction({
'from': deployer_account,
'nonce': w3.eth.getTransactionCount(deployer_account),
'gas': 2000000,
'gasPrice': w3.toWei('50', 'gwei')
})
# Sign transaction
signed_txn = w3.eth.account.sign_transaction(transaction, private_key=private_key)
# Send transaction and get transaction hash
txn_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction)
print(f'Transaction hash: {txn_hash.hex()}')
# Wait for transaction confirmation
txn_receipt = w3.eth.waitForTransactionReceipt(txn_hash)
print(f'Contract deployed at address: {txn_receipt.contractAddress}')
Summarize
The ABI and bytecode generated by compiling a smart contract are used to interact with the contract, and deploying the contract involves creating transactions, signing transactions, and sending transactions to the Ethereum network. After successful deployment, you can obtain the contract address through the transaction receipt and use this address to interact with the contract.