diff --git a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/main-device/shine_homeserver_main/shine_homeserver_main.ino b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/main-device/shine_homeserver_main/shine_homeserver_main.ino index 60e6656..0d7482a 100644 --- a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/main-device/shine_homeserver_main/shine_homeserver_main.ino +++ b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/main-device/shine_homeserver_main/shine_homeserver_main.ino @@ -2206,20 +2206,20 @@ static std::vector buildEd25519InstructionData(const uint8_t signature[ } static bool getLatestBlockhashBytes(uint8_t out[32], String &blockhashB58, String &messageOut) { - String payload; - if (!rpcCallSolana("getLatestBlockhash", "[{\"commitment\":\"confirmed\"}]", payload)) { - messageOut = "RPC did not return blockhash"; - return false; + for (int attempt = 0; attempt < 3; ++attempt) { + String payload; + if (rpcCallSolana("getLatestBlockhash", "[{\"commitment\":\"confirmed\"}]", payload) + && jsonStringField(payload, "blockhash", blockhashB58) + && !blockhashB58.isEmpty() + && base58ToFixed32(blockhashB58, out)) { + return true; + } + if (attempt < 2) { + delay(120); + } } - if (!jsonStringField(payload, "blockhash", blockhashB58) || blockhashB58.isEmpty()) { - messageOut = "Blockhash missing in response"; - return false; - } - if (!base58ToFixed32(blockhashB58, out)) { - messageOut = "Invalid blockhash"; - return false; - } - return true; + messageOut = "RPC did not return blockhash"; + return false; } static bool pdaAlreadyExists(const String &login, String &pdaAddress, String &messageOut) { @@ -3215,6 +3215,10 @@ static bool updateHomeserverSessionOnSolana(bool requireExisting, String &messag } diagDetails += String("wifi=connected:") + WiFi.localIP().toString() + "\n"; Serial.println("HOMESERVER_UPDATE_WIFI_OK"); + if (gShineAuthenticated || gShineWs.connected) { + Serial.println("HOMESERVER_UPDATE_CLOSE_SHINE_SESSION"); + clearShineSessionState(false); + } ShinePdaUserState currentState; String stateError; @@ -3224,6 +3228,7 @@ static bool updateHomeserverSessionOnSolana(bool requireExisting, String &messag usedCachedPda = true; diagDetails += "read_pda_source=cache\n"; } else { + Serial.println("HOMESERVER_UPDATE_READ_PDA_CALL"); if (!readShineUserPda(cleanLogin, currentState, stateError)) { diagDetails += String("read_pda_error=") + stateError + "\n"; return failWithDiag(stateError.isEmpty() ? "Failed to read user PDA" : stateError); @@ -3715,6 +3720,7 @@ static bool readShineUserPda(const String &login, ShinePdaUserState &outState, S } String pdaB58 = base58From32(userPda); + Serial.println(String("READ_PDA_RPC_START: ") + pdaB58); int code = -1; String payload; String req = "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"getAccountInfo\",\"params\":[\"" + pdaB58 + "\",{\"encoding\":\"base64\",\"commitment\":\"confirmed\"}]}"; @@ -3722,6 +3728,7 @@ static bool readShineUserPda(const String &login, ShinePdaUserState &outState, S errorOut = "Solana RPC unavailable"; return false; } + Serial.println(String("READ_PDA_RPC_DONE_CODE: ") + String(code)); if (payload.indexOf("\"value\":null") >= 0) { outState.found = false; return true; @@ -3777,6 +3784,10 @@ static void refreshAccountPdaStatus() { return; } + gCachedAccountPdaState = pdaState; + gCachedAccountPdaLogin = normalizeLoginValue(gLoginValue); + gCachedAccountPdaValid = true; + uint8_t recoveryPub[32] = {}; uint8_t rootPub[32] = {}; uint8_t clientPub[32] = {}; @@ -3845,9 +3856,6 @@ static void refreshAccountPdaStatus() { return; } - gCachedAccountPdaState = pdaState; - gCachedAccountPdaLogin = normalizeLoginValue(gLoginValue); - gCachedAccountPdaValid = true; gAccountPdaStatus = ACCOUNT_PDA_OK; gAccountPdaStatusMessage = "ok"; } @@ -5691,24 +5699,30 @@ static void actionButtonCb(lv_event_t *event) { showScreen(SCREEN_HOMESERVER_PDA_CONFIRM); break; case ACTION_HOMESERVER_PDA_ADD_EXECUTE: { + Serial.println("HOMESERVER_ADD_BUTTON_CLICK"); gRegisterTriggerSource = "manual-homeserver-add"; String updateMessage; + Serial.println("HOMESERVER_ADD_CALL_BEGIN"); if (!updateHomeserverSessionOnSolana(false, updateMessage)) { gHomeserverPdaResultSuccess = false; gHomeserverPdaResultMessage = updateMessage; gHomeserverPdaResultDetails = ""; } + Serial.println(String("HOMESERVER_ADD_CALL_END: ") + updateMessage); showScreen(SCREEN_HOMESERVER_PDA_RESULT); break; } case ACTION_HOMESERVER_PDA_FIX_EXECUTE: { + Serial.println("HOMESERVER_FIX_BUTTON_CLICK"); gRegisterTriggerSource = "manual-homeserver-fix"; String updateMessage; + Serial.println("HOMESERVER_FIX_CALL_BEGIN"); if (!updateHomeserverSessionOnSolana(true, updateMessage)) { gHomeserverPdaResultSuccess = false; gHomeserverPdaResultMessage = updateMessage; gHomeserverPdaResultDetails = ""; } + Serial.println(String("HOMESERVER_FIX_CALL_END: ") + updateMessage); showScreen(SCREEN_HOMESERVER_PDA_RESULT); break; } diff --git a/VERSION.properties b/VERSION.properties index f88f105..53f4e1f 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.2.253 -server.version=1.2.238 +client.version=1.2.258 +server.version=1.2.243 diff --git a/shine-solana/shine/tests/temp_delete_user_pda.md b/shine-solana/shine/tests/temp_delete_user_pda.md new file mode 100644 index 0000000..29814b8 --- /dev/null +++ b/shine-solana/shine/tests/temp_delete_user_pda.md @@ -0,0 +1,59 @@ +# Временная версия `shine_users` с удалением `user_pda` + +Статус: `только для тестов регистрации` + +Этот файл хранит временную версию логики, которая была нужна для отладки регистрации +пользователей через ESP32. В основной программе `shine_users` удаление PDA **не должно +оставаться**. + +## Зачем это нужно + +- быстро очищать тестовые user PDA на devnet/localnet; +- сохранять рабочий вариант на случай, если понадобится снова проверять регистрацию + без ручной очистки цепочки; +- не смешивать временную отладочную логику с нормальным контрактом. + +## Что было временно добавлено + +В devnet-версии программы существовала инструкция: + +```text +tag = 5 +delete_user_pda_temp +``` + +Она: + +- принимала любой `signer`; +- работала только с валидной `user_pda`; +- проверяла, что PDA действительно относится к `shine_users`; +- очищала данные PDA через `realloc(0, false)`; +- переносила лампорты тестового аккаунта в `DAO_AUTHORITY`. + +## Важные ограничения + +- это **не** часть нормальной модели `shine_users`; +- в основном контракте этой инструкции быть не должно; +- файл нужен только как архив для регрессионных тестов регистрации. + +## Фрагмент логики + +```rust +// Временная инструкция для ручной чистки тестовых user PDA на devnet/localnet. +// Любой signer мог удалить запись, но лампорты возвращались только в тестовый treasury. +// +// Порядок был таким: +// 1. найти и проверить user PDA; +// 2. обнулить data через realloc(0, false); +// 3. перенести лампорты в DAO_AUTHORITY; +// 4. завершить инструкцию. +``` + +## Что помнить при возврате этой фичи + +Если временное удаление снова понадобится: + +1. сначала отдельным патчем включить его в `shine_users`; +2. потом отдельно задеплоить в devnet; +3. после проверки удалить из основной программы снова. +