Feat: Backend commit

This commit is contained in:
Miranda
2026-02-26 21:50:13 -03:00
committed by LORDBABUINO
parent 494838d643
commit ba99b72b40
8 changed files with 31 additions and 590 deletions
@@ -1,127 +0,0 @@
package org.backend.stealth.controller;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.backend.stealth.domain.repository.BitcoinRepository;
import org.backend.stealth.service.dto.*;
import org.bitcoindevkit.Balance;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
/**
* REST API para conexão com Bitcoin Testnet4
*/
@Path("/api/testnet4")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = "Bitcoin Testnet4", description = "Operações com blockchain Bitcoin testnet4")
public class Testnet4Resource {
@Inject
BitcoinRepository bitcoinRepository;
@GET
@Path("/status")
@Operation(summary = "Verificar status da conexão", description = "Verifica se está conectado na blockchain testnet4")
public Response getStatus() {
try {
boolean connected = bitcoinRepository.isConnected();
long height = connected ? bitcoinRepository.getHeight() : -1;
String status = connected ? "✅ Conectado" : "❌ Desconectado";
return Response.ok(new Testnet4StatusDTO(
connected,
status,
height,
"https://mempool.space/testnet4/api"
)).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(new ErrorDTO("Erro: " + e.getMessage()))
.build();
}
}
@GET
@Path("/height")
@Operation(summary = "Obter altura da blockchain", description = "Retorna o número atual de blocos")
public Response getHeight() {
try {
long height = bitcoinRepository.getHeight();
return Response.ok(new BlockHeightDTO(height)).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(new ErrorDTO("Erro: " + e.getMessage()))
.build();
}
}
@GET
@Path("/address")
@Operation(summary = "Gerar novo endereço", description = "Gera um novo endereço para receber testnet4 bitcoins")
public Response getNewAddress() {
try {
String address = bitcoinRepository.getNewAddress();
if (address == null) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(new ErrorDTO("Erro ao gerar endereço"))
.build();
}
return Response.ok(new AddressResponseDTO(
address,
"Use um faucet para receber testnet4 bitcoins: https://mempool.space/testnet4"
)).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(new ErrorDTO("Erro: " + e.getMessage()))
.build();
}
}
@GET
@Path("/balance")
@Operation(summary = "Verificar saldo", description = "Retorna o saldo da wallet")
public Response getBalance() {
try {
Balance balance = bitcoinRepository.getBalance();
if (balance == null) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(new ErrorDTO("Erro ao obter saldo"))
.build();
}
return Response.ok(new BalanceDTO(
balance.total(),
balance.confirmed(),
balance.immature(),
balance.trustedPending(),
balance.untrustedPending()
)).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(new ErrorDTO("Erro: " + e.getMessage()))
.build();
}
}
@POST
@Path("/sync")
@Operation(summary = "Sincronizar wallet", description = "Sincroniza a wallet com a blockchain")
public Response sync() {
try {
bitcoinRepository.syncWallet();
return Response.ok(new MessageDTO("✅ Wallet sincronizada com sucesso!")).build();
} catch (Exception e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(new ErrorDTO("Erro: " + e.getMessage()))
.build();
}
}
}
@@ -0,0 +1,31 @@
package org.backend.stealth.domain.entity;
public class Wallet {
private Integer id;
private String descriptor;
public Wallet() {}
public Wallet(Integer id, String descriptor) {
this.id = id;
this.descriptor = descriptor;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDescriptor() {
return descriptor;
}
public void setDescriptor(String descriptor) {
this.descriptor = descriptor;
}
}
@@ -1,189 +1,4 @@
package org.backend.stealth.domain.repository;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import org.bitcoindevkit.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Repository for Bitcoin blockchain connection (Testnet4)
*/
@ApplicationScoped
public class BitcoinRepository {
private static final Logger logger = LoggerFactory.getLogger(BitcoinRepository.class);
private Blockchain blockchain;
private Wallet wallet;
private final Network network = Network.TESTNET;
private final String esploraUrl = "https://mempool.space/testnet4/api";
@PostConstruct
public void init() {
logger.info("🚀 Iniciando conexão com Bitcoin Testnet4...");
connectBlockchain();
}
/**
* Connect to Bitcoin blockchain
*/
public void connectBlockchain() {
try {
logger.info("📡 Conectando em: {}", esploraUrl);
// Create Esplora config - using correct Kotlin UByte conversion
EsploraConfig esploraConfig = new EsploraConfig(
esploraUrl,
null,
kotlin.UByte.valueOf((byte) 5), // timeout 5 seconds
(long) 100,
null
);
// Create blockchain config using correct method
BlockchainConfig blockchainConfig = new BlockchainConfig.Esplora(esploraConfig);
// Create blockchain
blockchain = new Blockchain(blockchainConfig);
logger.info("✅ Blockchain conectado com sucesso!");
// Get height
long height = blockchain.height();
logger.info("📊 Altura da blockchain: {} blocos", height);
// Initialize wallet
createWallet();
} catch (Exception e) {
logger.error("❌ Erro ao conectar: {}", e.getMessage(), e);
}
}
/**
* Create a new wallet
*/
private void createWallet() {
try {
logger.info("🔑 Criando wallet...");
// Generate mnemonic
Mnemonic mnemonic = new Mnemonic(WordCount.WORDS12);
logger.warn("⚠️ GUARDE ESTAS PALAVRAS:");
logger.warn("📝 {}", mnemonic.asString());
// Create descriptor secret key
DescriptorSecretKey descriptorSecretKey = new DescriptorSecretKey(
network,
mnemonic,
null
);
// Create descriptors (BIP84)
String descStr = "wpkh(" + descriptorSecretKey.asString() + "/84'/1'/0'/0/*)";
String changeDescStr = "wpkh(" + descriptorSecretKey.asString() + "/84'/1'/0'/1/*)";
Descriptor descriptor = new Descriptor(descStr, network);
Descriptor changeDescriptor = new Descriptor(changeDescStr, network);
// Create database config
DatabaseConfig databaseConfig = DatabaseConfig.memory();
// Create wallet
wallet = new Wallet(descriptor, changeDescriptor, network, databaseConfig);
logger.info("✅ Wallet criada!");
// Sync and show address
syncWallet();
showAddress();
} catch (Exception e) {
logger.error("❌ Erro ao criar wallet: {}", e.getMessage(), e);
}
}
/**
* Sync wallet with blockchain
*/
public void syncWallet() {
try {
if (wallet != null && blockchain != null) {
logger.info("🔄 Sincronizando...");
wallet.sync(blockchain, null);
logger.info("✅ Sincronizado!");
Balance balance = wallet.balance();
logger.info("💵 Saldo: {} satoshis", balance.total());
}
} catch (Exception e) {
logger.error("❌ Erro ao sincronizar: {}", e.getMessage(), e);
}
}
/**
* Show a receiving address
*/
private void showAddress() {
try {
AddressInfo addressInfo = wallet.revealNextAddress(KeychainKind.EXTERNAL);
logger.info("💰 Endereço: {}", addressInfo.address().asString());
logger.info("📍 Para receber testnet coins: https://mempool.space/testnet4");
} catch (Exception e) {
logger.error("Erro ao gerar endereço: {}", e.getMessage(), e);
}
}
/**
* Get blockchain height
*/
public long getHeight() {
return blockchain != null ? blockchain.height() : -1;
}
/**
* Get new address
*/
public String getNewAddress() {
try {
if (wallet == null) return null;
AddressInfo addressInfo = wallet.revealNextAddress(KeychainKind.EXTERNAL);
return addressInfo.address().asString();
} catch (Exception e) {
logger.error("Erro: {}", e.getMessage());
return null;
}
}
/**
* Get balance
*/
public Balance getBalance() {
try {
if (wallet == null) return null;
syncWallet();
return wallet.balance();
} catch (Exception e) {
logger.error("Erro: {}", e.getMessage());
return null;
}
}
public boolean isConnected() {
return blockchain != null;
}
public Blockchain getBlockchain() {
return blockchain;
}
public Wallet getWallet() {
return wallet;
}
public Network getNetwork() {
return network;
}
}
@@ -1,231 +0,0 @@
package org.backend.stealth.service;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import org.bitcoindevkit.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Service for connecting to Bitcoin Testnet4 blockchain
* This is a simplified version that connects to testnet4
*/
@ApplicationScoped
public class Testnet4ConnectionService {
private static final Logger logger = LoggerFactory.getLogger(Testnet4ConnectionService.class);
private Blockchain blockchain;
private Wallet wallet;
private Network network = Network.TESTNET;
private String esploraUrl = "https://mempool.space/testnet4/api";
/**
* Initialize connection on startup
*/
@PostConstruct
public void init() {
logger.info("🚀 Iniciando conexão com Bitcoin Testnet4...");
connectToBlockchain();
}
/**
* Connect to Bitcoin testnet4 blockchain
*/
public boolean connectToBlockchain() {
try {
logger.info("📡 Configurando conexão Esplora: {}", esploraUrl);
// Create Esplora configuration
EsploraConfig esploraConfig = new EsploraConfig(
esploraUrl,
null, // proxy
(byte) 5, // timeout in seconds
(long) 100, // stop_gap
null // timeout for long requests
);
// Create blockchain config
BlockchainConfig blockchainConfig = BlockchainConfig.newEsploraConfig(esploraConfig);
// Initialize blockchain connection
blockchain = new Blockchain(blockchainConfig);
logger.info("✅ Blockchain conectado com sucesso!");
// Get blockchain info
long height = blockchain.getHeight();
logger.info("📊 Altura atual da blockchain: {} blocos", height);
// Initialize a simple wallet
initializeWallet();
return true;
} catch (Exception e) {
logger.error("❌ Erro ao conectar na blockchain: {}", e.getMessage(), e);
return false;
}
}
/**
* Initialize a simple wallet
*/
private void initializeWallet() {
try {
logger.info("🔑 Inicializando wallet...");
// Generate mnemonic
Mnemonic mnemonic = new Mnemonic(WordCount.WORDS12);
String mnemonicWords = mnemonic.asString();
logger.warn("⚠️ IMPORTANTE - Guarde essas palavras com segurança:");
logger.warn("📝 {}", mnemonicWords);
// Create descriptor secret key
DescriptorSecretKey descriptorSecretKey = new DescriptorSecretKey(
network,
mnemonic,
null // no password
);
// Create descriptors (BIP84 - native segwit)
String descriptorStr = "wpkh(" + descriptorSecretKey.asString() + "/84'/1'/0'/0/*)";
String changeDescriptorStr = "wpkh(" + descriptorSecretKey.asString() + "/84'/1'/0'/1/*)";
// Create descriptor objects
Descriptor descriptor = new Descriptor(descriptorStr, network);
Descriptor changeDescriptor = new Descriptor(changeDescriptorStr, network);
// Create database config
DatabaseConfig databaseConfig = new DatabaseConfig.Memory();
// Create wallet
wallet = new Wallet(
descriptor,
changeDescriptor,
network,
databaseConfig
);
logger.info("✅ Wallet criada com sucesso!");
// Sync wallet
syncWallet();
// Generate and show address
AddressInfo addressInfo = wallet.getAddress(new AddressIndex.New());
logger.info("💰 Endereço para receber: {}", addressInfo.getAddress());
logger.info("📍 Índice: {}", addressInfo.getIndex());
} catch (Exception e) {
logger.error("❌ Erro ao criar wallet: {}", e.getMessage(), e);
}
}
/**
* Synchronize wallet with blockchain
*/
public void syncWallet() {
try {
if (wallet == null || blockchain == null) {
logger.error("Wallet ou blockchain não inicializados");
return;
}
logger.info("🔄 Sincronizando wallet...");
wallet.sync(blockchain, null);
logger.info("✅ Sincronização completa!");
// Show balance
Balance balance = wallet.getBalance();
logger.info("💵 Saldo total: {} satoshis", balance.getTotal());
logger.info("💵 Saldo confirmado: {} satoshis", balance.getConfirmed());
} catch (Exception e) {
logger.error("❌ Erro ao sincronizar: {}", e.getMessage(), e);
}
}
/**
* Get blockchain height
*/
public long getBlockchainHeight() {
try {
if (blockchain == null) {
throw new IllegalStateException("Blockchain não conectado");
}
return blockchain.getHeight();
} catch (Exception e) {
logger.error("Erro ao obter altura: {}", e.getMessage());
return -1;
}
}
/**
* Get new receiving address
*/
public String getNewAddress() {
try {
if (wallet == null) {
throw new IllegalStateException("Wallet não inicializada");
}
AddressInfo addressInfo = wallet.getAddress(new AddressIndex.New());
return addressInfo.getAddress();
} catch (Exception e) {
logger.error("Erro ao gerar endereço: {}", e.getMessage());
return null;
}
}
/**
* Get wallet balance
*/
public Balance getBalance() {
try {
if (wallet == null) {
throw new IllegalStateException("Wallet não inicializada");
}
syncWallet();
return wallet.getBalance();
} catch (Exception e) {
logger.error("Erro ao obter saldo: {}", e.getMessage());
return null;
}
}
/**
* Check if connected
*/
public boolean isConnected() {
return blockchain != null;
}
/**
* Get blockchain instance
*/
public Blockchain getBlockchain() {
return blockchain;
}
/**
* Get wallet instance
*/
public Wallet getWallet() {
return wallet;
}
/**
* Get network
*/
public Network getNetwork() {
return network;
}
/**
* Get Esplora URL
*/
public String getEsploraUrl() {
return esploraUrl;
}
}
@@ -1,11 +0,0 @@
package org.backend.stealth.service.dto;
/**
* DTO for address response with instructions
*/
public record AddressResponseDTO(
String address,
String instructions
) {
}
@@ -1,10 +0,0 @@
package org.backend.stealth.service.dto;
/**
* DTO for block height
*/
public record BlockHeightDTO(
long height
) {
}
@@ -1,13 +0,0 @@
package org.backend.stealth.service.dto;
/**
* DTO for blockchain information
*/
public record BlockchainInfoDTO(
String network,
long height,
String latestBlockHash,
String esploraUrl
) {
}
@@ -1,13 +0,0 @@
package org.backend.stealth.service.dto;
/**
* DTO for testnet4 connection status
*/
public record Testnet4StatusDTO(
boolean connected,
String status,
long blockHeight,
String esploraUrl
) {
}