Skip to content
IRC-CodingIRC-Coding
Основы BlockchainКриптографияДецентрализованные сетиSmart ContractsКриптовалютыАлгоритмыОсновы

Основы Blockchain: криптография и смарт-контракты

Основы Blockchain с криптографией, децентрализованными сетями, Smart Contracts и криптовалютами. Распределенные реестры и консенсус.

S

schutzgeist

20 min read
Основы Blockchain: криптография и смарт-контракты

Основы блокчейна: криптография, децентрализованные сети, смарт-контракты и криптовалюты

Это полное введение в основы блокчейна с охватом криптографии, децентрализованных сетей, смарт-контрактов и криптовалют, дополненное практическими примерами.

Суть в двух словах

Блокчейн — это децентрализованная, неизменяемая технология баз данных, которая использует криптографические методы для обеспечения целостности и безопасности транзакций в распределённых сетях.

Компактное технологическое описание

Блокчейн — это распределённая технология реестра, которая организует данные в блоках и связывает их через криптографические хеш-функции, создавая неизменяемую цепь транзакций.

Ключевые компоненты:

Основы криптографии

  • Хеш-функции: SHA-256, Keccak-256 для проверки целостности
  • Цифровые подписи: ECDSA, Ed25519 для аутентификации
  • Инфраструктура открытого ключа: асимметричное шифрование
  • Деревья Меркла: эффективная проверка данных

Децентрализованные сети

  • Peer-to-Peer: прямая коммуникация без центрального узла
  • Алгоритмы консенсуса: Proof of Work, Proof of Stake
  • Распределённый реестр: репликация данных
  • Топология сети: mesh-сети

Смарт-контракты

  • Автоматизированные контракты: самоисполняемая логика
  • Ethereum Virtual Machine: окружение выполнения
  • Solidity: язык программирования для смарт-контрактов
  • Gas Fees: расчёт стоимости транзакций

Криптовалюты

  • Bitcoin: первая децентрализованная криптовалюта
  • Ethereum: платформа для смарт-контрактов
  • Altcoins: альтернативные криптовалюты
  • Stablecoins: токены со стабильной стоимостью

Ключевые моменты

  • Блокчейн: децентрализованная, неизменяемая технология баз данных
  • Криптография: хеш-функции, цифровые подписи, открытый ключ
  • Децентрализованные сети: P2P, алгоритмы консенсуса, распределённый реестр
  • Смарт-контракты: самоисполняемые контракты, EVM, Solidity
  • Криптовалюты: Bitcoin, Ethereum, Altcoins, Stablecoins
  • Майнинг: Proof of Work, вознаграждения за блоки, корректировка сложности
  • Кошельки: приватные ключи, открытые ключи, генерация адресов
  • Консенсус: устойчивость к византийским отказам, консенсус в сети
  • Практическое значение: современные децентрализованные технологии и криптография

Основные компоненты

  1. Распределённый реестр: децентрализованное хранение данных
  2. Криптография: основы безопасности
  3. Алгоритмы консенсуса: согласие в сети
  4. Смарт-контракты: автоматизированные контракты
  5. Майнинг/валидация: создание блоков
  6. Кошельки: управление ключами
  7. Транзакции: передача данных
  8. Сетевой слой: протоколы коммуникации

Практические примеры

1. Реализация блокчейна на JavaScript

// Block structure
class Block {
    constructor(index, timestamp, data, previousHash = '') {
        this.index = index;
        this.timestamp = timestamp;
        this.data = data;
        this.previousHash = previousHash;
        this.hash = this.calculateHash();
        this.nonce = 0;
    }
    
    calculateHash() {
        return SHA256(
            this.index +
            this.previousHash +
            this.timestamp +
            JSON.stringify(this.data) +
            this.nonce
        ).toString();
    }
    
    mineBlock(difficulty) {
        const target = Array(difficulty + 1).join("0");
        
        while (this.hash.substring(0, difficulty) !== target) {
            this.nonce++;
            this.hash = this.calculateHash();
        }
        
        console.log(`Block mined: ${this.hash}`);
    }
}

// Blockchain structure
class Blockchain {
    constructor() {
        this.chain = [this.createGenesisBlock()];
        this.difficulty = 2;
        this.pendingTransactions = [];
        this.miningReward = 100;
    }
    
    createGenesisBlock() {
        return new Block(0, Date.now(), "Genesis Block", "0");
    }
    
    getLatestBlock() {
        return this.chain[this.chain.length - 1];
    }
    
    addBlock(newBlock) {
        newBlock.previousHash = this.getLatestBlock().hash;
        newBlock.mineBlock(this.difficulty);
        this.chain.push(newBlock);
    }
    
    isChainValid() {
        for (let i = 1; i < this.chain.length; i++) {
            const currentBlock = this.chain[i];
            const previousBlock = this.chain[i - 1];
            
            if (currentBlock.hash !== currentBlock.calculateHash()) {
                return false;
            }
            
            if (currentBlock.previousHash !== previousBlock.hash) {
                return false;
            }
        }
        
        return true;
    }
    
    createTransaction(transaction) {
        this.pendingTransactions.push(transaction);
    }
    
    minePendingTransactions(miningRewardAddress) {
        const rewardTx = {
            from: null,
            to: miningRewardAddress,
            amount: this.miningReward
        };
        
        const block = new Block(
            this.chain.length,
            Date.now(),
            this.pendingTransactions,
            this.getLatestBlock().hash
        );
        
        block.mineBlock(this.difficulty);
        
        console.log('Block successfully mined!');
        this.chain.push(block);
        
        this.pendingTransactions = [rewardTx];
    }
    
    getBalance(address) {
        let balance = 0;
        
        for (const block of this.chain) {
            for (const trans of block.data) {
                if (trans.from === address) {
                    balance -= trans.amount;
                }
                
                if (trans.to === address) {
                    balance += trans.amount;
                }
            }
        }
        
        return balance;
    }
}

// SHA256 implementation
function SHA256(msg) {
    // Convert string to bytes
    const msgBuffer = new TextEncoder().encode(msg);
    
    // Hash the message
    return crypto.subtle.digest('SHA-256', msgBuffer);
}

// Transaction structure
class Transaction {
    constructor(fromAddress, toAddress, amount) {
        this.fromAddress = fromAddress;
        this.toAddress = toAddress;
        this.amount = amount;
        this.timestamp = Date.now();
    }
    
    calculateHash() {
        return SHA256(this.fromAddress + this.toAddress + this.amount + this.timestamp);
    }
    
    signTransaction(signingKey) {
        if (signingKey.getPublic('hex') !== this.fromAddress) {
            throw new Error('You cannot sign transactions for other wallets!');
        }
        
        const hashTx = this.calculateHash();
        const sig = signingKey.sign(hashTx, 'base64');
        
        this.signature = sig;
    }
    
    isValid() {
        if (this.fromAddress === null) return true;
        
        if (!this.signature || this.signature.length === 0) {
            throw new Error('No signature in this transaction');
        }
        
        const publicKey = ec.keyFromPublic(this.fromAddress, 'hex');
        const hashTx = this.calculateHash();
        
        return publicKey.verify(hashTx, this.signature);
    }
}

// Wallet implementation
class Wallet {
    constructor() {
        const keyPair = ec.genKeyPair();
        this.privateKey = keyPair.getPrivate('hex');
        this.publicKey = keyPair.getPublic('hex');
    }
    
    getPublicKey() {
        return this.publicKey;
    }
    
    getPrivateKey() {
        return this.privateKey;
    }
    
    getAddress() {
        const hash = SHA256(this.publicKey);
        return hash.toString().substring(0, 40);
    }
    
    sign(data) {
        const key = ec.keyFromPrivate(this.privateKey, 'hex');
        const hash = SHA256(data);
        return key.sign(hash);
    }
    
    verify(data, signature) {
        const key = ec.keyFromPublic(this.publicKey, 'hex');
        const hash = SHA256(data);
        return key.verify(hash, signature);
    }
}

// Usage example
const myCoin = new Blockchain();
const walletA = new Wallet();
const walletB = new Wallet();

console.log('Starting the miner...');
myCoin.minePendingTransactions(walletA.getAddress());

console.log(`Balance of walletA is ${myCoin.getBalance(walletA.getAddress())}`);

// Create transactions
const tx1 = new Transaction(walletA.getAddress(), walletB.getAddress(), 100);
tx1.signTransaction(walletA);
myCoin.createTransaction(tx1);

console.log('Starting the miner again...');
myCoin.minePendingTransactions(walletA.getAddress());

console.log(`Balance of walletA is ${myCoin.getBalance(walletA.getAddress())}`);
console.log(`Balance of walletB is ${myCoin.getBalance(walletB.getAddress())}`);

// Verify chain integrity
console.log(`Is chain valid? ${myCoin.isChainValid()}`);

2. Smart Contract с Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Simple Token Contract
contract SimpleToken {
    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 public totalSupply;
    
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;
    
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    
    constructor(string memory _name, string memory _symbol, uint256 _totalSupply) {
        name = _name;
        symbol = _symbol;
        decimals = 18;
        totalSupply = _totalSupply * 10**decimals;
        balanceOf[msg.sender] = totalSupply;
        emit Transfer(address(0), msg.sender, totalSupply);
    }
    
    function transfer(address _to, uint256 _value) public returns (bool success) {
        require(_to != address(0), "Invalid address");
        require(balanceOf[msg.sender] >= _value, "Insufficient balance");
        require(balanceOf[_to] + _value >= balanceOf[_to], "Overflow check");
        
        balanceOf[msg.sender] -= _value;
        balanceOf[_to] += _value;
        
        emit Transfer(msg.sender, _to, _value);
        return true;
    }
    
    function approve(address _spender, uint256 _value) public returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }
    
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        require(_to != address(0), "Invalid address");
        require(balanceOf[_from] >= _value, "Insufficient balance");
        require(allowance[_from][msg.sender] >= _value, "Insufficient allowance");
        require(balanceOf[_to] + _value >= balanceOf[_to], "Overflow check");
        
        balanceOf[_from] -= _value;
        balanceOf[_to] += _value;
        allowance[_from][msg.sender] -= _value;
        
        emit Transfer(_from, _to, _value);
        return true;
    }
    
    function mint(address _to, uint256 _value) public returns (bool success) {
        require(_to != address(0), "Invalid address");
        require(totalSupply + _value >= totalSupply, "Overflow check");
        
        totalSupply += _value;
        balanceOf[_to] += _value;
        
        emit Transfer(address(0), _to, _value);
        return true;
    }
    
    function burn(uint256 _value) public returns (bool success) {
        require(balanceOf[msg.sender] >= _value, "Insufficient balance");
        require(totalSupply >= _value, "Total supply check");
        
        balanceOf[msg.sender] -= _value;
        totalSupply -= _value;
        
        emit Transfer(msg.sender, address(0), _value);
        return true;
    }
}

// Voting Contract
contract Voting {
    struct Candidate {
        string name;
        uint256 voteCount;
    }
    
    struct Voter {
        bool hasVoted;
        uint256 votedCandidateId;
        uint256 weight;
    }
    
    address public owner;
    string public electionName;
    uint256 public votingDeadline;
    bool public electionEnded;
    
    mapping(address => Voter) public voters;
    Candidate[] public candidates;
    
    event VoteCast(address voter, uint256 candidateId);
    event ElectionEnded(string electionName);
    
    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner can call this function");
        _;
    }
    
    modifier votingOpen() {
        require(!electionEnded, "Election has ended");
        require(block.timestamp < votingDeadline, "Voting deadline passed");
        _;
    }
    
    constructor(string memory _electionName, uint256 _votingDuration) {
        owner = msg.sender;
        electionName = _electionName;
        votingDeadline = block.timestamp + _votingDuration;
        electionEnded = false;
    }
    
    function addCandidate(string memory _name) public onlyOwner {
        candidates.push(Candidate({
            name: _name,
            voteCount: 0
        }));
    }
    
    function giveRightToVote(address _voter) public onlyOwner {
        voters[_voter].weight = 1;
    }
    
    function vote(uint256 _candidateId) public votingOpen {
        require(voters[msg.sender].weight > 0, "No voting rights");
        require(!voters[msg.sender].hasVoted, "Already voted");
        require(_candidateId < candidates.length, "Invalid candidate");
        
        voters[msg.sender].hasVoted = true;
        voters[msg.sender].votedCandidateId = _candidateId;
        
        candidates[_candidateId].voteCount += voters[msg.sender].weight;
        
        emit VoteCast(msg.sender, _candidateId);
    }
    
    function endElection() public onlyOwner {
        require(!electionEnded, "Election already ended");
        electionEnded = true;
        emit ElectionEnded(electionName);
    }
    
    function getWinner() public view returns (string memory winnerName, uint256 winnerVotes) {
        require(electionEnded, "Election not ended yet");
        
        uint256 maxVotes = 0;
        uint256 winnerIndex = 0;
        
        for (uint256 i = 0; i < candidates.length; i++) {
            if (candidates[i].voteCount > maxVotes) {
                maxVotes = candidates[i].voteCount;
                winnerIndex = i;
            }
        }
        
        return (candidates[winnerIndex].name, maxVotes);
    }
    
    function getCandidateCount() public view returns (uint256) {
        return candidates.length;
    }
    
    function getCandidate(uint256 _index) public view returns (string memory, uint256) {
        require(_index < candidates.length, "Invalid candidate index");
        return (candidates[_index].name, candidates[_index].voteCount);
    }
}

// Escrow Contract
contract Escrow {
    enum State { AWAITING_PAYMENT, AWAITING_DELIVERY, COMPLETED, REFUNDED }
    
    address public buyer;
    address public seller;
    address public arbiter;
    
    uint256 public amount;
    uint256 public fee;
    
    State public currentState;
    
    modifier inState(State _state) {
        require(currentState == _state, "Invalid state for this operation");
        _;
    }
    
    modifier onlyBuyer() {
        require(msg.sender == buyer, "Only buyer can call this function");
        _;
    }
    
    modifier onlySeller() {
        require(msg.sender == seller, "Only seller can call this function");
        _;
    }
    
    modifier onlyArbiter() {
        require(msg.sender == arbiter, "Only arbiter can call this function");
        _;
    }
    
    event PaymentReceived(address from, uint256 amount);
    event DeliveryConfirmed();
    escrowCompleted(uint256 amount);
    escrowRefunded(uint256 amount);
    
    constructor(address _seller, address _arbiter, uint256 _fee) {
        buyer = msg.sender;
        seller = _seller;
        arbiter = _arbiter;
        fee = _fee;
        currentState = State.AWAITING_PAYMENT;
    }
    
    function deposit() public payable onlyBuyer inState(State.AWAITING_PAYMENT) {
        require(msg.value == amount, "Incorrect amount");
        currentState = State.AWAITING_DELIVERY;
        emit PaymentReceived(msg.sender, msg.value);
    }
    
    function confirmDelivery() public onlyBuyer inState(State.AWAITING_DELIVERY) {
        currentState = State.COMPLETED;
        
        uint256 sellerAmount = amount - fee;
        payable(seller).transfer(sellerAmount);
        payable(arbiter).transfer(fee);
        
        emit DeliveryConfirmed();
        emit escrowCompleted(amount);
    }
    
    function refundBuyer() public onlyArbiter inState(State.AWAITING_DELIVERY) {
        currentState = State.REFUNDED;
        payable(buyer).transfer(amount);
        emit escrowRefunded(amount);
    }
    
    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
    
    function getState() public view returns (string memory) {
        if (currentState == State.AWAITING_PAYMENT) return "AWAITING_PAYMENT";
        if (currentState == State.AWAITING_DELIVERY) return "AWAITING_DELIVERY";
        if (currentState == State.COMPLETED) return "COMPLETED";
        if (currentState == State.REFUNDED) return "REFUNDED";
        return "UNKNOWN";
    }
}

// Decentralized Autonomous Organization (DAO)
contract DAO {
    struct Proposal {
        string description;
        uint256 amount;
        address recipient;
        uint256 votesFor;
        uint256 votesAgainst;
        uint256 deadline;
        bool executed;
        mapping(address => bool) hasVoted;
    }
    
    address public owner;
    uint256 public votingPeriod;
    uint256 public quorum;
    
    mapping(uint256 => Proposal) public proposals;
    mapping(address => uint256) public shares;
    uint256 public totalShares;
    
    uint256 public proposalCount;
    
    event ProposalCreated(uint256 proposalId, string description, uint256 amount);
    event VoteCast(address voter, uint256 proposalId, bool inFavor);
    event ProposalExecuted(uint256 proposalId);
    
    modifier onlyShareholder() {
        require(shares[msg.sender] > 0, "Only shareholders can vote");
        _;
    }
    
    constructor(uint256 _votingPeriod, uint256 _quorum) {
        owner = msg.sender;
        votingPeriod = _votingPeriod;
        quorum = _quorum;
    }
    
    function addShareholder(address _shareholder, uint256 _shares) public {
        require(msg.sender == owner, "Only owner can add shareholders");
        require(_shares > 0, "Shares must be greater than 0");
        
        if (shares[_shareholder] == 0) {
            totalShares += _shares;
        } else {
            totalShares += _shares - shares[_shareholder];
        }
        
        shares[_shareholder] = _shares;
    }
    
    function createProposal(string memory _description, uint256 _amount, address _recipient) public onlyShareholder {
        proposalCount++;
        
        proposals[proposalCount] = Proposal({
            description: _description,
            amount: _amount,
            recipient: _recipient,
            votesFor: 0,
            votesAgainst: 0,
            deadline: block.timestamp + votingPeriod,
            executed: false
        });
        
        emit ProposalCreated(proposalCount, _description, _amount);
    }
    
    function vote(uint256 _proposalId, bool _inFavor) public onlyShareholder {
        Proposal storage proposal = proposals[_proposalId];
        
        require(block.timestamp < proposal.deadline, "Voting period ended");
        require(!proposal.hasVoted[msg.sender], "Already voted");
        require(!proposal.executed, "Proposal already executed");
        
        proposal.hasVoted[msg.sender] = true;
        
        if (_inFavor) {
            proposal.votesFor += shares[msg.sender];
        } else {
            proposal.votesAgainst += shares[msg.sender];
        }
        
        emit VoteCast(msg.sender, _proposalId, _inFavor);
    }
    
    function executeProposal(uint256 _proposalId) public {
        Proposal storage proposal = proposals[_proposalId];
        
        require(block.timestamp >= proposal.deadline, "Voting period not ended");
        require(!proposal.executed, "Proposal already executed");
        
        uint256 totalVotes = proposal.votesFor + proposal.votesAgainst;
        require(totalVotes >= quorum, "Quorum not reached");
        require(proposal.votesFor > proposal.votesAgainst, "Proposal not approved");
        
        proposal.executed = true;
        
        if (address(this).balance >= proposal.amount) {
            payable(proposal.recipient).transfer(proposal.amount);
        }
        
        emit ProposalExecuted(_proposalId);
    }
    
    function deposit() public payable {
        // Allow anyone to deposit funds to the DAO
    }
    
    function getProposal(uint256 _proposalId) public view returns (
        string memory description,
        uint256 amount,
        address recipient,
        uint256 votesFor,
        uint256 votesAgainst,
        uint256 deadline,
        bool executed
    ) {
        Proposal storage proposal = proposals[_proposalId];
        return (
            proposal.description,
            proposal.amount,
            proposal.recipient,
            proposal.votesFor,
            proposal.votesAgainst,
            proposal.deadline,
            proposal.executed
        );
    }
    
    function hasVoted(uint256 _proposalId, address _voter) public view returns (bool) {
        return proposals[_proposalId].hasVoted[_voter];
    }
    
    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
}

3. Python блокчейн с майнингом

import hashlib
import json
from time import time
from uuid import uuid4
from flask import Flask, jsonify, request
from urllib.parse import urlparse
import requests

class Blockchain:
    def __init__(self):
        self.chain = []
        self.current_transactions = []
        self.nodes = set()
        
        # Create the genesis block
        self.new_block(previous_hash='1', proof=100)
    
    def new_block(self, proof, previous_hash=None):
        """
        Create a new Block in the Blockchain
        :param proof: The proof given by the Proof of Work algorithm
        :param previous_hash: Hash of previous Block
        :return: New Block
        """
        
        block = {
            'index': len(self.chain) + 1,
            'timestamp': time(),
            'transactions': self.current_transactions,
            'proof': proof,
            'previous_hash': previous_hash or self.hash(self.chain[-1]),
        }
        
        # Reset the current list of transactions
        self.current_transactions = []
        
        self.chain.append(block)
        return block
    
    def new_transaction(self, sender, recipient, amount):
        """
        Creates a new transaction to go into the next mined Block
        :param sender: Address of the Sender
        :param recipient: Address of the Recipient
        :param amount: Amount
        :return: The index of the Block that will hold this transaction
        """
        
        self.current_transactions.append({
            'sender': sender,
            'recipient': recipient,
            'amount': amount,
        })
        
        return self.last_block['index'] + 1
    
    @property
    def last_block(self):
        return self.chain[-1]
    
    @staticmethod
    def hash(block):
        """
        Creates a SHA-256 hash of a Block
        :param block: Block
        :return: hash
        """
        
        # We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()
    
    def proof_of_work(self, last_proof):
        """
        Simple Proof of Work Algorithm:
         - Find a number 'p' such that hash(pp') contains leading 4 zeroes
         - Where p is the previous Proof, and p' is the new Proof
        :param last_proof: Previous Proof
        :return: proof
        """
        
        proof = 0
        while self.valid_proof(last_proof, proof) is False:
            proof += 1
        
        return proof
    
    @staticmethod
    def valid_proof(last_proof, proof):
        """
        Validates the Proof: Does hash(last_proof, proof) contain 4 leading zeroes?
        :param last_proof: Previous Proof
        :param proof: Current Proof
        :return: True if correct, False if not.
        """
        
        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()
        return guess_hash[:4] == "0000"
    
    def register_node(self, address):
        """
        Add a new node to the list of nodes
        :param address: Address of node. Eg. 'http://192.168.0.1:5000'
        :return: None
        """
        
        parsed_url = urlparse(address)
        if parsed_url.netloc:
            self.nodes.add(parsed_url.netloc)
        elif parsed_url.path:
            # Accepts an URL without scheme like '192.168.0.1:5000'.
            self.nodes.add(parsed_url.path)
        else:
            raise ValueError('Invalid URL')
    
    def valid_chain(self, chain):
        """
        Determine if a given blockchain is valid
        :param chain: A blockchain
        :return: True if valid, False if not
        """
        
        last_block = chain[0]
        current_index = 1
        
        while current_index < len(chain):
            block = chain[current_index]
            print(f'{last_block}')
            print(f'{block}')
            print("\n-----------\n")
            
            # Check that the hash of the block is correct
            if block['previous_hash'] != self.hash(last_block):
                return False
            
            # Check that the Proof of Work is correct
            if not self.valid_proof(last_block['proof'], block['proof']):
                return False
            
            last_block = block
            current_index += 1
        
        return True
    
    def resolve_conflicts(self):
        """
        This is our Consensus Algorithm, it resolves conflicts
        by replacing our chain with the longest one in the network.
        :return: True if our chain was replaced, False if not
        """
        
        neighbours = self.nodes
        new_chain = None
        
        # We're only looking for chains longer than ours
        max_length = len(self.chain)
        
        # Grab and verify the chains from all the nodes in our network
        for node in neighbours:
            response = requests.get(f'http://{node}/chain')
            
            if response.status_code == 200:
                length = response.json()['length']
                chain = response.json()['chain']
                
                # Check if the length is longer and the chain is valid
                if length > max_length and self.valid_chain(chain):
                    max_length = length
                    new_chain = chain
        
        # Replace our chain if we discovered a new, valid chain longer than ours
        if new_chain:
            self.chain = new_chain
            return True
        
        return False

# Flask application
app = Flask(__name__)
node_identifier = str(uuid4()).replace('-', '')

# Instantiate the Blockchain
blockchain = Blockchain()

@app.route('/mine', methods=['GET'])
def mine():
    # We run the proof of work algorithm to get the next proof...
    last_block = blockchain.last_block
    last_proof = last_block['proof']
    proof = blockchain.proof_of_work(last_proof)
    
    # We must receive a reward for finding the proof.
    blockchain.new_transaction(
        sender="0",
        recipient=node_identifier,
        amount=1,
    )
    
    # Forge the new Block by adding it to the chain
    previous_hash = blockchain.hash(last_block)
    block = blockchain.new_block(proof, previous_hash)
    
    response = {
        'message': "New Block Forged",
        'index': block['index'],
        'transactions': block['transactions'],
        'proof': block['proof'],
        'previous_hash': block['previous_hash'],
    }
    return jsonify(response), 200

@app.route('/transactions/new', methods=['POST'])
def new_transaction():
    values = request.get_json()
    
    # Check that the required fields are in the POST'ed data
    required = ['sender', 'recipient', 'amount']
    if not all(k in values for k in required):
        return "Missing values", 400
    
    # Create a new Transaction
    index = blockchain.new_transaction(values['sender'], values['recipient'], values['amount'])
    
    response = {'message': f'Transaction will be added to Block {index}'}
    return jsonify(response), 201

@app.route('/chain', methods=['GET'])
def full_chain():
    response = {
        'chain': blockchain.chain,
        'length': len(blockchain.chain),
    }
    return jsonify(response), 200

@app.route('/nodes/register', methods=['POST'])
def register_nodes():
    values = request.get_json()
    
    nodes = values.get('nodes')
    if nodes is None:
        return "Error: Please supply a valid list of nodes", 400
    
    for node in nodes:
        blockchain.register_node(node)
    
    response = {
        'message': 'New nodes have been added',
        'total_nodes': list(blockchain.nodes),
    }
    return jsonify(response), 201

@app.route('/nodes/resolve', methods=['GET'])
def consensus():
    replaced = blockchain.resolve_conflicts()
    
    if replaced:
        response = {
            'message': 'Our chain was replaced',
            'new_chain': blockchain.chain
        }
    else:
        response = {
            'message': 'Our chain is authoritative',
            'chain': blockchain.chain
        }
    
    return jsonify(response), 200

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

# Cryptographic utilities
import base64
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend

class CryptoUtils:
    @staticmethod
    def generate_key_pair():
        """Generate RSA key pair for digital signatures"""
        private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
            backend=default_backend()
        )
        
        public_key = private_key.public_key()
        
        return private_key, public_key
    
    @staticmethod
    def sign_message(private_key, message):
        """Sign a message with private key"""
        signature = private_key.sign(
            message.encode('utf-8'),
            padding.PSS(
                mgf=padding.MGF1(hashes.SHA256()),
                salt_length=padding.PSS.MAX_LENGTH
            ),
            hashes.SHA256()
        )
        
        return base64.b64encode(signature).decode('utf-8')
    
    @staticmethod
    def verify_signature(public_key, message, signature):
        """Verify a signature with public key"""
        try:
            public_key.verify(
                base64.b64decode(signature),
                message.encode('utf-8'),
                padding.PSS(
                    mgf=padding.MGF1(hashes.SHA256()),
                    salt_length=padding.PSS.MAX_LENGTH
                ),
                hashes.SHA256()
            )
            return True
        except:
            return False
    
    @staticmethod
    def serialize_public_key(public_key):
        """Serialize public key to PEM format"""
        return public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo
        ).decode('utf-8')
    
    @staticmethod
    def deserialize_public_key(pem_data):
        """Deserialize public key from PEM format"""
        return serialization.load_pem_public_key(
            pem_data.encode('utf-8'),
            backend=default_backend()
        )

# Wallet implementation
class Wallet:
    def __init__(self):
        self.private_key, self.public_key = CryptoUtils.generate_key_pair()
        self.address = self.generate_address()
    
    def generate_address(self):
        """Generate wallet address from public key"""
        public_key_pem = CryptoUtils.serialize_public_key(self.public_key)
        address = hashlib.sha256(public_key_pem.encode('utf-8')).hexdigest()
        return address[:40]  # Use first 40 characters as address
    
    def sign_transaction(self, transaction_data):
        """Sign transaction data"""
        transaction_string = json.dumps(transaction_data, sort_keys=True)
        return CryptoUtils.sign_message(self.private_key, transaction_string)
    
    def get_address(self):
        """Get wallet address"""
        return self.address
    
    def get_public_key(self):
        """Get public key in PEM format"""
        return CryptoUtils.serialize_public_key(self.public_key)

# Usage example
if __name__ == "__main__":
    # Create wallets
    alice_wallet = Wallet()
    bob_wallet = Wallet()
    
    print(f"Alice's address: {alice_wallet.get_address()}")
    print(f"Bob's address: {bob_wallet.get_address()}")
    
    # Create transaction
    transaction = {
        'sender': alice_wallet.get_address(),
        'recipient': bob_wallet.get_address(),
        'amount': 10,
        'timestamp': time()
    }
    
    # Sign transaction
    signature = alice_wallet.sign_transaction(transaction)
    print(f"Transaction signature: {signature}")
    
    # Verify signature
    alice_public_key = CryptoUtils.deserialize_public_key(alice_wallet.get_public_key())
    transaction_string = json.dumps(transaction, sort_keys=True)
    is_valid = CryptoUtils.verify_signature(alice_public_key, transaction_string, signature)
    print(f"Signature valid: {is_valid}")

Архитектура блокчейна

Модель слоёв

graph TD
    A[Application Layer] --> B[Smart Contracts]
    B --> C[Virtual Machine]
    C --> D[Consensus Layer]
    D --> E[Network Layer]
    E --> F[Data Layer]
    
    A1[DApps] --> A
    A2[Wallets] --> A
    A3[Exchanges] --> A
    
    B1[Ethereum] --> B
    B2[Solidity] --> B
    B3[Gas Fees] --> B
    
    C1[EVM] --> C
    C2[WASM] --> C
    C3[Bytecode] --> C
    
    D1[PoW] --> D
    D2[PoS] --> D
    D3[DPoS] --> D
    
    E1[P2P] --> E
    E2[Gossip] --> E
    E3[RPC] --> E
    
    F1[Blocks] --> F
    F2[Merkle Trees] --> F
    F3[Hash Chains] --> F

Алгоритмы консенсуса

Proof of Work (PoW)

СвойствоОписаниеЭнергопотребление
БезопасностьВысокая благодаря криптографическим доказательствамОчень высокое
ЦентрализацияТенденция к централизацииВысокая
МасштабируемостьОграничена временем блокаНизкая
ПрименениеBitcoin, Ethereum (ранее)Майнинг

Proof of Stake (PoS)

СвойствоОписаниеЭнергопотребление
БезопасностьЭкономические стимулыНизкое
ЦентрализацияМенее централизованаСреднее
МасштабируемостьЛучше, чем PoWВысокая
ПрименениеEthereum 2.0, CardanoStaking

Криптографические основы

Хеш-функции

# SHA-256 Implementation
import hashlib

def sha256_hash(data):
    """Calculate SHA-256 hash of data"""
    return hashlib.sha256(data.encode()).hexdigest()

# Merkle Tree Implementation
class MerkleTree:
    def __init__(self, transactions):
        self.transactions = transactions
        self.tree = self.build_tree()
    
    def build_tree(self):
        """Build Merkle tree from transactions"""
        tree = [transactions]
        
        while len(tree[-1]) > 1:
            current_level = tree[-1]
            next_level = []
            
            for i in range(0, len(current_level), 2):
                if i + 1 < len(current_level):
                    combined = current_level[i] + current_level[i + 1]
                    next_level.append(sha256_hash(combined))
                else:
                    next_level.append(current_level[i])
            
            tree.append(next_level)
        
        return tree
    
    def get_root(self):
        """Get Merkle root"""
        return self.tree[-1][0] if self.tree else None
    
    def verify_proof(self, transaction_hash, proof, root):
        """Verify Merkle proof"""
        current_hash = transaction_hash
        
        for proof_element in proof:
            if current_hash < proof_element:
                combined = current_hash + proof_element
            else:
                combined = proof_element + current_hash
            
            current_hash = sha256_hash(combined)
        
        return current_hash == root

Цифровые подписи

# ECDSA Implementation
from ecdsa import SigningKey, VerifyingKey, NIST256p, SECP256k1

class DigitalSignature:
    def __init__(self):
        self.private_key = SigningKey.generate(SECP256k1)
        self.public_key = self.private_key.get_verifying_key()
    
    def sign_message(self, message):
        """Sign message with private key"""
        return self.private_key.sign(message.encode())
    
    def verify_signature(self, message, signature):
        """Verify signature with public key"""
        try:
            self.public_key.verify(signature, message.encode())
            return True
        except:
            return False
    
    def get_public_key_hex(self):
        """Get public key in hex format"""
        return self.public_key.to_string().hex()
    
    @staticmethod
    def from_public_key_hex(public_key_hex):
        """Create verifier from public key hex"""
        public_key = VerifyingKey.from_string(bytes.fromhex(public_key_hex), curve=SECP256k1)
        return DigitalSignature.from_public_key(public_key)

Разработка смарт-контрактов

Ethereum Virtual Machine (EVM)

КомпонентОписаниеФункция
BytecodeСкомпилированный смарт-контрактВыполнение
GasСтоимость транзакцииОграничение ресурсов
StorageПостоянное хранилищеСохранение данных
MemoryВременное хранилищеВычисления
StackСтек исполненияОперации

Solidity Best Practices

// Secure contract example
pragma solidity ^0.8.0;

contract SecureContract {
    // Use latest Solidity version
    // Use explicit visibility specifiers
    // Implement proper access control
    // Handle reentrancy attacks
    // Use safe math operations
    
    address private owner;
    mapping(address => uint256) private balances;
    bool private locked;
    
    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner can call this function");
        _;
    }
    
    modifier noReentrant() {
        require(!locked, "No reentrancy");
        locked = true;
        _;
        locked = false;
    }
    
    modifier safeTransfer(address to, uint256 amount) {
        require(to != address(0), "Invalid address");
        require(amount > 0, "Amount must be greater than 0");
        require(balances[msg.sender] >= amount, "Insufficient balance");
        _;
    }
    
    constructor() {
        owner = msg.sender;
    }
    
    function transfer(address to, uint256 amount) 
        public 
        safeTransfer(to, amount) 
        noReentrant 
        returns (bool) 
    {
        balances[msg.sender] -= amount;
        balances[to] += amount;
        return true;
    }
    
    function getBalance(address account) public view returns (uint256) {
        return balances[account];
    }
}

Децентрализованные приложения (DApps)

Интеграция Web3.js

// Web3.js for blockchain interaction
const Web3 = require('web3');
const web3 = new Web3('https://mainnet.infura.io/v3/YOUR_PROJECT_ID');

// Contract ABI and address
const contractABI = [...]; // Contract ABI
const contractAddress = '0x...'; // Contract address

// Create contract instance
const contract = new web3.eth.Contract(contractABI, contractAddress);

// Get account balance
async function getBalance(address) {
    const balance = await web3.eth.getBalance(address);
    return web3.utils.fromWei(balance, 'ether');
}

// Send transaction
async function sendTransaction(from, to, amount, privateKey) {
    const nonce = await web3.eth.getTransactionCount(from);
    const gasPrice = await web3.eth.getGasPrice();
    
    const tx = {
        from: from,
        to: to,
        value: web3.utils.toWei(amount, 'ether'),
        gas: 21000,
        gasPrice: gasPrice,
        nonce: nonce
    };
    
    const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey);
    const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
    
    return receipt;
}

// Interact with smart contract
async function callContract(method, ...args) {
    const result = await contract.methods[method](...args).call();
    return result;
}

async function sendContractTransaction(method, from, privateKey, ...args) {
    const nonce = await web3.eth.getTransactionCount(from);
    const gasPrice = await web3.eth.getGasPrice();
    
    const tx = contract.methods[method](...args);
    const gas = await tx.estimateGas({ from: from });
    
    const txData = {
        from: from,
        to: contractAddress,
        gas: gas,
        gasPrice: gasPrice,
        nonce: nonce,
        data: tx.encodeABI()
    };
    
    const signedTx = await web3.eth.accounts.signTransaction(txData, privateKey);
    const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
    
    return receipt;
}

Типы криптовалют

Категории

ТипОписаниеПримерыUse Cases
Payment CoinsЦифровые деньгиBitcoin, LitecoinПлатежи
Platform CoinsПлатформы для смарт-контрактовEthereum, SolanaDApps
Privacy CoinsАнонимные транзакцииMonero, ZcashПриватность
StablecoinsТокены со стабильной ценойUSDC, DAIСтабильность
Utility TokensСлужебные токены платформыBNB, LINKСервисы
Security TokensРегулируемые ценные бумагиSTOsИнвестиции

Майнинг и валидация

Процесс майнинга

# Mining simulation
import hashlib
import json
import time

class Miner:
    def __init__(self, blockchain):
        self.blockchain = blockchain
        self.mining_reward = 10
    
    def mine_block(self, transactions):
        """Mine a new block"""
        last_block = self.blockchain.get_last_block()
        proof = self.proof_of_work(last_proof=last_block.proof)
        
        # Create reward transaction
        reward_tx = {
            'sender': '0',
            'recipient': 'miner_address',
            'amount': self.mining_reward
        }
        
        transactions.append(reward_tx)
        
        # Create new block
        new_block = {
            'index': last_block.index + 1,
            'timestamp': time.time(),
            'transactions': transactions,
            'proof': proof,
            'previous_hash': self.hash_block(last_block)
        }
        
        # Add block to blockchain
        self.blockchain.add_block(new_block)
        
        return new_block
    
    def proof_of_work(self, last_proof):
        """Proof of Work algorithm"""
        proof = 0
        difficulty = 4  # Number of leading zeros
        
        while not self.valid_proof(last_proof, proof, difficulty):
            proof += 1
        
        return proof
    
    @staticmethod
    def valid_proof(last_proof, proof, difficulty):
        """Validate proof"""
        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()
        return guess_hash[:difficulty] == '0' * difficulty
    
    @staticmethod
    def hash_block(block):
        """Hash a block"""
        block_string = json.dumps(block, sort_keys=True).encode()
        return hashlib.sha256(block_string).hexdigest()

Управление кошельками

Иерархические детерминированные кошельки

# HD Wallet implementation
import hmac
import hashlib
from bip_utils import Bip39MnemonicValidator, Bip39SeedGenerator, Bip44, Bip44Coins, Bip44Changes

class HDWallet:
    def __init__(self, mnemonic=None):
        if mnemonic is None:
            # Generate new mnemonic
            self.mnemonic = self.generate_mnemonic()
        else:
            # Validate existing mnemonic
            if not Bip39MnemonicValidator().Validate(mnemonic):
                raise ValueError("Invalid mnemonic phrase")
            self.mnemonic = mnemonic
        
        # Generate seed from mnemonic
        self.seed_bytes = Bip39SeedGenerator(self.mnemonic).Generate()
        
        # Create master key
        self.master_key = Bip44.FromSeed(self.seed_bytes, Bip44Coins.BITCOIN)
    
    def generate_mnemonic(self, wordlist='english', strength=128):
        """Generate new mnemonic phrase"""
        return Bip39MnemonicValidator().Generate(strength, wordlist)
    
    def get_address(self, account=0, change=0, address_index=0):
        """Generate address from HD path"""
        # Derive key from HD path: m/44'/0'/0'/0/0
        bip44_obj = self.master_key.Purpose().Coin().Account(account).Change(change).AddressIndex(address_index)
        return bip44_obj.Address()
    
    def get_private_key(self, account=0, change=0, address_index=0):
        """Get private key from HD path"""
        bip44_obj = self.master_key.Purpose().Coin().Account(account).Change(change).AddressIndex(address_index)
        return bip44_obj.PrivateKey().Raw().ToHex()
    
    def get_public_key(self, account=0, change=0, address_index=0):
        """Get public key from HD path"""
        bip44_obj = self.master_key.Purpose().Coin().Account(account).Change(change).AddressIndex(address_index)
        return bip44_obj.PublicKey().RawCompressed().ToHex()
    
    def get_extended_public_key(self, account=0):
        """Get extended public key for account"""
        return self.master_key.Purpose().Coin().Account(account).Public()
    
    def get_extended_private_key(self, account=0):
        """Get extended private key for account"""
        return self.master_key.Purpose().Coin().Account(account).Private()

Достоинства и недостатки

Преимущества блокчейна

  • Децентрализация: отсутствие единого органа управления
  • Неизменяемость: данные невозможно изменить задним числом
  • Прозрачность: все транзакции открыты для просмотра
  • Безопасность: криптографическая защита
  • Эффективность: исключение посредников из процесса

Недостатки

  • Масштабируемость: ограниченная пропускная способность транзакций
  • Энергопотребление: высокие затраты энергии в PoW
  • Сложность: техническая сложность реализации
  • Регулирование: неопределённость в правовом статусе
  • Волатильность: резкие колебания цен

Часто задаваемые вопросы на экзаменах

  1. В чём разница между Proof of Work и Proof of Stake? PoW использует ресурсоёмкие вычисления для создания блоков, тогда как PoS полагается на экономические стимулы через блокировку монет.

  2. Объясните функцию смарт-контрактов! Смарт-контракты, это самоисполняющиеся соглашения, выполняемые на блокчейне, которые автоматически применяют условия договора через код.

  3. Как работует криптографическое хеширование в блокчейне? Каждый блок содержит хеш предыдущего блока, создавая неразрывную цепь. Любое изменение сделает все последующие хеши недействительными.

  4. Какова цель майнинга? Майнинг защищает сеть через Proof of Work, проверяет транзакции и создаёт новые блоки с вознаграждениями.

Основные источники

  1. https://bitcoin.org/
  2. https://ethereum.org/
  3. https://solidity.readthedocs.io/
  4. https://web3js.readthedocs.io/
Назад к блогу
Share:

Похожие статьи