import hashlib import datetime # ============== Estruturas de dados dos Blocos ============== class Data: ''' Classe base para os dados contidos em um bloco. ''' def __init__(self, amount, operation): self.amount = amount self.operation = operation def __str__(self): return f"{self.amount}{self.operation}" class GenesisData(Data): ''' Classe para dados do bloco Genese (primeiro bloco). ''' def __init__(self, acc_owner, amount): super().__init__(amount, operation="deposit") self.acc_owner = acc_owner self.creation_acc_date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") class TransactionData(Data): ''' Classe para dados de blocos de transação (deposito ou saque) ''' def __init__(self, amount, operation): super().__init__(amount, operation) class Block: ''' Define a estrutura de um bloco individual da cadeia. ''' def __init__(self, data, previousHash): self.data = data self.previousHash = previousHash self.hash = self.calculateBlockHash() def calculateBlockHash(self) -> str: ''' Calcula o hash usando SHA-256 do conteudo do bloco. Concatena previousHash e data. Retorna o hexdigest de 64 caracteres hexadecimais. ''' value = f"{self.previousHash}{self.data}" return hashlib.sha256(value.encode('utf-8')).hexdigest() # ============== Estruturas da Blockchain ============== class Blockchain: ''' Gerencia a cadeia de blocos. Possui a lista de blocos. Responsável por adicionar, validar e calcular o saldo. ''' def __init__(self): self.chain = [] def getBalance(self) -> int: ''' Calcula e retorna o saldo total da conta, somando todas as transações da cadeira. ''' if len(self.chain) == 0: return 0 balance = self.chain[0].data.amount # saldo inicial for i in range(1, len(self.chain)): data = self.chain[i].data if data.operation == "deposit": balance += data.amount elif data.operation == "withdraw": balance -= data.amount return balance def createGenesisBlock (self, acc_owner, amount) -> Block: ''' Cria o bloco gênesis (primeiro bloco da cadeia), o adiciona a cadeia e o retorna. ''' data = GenesisData(acc_owner, amount) genesis_block = Block(data, None) self.chain.append(genesis_block) return genesis_block def addBlock(self, amount, operation) -> Block: ''' Adiciona um novo bloco de transação à cadeia, fazendo a validação da cadeia e das regras de negócio. ''' if not self.isValid(): raise Exception("Blockchain inválida. Não é possível adicionar um novo bloco.") balance = self.getBalance() if operation == "withdraw" and amount > balance: raise Exception(f"Saque de {amount} maior que o saldo disponível ({balance}). Operação bloqueada.") if operation not in ("deposit", "withdraw"): raise Exception(f"Operação inválida: {operation}. Use 'deposit' ou 'withdraw'.") previous_block = self.chain[-1] data = TransactionData(amount, operation) new_block = Block(data, previous_block.hash) self.chain.append(new_block) return new_block def isValid(self) -> bool: ''' Valida a integridade da blockchain inteira, verificando o hash ''' genesis_block = self.chain[0] if genesis_block.hash != genesis_block.calculateBlockHash(): return False for i in range(1, len(self.chain)): curr = self.chain[i] prev = self.chain[i - 1] if curr.hash != curr.calculateBlockHash(): return False if curr.previousHash != prev.hash: return False return True