mirror of
https://github.com/LORDBABUINO/stealth.git
synced 2026-06-11 06:43:31 -07:00
Feat: Backend commit
This commit is contained in:
-127
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
-185
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-231
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
package org.backend.stealth.service.dto;
|
||||
|
||||
/**
|
||||
* DTO for address response with instructions
|
||||
*/
|
||||
public record AddressResponseDTO(
|
||||
String address,
|
||||
String instructions
|
||||
) {
|
||||
}
|
||||
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
package org.backend.stealth.service.dto;
|
||||
|
||||
/**
|
||||
* DTO for block height
|
||||
*/
|
||||
public record BlockHeightDTO(
|
||||
long height
|
||||
) {
|
||||
}
|
||||
|
||||
-13
@@ -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
|
||||
) {
|
||||
}
|
||||
|
||||
-13
@@ -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
|
||||
) {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user