Блокчейн е разпределена база данни, която се споделя между възлите на компютърна мрежа. Като база данни, блокчейнът съхранява информация електронно в цифров формат. Блокчейните са най-известни с тяхната ключова роля в криптовалутните системи като Bitcoin за поддържане на сигурен и децентрализиран запис на транзакциите.
Smart Contracts са самоизпълняващи се договори, където условията на споразумението между купувач и продавач са директно записани в програмен код. Кодът и споразуменията съществуват в разпределена, децентрализирана блокчейн мрежа.
Solidity е обектно-ориентиран програмен език за писане на smart contracts. Той е разработен специално за Ethereum платформата и е основният език за разработка на smart contracts.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MyFirstContract {
// Декларация на променливи
uint public myNumber;
// Конструктор
constructor() {
myNumber = 0;
}
// Функция за промяна на стойността
function setNumber(uint _newNumber) public {
myNumber = _newNumber;
}
// Функция за четене на стойността
function getNumber() public view returns (uint) {
return myNumber;
}
}
// Булеви
bool isActive = true;
// Цели числа
uint256 maxAmount = 1000; // Без знак, 256 бита
int8 temperature = -10; // Със знак, 8 бита
uint8 small = 255; // 8 бита
uint16 medium = 65535; // 16 бита
// Адреси
address owner = msg.sender;
address payable recipient; // Може да получава ETH
// Изброявания
enum Status { Pending, Active, Closed }
Status current = Status.Pending;
// Fixed-point числа
fixed256x18 price = 3.14; // 256 бита с 18 десетични позиции
// Масиви
uint[] numbers; // Динамичен масив
uint[5] fixedNumbers; // Фиксиран масив
bytes32 hash; // Фиксиран bytes масив
bytes data; // Динамичен bytes масив
// Структури
struct Person {
string name;
uint age;
address wallet;
}
// Mapping (асоциативни масиви)
mapping(address => uint) public balances;
mapping(uint => mapping(address => bool)) public complexMapping;
uint a = 10;
uint b = 5;
uint sum = a + b; // Събиране
uint diff = a - b; // Изваждане
uint prod = a * b; // Умножение
uint quot = a / b; // Деление
uint rem = a % b; // Остатък
uint inc = a++; // Инкрементиране
uint dec = b--; // Декрементиране
bool isEqual = a == b; // Равенство
bool notEqual = a != b; // Неравенство
bool greater = a > b; // По-голямо
bool less = a < b; // По-малко
bool greaterEq = a >= b; // По-голямо или равно
bool lessEq = a <= b; // По-малко или равно
bool result1 = true && false; // Логическо И
bool result2 = true || false; // Логическо ИЛИ
bool result3 = !true; // Логическо НЕ
uint c = a & b; // Побитово И
uint d = a | b; // Побитово ИЛИ
uint e = a ^ b; // Побитово изключващо ИЛИ
uint f = ~a; // Побитово НЕ
uint g = a << 1; // Побитово изместване наляво
uint h = a >> 1; // Побитово изместване надясно
// Константи - стойността се определя по време на компилация
uint256 constant MAX_UINT = 2**256 - 1;
string constant VERSION = "1.0.0";
// Имутабилни променливи - стойността се определя в конструктора
address immutable owner;
uint256 immutable creationTime;
constructor() {
owner = msg.sender;
creationTime = block.timestamp;
}
address sender = msg.sender; // Адрес на изпращача
uint value = msg.value; // Изпратени ETH
bytes data = msg.data; // Данни на съобщението
uint timestamp = block.timestamp; // Timestamp на блока
uint blockNumber = block.number; // Номер на блока
address coinbase = block.coinbase; // Адрес на майнъра
uint difficulty = block.difficulty; // Трудност на блока
uint gasLimit = block.gaslimit; // Gas лимит на блока
contract VisibilityExample {
uint private privateVar; // Достъпна само в текущия contract
uint internal internalVar; // Достъпна в текущия contract и наследниците
uint public publicVar; // Достъпна отвсякъде, създава getter
// External не се прилага за променливи
}
contract FunctionExample {
// Public функция - достъпна отвсякъде
function publicFunction() public {
// код
}
// Private функция - достъпна само в текущия contract
function privateFunction() private {
// код
}
// Internal функция - достъпна в текущия contract и наследниците
function internalFunction() internal {
// код
}
// External функция - достъпна само отвън
function externalFunction() external {
// код
}
}
contract ModifierExample {
// View - не променя състоянието
function viewFunction() public view returns (uint) {
return someValue;
}
// Pure - не чете и не променя състоянието
function pureFunction(uint x) public pure returns (uint) {
return x * 2;
}
// Payable - може да получава ETH
function payableFunction() public payable {
// код
}
// Виртуална функция - може да бъде презаписана
function virtualFunction() public virtual {
// код
}
// Презаписана функция
function overriddenFunction() public override {
// код
}
}
contract ModifierPatterns {
address public owner;
bool public locked;
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
modifier noReentrant() {
require(!locked, "No reentrancy");
locked = true;
_;
locked = false;
}
// Използване на модификатори
function sensitiveFunction()
public
onlyOwner
noReentrant
{
// код
}
}
contract EventExample {
// Деклариране на event
event Transfer(
address indexed from,
address indexed to,
uint256 amount
);
function transfer(address to, uint256 amount) public {
// Емитиране на event
emit Transfer(msg.sender, to, amount);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Token {
string public name;
string public symbol;
uint8 public decimals;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
event Transfer(address indexed from, address indexed to, uint256 value);
constructor(string memory _name, string memory _symbol) {
name = _name;
symbol = _symbol;
decimals = 18;
totalSupply = 1000000 * (10 ** uint256(decimals));
balanceOf[msg.sender] = totalSupply;
}
function transfer(address to, uint256 value) public returns (bool success) {
require(balanceOf[msg.sender] >= value, "Insufficient balance");
balanceOf[msg.sender] -= value;
balanceOf[to] += value;
emit Transfer(msg.sender, to, value);
return true;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SecureContract {
mapping(address => uint) public balances;
bool private locked;
modifier noReentrant() {
require(!locked, "No reentrancy");
locked = true;
_;
locked = false;
}
function withdraw() public noReentrant {
uint balance = balances[msg.sender];
require(balance > 0, "No balance");
balances[msg.sender] = 0;
(bool success, ) = msg.sender.call{value: balance}("");
require(success, "Transfer failed");
}
}
Това въведение в блокчейн програмирането и Solidity покрива основните концепции и практики, необходими за започване на разработка на smart contracts. За да станете успешен блокчейн разработчик, е важно да:
# Инсталиране на Python пакети
pip install web3
pip install python-dotenv
pip install eth-account
# Инсталиране на Ganache за локална blockchain мрежа
npm install -g ganache-cli
my_blockchain_project/
├── contracts/
│ └── MyContract.sol
├── build/
│ └── contracts/
├── scripts/
│ └── deploy.py
│ └── interact.py
├── .env
└── requirements.txt
from web3 import Web3
from eth_account import Account
import json
import os
from dotenv import load_dotenv
# Зареждане на environment променливи
load_dotenv()
# Конфигурация
INFURA_URL = os.getenv("INFURA_URL") # или локален URL за тестване
PRIVATE_KEY = os.getenv("PRIVATE_KEY")
# Свързване към blockchain
w3 = Web3(Web3.HTTPProvider(INFURA_URL))
# Създаване на акаунт от private key
account = Account.from_key(PRIVATE_KEY)
def deploy_contract():
# Зареждане на компилирания contract
with open("build/contracts/MyContract.json") as f:
contract_json = json.load(f)
# Извличане на contract ABI и bytecode
contract_abi = contract_json['abi']
contract_bytecode = contract_json['bytecode']
# Създаване на contract обект
Contract = w3.eth.contract(abi=contract_abi, bytecode=contract_bytecode)
# Изграждане на транзакция
transaction = Contract.constructor().build_transaction({
'from': account.address,
'nonce': w3.eth.get_transaction_count(account.address),
'gas': 2000000,
'gasPrice': w3.eth.gas_price
})
# Подписване на транзакцията
signed_txn = w3.eth.account.sign_transaction(transaction, PRIVATE_KEY)
# Изпращане на транзакцията
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
# Чакане за потвърждение
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
return tx_receipt.contractAddress
if __name__ == "__main__":
contract_address = deploy_contract()
print(f"Contract deployed at: {contract_address}")
from web3 import Web3
from eth_account import Account
import json
import os
from dotenv import load_dotenv
load_dotenv()
# Конфигурация
INFURA_URL = os.getenv("INFURA_URL")
PRIVATE_KEY = os.getenv("PRIVATE_KEY")
CONTRACT_ADDRESS = os.getenv("CONTRACT_ADDRESS")
# Свързване към blockchain
w3 = Web3(Web3.HTTPProvider(INFURA_URL))
# Създаване на акаунт
account = Account.from_key(PRIVATE_KEY)
def load_contract():
# Зареждане на contract ABI
with open("build/contracts/MyContract.json") as f:
contract_json = json.load(f)
contract_abi = contract_json['abi']
# Създаване на contract обект
contract = w3.eth.contract(
address=CONTRACT_ADDRESS,
abi=contract_abi
)
return contract
def read_contract_data():
contract = load_contract()
# Извикване на view функция
result = contract.functions.getNumber().call()
return result
def send_transaction():
contract = load_contract()
# Изграждане на транзакция
transaction = contract.functions.setNumber(42).build_transaction({
'from': account.address,
'nonce': w3.eth.get_transaction_count(account.address),
'gas': 100000,
'gasPrice': w3.eth.gas_price
})
# Подписване и изпращане на транзакцията
signed_txn = w3.eth.account.sign_transaction(transaction, PRIVATE_KEY)
tx_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
# Чакане за потвърждение
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
return tx_receipt
def handle_event(event):
print(f"New event: {event}")
def listen_for_events():
contract = load_contract()
# Дефиниране на event filter
event_filter = contract.events.MyEvent.create_filter(fromBlock='latest')
# Безкраен цикъл за следене на събития
while True:
for event in event_filter.get_new_entries():
handle_event(event)
if __name__ == "__main__":
# Пример за използване
current_value = read_contract_data()
print(f"Current value: {current_value}")
# Изпращане на транзакция
tx_receipt = send_transaction()
print(f"Transaction successful: {tx_receipt.transactionHash.hex()}")
# .env file
INFURA_URL=https://mainnet.infura.io/v3/your-project-id
PRIVATE_KEY=your-private-key
CONTRACT_ADDRESS=deployed-contract-address
from web3.exceptions import ContractLogicError
def safe_contract_call():
try:
result = contract.functions.myFunction().call()
return result
except ContractLogicError as e:
print(f"Contract error: {e}")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
def estimate_gas_and_send():
# Оценка на gas
gas_estimate = contract.functions.myFunction().estimate_gas()
# Добавяне на buffer
gas_limit = int(gas_estimate * 1.2)
# Изграждане на транзакция с оптимизиран gas
transaction = contract.functions.myFunction().build_transaction({
'from': account.address,
'gas': gas_limit,
'gasPrice': w3.eth.gas_price,
'nonce': w3.eth.get_transaction_count(account.address)
})
import asyncio
from web3.auto import w3
async def async_contract_interaction():
async for event in contract.events.MyEvent.create_filter(fromBlock='latest').get_all_entries():
print(f"New event: {event}")
async def main():
await async_contract_interaction()
if __name__ == "__main__":
asyncio.run(main())
import pytest
from web3 import Web3
from eth_tester import EthereumTester
from web3.providers.eth_tester import EthereumTesterProvider
@pytest.fixture
def web3_test():
return Web3(EthereumTesterProvider(EthereumTester()))
@pytest.fixture
def contract(web3_test):
with open("build/contracts/MyContract.json") as f:
contract_json = json.load(f)
contract = web3_test.eth.contract(
abi=contract_json['abi'],
bytecode=contract_json['bytecode']
)
tx_hash = contract.constructor().transact()
tx_receipt = web3_test.eth.wait_for_transaction_receipt(tx_hash)
return web3_test.eth.contract(
address=tx_receipt.contractAddress,
abi=contract_json['abi']
)
def test_contract_function(contract, web3_test):
# Arrange
account = web3_test.eth.accounts[0]
# Act
tx_hash = contract.functions.setNumber(42).transact({'from': account})
web3_test.eth.wait_for_transaction_receipt(tx_hash)
# Assert
result = contract.functions.getNumber().call()
assert result == 42