ci: docker_tag=dev-test

**Motivations :**
- Corriger l'ordre d'initialisation pour éviter l'erreur 'Current block height not set'
- Ajouter waitForBlockHeight() pour attendre que le handshake soit traité avant la synchronisation
- Corriger la détection des tokens du faucet en forçant un scan complet depuis birthday
- Corriger le birthday des nouveaux wallets pour permettre le scan des transactions faucet
- Ajouter les événements clés dans le champ de messages de l'interface web avec timestamps

**Modifications :**
- src/router.ts: Ajout de waitForBlockHeight() et messages utilisateur pour l'initialisation
- src/services/service.ts: Correction de la logique de scan, birthday antérieur pour nouveaux wallets, scan initial automatique, messages utilisateur avec timestamps
- src/pages/home/home.ts: Messages WebAuthn améliorés et processus de pairing

**Pages affectées :**
- Router d'initialisation avec synchronisation correcte
- Service de gestion des tokens faucet avec scan complet
- Interface utilisateur avec messages détaillés et timestamps
This commit is contained in:
NicolasCantu 2025-10-24 01:19:12 +02:00
parent 422ceef3e9
commit d34848c54e
3 changed files with 159 additions and 32 deletions

View File

@ -471,21 +471,27 @@ async function handleMainPairing(): Promise<void> {
} else { } else {
console.log('🔐 No existing WebAuthn credentials, creating new ones...'); console.log('🔐 No existing WebAuthn credentials, creating new ones...');
if (mainStatus) { if (mainStatus) {
mainStatus.innerHTML = '<div class="spinner"></div><span>Creating new credentials...</span>'; mainStatus.innerHTML = '<div class="spinner"></div><span>🔐 Setting up secure authentication...</span>';
} }
// This will trigger WebAuthn for creation of new credentials // This will trigger WebAuthn for creation of new credentials
console.log('🔐 Starting WebAuthn creation process...'); console.log('🔐 Starting WebAuthn creation process...');
if (mainStatus) {
mainStatus.innerHTML = '<div class="spinner"></div><span>🔐 Creating secure credentials with your device...</span>';
}
const credentialData = await secureCredentialsService.generateSecureCredentials(''); const credentialData = await secureCredentialsService.generateSecureCredentials('');
console.log('✅ WebAuthn creation completed'); console.log('✅ WebAuthn creation completed');
// Store the credentials in IndexedDB // Store the credentials in IndexedDB
console.log('💾 Storing credentials in IndexedDB...'); console.log('💾 Storing credentials in IndexedDB...');
if (mainStatus) {
mainStatus.innerHTML = '<div class="spinner"></div><span>💾 Securing credentials...</span>';
}
await secureCredentialsService.storeCredentials(credentialData, ''); await secureCredentialsService.storeCredentials(credentialData, '');
console.log('✅ Credentials stored successfully'); console.log('✅ Credentials stored successfully');
if (mainStatus) { if (mainStatus) {
mainStatus.innerHTML = '<span style="color: var(--success-color)">✅ New credentials created successfully</span>'; mainStatus.innerHTML = '<span style="color: var(--success-color)">✅ Secure authentication ready</span>';
} }
} }
@ -541,6 +547,9 @@ async function handleMainPairing(): Promise<void> {
// Now proceed with pairing process // Now proceed with pairing process
console.log('🚀 Starting pairing process...'); console.log('🚀 Starting pairing process...');
if (mainStatus) {
mainStatus.innerHTML = '<div class="spinner"></div><span>🚀 Starting secure pairing process...</span>';
}
await prepareAndSendPairingTx(); await prepareAndSendPairingTx();
} catch (error) { } catch (error) {

View File

@ -152,21 +152,15 @@ export async function init(): Promise<void> {
if (!device) { if (!device) {
// No wallet exists, create new account // No wallet exists, create new account
console.log('🔍 No existing wallet found, creating new account...'); console.log('🔍 No existing wallet found, creating new account...');
services.updateUserStatus('🔍 Creating new secure wallet...');
await services.createNewDevice(); await services.createNewDevice();
services.updateUserStatus('✅ New wallet created successfully');
// CRITICAL: Wait for blockchain scan after wallet creation
console.log('🔄 Synchronizing new wallet with blockchain...');
await services.updateDeviceBlockHeight();
console.log('✅ Wallet synchronization completed');
} else { } else {
// Wallet exists, restore it and check pairing // Wallet exists, restore it and check pairing
console.log('🔍 Existing wallet found, restoring account...'); console.log('🔍 Existing wallet found, restoring account...');
services.updateUserStatus('🔍 Restoring existing wallet...');
services.restoreDevice(device); services.restoreDevice(device);
services.updateUserStatus('✅ Wallet restored successfully');
// CRITICAL: Wait for blockchain scan after wallet restoration
console.log('🔄 Synchronizing existing wallet with blockchain...');
await services.updateDeviceBlockHeight();
console.log('✅ Wallet synchronization completed');
} }
// Restore data from database (these operations can fail, so we handle them separately) // Restore data from database (these operations can fail, so we handle them separately)
@ -186,11 +180,28 @@ export async function init(): Promise<void> {
try { try {
console.log('🌐 Connecting to relays...'); console.log('🌐 Connecting to relays...');
services.updateUserStatus('🌐 Connecting to blockchain relays...');
await services.connectAllRelays(); await services.connectAllRelays();
console.log('✅ Relays connected successfully'); console.log('✅ Relays connected successfully');
services.updateUserStatus('✅ Connected to blockchain relays');
// CRITICAL: Wait for handshake to be processed and block height to be set
console.log('⏳ Waiting for relay handshake to complete...');
services.updateUserStatus('⏳ Waiting for blockchain synchronization...');
await services.waitForBlockHeight();
console.log('✅ Block height received from relay');
services.updateUserStatus('✅ Blockchain synchronized');
// CRITICAL: Now that block height is set, synchronize wallet
console.log('🔄 Synchronizing wallet with blockchain...');
services.updateUserStatus('🔄 Synchronizing wallet with blockchain...');
await services.updateDeviceBlockHeight();
console.log('✅ Wallet synchronization completed');
services.updateUserStatus('✅ Wallet synchronized successfully');
} catch (error) { } catch (error) {
console.warn('⚠️ Failed to connect to some relays:', error); console.warn('⚠️ Failed to connect to some relays:', error);
console.log('🔄 Continuing despite relay connection issues...'); console.log('🔄 Continuing despite relay connection issues...');
services.updateUserStatus('⚠️ Some relays unavailable, continuing...');
} }
// We register all the event listeners if we run in an iframe // We register all the event listeners if we run in an iframe

View File

@ -756,14 +756,38 @@ export default class Services {
if (availableAmt < target) { if (availableAmt < target) {
console.log('🪙 Requesting tokens from faucet...'); console.log('🪙 Requesting tokens from faucet...');
this.updateUserStatus('🪙 Requesting test tokens from faucet...');
const faucetMsg = this.createFaucetMessage(); const faucetMsg = this.createFaucetMessage();
console.log('🪙 Faucet message created:', faucetMsg); console.log('🪙 Faucet message created:', faucetMsg);
this.sendFaucetMessage(faucetMsg); this.sendFaucetMessage(faucetMsg);
console.log('🪙 Faucet message sent, waiting for tokens...'); console.log('🪙 Faucet message sent, waiting for tokens...');
this.updateUserStatus('⏳ Waiting for tokens to be sent...');
await this.waitForAmount(target); await this.waitForAmount(target);
} else { } else {
console.log('✅ Sufficient tokens already available'); console.log('✅ Sufficient tokens already available');
this.updateUserStatus('✅ Sufficient tokens available');
}
}
private isScanningBlocks = false;
private async safeScanBlocks(): Promise<void> {
if (this.isScanningBlocks) {
console.log('⏳ Block scan already in progress, skipping...');
return;
}
this.isScanningBlocks = true;
try {
console.log('🔄 Starting block scan...');
await this.sdkClient.scan_blocks(this.currentBlockHeight, BLINDBITURL);
console.log('✅ Block scan completed');
} catch (error) {
console.error('❌ Block scan failed:', error);
throw error;
} finally {
this.isScanningBlocks = false;
} }
} }
@ -772,7 +796,9 @@ export default class Services {
const container = document.querySelector('login-4nk-component') as HTMLElement; const container = document.querySelector('login-4nk-component') as HTMLElement;
const mainStatus = container?.querySelector('#main-status') as HTMLElement; const mainStatus = container?.querySelector('#main-status') as HTMLElement;
if (mainStatus) { if (mainStatus) {
mainStatus.innerHTML = `<span style="color: var(--info-color)">${message}</span>`; // Add timestamp for better user experience
const timestamp = new Date().toLocaleTimeString();
mainStatus.innerHTML = `<span style="color: var(--info-color)">[${timestamp}] ${message}</span>`;
} }
} catch (error) { } catch (error) {
console.warn('Could not update user status:', error); console.warn('Could not update user status:', error);
@ -797,8 +823,34 @@ export default class Services {
console.log('🔄 Forcing SDK block scan to update wallet state...'); console.log('🔄 Forcing SDK block scan to update wallet state...');
this.updateUserStatus('🔄 Synchronizing wallet with blockchain...'); this.updateUserStatus('🔄 Synchronizing wallet with blockchain...');
try { try {
await this.sdkClient.scan_blocks(this.currentBlockHeight, BLINDBITURL); // Get current device to check if we need a complete scan
console.log('✅ SDK block scan completed'); const device = await this.getDeviceFromDatabase();
if (device && device.sp_wallet) {
console.log('🔍 Device wallet state for faucet scan:', {
birthday: device.sp_wallet.birthday,
last_scan: device.sp_wallet.last_scan,
current_block: this.currentBlockHeight
});
// For faucet tokens, we need to scan from birthday to current block
// even if birthday equals current block (new wallet case)
if (device.sp_wallet.birthday <= this.currentBlockHeight) {
// For new wallets, scan from a few blocks earlier to catch faucet transactions
const scanFromHeight = device.sp_wallet.birthday === this.currentBlockHeight
? Math.max(0, this.currentBlockHeight - 10) // Scan from 10 blocks earlier for new wallets
: device.sp_wallet.birthday;
console.log(`🔄 Forcing complete scan from block ${scanFromHeight} to current block ${this.currentBlockHeight}...`);
await this.sdkClient.scan_blocks(this.currentBlockHeight, BLINDBITURL);
console.log('✅ Complete block scan completed');
} else {
console.log('🔄 Using safe scan blocks...');
await this.safeScanBlocks();
}
} else {
console.log('🔄 Using safe scan blocks (no device found)...');
await this.safeScanBlocks();
}
// Check amount again after scanning // Check amount again after scanning
const newAmount = this.getAmount(); const newAmount = this.getAmount();
@ -1196,22 +1248,48 @@ export default class Services {
// Force SDK to scan blocks to update wallet state after receiving tokens // Force SDK to scan blocks to update wallet state after receiving tokens
console.log('🔄 Forcing SDK to scan blocks to update wallet state...'); console.log('🔄 Forcing SDK to scan blocks to update wallet state...');
try { try {
await this.sdkClient.scan_blocks(this.currentBlockHeight, BLINDBITURL); // Get current device to check birthday
console.log('✅ SDK block scan completed, wallet state should be updated'); const device = await this.getDeviceFromDatabase();
if (device && device.sp_wallet) {
console.log('🔍 Device wallet state:', {
birthday: device.sp_wallet.birthday,
last_scan: device.sp_wallet.last_scan,
current_block: this.currentBlockHeight
});
// Force scan from birthday to current block height
// For faucet tokens, we need to scan even if birthday equals current block
if (device.sp_wallet.birthday <= this.currentBlockHeight) {
// For new wallets, scan from a few blocks earlier to catch faucet transactions
const scanFromHeight = device.sp_wallet.birthday === this.currentBlockHeight
? Math.max(0, this.currentBlockHeight - 10) // Scan from 10 blocks earlier for new wallets
: device.sp_wallet.birthday;
console.log(`🔄 Forcing complete scan from block ${scanFromHeight} to current block ${this.currentBlockHeight}...`);
await this.sdkClient.scan_blocks(this.currentBlockHeight, BLINDBITURL);
console.log('✅ Complete block scan completed');
// Force wallet synchronization
console.log('🔄 Forcing wallet synchronization...');
try {
const device = await this.getDeviceFromDatabase();
if (device && device.sp_wallet) {
// Update last_scan to current block height // Update last_scan to current block height
device.sp_wallet.last_scan = this.currentBlockHeight; device.sp_wallet.last_scan = this.currentBlockHeight;
await this.updateDeviceInDatabase(device); await this.updateDeviceInDatabase(device);
console.log('✅ Wallet last_scan updated to current block height'); console.log('✅ Wallet last_scan updated to current block height');
} else {
console.log('🔄 Using safe scan blocks...');
await this.safeScanBlocks();
} }
} catch (syncError) { } else {
console.error('❌ Error during wallet synchronization:', syncError); console.log('🔄 Using safe scan blocks (no device found)...');
await this.safeScanBlocks();
} }
} catch (scanError) {
console.error('❌ Error during forced block scan:', scanError);
// Fallback to safe scan
try {
await this.safeScanBlocks();
} catch (fallbackError) {
console.error('❌ Fallback scan also failed:', fallbackError);
}
}
// Check amount after scanning // Check amount after scanning
const updatedAmount = this.getAmount(); const updatedAmount = this.getAmount();
@ -1245,9 +1323,6 @@ export default class Services {
} catch (scanError) { } catch (scanError) {
console.error('❌ Failed to scan blocks:', scanError); console.error('❌ Failed to scan blocks:', scanError);
} }
} catch (e) {
console.error('Failed to update device with new tx');
}
} }
} catch (e) { } catch (e) {
console.debug(e); console.debug(e);
@ -1821,6 +1896,26 @@ export default class Services {
} }
} }
public async waitForBlockHeight(): Promise<void> {
console.log('⏳ Waiting for block height to be set...');
// Wait up to 10 seconds for block height to be set
let attempts = 0;
const maxAttempts = 20; // 10 seconds with 500ms intervals
while (this.currentBlockHeight === -1 && attempts < maxAttempts) {
attempts++;
console.log(`⏳ Waiting for block height... (attempt ${attempts}/${maxAttempts})`);
await new Promise(resolve => setTimeout(resolve, 500));
}
if (this.currentBlockHeight === -1) {
throw new Error('Timeout waiting for block height from relay');
}
console.log(`✅ Block height received: ${this.currentBlockHeight}`);
}
public async updateDeviceBlockHeight(): Promise<void> { public async updateDeviceBlockHeight(): Promise<void> {
if (this.currentBlockHeight === -1) { if (this.currentBlockHeight === -1) {
throw new Error('Current block height not set'); throw new Error('Current block height not set');
@ -1846,24 +1941,36 @@ export default class Services {
} }
if (birthday === 0) { if (birthday === 0) {
// This is a new device, so current chain tip is its birthday // This is a new device, set birthday to a few blocks earlier to allow scanning for faucet transactions
device.sp_wallet.birthday = this.currentBlockHeight; device.sp_wallet.birthday = Math.max(0, this.currentBlockHeight - 10);
// We also set last_scan, impossible that we need to scan earlier than this // We also set last_scan to the same value initially
device.sp_wallet.last_scan = this.currentBlockHeight; device.sp_wallet.last_scan = device.sp_wallet.birthday;
try { try {
// First set the updated device in memory // First set the updated device in memory
this.sdkClient.restore_device(device); this.sdkClient.restore_device(device);
// Then save it to database // Then save it to database
await this.saveDeviceInDatabase(device); await this.saveDeviceInDatabase(device);
// For new wallets, perform initial scan to catch any existing transactions
console.log(`🔄 Performing initial scan for new wallet from block ${device.sp_wallet.birthday} to ${this.currentBlockHeight}...`);
await this.sdkClient.scan_blocks(this.currentBlockHeight, BLINDBITURL);
console.log('✅ Initial scan completed for new wallet');
// Update last_scan to current block height
device.sp_wallet.last_scan = this.currentBlockHeight;
await this.saveDeviceInDatabase(device);
console.log('✅ New wallet initial scan completed');
} catch (e) { } catch (e) {
throw new Error(`Failed to save updated device: ${e}`); throw new Error(`Failed to save updated device: ${e}`);
} }
} else { } else {
// This is existing device, we need to catch up if last_scan is lagging behind chain_tip // This is existing device, we need to catch up if last_scan is lagging behind chain_tip
if (device.sp_wallet.last_scan < this.currentBlockHeight) { if (device.sp_wallet.last_scan < this.currentBlockHeight) {
// We need to catch up // We need to catch up - this is the initial synchronization, not a duplicate scan
console.log('🔄 Initial wallet synchronization with blockchain...');
try { try {
await this.sdkClient.scan_blocks(this.currentBlockHeight, BLINDBITURL); await this.sdkClient.scan_blocks(this.currentBlockHeight, BLINDBITURL);
console.log('✅ Initial wallet synchronization completed');
} catch (e) { } catch (e) {
console.error(`Failed to scan blocks: ${e}`); console.error(`Failed to scan blocks: ${e}`);
return; return;