From 237b39a524d121701479fed9f60e55ef8269a23f Mon Sep 17 00:00:00 2001 From: lexandr0s Date: Sat, 4 Jun 2022 23:50:03 +0400 Subject: [PATCH 01/31] Update SysTray_ru.properties --- src/main/resources/i18n/SysTray_ru.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/i18n/SysTray_ru.properties b/src/main/resources/i18n/SysTray_ru.properties index fc3d8648..4f575c90 100644 --- a/src/main/resources/i18n/SysTray_ru.properties +++ b/src/main/resources/i18n/SysTray_ru.properties @@ -1,7 +1,7 @@ #Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/) # SysTray pop-up menu -APPLYING_UPDATE_AND_RESTARTING = Применение автоматического обновления и перезапуска... +APPLYING_UPDATE_AND_RESTARTING = Применение автоматического обновления и перезапуск... AUTO_UPDATE = Автоматическое обновление From c03344caaea5ffcc8e735eed4d855c04c8d37a98 Mon Sep 17 00:00:00 2001 From: lexandr0s Date: Sat, 4 Jun 2022 23:57:25 +0400 Subject: [PATCH 02/31] Update ApiError_ru.properties --- src/main/resources/i18n/ApiError_ru.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/i18n/ApiError_ru.properties b/src/main/resources/i18n/ApiError_ru.properties index 52580ac8..1367f29b 100644 --- a/src/main/resources/i18n/ApiError_ru.properties +++ b/src/main/resources/i18n/ApiError_ru.properties @@ -16,7 +16,7 @@ NON_PRODUCTION = этот вызов API не разрешен для произ BLOCKCHAIN_NEEDS_SYNC = блокчейн должен сначала синхронизироваться -NO_TIME_SYNC = пока нет синхронизации часов +NO_TIME_SYNC = время не синхронизировано ### Validation ### INVALID_SIGNATURE = недействительная подпись @@ -72,7 +72,7 @@ FOREIGN_BLOCKCHAIN_NETWORK_ISSUE = проблема с внешним блокч FOREIGN_BLOCKCHAIN_BALANCE_ISSUE = недостаточный баланс на внешнем блокчейне -FOREIGN_BLOCKCHAIN_TOO_SOON = слишком рано для трансляции транзакции во внений блокчей (время блокировки/среднее время блока) +FOREIGN_BLOCKCHAIN_TOO_SOON = слишком рано для трансляции транзакции во внешний блокчей (время блокировки/среднее время блока) ### Trade Portal ### ORDER_SIZE_TOO_SMALL = слишком маленькая сумма ордера @@ -80,4 +80,4 @@ ORDER_SIZE_TOO_SMALL = слишком маленькая сумма ордера ### Data ### FILE_NOT_FOUND = файл не найден -NO_REPLY = узел не ответил данными +NO_REPLY = нет ответа From ff40b8f8ab8801c44b6045c066ededf056e119e0 Mon Sep 17 00:00:00 2001 From: QuickMythril Date: Thu, 23 Jun 2022 01:43:33 -0400 Subject: [PATCH 03/31] Updated German translations --- src/main/resources/i18n/SysTray_de.properties | 16 +- .../i18n/TransactionValidity_de.properties | 195 ++++++++++++++++++ 2 files changed, 203 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/i18n/TransactionValidity_de.properties diff --git a/src/main/resources/i18n/SysTray_de.properties b/src/main/resources/i18n/SysTray_de.properties index b949ca8c..d4abf2a3 100644 --- a/src/main/resources/i18n/SysTray_de.properties +++ b/src/main/resources/i18n/SysTray_de.properties @@ -5,9 +5,9 @@ APPLYING_UPDATE_AND_RESTARTING = Automatisches Update anwenden und neu starten AUTO_UPDATE = Automatisches Update -BLOCK_HEIGHT = height +BLOCK_HEIGHT = Blockhöhe -BUILD_VERSION = Build-Version +BUILD_VERSION = Entwicklungs-Version CHECK_TIME_ACCURACY = Prüfe Zeitgenauigkeit @@ -21,7 +21,7 @@ CREATING_BACKUP_OF_DB_FILES = Erstellen Backup von Datenbank Dateien … DB_BACKUP = Datenbank Backup -DB_CHECKPOINT = Datenbank Kontrollpunkt +DB_CHECKPOINT = Datenbank Check DB_MAINTENANCE = Datenbank Instandhaltung @@ -29,18 +29,18 @@ EXIT = Verlassen LITE_NODE = Lite node -MINTING_DISABLED = NOT minting +MINTING_DISABLED = Kein minting -MINTING_ENABLED = \u2714 Minting +MINTING_ENABLED = \u2714 Minting aktiviert OPEN_UI = Öffne UI -PERFORMING_DB_CHECKPOINT = Speichern nicht übergebener Datenbank Änderungen … +PERFORMING_DB_CHECKPOINT = Speichern von unbestätigten Datenbankänderungen... PERFORMING_DB_MAINTENANCE = Planmäßige Wartung durchführen... SYNCHRONIZE_CLOCK = Synchronisiere Uhr -SYNCHRONIZING_BLOCKCHAIN = Synchronisierung +SYNCHRONIZING_BLOCKCHAIN = Synchronisierung der Blockchain -SYNCHRONIZING_CLOCK = Synchronisierung Uhr +SYNCHRONIZING_CLOCK = Synchronisierung der Uhr diff --git a/src/main/resources/i18n/TransactionValidity_de.properties b/src/main/resources/i18n/TransactionValidity_de.properties new file mode 100644 index 00000000..1827482b --- /dev/null +++ b/src/main/resources/i18n/TransactionValidity_de.properties @@ -0,0 +1,195 @@ +# + +ACCOUNT_ALREADY_EXISTS = Account existiert bereits + +ACCOUNT_CANNOT_REWARD_SHARE = Account kann keine Belohnung teilen + +ADDRESS_ABOVE_RATE_LIMIT = address hat das angegebene Geschwindigkeitlimit erreicht + +ADDRESS_BLOCKED = Addresse ist geblockt + +ALREADY_GROUP_ADMIN = bereits Gruppen Admin + +ALREADY_GROUP_MEMBER = bereits Gruppen Mitglied + +ALREADY_VOTED_FOR_THAT_OPTION = bereits für diese Option gestimmt + +ASSET_ALREADY_EXISTS = asset existiert bereits + +ASSET_DOES_NOT_EXIST = asset nicht gefunden + +ASSET_DOES_NOT_MATCH_AT = asset passt nicht mit AT's asset + +ASSET_NOT_SPENDABLE = asset ist nicht ausgabefähig + +AT_ALREADY_EXISTS = AT existiert bereits + +AT_IS_FINISHED = AT ist fertig + +AT_UNKNOWN = AT unbekannt + +BAN_EXISTS = ban besteht bereits + +BAN_UNKNOWN = ban unbekannt + +BANNED_FROM_GROUP = von der gruppe gebannt + +BUYER_ALREADY_OWNER = Käufer ist bereits Besitzer + +CLOCK_NOT_SYNCED = Uhr nicht synchronisiert + +DUPLICATE_MESSAGE = Adresse sendete doppelte Nachricht + +DUPLICATE_OPTION = Duplizierungsmöglichkeit + +GROUP_ALREADY_EXISTS = Gruppe besteht bereits + +GROUP_APPROVAL_DECIDED = Gruppenfreigabe bereits beschlossen + +GROUP_APPROVAL_NOT_REQUIRED = Gruppenfreigabe nicht erforderlich + +GROUP_DOES_NOT_EXIST = Gruppe nicht vorhanden + +GROUP_ID_MISMATCH = Gruppen-ID stimmt nicht überein + +GROUP_OWNER_CANNOT_LEAVE = Gruppenbesitzer kann Gruppe nicht verlassen + +HAVE_EQUALS_WANT = das bessesene-asset ist das selbe wie das gesuchte-asset + +INCORRECT_NONCE = falsche PoW-Nonce + +INSUFFICIENT_FEE = unzureichende Gebühr + +INVALID_ADDRESS = ungültige Adresse + +INVALID_AMOUNT = ungültiger Betrag + +INVALID_ASSET_OWNER = Ungültiger Eigentümer + +INVALID_AT_TRANSACTION = ungültige AT-Transaktion + +INVALID_AT_TYPE_LENGTH = ungültige AT 'Typ' Länge + +INVALID_BUT_OK = ungültig aber OK + +INVALID_CREATION_BYTES = ungültige Erstellungs der bytes + +INVALID_DATA_LENGTH = ungültige Datenlänge + +INVALID_DESCRIPTION_LENGTH = ungültige Länge der Beschreibung + +INVALID_GROUP_APPROVAL_THRESHOLD = ungültiger Schwellenwert für die Gruppenzulassung + +INVALID_GROUP_BLOCK_DELAY = Ungültige Blockverzögerung der Gruppenfreigabe + +INVALID_GROUP_ID = ungültige Gruppen-ID + +INVALID_GROUP_OWNER = ungültiger Gruppenbesitzer + +INVALID_LIFETIME = unzulässige Lebensdauer + +INVALID_NAME_LENGTH = ungültige Namenslänge + +INVALID_NAME_OWNER = ungültiger Besitzername + +INVALID_OPTION_LENGTH = ungültige Länge der Optionen + +INVALID_OPTIONS_COUNT = Anzahl ungültiger Optionen + +INVALID_ORDER_CREATOR = ungültiger Auftragsersteller + +INVALID_PAYMENTS_COUNT = Anzahl ungültiger Zahlungen + +INVALID_PUBLIC_KEY = ungültiger öffentlicher Schlüssel + +INVALID_QUANTITY = unzulässige Menge + +INVALID_REFERENCE = ungültige Referenz + +INVALID_RETURN = ungültige Rückgabe + +INVALID_REWARD_SHARE_PERCENT = ungültig Prozent der Belohnunganteile + +INVALID_SELLER = unzulässiger Verkäufer + +INVALID_TAGS_LENGTH = ungültige 'tags'-Länge + +INVALID_TIMESTAMP_SIGNATURE = Ungültige Zeitstempel-Signatur + +INVALID_TX_GROUP_ID = Ungültige Transaktionsgruppen-ID + +INVALID_VALUE_LENGTH = ungültige 'Wert'-Länge + +INVITE_UNKNOWN = Gruppeneinladung unbekannt + +JOIN_REQUEST_EXISTS = Gruppeneinladung existiert bereits + +MAXIMUM_REWARD_SHARES = die maximale Anzahl von Reward-Shares für dieses Konto erreicht + +MISSING_CREATOR = fehlender Ersteller + +MULTIPLE_NAMES_FORBIDDEN = mehrere registrierte Namen pro Konto sind untersagt + +NAME_ALREADY_FOR_SALE = Name bereits zum Verkauf + +NAME_ALREADY_REGISTERED = Name bereits registriert + +NAME_BLOCKED = Name geblockt + +NAME_DOES_NOT_EXIST = Name nicht vorhanden + +NAME_NOT_FOR_SALE = Name ist unverkäuflich + +NAME_NOT_NORMALIZED = Name nicht in Unicode-'normalisierter' Form + +NEGATIVE_AMOUNT = ungültiger/negativer Betrag + +NEGATIVE_FEE = ungültige/negative Gebühr + +NEGATIVE_PRICE = ungültiger/negativer Preis + +NO_BALANCE = unzureichendes Guthaben + +NO_BLOCKCHAIN_LOCK = die Blockchain des Knotens ist beschäftigt + +NO_FLAG_PERMISSION = Konto hat diese Berechtigung nicht + +NOT_GROUP_ADMIN = Account ist kein Gruppenadmin + +NOT_GROUP_MEMBER = Account kein Gruppenmitglied + +NOT_MINTING_ACCOUNT = Account kann nicht minten + +NOT_YET_RELEASED = Funktion noch nicht freigegeben + +OK = OK + +ORDER_ALREADY_CLOSED = Asset Trade Order ist bereits geschlossen + +ORDER_DOES_NOT_EXIST = asset trade order existiert nicht + +POLL_ALREADY_EXISTS = Umfrage bereits vorhanden + +POLL_DOES_NOT_EXIST = Umfrage nicht vorhanden + +POLL_OPTION_DOES_NOT_EXIST = Umfrageoption existiert nicht + +PUBLIC_KEY_UNKNOWN = öffentlicher Schlüssel unbekannt + +REWARD_SHARE_UNKNOWN = Geteilte Belohnungen unbekant + +SELF_SHARE_EXISTS = Selbstbeteiligung (Geteilte Belohnungen) sind breits vorhanden + +TIMESTAMP_TOO_NEW = Zeitstempel zu neu + +TIMESTAMP_TOO_OLD = Zeitstempel zu alt + +TOO_MANY_UNCONFIRMED = Account hat zu viele unbestätigte Transaktionen am laufen + +TRANSACTION_ALREADY_CONFIRMED = Transaktionen sind bereits bestätigt + +TRANSACTION_ALREADY_EXISTS = Transaktionen existiert bereits + +TRANSACTION_UNKNOWN = Unbekante Transaktion + +TX_GROUP_ID_MISMATCH = Transaktion Gruppen ID stimmt nicht überein From 8ddf4c9f9f6b14db7676261da95c10d4f26cbcbe Mon Sep 17 00:00:00 2001 From: Nuc1eoN <2538022+Nuc1eoN@users.noreply.github.com> Date: Sun, 9 Oct 2022 15:35:19 +0200 Subject: [PATCH 04/31] Add polish translation --- .../resources/i18n/ApiError_pl.properties | 83 ++++++++ src/main/resources/i18n/SysTray_pl.properties | 46 ++++ .../i18n/TransactionValidity_pl.properties | 196 ++++++++++++++++++ 3 files changed, 325 insertions(+) create mode 100644 src/main/resources/i18n/ApiError_pl.properties create mode 100644 src/main/resources/i18n/SysTray_pl.properties create mode 100644 src/main/resources/i18n/TransactionValidity_pl.properties diff --git a/src/main/resources/i18n/ApiError_pl.properties b/src/main/resources/i18n/ApiError_pl.properties new file mode 100644 index 00000000..fcb6191c --- /dev/null +++ b/src/main/resources/i18n/ApiError_pl.properties @@ -0,0 +1,83 @@ +#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/) +# Keys are from api.ApiError enum + +# "localeLang": "pl", + +### Common ### +JSON = nie udało się przetworzyć wiadomości JSON + +INSUFFICIENT_BALANCE = niedostateczne środki + +UNAUTHORIZED = nieautoryzowane połączenie API + +REPOSITORY_ISSUE = błąd repozytorium + +NON_PRODUCTION = to wywołanie API nie jest dozwolone dla systemów produkcyjnych + +BLOCKCHAIN_NEEDS_SYNC = blockchain musi się najpierw zsynchronizować + +NO_TIME_SYNC = zegar się jeszcze nie zsynchronizował + +### Validation ### +INVALID_SIGNATURE = nieprawidłowa sygnatura + +INVALID_ADDRESS = nieprawidłowy adres + +INVALID_PUBLIC_KEY = nieprawidłowy klucz publiczny + +INVALID_DATA = nieprawidłowe dane + +INVALID_NETWORK_ADDRESS = nieprawidłowy adres sieci + +ADDRESS_UNKNOWN = nieznany adres konta + +INVALID_CRITERIA = nieprawidłowe kryteria wyszukiwania + +INVALID_REFERENCE = nieprawidłowe skierowanie + +TRANSFORMATION_ERROR = nie udało się przekształcić JSON w transakcję + +INVALID_PRIVATE_KEY = klucz prywatny jest niepoprawny + +INVALID_HEIGHT = nieprawidłowa wysokość bloku + +CANNOT_MINT = konto nie możne bić monet + +### Blocks ### +BLOCK_UNKNOWN = blok nieznany + +### Transactions ### +TRANSACTION_UNKNOWN = nieznana transakcja + +PUBLIC_KEY_NOT_FOUND = nie znaleziono klucza publicznego + +# this one is special in that caller expected to pass two additional strings, hence the two %s +TRANSACTION_INVALID = transakcja nieważna: %s (%s) + +### Naming ### +NAME_UNKNOWN = nazwa nieznana + +### Asset ### +INVALID_ASSET_ID = nieprawidłowy identyfikator aktywy + +INVALID_ORDER_ID = nieprawidłowy identyfikator zlecenia aktywy + +ORDER_UNKNOWN = nieznany identyfikator zlecenia aktywy + +### Groups ### +GROUP_UNKNOWN = nieznana grupa + +### Foreign Blockchain ### +FOREIGN_BLOCKCHAIN_NETWORK_ISSUE = obcy blockchain lub problem z siecią ElectrumX + +FOREIGN_BLOCKCHAIN_BALANCE_ISSUE = niewystarczające środki na obcym blockchainie + +FOREIGN_BLOCKCHAIN_TOO_SOON = zbyt wczesne nadawanie transakcji na obcym blockchainie (okres karencji/średni czas bloku) + +### Trade Portal ### +ORDER_SIZE_TOO_SMALL = zbyt niska kwota zlecenia + +### Data ### +FILE_NOT_FOUND = plik nie został znaleziony + +NO_REPLY = peer nie odpowiedział w wyznaczonym czasie diff --git a/src/main/resources/i18n/SysTray_pl.properties b/src/main/resources/i18n/SysTray_pl.properties new file mode 100644 index 00000000..84740da0 --- /dev/null +++ b/src/main/resources/i18n/SysTray_pl.properties @@ -0,0 +1,46 @@ +#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/) +# SysTray pop-up menu + +APPLYING_UPDATE_AND_RESTARTING = Zastosowanie automatycznej aktualizacji i ponowne uruchomienie... + +AUTO_UPDATE = Automatyczna aktualizacja + +BLOCK_HEIGHT = wysokość + +BUILD_VERSION = Wersja kompilacji + +CHECK_TIME_ACCURACY = Sprawdz dokładność czasu + +CONNECTING = Łączenie + +CONNECTION = połączenie + +CONNECTIONS = połączenia + +CREATING_BACKUP_OF_DB_FILES = Tworzenie kopii zapasowej plików bazy danych... + +DB_BACKUP = Kopia zapasowa bazy danych + +DB_CHECKPOINT = Punkt kontrolny bazy danych... + +DB_MAINTENANCE = Konserwacja bazy danych + +EXIT = Zakończ + +LITE_NODE = Lite node + +MINTING_DISABLED = Mennica zamknięta + +MINTING_ENABLED = \u2714 Mennica aktywna + +OPEN_UI = Otwórz interfejs użytkownika + +PERFORMING_DB_CHECKPOINT = Zapisywanie niezaksięgowanych zmian w bazie danych... + +PERFORMING_DB_MAINTENANCE = Performing scheduled maintenance... + +SYNCHRONIZE_CLOCK = Synchronizuj zegar + +SYNCHRONIZING_BLOCKCHAIN = Synchronizacja + +SYNCHRONIZING_CLOCK = Synchronizacja zegara diff --git a/src/main/resources/i18n/TransactionValidity_pl.properties b/src/main/resources/i18n/TransactionValidity_pl.properties new file mode 100644 index 00000000..bcdceb6e --- /dev/null +++ b/src/main/resources/i18n/TransactionValidity_pl.properties @@ -0,0 +1,196 @@ +# + +ACCOUNT_ALREADY_EXISTS = konto już istnieje + +ACCOUNT_CANNOT_REWARD_SHARE = konto nie może udostępniać nagród + +ADDRESS_ABOVE_RATE_LIMIT = adres osiągnął określony limit stawki + +ADDRESS_BLOCKED = ten adres jest zablokowany + +ALREADY_GROUP_ADMIN = już adminem grupy + +ALREADY_GROUP_MEMBER = już członkiem grupy + +ALREADY_VOTED_FOR_THAT_OPTION = już zagłosowano na ta opcje + +ASSET_ALREADY_EXISTS = aktywa już istnieje + +ASSET_DOES_NOT_EXIST = aktywa nie istnieje + +ASSET_DOES_NOT_MATCH_AT = aktywa nie pasuje do aktywy AT + +ASSET_NOT_SPENDABLE = aktywa nie jest rozporządzalna + +AT_ALREADY_EXISTS = AT już istnieje + +AT_IS_FINISHED = AT zakończył + +AT_UNKNOWN = AT nieznany + +BAN_EXISTS = ban już istnieje + +BAN_UNKNOWN = ban nieznany + +BANNED_FROM_GROUP = zbanowany z grupy + +BUYER_ALREADY_OWNER = kupca jest już właścicielem + +CLOCK_NOT_SYNCED = zegar nie zsynchronizowany + +DUPLICATE_MESSAGE = adres wysłał duplikat wiadomości + +DUPLICATE_OPTION = duplikat opcji + +GROUP_ALREADY_EXISTS = grupa już istnieje + +GROUP_APPROVAL_DECIDED = zatwierdzenie grupy już zdecydowano + +GROUP_APPROVAL_NOT_REQUIRED = zatwierdzenie grupy nie jest wymagane + +GROUP_DOES_NOT_EXIST = grupa nie istnieje + +GROUP_ID_MISMATCH = niedopasowanie identyfikatora grupy + +GROUP_OWNER_CANNOT_LEAVE = właściciel grupy nie może opuścić grupy + +HAVE_EQUALS_WANT = posiadana aktywa równa się chcianej aktywie + +INCORRECT_NONCE = nieprawidłowy nonce PoW + +INSUFFICIENT_FEE = niewystarczająca opłata + +INVALID_ADDRESS = nieprawidłowy adres + +INVALID_AMOUNT = nieprawidłowa kwota + +INVALID_ASSET_OWNER = nieprawidłowy właściciel aktywów + +INVALID_AT_TRANSACTION = nieważna transakcja AT + +INVALID_AT_TYPE_LENGTH = nieprawidłowa długość typu AT + +INVALID_BUT_OK = nieważne, ale OK + +INVALID_CREATION_BYTES = nieprawidłowe bajty tworzenia + +INVALID_DATA_LENGTH = nieprawidłowa długość danych + +INVALID_DESCRIPTION_LENGTH = nieprawidłowa długość opisu + +INVALID_GROUP_APPROVAL_THRESHOLD = nieprawidłowy próg zatwierdzenia grupy + +INVALID_GROUP_BLOCK_DELAY = nieprawidłowe opóźnienie bloku zatwierdzenia grupy + +INVALID_GROUP_ID = nieprawidłowy identyfikator grupy + +INVALID_GROUP_OWNER = nieprawidłowy właściciel grupy + +INVALID_LIFETIME = nieprawidłowy czas istnienia + +INVALID_NAME_LENGTH = nieprawidłowa długość nazwy + +INVALID_NAME_OWNER = nieprawidłowy właściciel nazwy + +INVALID_OPTION_LENGTH = nieprawidłowa długość opcji + +INVALID_OPTIONS_COUNT = nieprawidłowa liczba opcji + +INVALID_ORDER_CREATOR = nieprawidłowy twórca zlecenia + +INVALID_PAYMENTS_COUNT = nieprawidłowa liczba płatności + +INVALID_PUBLIC_KEY = nieprawidłowy klucz publiczny + +INVALID_QUANTITY = nieprawidłowa ilość + +INVALID_REFERENCE = nieprawidłowe skierowanie + +INVALID_RETURN = nieprawidłowy zwrot + +INVALID_REWARD_SHARE_PERCENT = nieprawidłowy procent udziału w nagrodzie + +INVALID_SELLER = nieprawidłowy sprzedawca + +INVALID_TAGS_LENGTH = nieprawidłowa długość tagów + +INVALID_TIMESTAMP_SIGNATURE = nieprawidłowa sygnatura znacznika czasu + +INVALID_TX_GROUP_ID = nieprawidłowy identyfikator grupy transakcji + +INVALID_VALUE_LENGTH = nieprawidłowa długość wartości + +INVITE_UNKNOWN = zaproszenie do grupy nieznane + +JOIN_REQUEST_EXISTS = wniosek o dołączenie do grupy już istnieje + +MAXIMUM_REWARD_SHARES = osiągnięto już maksymalną liczbę udziałów w nagrodzie dla tego konta + +MISSING_CREATOR = brak twórcy + +MULTIPLE_NAMES_FORBIDDEN = zabronione jest używanie wielu nazw na jednym koncie + +NAME_ALREADY_FOR_SALE = nazwa już wystawiona na sprzedaż + +NAME_ALREADY_REGISTERED = nazwa już zarejestrowana + +NAME_BLOCKED = ta nazwa jest zablokowana + +NAME_DOES_NOT_EXIST = nazwa nie istnieje + +NAME_NOT_FOR_SALE = nazwa nie jest przeznaczona do sprzedaży + +NAME_NOT_NORMALIZED = nazwa nie jest w formie 'znormalizowanej' Unicode + +NEGATIVE_AMOUNT = nieprawidłowa/ujemna kwota + +NEGATIVE_FEE = nieprawidłowa/ujemna opłata + +NEGATIVE_PRICE = nieprawidłowa/ujemna cena + +NO_BALANCE = niewystarczające środki + +NO_BLOCKCHAIN_LOCK = węzeł blockchain jest obecnie zajęty + +NO_FLAG_PERMISSION = konto nie ma tego uprawnienia + +NOT_GROUP_ADMIN = konto nie jest adminem grupy + +NOT_GROUP_MEMBER = konto nie jest członkiem grupy + +NOT_MINTING_ACCOUNT = konto nie może bić monet + +NOT_YET_RELEASED = funkcja nie została jeszcze udostępniona + +OK = OK + +ORDER_ALREADY_CLOSED = zlecenie handlu aktywami jest już zakończone + +ORDER_DOES_NOT_EXIST = zlecenie sprzedaży aktywów nie istnieje + +POLL_ALREADY_EXISTS = ankieta już istnieje + +POLL_DOES_NOT_EXIST = ankieta nie istnieje + +POLL_OPTION_DOES_NOT_EXIST = opcja ankiety nie istnieje + +PUBLIC_KEY_UNKNOWN = klucz publiczny nieznany + +REWARD_SHARE_UNKNOWN = nieznany udział w nagrodzie + +SELF_SHARE_EXISTS = samoudział (udział w nagrodzie) już istnieje + +TIMESTAMP_TOO_NEW = zbyt nowy znacznik czasu + +TIMESTAMP_TOO_OLD = zbyt stary znacznik czasu + +TOO_MANY_UNCONFIRMED = rachunek ma zbyt wiele niepotwierdzonych transakcji w toku + +TRANSACTION_ALREADY_CONFIRMED = transakcja została już potwierdzona + +TRANSACTION_ALREADY_EXISTS = transakcja już istnieje + +TRANSACTION_UNKNOWN = transakcja nieznana + +TX_GROUP_ID_MISMATCH = niezgodność ID grupy transakcji + From bd4c47dba602f5964ed3d97ffda64b5f04a22e05 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 15 Jan 2023 14:32:33 +0000 Subject: [PATCH 05/31] Rework of AT state trimming and pruning, in order to more reliably track the "latest" AT states. This should fix an edge case where AT states data was pruned/trimmed but it was then later required in consensus. The older state was deleted because it was replaced by a new "latest" state in a brand new block. But once the new "latest" state was orphaned from the block, the old "latest" state was then required again. This works around the problem by excluding very recent blocks in the latest AT states data, so that it is unaffected by real-time sync activity. The trade off is that we could end up retaining more AT states than needed, so a secondary cleanup process may need to run at some time in the future to remove these. But it should only be a minimal amount of data, and can be cleaned up with a single query. This would have been happening to a certain degree already. --- .../controller/repository/AtStatesPruner.java | 6 +- .../repository/AtStatesTrimmer.java | 6 +- .../controller/repository/PruneManager.java | 14 ++ .../org/qortal/repository/ATRepository.java | 2 +- .../repository/hsqldb/HSQLDBATRepository.java | 5 +- .../hsqldb/HSQLDBDatabasePruning.java | 2 +- .../org/qortal/test/BlockArchiveTests.java | 26 ++-- .../java/org/qortal/test/BootstrapTests.java | 3 +- src/test/java/org/qortal/test/PruneTests.java | 143 +++++++++++++++++- .../org/qortal/test/at/AtRepositoryTests.java | 19 +-- .../org/qortal/test/common/BlockUtils.java | 9 ++ 11 files changed, 197 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/qortal/controller/repository/AtStatesPruner.java b/src/main/java/org/qortal/controller/repository/AtStatesPruner.java index bd12f784..1faeda98 100644 --- a/src/main/java/org/qortal/controller/repository/AtStatesPruner.java +++ b/src/main/java/org/qortal/controller/repository/AtStatesPruner.java @@ -39,9 +39,10 @@ public class AtStatesPruner implements Runnable { try (final Repository repository = RepositoryManager.getRepository()) { int pruneStartHeight = repository.getATRepository().getAtPruneHeight(); + int maxLatestAtStatesHeight = PruneManager.getMaxHeightForLatestAtStates(repository); repository.discardChanges(); - repository.getATRepository().rebuildLatestAtStates(); + repository.getATRepository().rebuildLatestAtStates(maxLatestAtStatesHeight); while (!Controller.isStopping()) { repository.discardChanges(); @@ -91,7 +92,8 @@ public class AtStatesPruner implements Runnable { if (upperPrunableHeight > upperBatchHeight) { pruneStartHeight = upperBatchHeight; repository.getATRepository().setAtPruneHeight(pruneStartHeight); - repository.getATRepository().rebuildLatestAtStates(); + maxLatestAtStatesHeight = PruneManager.getMaxHeightForLatestAtStates(repository); + repository.getATRepository().rebuildLatestAtStates(maxLatestAtStatesHeight); repository.saveChanges(); final int finalPruneStartHeight = pruneStartHeight; diff --git a/src/main/java/org/qortal/controller/repository/AtStatesTrimmer.java b/src/main/java/org/qortal/controller/repository/AtStatesTrimmer.java index 69fa347c..ea56699c 100644 --- a/src/main/java/org/qortal/controller/repository/AtStatesTrimmer.java +++ b/src/main/java/org/qortal/controller/repository/AtStatesTrimmer.java @@ -26,9 +26,10 @@ public class AtStatesTrimmer implements Runnable { try (final Repository repository = RepositoryManager.getRepository()) { int trimStartHeight = repository.getATRepository().getAtTrimHeight(); + int maxLatestAtStatesHeight = PruneManager.getMaxHeightForLatestAtStates(repository); repository.discardChanges(); - repository.getATRepository().rebuildLatestAtStates(); + repository.getATRepository().rebuildLatestAtStates(maxLatestAtStatesHeight); while (!Controller.isStopping()) { repository.discardChanges(); @@ -69,7 +70,8 @@ public class AtStatesTrimmer implements Runnable { if (upperTrimmableHeight > upperBatchHeight) { trimStartHeight = upperBatchHeight; repository.getATRepository().setAtTrimHeight(trimStartHeight); - repository.getATRepository().rebuildLatestAtStates(); + maxLatestAtStatesHeight = PruneManager.getMaxHeightForLatestAtStates(repository); + repository.getATRepository().rebuildLatestAtStates(maxLatestAtStatesHeight); repository.saveChanges(); final int finalTrimStartHeight = trimStartHeight; diff --git a/src/main/java/org/qortal/controller/repository/PruneManager.java b/src/main/java/org/qortal/controller/repository/PruneManager.java index ec27456f..dfb6290b 100644 --- a/src/main/java/org/qortal/controller/repository/PruneManager.java +++ b/src/main/java/org/qortal/controller/repository/PruneManager.java @@ -157,4 +157,18 @@ public class PruneManager { return (height < latestUnprunedHeight); } + /** + * When rebuilding the latest AT states, we need to specify a maxHeight, so that we aren't tracking + * very recent AT states that could potentially be orphaned. This method ensures that AT states + * are given a sufficient number of blocks to confirm before being tracked as a latest AT state. + */ + public static int getMaxHeightForLatestAtStates(Repository repository) throws DataException { + // Get current chain height, and subtract a certain number of "confirmation" blocks + // This is to ensure we are basing our latest AT states data on confirmed blocks - + // ones that won't be orphaned in any normal circumstances + final int confirmationBlocks = 250; + final int chainHeight = repository.getBlockRepository().getBlockchainHeight(); + return chainHeight - confirmationBlocks; + } + } diff --git a/src/main/java/org/qortal/repository/ATRepository.java b/src/main/java/org/qortal/repository/ATRepository.java index 0f537ae9..93da924c 100644 --- a/src/main/java/org/qortal/repository/ATRepository.java +++ b/src/main/java/org/qortal/repository/ATRepository.java @@ -119,7 +119,7 @@ public interface ATRepository { *

* NOTE: performs implicit repository.saveChanges(). */ - public void rebuildLatestAtStates() throws DataException; + public void rebuildLatestAtStates(int maxHeight) throws DataException; /** Returns height of first trimmable AT state. */ diff --git a/src/main/java/org/qortal/repository/hsqldb/HSQLDBATRepository.java b/src/main/java/org/qortal/repository/hsqldb/HSQLDBATRepository.java index 04823925..dd0404a8 100644 --- a/src/main/java/org/qortal/repository/hsqldb/HSQLDBATRepository.java +++ b/src/main/java/org/qortal/repository/hsqldb/HSQLDBATRepository.java @@ -603,7 +603,7 @@ public class HSQLDBATRepository implements ATRepository { @Override - public void rebuildLatestAtStates() throws DataException { + public void rebuildLatestAtStates(int maxHeight) throws DataException { // latestATStatesLock is to prevent concurrent updates on LatestATStates // that could result in one process using a partial or empty dataset // because it was in the process of being rebuilt by another thread @@ -624,11 +624,12 @@ public class HSQLDBATRepository implements ATRepository { + "CROSS JOIN LATERAL(" + "SELECT height FROM ATStates " + "WHERE ATStates.AT_address = ATs.AT_address " + + "AND height <= ?" + "ORDER BY AT_address DESC, height DESC LIMIT 1" + ") " + ")"; try { - this.repository.executeCheckedUpdate(insertSql); + this.repository.executeCheckedUpdate(insertSql, maxHeight); } catch (SQLException e) { repository.examineException(e); throw new DataException("Unable to populate temporary latest AT states cache in repository", e); diff --git a/src/main/java/org/qortal/repository/hsqldb/HSQLDBDatabasePruning.java b/src/main/java/org/qortal/repository/hsqldb/HSQLDBDatabasePruning.java index 978ba25e..e2bfc9ef 100644 --- a/src/main/java/org/qortal/repository/hsqldb/HSQLDBDatabasePruning.java +++ b/src/main/java/org/qortal/repository/hsqldb/HSQLDBDatabasePruning.java @@ -99,7 +99,7 @@ public class HSQLDBDatabasePruning { // It's essential that we rebuild the latest AT states here, as we are using this data in the next query. // Failing to do this will result in important AT states being deleted, rendering the database unusable. - repository.getATRepository().rebuildLatestAtStates(); + repository.getATRepository().rebuildLatestAtStates(endHeight); // Loop through all the LatestATStates and copy them to the new table diff --git a/src/test/java/org/qortal/test/BlockArchiveTests.java b/src/test/java/org/qortal/test/BlockArchiveTests.java index 3bfa4e84..8b3de67b 100644 --- a/src/test/java/org/qortal/test/BlockArchiveTests.java +++ b/src/test/java/org/qortal/test/BlockArchiveTests.java @@ -23,7 +23,6 @@ import org.qortal.transform.TransformationException; import org.qortal.transform.block.BlockTransformation; import org.qortal.utils.BlockArchiveUtils; import org.qortal.utils.NTP; -import org.qortal.utils.Triple; import java.io.File; import java.io.IOException; @@ -314,9 +313,10 @@ public class BlockArchiveTests extends Common { repository.getBlockRepository().setBlockPruneHeight(901); // Prune the AT states for the archived blocks - repository.getATRepository().rebuildLatestAtStates(); + repository.getATRepository().rebuildLatestAtStates(900); + repository.saveChanges(); int numATStatesPruned = repository.getATRepository().pruneAtStates(0, 900); - assertEquals(900-1, numATStatesPruned); + assertEquals(900-2, numATStatesPruned); // Minus 1 for genesis block, and another for the latest AT state repository.getATRepository().setAtPruneHeight(901); // Now ensure the SQL repository is missing blocks 2 and 900... @@ -563,16 +563,23 @@ public class BlockArchiveTests extends Common { // Trim the first 500 blocks repository.getBlockRepository().trimOldOnlineAccountsSignatures(0, 500); repository.getBlockRepository().setOnlineAccountsSignaturesTrimHeight(501); + repository.getATRepository().rebuildLatestAtStates(500); repository.getATRepository().trimAtStates(0, 500, 1000); repository.getATRepository().setAtTrimHeight(501); - // Now block 500 should only have the AT state data hash - block500AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(500); - atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500); + // Now block 499 should only have the AT state data hash + List block499AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(499); + atStatesData = repository.getATRepository().getATStateAtHeight(block499AtStatesData.get(0).getATAddress(), 499); assertNotNull(atStatesData.getStateHash()); assertNull(atStatesData.getStateData()); - // ... but block 501 should have the full data + // ... but block 500 should have the full data (due to being retained as the "latest" AT state in the trimmed range + block500AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(500); + atStatesData = repository.getATRepository().getATStateAtHeight(block500AtStatesData.get(0).getATAddress(), 500); + assertNotNull(atStatesData.getStateHash()); + assertNotNull(atStatesData.getStateData()); + + // ... and block 501 should also have the full data List block501AtStatesData = repository.getATRepository().getBlockATStatesAtHeight(501); atStatesData = repository.getATRepository().getATStateAtHeight(block501AtStatesData.get(0).getATAddress(), 501); assertNotNull(atStatesData.getStateHash()); @@ -612,9 +619,10 @@ public class BlockArchiveTests extends Common { repository.getBlockRepository().setBlockPruneHeight(501); // Prune the AT states for the archived blocks - repository.getATRepository().rebuildLatestAtStates(); + repository.getATRepository().rebuildLatestAtStates(500); + repository.saveChanges(); int numATStatesPruned = repository.getATRepository().pruneAtStates(2, 500); - assertEquals(499, numATStatesPruned); + assertEquals(498, numATStatesPruned); // Minus 1 for genesis block, and another for the latest AT state repository.getATRepository().setAtPruneHeight(501); // Now ensure the SQL repository is missing blocks 2 and 500... diff --git a/src/test/java/org/qortal/test/BootstrapTests.java b/src/test/java/org/qortal/test/BootstrapTests.java index aa641e71..b60b412c 100644 --- a/src/test/java/org/qortal/test/BootstrapTests.java +++ b/src/test/java/org/qortal/test/BootstrapTests.java @@ -176,7 +176,8 @@ public class BootstrapTests extends Common { repository.getBlockRepository().setBlockPruneHeight(901); // Prune the AT states for the archived blocks - repository.getATRepository().rebuildLatestAtStates(); + repository.getATRepository().rebuildLatestAtStates(900); + repository.saveChanges(); repository.getATRepository().pruneAtStates(0, 900); repository.getATRepository().setAtPruneHeight(901); diff --git a/src/test/java/org/qortal/test/PruneTests.java b/src/test/java/org/qortal/test/PruneTests.java index 0914d794..5a31146e 100644 --- a/src/test/java/org/qortal/test/PruneTests.java +++ b/src/test/java/org/qortal/test/PruneTests.java @@ -1,16 +1,33 @@ package org.qortal.test; +import com.google.common.hash.HashCode; import org.junit.Before; import org.junit.Test; +import org.qortal.account.Account; import org.qortal.account.PrivateKeyAccount; +import org.qortal.asset.Asset; +import org.qortal.block.Block; import org.qortal.controller.BlockMinter; +import org.qortal.crosschain.AcctMode; +import org.qortal.crosschain.LitecoinACCTv3; +import org.qortal.data.at.ATData; import org.qortal.data.at.ATStateData; import org.qortal.data.block.BlockData; +import org.qortal.data.crosschain.CrossChainTradeData; +import org.qortal.data.transaction.BaseTransactionData; +import org.qortal.data.transaction.DeployAtTransactionData; +import org.qortal.data.transaction.MessageTransactionData; +import org.qortal.data.transaction.TransactionData; +import org.qortal.group.Group; import org.qortal.repository.DataException; import org.qortal.repository.Repository; import org.qortal.repository.RepositoryManager; import org.qortal.test.common.AtUtils; +import org.qortal.test.common.BlockUtils; import org.qortal.test.common.Common; +import org.qortal.test.common.TransactionUtils; +import org.qortal.transaction.DeployAtTransaction; +import org.qortal.transaction.MessageTransaction; import java.util.ArrayList; import java.util.List; @@ -19,6 +36,13 @@ import static org.junit.Assert.*; public class PruneTests extends Common { + // Constants for test AT (an LTC ACCT) + public static final byte[] litecoinPublicKeyHash = HashCode.fromString("bb00bb11bb22bb33bb44bb55bb66bb77bb88bb99").asBytes(); + public static final int tradeTimeout = 20; // blocks + public static final long redeemAmount = 80_40200000L; + public static final long fundingAmount = 123_45600000L; + public static final long litecoinAmount = 864200L; // 0.00864200 LTC + @Before public void beforeTest() throws DataException { Common.useDefaultSettings(); @@ -62,23 +86,32 @@ public class PruneTests extends Common { repository.getBlockRepository().setBlockPruneHeight(6); // Prune AT states for blocks 2-5 + repository.getATRepository().rebuildLatestAtStates(5); + repository.saveChanges(); int numATStatesPruned = repository.getATRepository().pruneAtStates(0, 5); - assertEquals(4, numATStatesPruned); + assertEquals(3, numATStatesPruned); repository.getATRepository().setAtPruneHeight(6); - // Make sure that blocks 2-5 are now missing block data and AT states data - for (Integer i=2; i <= 5; i++) { + // Make sure that blocks 2-4 are now missing block data and AT states data + for (Integer i=2; i <= 4; i++) { BlockData blockData = repository.getBlockRepository().fromHeight(i); assertNull(blockData); List atStatesDataList = repository.getATRepository().getBlockATStatesAtHeight(i); assertTrue(atStatesDataList.isEmpty()); } - // ... but blocks 6-10 have block data and full AT states data + // Block 5 should have full AT states data even though it was pruned. + // This is because we identified that as the "latest" AT state in that block range + BlockData blockData = repository.getBlockRepository().fromHeight(5); + assertNull(blockData); + List atStatesDataList = repository.getATRepository().getBlockATStatesAtHeight(5); + assertEquals(1, atStatesDataList.size()); + + // Blocks 6-10 have block data and full AT states data for (Integer i=6; i <= 10; i++) { - BlockData blockData = repository.getBlockRepository().fromHeight(i); + blockData = repository.getBlockRepository().fromHeight(i); assertNotNull(blockData.getSignature()); - List atStatesDataList = repository.getATRepository().getBlockATStatesAtHeight(i); + atStatesDataList = repository.getATRepository().getBlockATStatesAtHeight(i); assertNotNull(atStatesDataList); assertFalse(atStatesDataList.isEmpty()); ATStateData atStatesData = repository.getATRepository().getATStateAtHeight(atStatesDataList.get(0).getATAddress(), i); @@ -88,4 +121,102 @@ public class PruneTests extends Common { } } + @Test + public void testPruneSleepingAt() throws DataException { + try (final Repository repository = RepositoryManager.getRepository()) { + PrivateKeyAccount deployer = Common.getTestAccount(repository, "chloe"); + PrivateKeyAccount tradeAccount = Common.getTestAccount(repository, "alice"); + + DeployAtTransaction deployAtTransaction = doDeploy(repository, deployer, tradeAccount.getAddress()); + Account at = deployAtTransaction.getATAccount(); + String atAddress = at.getAddress(); + + // Mint enough blocks to take the original DEPLOY_AT past the prune threshold (in this case 20) + Block block = BlockUtils.mintBlocks(repository, 25); + + // Send creator's address to AT, instead of typical partner's address + byte[] messageData = LitecoinACCTv3.getInstance().buildCancelMessage(deployer.getAddress()); + long txTimestamp = block.getBlockData().getTimestamp(); + MessageTransaction messageTransaction = sendMessage(repository, deployer, messageData, atAddress, txTimestamp); + + // AT should process 'cancel' message in next block + BlockUtils.mintBlock(repository); + + // Prune AT states up to block 20 + repository.getATRepository().rebuildLatestAtStates(20); + repository.saveChanges(); + int numATStatesPruned = repository.getATRepository().pruneAtStates(0, 20); + assertEquals(1, numATStatesPruned); // deleted state at heights 2, but state at height 3 remains + + // Check AT is finished + ATData atData = repository.getATRepository().fromATAddress(atAddress); + assertTrue(atData.getIsFinished()); + + // AT should be in CANCELLED mode + CrossChainTradeData tradeData = LitecoinACCTv3.getInstance().populateTradeData(repository, atData); + assertEquals(AcctMode.CANCELLED, tradeData.mode); + + // Test orphaning - should be possible because the previous AT state at height 3 is still available + BlockUtils.orphanLastBlock(repository); + } + } + + + // Helper methods for AT testing + private DeployAtTransaction doDeploy(Repository repository, PrivateKeyAccount deployer, String tradeAddress) throws DataException { + byte[] creationBytes = LitecoinACCTv3.buildQortalAT(tradeAddress, litecoinPublicKeyHash, redeemAmount, litecoinAmount, tradeTimeout); + + long txTimestamp = System.currentTimeMillis(); + byte[] lastReference = deployer.getLastReference(); + + if (lastReference == null) { + System.err.println(String.format("Qortal account %s has no last reference", deployer.getAddress())); + System.exit(2); + } + + Long fee = null; + String name = "QORT-LTC cross-chain trade"; + String description = String.format("Qortal-Litecoin cross-chain trade"); + String atType = "ACCT"; + String tags = "QORT-LTC ACCT"; + + BaseTransactionData baseTransactionData = new BaseTransactionData(txTimestamp, Group.NO_GROUP, lastReference, deployer.getPublicKey(), fee, null); + TransactionData deployAtTransactionData = new DeployAtTransactionData(baseTransactionData, name, description, atType, tags, creationBytes, fundingAmount, Asset.QORT); + + DeployAtTransaction deployAtTransaction = new DeployAtTransaction(repository, deployAtTransactionData); + + fee = deployAtTransaction.calcRecommendedFee(); + deployAtTransactionData.setFee(fee); + + TransactionUtils.signAndMint(repository, deployAtTransactionData, deployer); + + return deployAtTransaction; + } + + private MessageTransaction sendMessage(Repository repository, PrivateKeyAccount sender, byte[] data, String recipient, long txTimestamp) throws DataException { + byte[] lastReference = sender.getLastReference(); + + if (lastReference == null) { + System.err.println(String.format("Qortal account %s has no last reference", sender.getAddress())); + System.exit(2); + } + + Long fee = null; + int version = 4; + int nonce = 0; + long amount = 0; + Long assetId = null; // because amount is zero + + BaseTransactionData baseTransactionData = new BaseTransactionData(txTimestamp, Group.NO_GROUP, lastReference, sender.getPublicKey(), fee, null); + TransactionData messageTransactionData = new MessageTransactionData(baseTransactionData, version, nonce, recipient, amount, assetId, data, false, false); + + MessageTransaction messageTransaction = new MessageTransaction(repository, messageTransactionData); + + fee = messageTransaction.calcRecommendedFee(); + messageTransactionData.setFee(fee); + + TransactionUtils.signAndMint(repository, messageTransactionData, sender); + + return messageTransaction; + } } diff --git a/src/test/java/org/qortal/test/at/AtRepositoryTests.java b/src/test/java/org/qortal/test/at/AtRepositoryTests.java index 8ef4c774..8441731f 100644 --- a/src/test/java/org/qortal/test/at/AtRepositoryTests.java +++ b/src/test/java/org/qortal/test/at/AtRepositoryTests.java @@ -2,29 +2,20 @@ package org.qortal.test.at; import static org.junit.Assert.*; -import java.nio.ByteBuffer; import java.util.List; -import org.ciyam.at.CompilationException; import org.ciyam.at.MachineState; -import org.ciyam.at.OpCode; import org.junit.Before; import org.junit.Test; import org.qortal.account.PrivateKeyAccount; -import org.qortal.asset.Asset; import org.qortal.data.at.ATData; import org.qortal.data.at.ATStateData; -import org.qortal.data.transaction.BaseTransactionData; -import org.qortal.data.transaction.DeployAtTransactionData; -import org.qortal.data.transaction.TransactionData; -import org.qortal.group.Group; import org.qortal.repository.DataException; import org.qortal.repository.Repository; import org.qortal.repository.RepositoryManager; import org.qortal.test.common.AtUtils; import org.qortal.test.common.BlockUtils; import org.qortal.test.common.Common; -import org.qortal.test.common.TransactionUtils; import org.qortal.transaction.DeployAtTransaction; public class AtRepositoryTests extends Common { @@ -76,7 +67,7 @@ public class AtRepositoryTests extends Common { Integer testHeight = maxHeight - 2; // Trim AT state data - repository.getATRepository().rebuildLatestAtStates(); + repository.getATRepository().rebuildLatestAtStates(maxHeight); repository.getATRepository().trimAtStates(2, maxHeight, 1000); ATStateData atStateData = repository.getATRepository().getATStateAtHeight(atAddress, testHeight); @@ -130,7 +121,7 @@ public class AtRepositoryTests extends Common { Integer testHeight = blockchainHeight; // Trim AT state data - repository.getATRepository().rebuildLatestAtStates(); + repository.getATRepository().rebuildLatestAtStates(maxHeight); // COMMIT to check latest AT states persist / TEMPORARY table interaction repository.saveChanges(); @@ -163,8 +154,8 @@ public class AtRepositoryTests extends Common { int maxTrimHeight = blockchainHeight - 4; Integer testHeight = maxTrimHeight + 1; - // Trim AT state data - repository.getATRepository().rebuildLatestAtStates(); + // Trim AT state data (using a max height of maxTrimHeight + 1, so it is beyond the trimmed range) + repository.getATRepository().rebuildLatestAtStates(maxTrimHeight + 1); repository.saveChanges(); repository.getATRepository().trimAtStates(2, maxTrimHeight, 1000); @@ -333,7 +324,7 @@ public class AtRepositoryTests extends Common { Integer testHeight = maxHeight - 2; // Trim AT state data - repository.getATRepository().rebuildLatestAtStates(); + repository.getATRepository().rebuildLatestAtStates(maxHeight); repository.getATRepository().trimAtStates(2, maxHeight, 1000); List atStates = repository.getATRepository().getBlockATStatesAtHeight(testHeight); diff --git a/src/test/java/org/qortal/test/common/BlockUtils.java b/src/test/java/org/qortal/test/common/BlockUtils.java index 3077b65b..ab57dadf 100644 --- a/src/test/java/org/qortal/test/common/BlockUtils.java +++ b/src/test/java/org/qortal/test/common/BlockUtils.java @@ -20,6 +20,15 @@ public class BlockUtils { return BlockMinter.mintTestingBlock(repository, mintingAccount); } + /** Mints multiple blocks using "alice-reward-share" test account, and returns the final block. */ + public static Block mintBlocks(Repository repository, int count) throws DataException { + Block block = null; + for (int i=0; i Date: Sun, 15 Jan 2023 15:51:10 +0000 Subject: [PATCH 06/31] Fixed bug causing initial latestATStates data to be discarded. --- .../java/org/qortal/controller/repository/AtStatesPruner.java | 1 + .../java/org/qortal/controller/repository/AtStatesTrimmer.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/org/qortal/controller/repository/AtStatesPruner.java b/src/main/java/org/qortal/controller/repository/AtStatesPruner.java index 1faeda98..f06efdb8 100644 --- a/src/main/java/org/qortal/controller/repository/AtStatesPruner.java +++ b/src/main/java/org/qortal/controller/repository/AtStatesPruner.java @@ -43,6 +43,7 @@ public class AtStatesPruner implements Runnable { repository.discardChanges(); repository.getATRepository().rebuildLatestAtStates(maxLatestAtStatesHeight); + repository.saveChanges(); while (!Controller.isStopping()) { repository.discardChanges(); diff --git a/src/main/java/org/qortal/controller/repository/AtStatesTrimmer.java b/src/main/java/org/qortal/controller/repository/AtStatesTrimmer.java index ea56699c..125628f1 100644 --- a/src/main/java/org/qortal/controller/repository/AtStatesTrimmer.java +++ b/src/main/java/org/qortal/controller/repository/AtStatesTrimmer.java @@ -30,6 +30,7 @@ public class AtStatesTrimmer implements Runnable { repository.discardChanges(); repository.getATRepository().rebuildLatestAtStates(maxLatestAtStatesHeight); + repository.saveChanges(); while (!Controller.isStopping()) { repository.discardChanges(); From 21f5d9a3d06089717be29fc517e07ce1c35c9ba1 Mon Sep 17 00:00:00 2001 From: QuickMythril Date: Tue, 31 Jan 2023 17:23:25 -0500 Subject: [PATCH 07/31] Add foreign chain height to API calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GET ​/crosschain​/{COIN}/height --- .../resource/CrossChainBitcoinResource.java | 32 +++++++++++++++++++ .../resource/CrossChainDigibyteResource.java | 32 +++++++++++++++++++ .../resource/CrossChainDogecoinResource.java | 32 +++++++++++++++++++ .../resource/CrossChainLitecoinResource.java | 32 +++++++++++++++++++ .../CrossChainPirateChainResource.java | 32 +++++++++++++++++++ .../resource/CrossChainRavencoinResource.java | 32 +++++++++++++++++++ .../java/org/qortal/crosschain/Bitcoiny.java | 10 ++++++ 7 files changed, 202 insertions(+) diff --git a/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java index dd967451..80f9ff04 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java @@ -14,6 +14,7 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; +import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; @@ -35,6 +36,37 @@ public class CrossChainBitcoinResource { @Context HttpServletRequest request; + @GET + @Path("/height") + @Operation( + summary = "Returns current Bitcoin block height", + description = "Returns the height of the most recent block in the Bitcoin chain.", + responses = { + @ApiResponse( + content = @Content( + schema = @Schema( + type = "number" + ) + ) + ) + } + ) + @ApiErrors({ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + public String getBitcoinHeight() { + Bitcoin bitcoin = Bitcoin.getInstance(); + + try { + Integer height = bitcoin.getBlockchainHeight(); + if (height == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + + return height.toString(); + + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } + } + @POST @Path("/walletbalance") @Operation( diff --git a/src/main/java/org/qortal/api/resource/CrossChainDigibyteResource.java b/src/main/java/org/qortal/api/resource/CrossChainDigibyteResource.java index 31d51c73..e315947a 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainDigibyteResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainDigibyteResource.java @@ -14,6 +14,7 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; +import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; @@ -35,6 +36,37 @@ public class CrossChainDigibyteResource { @Context HttpServletRequest request; + @GET + @Path("/height") + @Operation( + summary = "Returns current Digibyte block height", + description = "Returns the height of the most recent block in the Digibyte chain.", + responses = { + @ApiResponse( + content = @Content( + schema = @Schema( + type = "number" + ) + ) + ) + } + ) + @ApiErrors({ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + public String getDigibyteHeight() { + Digibyte digibyte = Digibyte.getInstance(); + + try { + Integer height = digibyte.getBlockchainHeight(); + if (height == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + + return height.toString(); + + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } + } + @POST @Path("/walletbalance") @Operation( diff --git a/src/main/java/org/qortal/api/resource/CrossChainDogecoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainDogecoinResource.java index 28bebfb8..602d131b 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainDogecoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainDogecoinResource.java @@ -21,6 +21,7 @@ import org.qortal.crosschain.SimpleTransaction; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; +import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; @@ -33,6 +34,37 @@ public class CrossChainDogecoinResource { @Context HttpServletRequest request; + @GET + @Path("/height") + @Operation( + summary = "Returns current Dogecoin block height", + description = "Returns the height of the most recent block in the Dogecoin chain.", + responses = { + @ApiResponse( + content = @Content( + schema = @Schema( + type = "number" + ) + ) + ) + } + ) + @ApiErrors({ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + public String getDogecoinHeight() { + Dogecoin dogecoin = Dogecoin.getInstance(); + + try { + Integer height = dogecoin.getBlockchainHeight(); + if (height == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + + return height.toString(); + + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } + } + @POST @Path("/walletbalance") @Operation( diff --git a/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java index d12dd94c..653cc2ec 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java @@ -14,6 +14,7 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; +import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; @@ -35,6 +36,37 @@ public class CrossChainLitecoinResource { @Context HttpServletRequest request; + @GET + @Path("/height") + @Operation( + summary = "Returns current Litecoin block height", + description = "Returns the height of the most recent block in the Litecoin chain.", + responses = { + @ApiResponse( + content = @Content( + schema = @Schema( + type = "number" + ) + ) + ) + } + ) + @ApiErrors({ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + public String getLitecoinHeight() { + Litecoin litecoin = Litecoin.getInstance(); + + try { + Integer height = litecoin.getBlockchainHeight(); + if (height == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + + return height.toString(); + + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } + } + @POST @Path("/walletbalance") @Operation( diff --git a/src/main/java/org/qortal/api/resource/CrossChainPirateChainResource.java b/src/main/java/org/qortal/api/resource/CrossChainPirateChainResource.java index bd7bf57d..6989e7c7 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainPirateChainResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainPirateChainResource.java @@ -20,6 +20,7 @@ import org.qortal.crosschain.SimpleTransaction; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; +import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; @@ -32,6 +33,37 @@ public class CrossChainPirateChainResource { @Context HttpServletRequest request; + @GET + @Path("/height") + @Operation( + summary = "Returns current PirateChain block height", + description = "Returns the height of the most recent block in the PirateChain chain.", + responses = { + @ApiResponse( + content = @Content( + schema = @Schema( + type = "number" + ) + ) + ) + } + ) + @ApiErrors({ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + public String getPirateChainHeight() { + PirateChain pirateChain = PirateChain.getInstance(); + + try { + Integer height = pirateChain.getBlockchainHeight(); + if (height == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + + return height.toString(); + + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } + } + @POST @Path("/walletbalance") @Operation( diff --git a/src/main/java/org/qortal/api/resource/CrossChainRavencoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainRavencoinResource.java index 97550392..9e76b8a2 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainRavencoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainRavencoinResource.java @@ -14,6 +14,7 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; +import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; @@ -35,6 +36,37 @@ public class CrossChainRavencoinResource { @Context HttpServletRequest request; + @GET + @Path("/height") + @Operation( + summary = "Returns current Ravencoin block height", + description = "Returns the height of the most recent block in the Ravencoin chain.", + responses = { + @ApiResponse( + content = @Content( + schema = @Schema( + type = "number" + ) + ) + ) + } + ) + @ApiErrors({ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + public String getRavencoinHeight() { + Ravencoin ravencoin = Ravencoin.getInstance(); + + try { + Integer height = ravencoin.getBlockchainHeight(); + if (height == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + + return height.toString(); + + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } + } + @POST @Path("/walletbalance") @Operation( diff --git a/src/main/java/org/qortal/crosschain/Bitcoiny.java b/src/main/java/org/qortal/crosschain/Bitcoiny.java index c08bd91e..d1523b50 100644 --- a/src/main/java/org/qortal/crosschain/Bitcoiny.java +++ b/src/main/java/org/qortal/crosschain/Bitcoiny.java @@ -167,6 +167,16 @@ public abstract class Bitcoiny implements ForeignBlockchain { return blockTimestamps.get(5); } + /** + * Returns height from latest block. + *

+ * @throws ForeignBlockchainException if error occurs + */ + public int getBlockchainHeight() throws ForeignBlockchainException { + int height = this.blockchainProvider.getCurrentHeight(); + return height; + } + /** Returns fee per transaction KB. To be overridden for testnet/regtest. */ public Coin getFeePerKb() { return this.bitcoinjContext.getFeePerKb(); From 1f410a503e985122ee7c344bab2b29aafbcc0de3 Mon Sep 17 00:00:00 2001 From: QuickMythril Date: Sat, 4 Feb 2023 18:30:31 -0500 Subject: [PATCH 08/31] Updated ElectrumX servers --- .../java/org/qortal/crosschain/Bitcoin.java | 54 +++++++++++++++++-- .../java/org/qortal/crosschain/Digibyte.java | 1 + .../java/org/qortal/crosschain/Dogecoin.java | 7 +-- .../java/org/qortal/crosschain/Litecoin.java | 9 ++-- .../java/org/qortal/crosschain/Ravencoin.java | 12 +++-- 5 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/qortal/crosschain/Bitcoin.java b/src/main/java/org/qortal/crosschain/Bitcoin.java index 7fec5a17..b65bac8e 100644 --- a/src/main/java/org/qortal/crosschain/Bitcoin.java +++ b/src/main/java/org/qortal/crosschain/Bitcoin.java @@ -49,6 +49,7 @@ public class Bitcoin extends Bitcoiny { //CLOSED new Server("bitcoin.grey.pw", Server.ConnectionType.SSL, 50002), //CLOSED new Server("btc.litepay.ch", Server.ConnectionType.SSL, 50002), //CLOSED new Server("electrum.pabu.io", Server.ConnectionType.SSL, 50002), + //CLOSED new Server("electrumx.dev", Server.ConnectionType.SSL, 50002), //CLOSED new Server("electrumx.hodlwallet.com", Server.ConnectionType.SSL, 50002), //CLOSED new Server("gd42.org", Server.ConnectionType.SSL, 50002), //CLOSED new Server("korea.electrum-server.com", Server.ConnectionType.SSL, 50002), @@ -56,28 +57,75 @@ public class Bitcoin extends Bitcoiny { //1.15.0 new Server("alviss.coinjoined.com", Server.ConnectionType.SSL, 50002), //1.15.0 new Server("electrum.acinq.co", Server.ConnectionType.SSL, 50002), //1.14.0 new Server("electrum.coinext.com.br", Server.ConnectionType.SSL, 50002), + //F1.7.0 new Server("btc.lastingcoin.net", Server.ConnectionType.SSL, 50002), new Server("104.248.139.211", Server.ConnectionType.SSL, 50002), + new Server("128.0.190.26", Server.ConnectionType.SSL, 50002), new Server("142.93.6.38", Server.ConnectionType.SSL, 50002), new Server("157.245.172.236", Server.ConnectionType.SSL, 50002), new Server("167.172.226.175", Server.ConnectionType.SSL, 50002), new Server("167.172.42.31", Server.ConnectionType.SSL, 50002), new Server("178.62.80.20", Server.ConnectionType.SSL, 50002), new Server("185.64.116.15", Server.ConnectionType.SSL, 50002), + new Server("188.165.206.215", Server.ConnectionType.SSL, 50002), + new Server("188.165.211.112", Server.ConnectionType.SSL, 50002), + new Server("2azzarita.hopto.org", Server.ConnectionType.SSL, 50002), + new Server("2electrumx.hopto.me", Server.ConnectionType.SSL, 56022), + new Server("2ex.digitaleveryware.com", Server.ConnectionType.SSL, 50002), + new Server("65.39.140.37", Server.ConnectionType.SSL, 50002), new Server("68.183.188.105", Server.ConnectionType.SSL, 50002), + new Server("71.73.14.254", Server.ConnectionType.SSL, 50002), + new Server("94.23.247.135", Server.ConnectionType.SSL, 50002), + new Server("assuredly.not.fyi", Server.ConnectionType.SSL, 50002), + new Server("ax101.blockeng.ch", Server.ConnectionType.SSL, 50002), + new Server("ax102.blockeng.ch", Server.ConnectionType.SSL, 50002), + new Server("b.1209k.com", Server.ConnectionType.SSL, 50002), + new Server("b6.1209k.com", Server.ConnectionType.SSL, 50002), + new Server("bitcoin.dermichi.com", Server.ConnectionType.SSL, 50002), + new Server("bitcoin.lu.ke", Server.ConnectionType.SSL, 50002), new Server("bitcoin.lukechilds.co", Server.ConnectionType.SSL, 50002), new Server("blkhub.net", Server.ConnectionType.SSL, 50002), - new Server("btc.lastingcoin.net", Server.ConnectionType.SSL, 50002), + new Server("btc.electroncash.dk", Server.ConnectionType.SSL, 60002), + new Server("btc.ocf.sh", Server.ConnectionType.SSL, 50002), new Server("btce.iiiiiii.biz", Server.ConnectionType.SSL, 50002), new Server("caleb.vegas", Server.ConnectionType.SSL, 50002), new Server("eai.coincited.net", Server.ConnectionType.SSL, 50002), + new Server("electrum.bhoovd.com", Server.ConnectionType.SSL, 50002), new Server("electrum.bitaroo.net", Server.ConnectionType.SSL, 50002), - new Server("electrumx.dev", Server.ConnectionType.SSL, 50002), + new Server("electrum.bitcoinlizard.net", Server.ConnectionType.SSL, 50002), + new Server("electrum.blockstream.info", Server.ConnectionType.SSL, 50002), + new Server("electrum.emzy.de", Server.ConnectionType.SSL, 50002), + new Server("electrum.exan.tech", Server.ConnectionType.SSL, 50002), + new Server("electrum.kendigisland.xyz", Server.ConnectionType.SSL, 50002), + new Server("electrum.mmitech.info", Server.ConnectionType.SSL, 50002), + new Server("electrum.petrkr.net", Server.ConnectionType.SSL, 50002), + new Server("electrum.stippy.com", Server.ConnectionType.SSL, 50002), + new Server("electrum.thomasfischbach.de", Server.ConnectionType.SSL, 50002), + new Server("electrum0.snel.it", Server.ConnectionType.SSL, 50002), + new Server("electrum1.cipig.net", Server.ConnectionType.SSL, 50002), + new Server("electrum2.cipig.net", Server.ConnectionType.SSL, 50002), + new Server("electrum3.cipig.net", Server.ConnectionType.SSL, 50002), + new Server("electrumx.alexridevski.net", Server.ConnectionType.SSL, 50002), + new Server("electrumx-core.1209k.com", Server.ConnectionType.SSL, 50002), new Server("elx.bitske.com", Server.ConnectionType.SSL, 50002), + new Server("ex03.axalgo.com", Server.ConnectionType.SSL, 50002), + new Server("ex05.axalgo.com", Server.ConnectionType.SSL, 50002), + new Server("ex07.axalgo.com", Server.ConnectionType.SSL, 50002), new Server("fortress.qtornado.com", Server.ConnectionType.SSL, 50002), + new Server("fulcrum.grey.pw", Server.ConnectionType.SSL, 50002), + new Server("fulcrum.sethforprivacy.com", Server.ConnectionType.SSL, 51002), new Server("guichet.centure.cc", Server.ConnectionType.SSL, 50002), - new Server("kareoke.qoppa.org", Server.ConnectionType.SSL, 50002), new Server("hodlers.beer", Server.ConnectionType.SSL, 50002), + new Server("kareoke.qoppa.org", Server.ConnectionType.SSL, 50002), + new Server("kirsche.emzy.de", Server.ConnectionType.SSL, 50002), new Server("node1.btccuracao.com", Server.ConnectionType.SSL, 50002), + new Server("osr1ex1.compumundohipermegared.one", Server.ConnectionType.SSL, 50002), + new Server("smmalis37.ddns.net", Server.ConnectionType.SSL, 50002), + new Server("ulrichard.ch", Server.ConnectionType.SSL, 50002), + new Server("vmd104012.contaboserver.net", Server.ConnectionType.SSL, 50002), + new Server("vmd104014.contaboserver.net", Server.ConnectionType.SSL, 50002), + new Server("vmd63185.contaboserver.net", Server.ConnectionType.SSL, 50002), + new Server("vmd71287.contaboserver.net", Server.ConnectionType.SSL, 50002), + new Server("vmd84592.contaboserver.net", Server.ConnectionType.SSL, 50002), new Server("xtrum.com", Server.ConnectionType.SSL, 50002)); } diff --git a/src/main/java/org/qortal/crosschain/Digibyte.java b/src/main/java/org/qortal/crosschain/Digibyte.java index 4358b3b3..42ab2a5a 100644 --- a/src/main/java/org/qortal/crosschain/Digibyte.java +++ b/src/main/java/org/qortal/crosschain/Digibyte.java @@ -45,6 +45,7 @@ public class Digibyte extends Bitcoiny { return Arrays.asList( // Servers chosen on NO BASIS WHATSOEVER from various sources! // Status verified at https://1209k.com/bitcoin-eye/ele.php?chain=dgb + new Server("electrum-dgb.qortal.online", ConnectionType.SSL, 50002), new Server("electrum1.cipig.net", ConnectionType.SSL, 20059), new Server("electrum2.cipig.net", ConnectionType.SSL, 20059), new Server("electrum3.cipig.net", ConnectionType.SSL, 20059)); diff --git a/src/main/java/org/qortal/crosschain/Dogecoin.java b/src/main/java/org/qortal/crosschain/Dogecoin.java index 9af8d990..5bdbeed8 100644 --- a/src/main/java/org/qortal/crosschain/Dogecoin.java +++ b/src/main/java/org/qortal/crosschain/Dogecoin.java @@ -45,11 +45,12 @@ public class Dogecoin extends Bitcoiny { public Collection getServers() { return Arrays.asList( // Servers chosen on NO BASIS WHATSOEVER from various sources! + // Status verified at https://1209k.com/bitcoin-eye/ele.php?chain=doge + new Server("161.97.137.235", ConnectionType.SSL, 50002), + new Server("electrum-doge.qortal.online", ConnectionType.SSL, 50002), new Server("electrum1.cipig.net", ConnectionType.SSL, 20060), new Server("electrum2.cipig.net", ConnectionType.SSL, 20060), - new Server("electrum3.cipig.net", ConnectionType.SSL, 20060), - new Server("161.97.137.235", ConnectionType.SSL, 50002)); - // TODO: add more mainnet servers. It's too centralized. + new Server("electrum3.cipig.net", ConnectionType.SSL, 20060)); } @Override diff --git a/src/main/java/org/qortal/crosschain/Litecoin.java b/src/main/java/org/qortal/crosschain/Litecoin.java index 6fc6ba50..33650d81 100644 --- a/src/main/java/org/qortal/crosschain/Litecoin.java +++ b/src/main/java/org/qortal/crosschain/Litecoin.java @@ -45,17 +45,18 @@ public class Litecoin extends Bitcoiny { return Arrays.asList( // Servers chosen on NO BASIS WHATSOEVER from various sources! // Status verified at https://1209k.com/bitcoin-eye/ele.php?chain=ltc - //CLOSED new Server("electrum-ltc.petrkr.net", Server.ConnectionType.SSL, 60002), //CLOSED new Server("electrum-ltc.someguy123.net", Server.ConnectionType.SSL, 50002), + //CLOSED new Server("ltc.litepay.ch", Server.ConnectionType.SSL, 50022), + //BEHIND new Server("62.171.169.176", Server.ConnectionType.SSL, 50002), //PHISHY new Server("electrum-ltc.bysh.me", Server.ConnectionType.SSL, 50002), new Server("backup.electrum-ltc.org", Server.ConnectionType.SSL, 443), new Server("electrum.ltc.xurious.com", Server.ConnectionType.SSL, 50002), + new Server("electrum-ltc.petrkr.net", Server.ConnectionType.SSL, 60002), + new Server("electrum-ltc.qortal.online", Server.ConnectionType.SSL, 50002), new Server("electrum1.cipig.net", Server.ConnectionType.SSL, 20063), new Server("electrum2.cipig.net", Server.ConnectionType.SSL, 20063), new Server("electrum3.cipig.net", Server.ConnectionType.SSL, 20063), - new Server("ltc.litepay.ch", Server.ConnectionType.SSL, 50022), - new Server("ltc.rentonrisk.com", Server.ConnectionType.SSL, 50002), - new Server("62.171.169.176", Server.ConnectionType.SSL, 50002)); + new Server("ltc.rentonrisk.com", Server.ConnectionType.SSL, 50002)); } @Override diff --git a/src/main/java/org/qortal/crosschain/Ravencoin.java b/src/main/java/org/qortal/crosschain/Ravencoin.java index 7bf5b20f..9735f51c 100644 --- a/src/main/java/org/qortal/crosschain/Ravencoin.java +++ b/src/main/java/org/qortal/crosschain/Ravencoin.java @@ -45,13 +45,15 @@ public class Ravencoin extends Bitcoiny { return Arrays.asList( // Servers chosen on NO BASIS WHATSOEVER from various sources! // Status verified at https://1209k.com/bitcoin-eye/ele.php?chain=rvn - new Server("aethyn.com", ConnectionType.SSL, 50002), - new Server("electrum2.rvn.rocks", ConnectionType.SSL, 50002), - new Server("rvn-dashboard.com", ConnectionType.SSL, 50002), - new Server("rvn4lyfe.com", ConnectionType.SSL, 50002), + //CLOSED new Server("aethyn.com", ConnectionType.SSL, 50002), + //CLOSED new Server("electrum2.rvn.rocks", ConnectionType.SSL, 50002), + //BEHIND new Server("electrum3.rvn.rocks", ConnectionType.SSL, 50002), + new Server("electrum-rvn.qortal.online", ConnectionType.SSL, 50002), new Server("electrum1.cipig.net", ConnectionType.SSL, 20051), new Server("electrum2.cipig.net", ConnectionType.SSL, 20051), - new Server("electrum3.cipig.net", ConnectionType.SSL, 20051)); + new Server("electrum3.cipig.net", ConnectionType.SSL, 20051), + new Server("rvn-dashboard.com", ConnectionType.SSL, 50002), + new Server("rvn4lyfe.com", ConnectionType.SSL, 50002)); } @Override From 30c9f63cb1c03b8382cae7be7f4406d53c0d0f68 Mon Sep 17 00:00:00 2001 From: QuickMythril Date: Sat, 4 Feb 2023 21:03:55 -0500 Subject: [PATCH 09/31] Add unused foreign address to API calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit POST ​/crosschain​/{COIN}/unusedaddress --- .../resource/CrossChainBitcoinResource.java | 39 +++++++++++++++++++ .../resource/CrossChainDigibyteResource.java | 39 +++++++++++++++++++ .../resource/CrossChainDogecoinResource.java | 39 +++++++++++++++++++ .../resource/CrossChainLitecoinResource.java | 39 +++++++++++++++++++ .../resource/CrossChainRavencoinResource.java | 39 +++++++++++++++++++ 5 files changed, 195 insertions(+) diff --git a/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java index 80f9ff04..1e276e59 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainBitcoinResource.java @@ -150,6 +150,45 @@ public class CrossChainBitcoinResource { } } + @POST + @Path("/unusedaddress") + @Operation( + summary = "Returns first unused address for hierarchical, deterministic BIP32 wallet", + description = "Supply BIP32 'm' private/public key in base58, starting with 'xprv'/'xpub' for mainnet, 'tprv'/'tpub' for testnet", + requestBody = @RequestBody( + required = true, + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string", + description = "BIP32 'm' private/public key in base58", + example = "tpubD6NzVbkrYhZ4XTPc4btCZ6SMgn8CxmWkj6VBVZ1tfcJfMq4UwAjZbG8U74gGSypL9XBYk2R2BLbDBe8pcEyBKM1edsGQEPKXNbEskZozeZc" + ) + ) + ), + responses = { + @ApiResponse( + content = @Content(array = @ArraySchema( schema = @Schema( implementation = SimpleTransaction.class ) ) ) + ) + } + ) + @ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + @SecurityRequirement(name = "apiKey") + public String getUnusedBitcoinReceiveAddress(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String key58) { + Security.checkApiCallAllowed(request); + + Bitcoin bitcoin = Bitcoin.getInstance(); + + if (!bitcoin.isValidDeterministicKey(key58)) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY); + + try { + return bitcoin.getUnusedReceiveAddress(key58); + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } + } + @POST @Path("/send") @Operation( diff --git a/src/main/java/org/qortal/api/resource/CrossChainDigibyteResource.java b/src/main/java/org/qortal/api/resource/CrossChainDigibyteResource.java index e315947a..781d78f6 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainDigibyteResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainDigibyteResource.java @@ -150,6 +150,45 @@ public class CrossChainDigibyteResource { } } + @POST + @Path("/unusedaddress") + @Operation( + summary = "Returns first unused address for hierarchical, deterministic BIP32 wallet", + description = "Supply BIP32 'm' private/public key in base58, starting with 'xprv'/'xpub' for mainnet, 'tprv'/'tpub' for testnet", + requestBody = @RequestBody( + required = true, + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string", + description = "BIP32 'm' private/public key in base58", + example = "tpubD6NzVbkrYhZ4XTPc4btCZ6SMgn8CxmWkj6VBVZ1tfcJfMq4UwAjZbG8U74gGSypL9XBYk2R2BLbDBe8pcEyBKM1edsGQEPKXNbEskZozeZc" + ) + ) + ), + responses = { + @ApiResponse( + content = @Content(array = @ArraySchema( schema = @Schema( implementation = SimpleTransaction.class ) ) ) + ) + } + ) + @ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + @SecurityRequirement(name = "apiKey") + public String getUnusedDigibyteReceiveAddress(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String key58) { + Security.checkApiCallAllowed(request); + + Digibyte digibyte = Digibyte.getInstance(); + + if (!digibyte.isValidDeterministicKey(key58)) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY); + + try { + return digibyte.getUnusedReceiveAddress(key58); + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } + } + @POST @Path("/send") @Operation( diff --git a/src/main/java/org/qortal/api/resource/CrossChainDogecoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainDogecoinResource.java index 602d131b..ff1d6d14 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainDogecoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainDogecoinResource.java @@ -148,6 +148,45 @@ public class CrossChainDogecoinResource { } } + @POST + @Path("/unusedaddress") + @Operation( + summary = "Returns first unused address for hierarchical, deterministic BIP32 wallet", + description = "Supply BIP32 'm' private/public key in base58, starting with 'xprv'/'xpub' for mainnet, 'tprv'/'tpub' for testnet", + requestBody = @RequestBody( + required = true, + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string", + description = "BIP32 'm' private/public key in base58", + example = "tpubD6NzVbkrYhZ4XTPc4btCZ6SMgn8CxmWkj6VBVZ1tfcJfMq4UwAjZbG8U74gGSypL9XBYk2R2BLbDBe8pcEyBKM1edsGQEPKXNbEskZozeZc" + ) + ) + ), + responses = { + @ApiResponse( + content = @Content(array = @ArraySchema( schema = @Schema( implementation = SimpleTransaction.class ) ) ) + ) + } + ) + @ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + @SecurityRequirement(name = "apiKey") + public String getUnusedDogecoinReceiveAddress(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String key58) { + Security.checkApiCallAllowed(request); + + Dogecoin dogecoin = Dogecoin.getInstance(); + + if (!dogecoin.isValidDeterministicKey(key58)) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY); + + try { + return dogecoin.getUnusedReceiveAddress(key58); + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } + } + @POST @Path("/send") @Operation( diff --git a/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java index 653cc2ec..3e2ff799 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainLitecoinResource.java @@ -150,6 +150,45 @@ public class CrossChainLitecoinResource { } } + @POST + @Path("/unusedaddress") + @Operation( + summary = "Returns first unused address for hierarchical, deterministic BIP32 wallet", + description = "Supply BIP32 'm' private/public key in base58, starting with 'xprv'/'xpub' for mainnet, 'tprv'/'tpub' for testnet", + requestBody = @RequestBody( + required = true, + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string", + description = "BIP32 'm' private/public key in base58", + example = "tpubD6NzVbkrYhZ4XTPc4btCZ6SMgn8CxmWkj6VBVZ1tfcJfMq4UwAjZbG8U74gGSypL9XBYk2R2BLbDBe8pcEyBKM1edsGQEPKXNbEskZozeZc" + ) + ) + ), + responses = { + @ApiResponse( + content = @Content(array = @ArraySchema( schema = @Schema( implementation = SimpleTransaction.class ) ) ) + ) + } + ) + @ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + @SecurityRequirement(name = "apiKey") + public String getUnusedLitecoinReceiveAddress(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String key58) { + Security.checkApiCallAllowed(request); + + Litecoin litecoin = Litecoin.getInstance(); + + if (!litecoin.isValidDeterministicKey(key58)) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY); + + try { + return litecoin.getUnusedReceiveAddress(key58); + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } + } + @POST @Path("/send") @Operation( diff --git a/src/main/java/org/qortal/api/resource/CrossChainRavencoinResource.java b/src/main/java/org/qortal/api/resource/CrossChainRavencoinResource.java index 9e76b8a2..b1d6aed4 100644 --- a/src/main/java/org/qortal/api/resource/CrossChainRavencoinResource.java +++ b/src/main/java/org/qortal/api/resource/CrossChainRavencoinResource.java @@ -150,6 +150,45 @@ public class CrossChainRavencoinResource { } } + @POST + @Path("/unusedaddress") + @Operation( + summary = "Returns first unused address for hierarchical, deterministic BIP32 wallet", + description = "Supply BIP32 'm' private/public key in base58, starting with 'xprv'/'xpub' for mainnet, 'tprv'/'tpub' for testnet", + requestBody = @RequestBody( + required = true, + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string", + description = "BIP32 'm' private/public key in base58", + example = "tpubD6NzVbkrYhZ4XTPc4btCZ6SMgn8CxmWkj6VBVZ1tfcJfMq4UwAjZbG8U74gGSypL9XBYk2R2BLbDBe8pcEyBKM1edsGQEPKXNbEskZozeZc" + ) + ) + ), + responses = { + @ApiResponse( + content = @Content(array = @ArraySchema( schema = @Schema( implementation = SimpleTransaction.class ) ) ) + ) + } + ) + @ApiErrors({ApiError.INVALID_PRIVATE_KEY, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE}) + @SecurityRequirement(name = "apiKey") + public String getUnusedRavencoinReceiveAddress(@HeaderParam(Security.API_KEY_HEADER) String apiKey, String key58) { + Security.checkApiCallAllowed(request); + + Ravencoin ravencoin = Ravencoin.getInstance(); + + if (!ravencoin.isValidDeterministicKey(key58)) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_PRIVATE_KEY); + + try { + return ravencoin.getUnusedReceiveAddress(key58); + } catch (ForeignBlockchainException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.FOREIGN_BLOCKCHAIN_NETWORK_ISSUE); + } + } + @POST @Path("/send") @Operation( From 8f589391a6023aa59b45c623873795cdc668ee7f Mon Sep 17 00:00:00 2001 From: QuickMythril Date: Sat, 4 Feb 2023 21:57:31 -0500 Subject: [PATCH 10/31] Updated depreciated actions Node.js 12 actions are deprecated. Please update the following actions to use Node.js 16: actions/checkout@v2, actions/cache@v2, actions/setup-java@v2. For more information see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/ --- .github/workflows/pr-testing.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-testing.yml b/.github/workflows/pr-testing.yml index f712a321..3d0925df 100644 --- a/.github/workflows/pr-testing.yml +++ b/.github/workflows/pr-testing.yml @@ -8,16 +8,16 @@ jobs: mavenTesting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Cache local Maven repository - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - name: Set up the Java JDK - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: java-version: '11' distribution: 'adopt' From 6f867031e2d31fb66b41437412fb706c24a83a86 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Sun, 5 Feb 2023 12:53:49 +0100 Subject: [PATCH 11/31] Add electrum servers and fix java reflect error --- pom.xml | 1 + src/main/java/org/qortal/crosschain/Digibyte.java | 1 + src/main/java/org/qortal/crosschain/Dogecoin.java | 2 +- src/main/java/org/qortal/crosschain/Litecoin.java | 1 + src/main/java/org/qortal/crosschain/Ravencoin.java | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 12f8472c..c6dffd04 100644 --- a/pom.xml +++ b/pom.xml @@ -304,6 +304,7 @@ implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> org.qortal.controller.Controller + true . .. diff --git a/src/main/java/org/qortal/crosschain/Digibyte.java b/src/main/java/org/qortal/crosschain/Digibyte.java index 42ab2a5a..2b31468d 100644 --- a/src/main/java/org/qortal/crosschain/Digibyte.java +++ b/src/main/java/org/qortal/crosschain/Digibyte.java @@ -46,6 +46,7 @@ public class Digibyte extends Bitcoiny { // Servers chosen on NO BASIS WHATSOEVER from various sources! // Status verified at https://1209k.com/bitcoin-eye/ele.php?chain=dgb new Server("electrum-dgb.qortal.online", ConnectionType.SSL, 50002), + new Server("electrum1-dgb.qortal.online", ConnectionType.SSL, 50002), new Server("electrum1.cipig.net", ConnectionType.SSL, 20059), new Server("electrum2.cipig.net", ConnectionType.SSL, 20059), new Server("electrum3.cipig.net", ConnectionType.SSL, 20059)); diff --git a/src/main/java/org/qortal/crosschain/Dogecoin.java b/src/main/java/org/qortal/crosschain/Dogecoin.java index 5bdbeed8..6e763377 100644 --- a/src/main/java/org/qortal/crosschain/Dogecoin.java +++ b/src/main/java/org/qortal/crosschain/Dogecoin.java @@ -46,8 +46,8 @@ public class Dogecoin extends Bitcoiny { return Arrays.asList( // Servers chosen on NO BASIS WHATSOEVER from various sources! // Status verified at https://1209k.com/bitcoin-eye/ele.php?chain=doge - new Server("161.97.137.235", ConnectionType.SSL, 50002), new Server("electrum-doge.qortal.online", ConnectionType.SSL, 50002), + new Server("electrum1-doge.qortal.online", ConnectionType.SSL, 50002), new Server("electrum1.cipig.net", ConnectionType.SSL, 20060), new Server("electrum2.cipig.net", ConnectionType.SSL, 20060), new Server("electrum3.cipig.net", ConnectionType.SSL, 20060)); diff --git a/src/main/java/org/qortal/crosschain/Litecoin.java b/src/main/java/org/qortal/crosschain/Litecoin.java index 33650d81..4e672d3f 100644 --- a/src/main/java/org/qortal/crosschain/Litecoin.java +++ b/src/main/java/org/qortal/crosschain/Litecoin.java @@ -53,6 +53,7 @@ public class Litecoin extends Bitcoiny { new Server("electrum.ltc.xurious.com", Server.ConnectionType.SSL, 50002), new Server("electrum-ltc.petrkr.net", Server.ConnectionType.SSL, 60002), new Server("electrum-ltc.qortal.online", Server.ConnectionType.SSL, 50002), + new Server("electrum1-ltc.qortal.online", Server.ConnectionType.SSL, 50002), new Server("electrum1.cipig.net", Server.ConnectionType.SSL, 20063), new Server("electrum2.cipig.net", Server.ConnectionType.SSL, 20063), new Server("electrum3.cipig.net", Server.ConnectionType.SSL, 20063), diff --git a/src/main/java/org/qortal/crosschain/Ravencoin.java b/src/main/java/org/qortal/crosschain/Ravencoin.java index 9735f51c..f571a141 100644 --- a/src/main/java/org/qortal/crosschain/Ravencoin.java +++ b/src/main/java/org/qortal/crosschain/Ravencoin.java @@ -49,6 +49,7 @@ public class Ravencoin extends Bitcoiny { //CLOSED new Server("electrum2.rvn.rocks", ConnectionType.SSL, 50002), //BEHIND new Server("electrum3.rvn.rocks", ConnectionType.SSL, 50002), new Server("electrum-rvn.qortal.online", ConnectionType.SSL, 50002), + new Server("electrum1-rvn.qortal.online", ConnectionType.SSL, 50002), new Server("electrum1.cipig.net", ConnectionType.SSL, 20051), new Server("electrum2.cipig.net", ConnectionType.SSL, 20051), new Server("electrum3.cipig.net", ConnectionType.SSL, 20051), From bef170df7e858e24af52493d039435e424b5587c Mon Sep 17 00:00:00 2001 From: CalDescent Date: Mon, 6 Feb 2023 18:42:37 +0000 Subject: [PATCH 12/31] Updated PirateChain lightwallet servers. --- src/main/java/org/qortal/crosschain/PirateChain.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/qortal/crosschain/PirateChain.java b/src/main/java/org/qortal/crosschain/PirateChain.java index 09b37481..a1d31a4e 100644 --- a/src/main/java/org/qortal/crosschain/PirateChain.java +++ b/src/main/java/org/qortal/crosschain/PirateChain.java @@ -57,9 +57,9 @@ public class PirateChain extends Bitcoiny { public Collection getServers() { return Arrays.asList( // Servers chosen on NO BASIS WHATSOEVER from various sources! - new Server("arrrlightd.qortal.online", ConnectionType.SSL, 443), - new Server("arrrlightd1.qortal.online", ConnectionType.SSL, 443), - new Server("arrrlightd2.qortal.online", ConnectionType.SSL, 443), + new Server("wallet-arrr1.qortal.online", ConnectionType.SSL, 443), + new Server("wallet-arrr2.qortal.online", ConnectionType.SSL, 443), + new Server("wallet-arrr3.qortal.online", ConnectionType.SSL, 443), new Server("lightd.pirate.black", ConnectionType.SSL, 443)); } From 6fca30ce75e2f6e3b9b46bf4fc8ddcfec80ad6ef Mon Sep 17 00:00:00 2001 From: CalDescent Date: Tue, 7 Feb 2023 19:56:54 +0000 Subject: [PATCH 13/31] Added GET /admin/summary/alltime endpoint, to view a summary of chain activity since genesis. --- .../qortal/api/resource/AdminResource.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/main/java/org/qortal/api/resource/AdminResource.java b/src/main/java/org/qortal/api/resource/AdminResource.java index 9cff1bbb..46e204db 100644 --- a/src/main/java/org/qortal/api/resource/AdminResource.java +++ b/src/main/java/org/qortal/api/resource/AdminResource.java @@ -222,6 +222,42 @@ public class AdminResource { } } + @GET + @Path("/summary/alltime") + @Operation( + summary = "Summary of activity since genesis", + responses = { + @ApiResponse( + content = @Content(schema = @Schema(implementation = ActivitySummary.class)) + ) + } + ) + @ApiErrors({ApiError.REPOSITORY_ISSUE}) + @SecurityRequirement(name = "apiKey") + public ActivitySummary allTimeSummary(@HeaderParam(Security.API_KEY_HEADER) String apiKey) { + Security.checkApiCallAllowed(request); + + ActivitySummary summary = new ActivitySummary(); + + try (final Repository repository = RepositoryManager.getRepository()) { + int startHeight = 1; + long start = repository.getBlockRepository().fromHeight(startHeight).getTimestamp(); + int endHeight = repository.getBlockRepository().getBlockchainHeight(); + + summary.setBlockCount(endHeight - startHeight); + + summary.setTransactionCountByType(repository.getTransactionRepository().getTransactionSummary(startHeight + 1, endHeight)); + + summary.setAssetsIssued(repository.getAssetRepository().getRecentAssetIds(start).size()); + + summary.setNamesRegistered (repository.getNameRepository().getRecentNames(start).size()); + + return summary; + } catch (DataException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); + } + } + @GET @Path("/enginestats") @Operation( From e7a3e511bda479b832caf6cb7820bbc6ff9c35a9 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Wed, 8 Feb 2023 19:37:01 +0000 Subject: [PATCH 14/31] Bump version to 3.8.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c6dffd04..1eb8adb1 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.qortal qortal - 3.8.4 + 3.8.5 jar true From ea356d102648eac431bd1d4a0860a21fff1bdf82 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Fri, 10 Feb 2023 10:27:28 +0100 Subject: [PATCH 15/31] add signatures to websockt --- .../java/org/qortal/data/chat/ActiveChats.java | 10 ++++++++-- .../repository/hsqldb/HSQLDBChatRepository.java | 15 +++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/qortal/data/chat/ActiveChats.java b/src/main/java/org/qortal/data/chat/ActiveChats.java index c546d637..f9e48a1d 100644 --- a/src/main/java/org/qortal/data/chat/ActiveChats.java +++ b/src/main/java/org/qortal/data/chat/ActiveChats.java @@ -17,17 +17,19 @@ public class ActiveChats { private Long timestamp; private String sender; private String senderName; + private byte[] signature; protected GroupChat() { /* JAXB */ } - public GroupChat(int groupId, String groupName, Long timestamp, String sender, String senderName) { + public GroupChat(int groupId, String groupName, Long timestamp, String sender, String senderName, byte[] signature) { this.groupId = groupId; this.groupName = groupName; this.timestamp = timestamp; this.sender = sender; this.senderName = senderName; + this.signature = signature; } public int getGroupId() { @@ -49,6 +51,10 @@ public class ActiveChats { public String getSenderName() { return this.senderName; } + + public byte[] getSignature() { + return this.signature; + } } @XmlAccessorType(XmlAccessType.FIELD) @@ -118,4 +124,4 @@ public class ActiveChats { return this.direct; } -} +} \ No newline at end of file diff --git a/src/main/java/org/qortal/repository/hsqldb/HSQLDBChatRepository.java b/src/main/java/org/qortal/repository/hsqldb/HSQLDBChatRepository.java index 08226d53..b5b64594 100644 --- a/src/main/java/org/qortal/repository/hsqldb/HSQLDBChatRepository.java +++ b/src/main/java/org/qortal/repository/hsqldb/HSQLDBChatRepository.java @@ -177,11 +177,11 @@ public class HSQLDBChatRepository implements ChatRepository { private List getActiveGroupChats(String address) throws DataException { // Find groups where address is a member and potential latest message details - String groupsSql = "SELECT group_id, group_name, latest_timestamp, sender, sender_name " + String groupsSql = "SELECT group_id, group_name, latest_timestamp, sender, sender_name, signature " + "FROM GroupMembers " + "JOIN Groups USING (group_id) " + "LEFT OUTER JOIN LATERAL(" - + "SELECT created_when AS latest_timestamp, sender, name AS sender_name " + + "SELECT created_when AS latest_timestamp, sender, name AS sender_name, signature " + "FROM ChatTransactions " + "JOIN Transactions USING (signature) " + "LEFT OUTER JOIN Names AS SenderNames ON SenderNames.owner = sender " @@ -205,8 +205,9 @@ public class HSQLDBChatRepository implements ChatRepository { String sender = resultSet.getString(4); String senderName = resultSet.getString(5); + byte[] signature = resultSet.getBytes(6); - GroupChat groupChat = new GroupChat(groupId, groupName, timestamp, sender, senderName); + GroupChat groupChat = new GroupChat(groupId, groupName, timestamp, sender, senderName, signature); groupChats.add(groupChat); } while (resultSet.next()); } @@ -215,7 +216,7 @@ public class HSQLDBChatRepository implements ChatRepository { } // We need different SQL to handle group-less chat - String grouplessSql = "SELECT created_when, sender, SenderNames.name " + String grouplessSql = "SELECT created_when, sender, SenderNames.name, signature " + "FROM ChatTransactions " + "JOIN Transactions USING (signature) " + "LEFT OUTER JOIN Names AS SenderNames ON SenderNames.owner = sender " @@ -228,15 +229,17 @@ public class HSQLDBChatRepository implements ChatRepository { Long timestamp = null; String sender = null; String senderName = null; + byte[] signature = null; if (resultSet != null) { // We found a recipient-less, group-less CHAT message, so report its details timestamp = resultSet.getLong(1); sender = resultSet.getString(2); senderName = resultSet.getString(3); + signature = resultSet.getBytes(4); } - GroupChat groupChat = new GroupChat(0, null, timestamp, sender, senderName); + GroupChat groupChat = new GroupChat(0, null, timestamp, sender, senderName, signature); groupChats.add(groupChat); } catch (SQLException e) { throw new DataException("Unable to fetch active group chats from repository", e); @@ -291,4 +294,4 @@ public class HSQLDBChatRepository implements ChatRepository { return directChats; } -} +} \ No newline at end of file From 11654ba9c6963445ffaa3f323a7a15f45ccdf54b Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Fri, 10 Feb 2023 11:05:54 +0100 Subject: [PATCH 16/31] Add Chat Data --- src/main/java/org/qortal/data/chat/ActiveChats.java | 8 +++++++- .../repository/hsqldb/HSQLDBChatRepository.java | 13 ++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/qortal/data/chat/ActiveChats.java b/src/main/java/org/qortal/data/chat/ActiveChats.java index f9e48a1d..d5ebcf3f 100644 --- a/src/main/java/org/qortal/data/chat/ActiveChats.java +++ b/src/main/java/org/qortal/data/chat/ActiveChats.java @@ -18,18 +18,20 @@ public class ActiveChats { private String sender; private String senderName; private byte[] signature; + private byte[] data; protected GroupChat() { /* JAXB */ } - public GroupChat(int groupId, String groupName, Long timestamp, String sender, String senderName, byte[] signature) { + public GroupChat(int groupId, String groupName, Long timestamp, String sender, String senderName, byte[] signature, byte[] data) { this.groupId = groupId; this.groupName = groupName; this.timestamp = timestamp; this.sender = sender; this.senderName = senderName; this.signature = signature; + this.data = data; } public int getGroupId() { @@ -55,6 +57,10 @@ public class ActiveChats { public byte[] getSignature() { return this.signature; } + + public byte[] getData() { + return this.data; + } } @XmlAccessorType(XmlAccessType.FIELD) diff --git a/src/main/java/org/qortal/repository/hsqldb/HSQLDBChatRepository.java b/src/main/java/org/qortal/repository/hsqldb/HSQLDBChatRepository.java index b5b64594..a995a0b3 100644 --- a/src/main/java/org/qortal/repository/hsqldb/HSQLDBChatRepository.java +++ b/src/main/java/org/qortal/repository/hsqldb/HSQLDBChatRepository.java @@ -177,11 +177,11 @@ public class HSQLDBChatRepository implements ChatRepository { private List getActiveGroupChats(String address) throws DataException { // Find groups where address is a member and potential latest message details - String groupsSql = "SELECT group_id, group_name, latest_timestamp, sender, sender_name, signature " + String groupsSql = "SELECT group_id, group_name, latest_timestamp, sender, sender_name, signature, data " + "FROM GroupMembers " + "JOIN Groups USING (group_id) " + "LEFT OUTER JOIN LATERAL(" - + "SELECT created_when AS latest_timestamp, sender, name AS sender_name, signature " + + "SELECT created_when AS latest_timestamp, sender, name AS sender_name, signature, data " + "FROM ChatTransactions " + "JOIN Transactions USING (signature) " + "LEFT OUTER JOIN Names AS SenderNames ON SenderNames.owner = sender " @@ -206,8 +206,9 @@ public class HSQLDBChatRepository implements ChatRepository { String sender = resultSet.getString(4); String senderName = resultSet.getString(5); byte[] signature = resultSet.getBytes(6); + byte[] data = resultSet.getBytes(7); - GroupChat groupChat = new GroupChat(groupId, groupName, timestamp, sender, senderName, signature); + GroupChat groupChat = new GroupChat(groupId, groupName, timestamp, sender, senderName, signature, data); groupChats.add(groupChat); } while (resultSet.next()); } @@ -216,7 +217,7 @@ public class HSQLDBChatRepository implements ChatRepository { } // We need different SQL to handle group-less chat - String grouplessSql = "SELECT created_when, sender, SenderNames.name, signature " + String grouplessSql = "SELECT created_when, sender, SenderNames.name, signature, data " + "FROM ChatTransactions " + "JOIN Transactions USING (signature) " + "LEFT OUTER JOIN Names AS SenderNames ON SenderNames.owner = sender " @@ -230,6 +231,7 @@ public class HSQLDBChatRepository implements ChatRepository { String sender = null; String senderName = null; byte[] signature = null; + byte[] data = null; if (resultSet != null) { // We found a recipient-less, group-less CHAT message, so report its details @@ -237,9 +239,10 @@ public class HSQLDBChatRepository implements ChatRepository { sender = resultSet.getString(2); senderName = resultSet.getString(3); signature = resultSet.getBytes(4); + data = resultSet.getBytes(5); } - GroupChat groupChat = new GroupChat(0, null, timestamp, sender, senderName, signature); + GroupChat groupChat = new GroupChat(0, null, timestamp, sender, senderName, signature, data); groupChats.add(groupChat); } catch (SQLException e) { throw new DataException("Unable to fetch active group chats from repository", e); From ec09312cc5cf403add447649ede004f0cff0b1d3 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Fri, 10 Feb 2023 17:42:12 +0000 Subject: [PATCH 17/31] Updated AdvancedInstaller project for 3.8.5 --- WindowsInstaller/Qortal.aip | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/WindowsInstaller/Qortal.aip b/WindowsInstaller/Qortal.aip index 7af02485..51ba5f69 100755 --- a/WindowsInstaller/Qortal.aip +++ b/WindowsInstaller/Qortal.aip @@ -17,10 +17,10 @@ - + - + @@ -212,7 +212,7 @@ - + From eb6d84c04d37de22c16eb6cc3f8270061a09126c Mon Sep 17 00:00:00 2001 From: QuickMythril Date: Sun, 12 Feb 2023 00:10:13 -0500 Subject: [PATCH 18/31] Add new ElectrumX servers --- src/main/java/org/qortal/crosschain/Digibyte.java | 1 + src/main/java/org/qortal/crosschain/Dogecoin.java | 1 + src/main/java/org/qortal/crosschain/Litecoin.java | 1 + src/main/java/org/qortal/crosschain/Ravencoin.java | 1 + 4 files changed, 4 insertions(+) diff --git a/src/main/java/org/qortal/crosschain/Digibyte.java b/src/main/java/org/qortal/crosschain/Digibyte.java index 2b31468d..c5d96383 100644 --- a/src/main/java/org/qortal/crosschain/Digibyte.java +++ b/src/main/java/org/qortal/crosschain/Digibyte.java @@ -45,6 +45,7 @@ public class Digibyte extends Bitcoiny { return Arrays.asList( // Servers chosen on NO BASIS WHATSOEVER from various sources! // Status verified at https://1209k.com/bitcoin-eye/ele.php?chain=dgb + new Server("electrum.qortal.link", Server.ConnectionType.SSL, 55002), new Server("electrum-dgb.qortal.online", ConnectionType.SSL, 50002), new Server("electrum1-dgb.qortal.online", ConnectionType.SSL, 50002), new Server("electrum1.cipig.net", ConnectionType.SSL, 20059), diff --git a/src/main/java/org/qortal/crosschain/Dogecoin.java b/src/main/java/org/qortal/crosschain/Dogecoin.java index 6e763377..99f557a5 100644 --- a/src/main/java/org/qortal/crosschain/Dogecoin.java +++ b/src/main/java/org/qortal/crosschain/Dogecoin.java @@ -46,6 +46,7 @@ public class Dogecoin extends Bitcoiny { return Arrays.asList( // Servers chosen on NO BASIS WHATSOEVER from various sources! // Status verified at https://1209k.com/bitcoin-eye/ele.php?chain=doge + new Server("electrum.qortal.link", Server.ConnectionType.SSL, 54002), new Server("electrum-doge.qortal.online", ConnectionType.SSL, 50002), new Server("electrum1-doge.qortal.online", ConnectionType.SSL, 50002), new Server("electrum1.cipig.net", ConnectionType.SSL, 20060), diff --git a/src/main/java/org/qortal/crosschain/Litecoin.java b/src/main/java/org/qortal/crosschain/Litecoin.java index 4e672d3f..1dd9037a 100644 --- a/src/main/java/org/qortal/crosschain/Litecoin.java +++ b/src/main/java/org/qortal/crosschain/Litecoin.java @@ -50,6 +50,7 @@ public class Litecoin extends Bitcoiny { //BEHIND new Server("62.171.169.176", Server.ConnectionType.SSL, 50002), //PHISHY new Server("electrum-ltc.bysh.me", Server.ConnectionType.SSL, 50002), new Server("backup.electrum-ltc.org", Server.ConnectionType.SSL, 443), + new Server("electrum.qortal.link", Server.ConnectionType.SSL, 50002), new Server("electrum.ltc.xurious.com", Server.ConnectionType.SSL, 50002), new Server("electrum-ltc.petrkr.net", Server.ConnectionType.SSL, 60002), new Server("electrum-ltc.qortal.online", Server.ConnectionType.SSL, 50002), diff --git a/src/main/java/org/qortal/crosschain/Ravencoin.java b/src/main/java/org/qortal/crosschain/Ravencoin.java index f571a141..6030fa50 100644 --- a/src/main/java/org/qortal/crosschain/Ravencoin.java +++ b/src/main/java/org/qortal/crosschain/Ravencoin.java @@ -48,6 +48,7 @@ public class Ravencoin extends Bitcoiny { //CLOSED new Server("aethyn.com", ConnectionType.SSL, 50002), //CLOSED new Server("electrum2.rvn.rocks", ConnectionType.SSL, 50002), //BEHIND new Server("electrum3.rvn.rocks", ConnectionType.SSL, 50002), + new Server("electrum.qortal.link", Server.ConnectionType.SSL, 56002), new Server("electrum-rvn.qortal.online", ConnectionType.SSL, 50002), new Server("electrum1-rvn.qortal.online", ConnectionType.SSL, 50002), new Server("electrum1.cipig.net", ConnectionType.SSL, 20051), From 074cba22663b490a00bf9a6bbccd2ea9f609abc8 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 19 Feb 2023 17:33:17 +0000 Subject: [PATCH 19/31] Added QCHAT_AUDIO and QCHAT_VOICE services (limited to 10MB each) --- src/main/java/org/qortal/arbitrary/misc/Service.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/qortal/arbitrary/misc/Service.java b/src/main/java/org/qortal/arbitrary/misc/Service.java index 01419d2f..5ea1b7aa 100644 --- a/src/main/java/org/qortal/arbitrary/misc/Service.java +++ b/src/main/java/org/qortal/arbitrary/misc/Service.java @@ -84,6 +84,8 @@ public enum Service { QCHAT_IMAGE(420, true, 500*1024L, null), VIDEO(500, false, null, null), AUDIO(600, false, null, null), + QCHAT_AUDIO(610, true, 10*1024*1024L, null), + QCHAT_VOICE(620, true, 10*1024*1024L, null), BLOG(700, false, null, null), BLOG_POST(777, false, null, null), BLOG_COMMENT(778, false, null, null), From edacce1bac10147956fd1c6056bfea5292a014f5 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 19 Feb 2023 17:43:13 +0000 Subject: [PATCH 20/31] Improved logging when creating bootstraps, and catch/log all exceptions. --- src/main/java/org/qortal/api/resource/BootstrapResource.java | 2 +- src/main/java/org/qortal/repository/Bootstrap.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/qortal/api/resource/BootstrapResource.java b/src/main/java/org/qortal/api/resource/BootstrapResource.java index b9382dcb..78630dfb 100644 --- a/src/main/java/org/qortal/api/resource/BootstrapResource.java +++ b/src/main/java/org/qortal/api/resource/BootstrapResource.java @@ -60,7 +60,7 @@ public class BootstrapResource { bootstrap.validateBlockchain(); return bootstrap.create(); - } catch (DataException | InterruptedException | IOException e) { + } catch (Exception e) { LOGGER.info("Unable to create bootstrap", e); throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.REPOSITORY_ISSUE, e.getMessage()); } diff --git a/src/main/java/org/qortal/repository/Bootstrap.java b/src/main/java/org/qortal/repository/Bootstrap.java index 626433e8..2d2605cc 100644 --- a/src/main/java/org/qortal/repository/Bootstrap.java +++ b/src/main/java/org/qortal/repository/Bootstrap.java @@ -279,7 +279,9 @@ public class Bootstrap { LOGGER.info("Generating checksum file..."); String checksum = Crypto.digestHexString(compressedOutputPath.toFile(), 1024*1024); + LOGGER.info("checksum: {}", checksum); Path checksumPath = Paths.get(String.format("%s.sha256", compressedOutputPath.toString())); + LOGGER.info("Writing checksum to path: {}", checksumPath); Files.writeString(checksumPath, checksum, StandardOpenOption.CREATE); // Return the path to the compressed bootstrap file From cfa0b1d8ea27b1ca2fd0e6dae47f4b93bbcc2700 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 19 Feb 2023 18:02:22 +0000 Subject: [PATCH 21/31] Bump version to 3.8.6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1eb8adb1..a7bac334 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.qortal qortal - 3.8.5 + 3.8.6 jar true From b2d31a7e0232fcaafd9e009e83e2cb7f038d8468 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 19 Feb 2023 22:26:22 +0000 Subject: [PATCH 22/31] Rebuild the name's history before processing a CancelSellNameTransaction. --- .../qortal/transaction/CancelSellNameTransaction.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/qortal/transaction/CancelSellNameTransaction.java b/src/main/java/org/qortal/transaction/CancelSellNameTransaction.java index 788492a9..876f0aed 100644 --- a/src/main/java/org/qortal/transaction/CancelSellNameTransaction.java +++ b/src/main/java/org/qortal/transaction/CancelSellNameTransaction.java @@ -5,6 +5,7 @@ import java.util.List; import org.qortal.account.Account; import org.qortal.asset.Asset; +import org.qortal.controller.repository.NamesDatabaseIntegrityCheck; import org.qortal.data.naming.NameData; import org.qortal.data.transaction.CancelSellNameTransactionData; import org.qortal.data.transaction.TransactionData; @@ -81,7 +82,13 @@ public class CancelSellNameTransaction extends Transaction { @Override public void preProcess() throws DataException { - // Nothing to do + CancelSellNameTransactionData cancelSellNameTransactionData = (CancelSellNameTransactionData) transactionData; + + // Rebuild this name in the Names table from the transaction history + // This is necessary because in some rare cases names can be missing from the Names table after registration + // but we have been unable to reproduce the issue and track down the root cause + NamesDatabaseIntegrityCheck namesDatabaseIntegrityCheck = new NamesDatabaseIntegrityCheck(); + namesDatabaseIntegrityCheck.rebuildName(cancelSellNameTransactionData.getName(), this.repository); } @Override From 52c806f9e6b7171d4dd3c9bc33c371f4772a119f Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 19 Feb 2023 22:44:59 +0000 Subject: [PATCH 23/31] Bump version to 3.8.7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a7bac334..fe59d980 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.qortal qortal - 3.8.6 + 3.8.7 jar true From d30eb6141ae7f8501d8a77d0045563c964fbb184 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Mon, 20 Feb 2023 18:10:21 +0000 Subject: [PATCH 24/31] Default minPeerVersion set to 3.8.7 --- src/main/java/org/qortal/settings/Settings.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/qortal/settings/Settings.java b/src/main/java/org/qortal/settings/Settings.java index 5799bd26..ae5dc173 100644 --- a/src/main/java/org/qortal/settings/Settings.java +++ b/src/main/java/org/qortal/settings/Settings.java @@ -215,7 +215,7 @@ public class Settings { public long recoveryModeTimeout = 10 * 60 * 1000L; /** Minimum peer version number required in order to sync with them */ - private String minPeerVersion = "3.8.2"; + private String minPeerVersion = "3.8.7"; /** Whether to allow connections with peers below minPeerVersion * If true, we won't sync with them but they can still sync with us, and will show in the peers list * If false, sync will be blocked both ways, and they will not appear in the peers list */ From c39b9c764b1e4a6589be19106d284a0d7d0e1204 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Mon, 20 Feb 2023 18:12:40 +0000 Subject: [PATCH 25/31] Bump version to 3.8.8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fe59d980..f94e39b3 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.qortal qortal - 3.8.7 + 3.8.8 jar true From 148ca0af05fe15aaf76da9e0a01ecd9d257a460e Mon Sep 17 00:00:00 2001 From: CalDescent Date: Wed, 22 Feb 2023 09:16:52 +0000 Subject: [PATCH 26/31] Fixed long term bug with UPDATE_NAME transactions, causing name data to be incorrectly deleted if newName == name. --- src/main/java/org/qortal/naming/Name.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/qortal/naming/Name.java b/src/main/java/org/qortal/naming/Name.java index ecf826a5..1751cca8 100644 --- a/src/main/java/org/qortal/naming/Name.java +++ b/src/main/java/org/qortal/naming/Name.java @@ -16,6 +16,8 @@ import org.qortal.repository.Repository; import org.qortal.transaction.Transaction.TransactionType; import org.qortal.utils.Unicode; +import java.util.Objects; + public class Name { // Properties @@ -116,7 +118,7 @@ public class Name { this.repository.getNameRepository().save(this.nameData); - if (!updateNameTransactionData.getNewName().isEmpty()) + if (!updateNameTransactionData.getNewName().isEmpty() && !Objects.equals(updateNameTransactionData.getName(), updateNameTransactionData.getNewName())) // Name has changed, delete old entry this.repository.getNameRepository().delete(updateNameTransactionData.getNewName()); From ba9f3b335c1efa530a9979b8c1304bf02df77a31 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Wed, 22 Feb 2023 18:59:43 +0000 Subject: [PATCH 27/31] Added unit test to reproduce the UPDATE_NAME issue and prove that the fix is working correctly. --- .../org/qortal/test/naming/UpdateTests.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/test/java/org/qortal/test/naming/UpdateTests.java b/src/test/java/org/qortal/test/naming/UpdateTests.java index 24af5317..54227e94 100644 --- a/src/test/java/org/qortal/test/naming/UpdateTests.java +++ b/src/test/java/org/qortal/test/naming/UpdateTests.java @@ -219,6 +219,65 @@ public class UpdateTests extends Common { } } + // Test that multiple UPDATE_NAME transactions work as expected, when using a matching name and newName string + @Test + public void testDoubleUpdateNameWithMatchingNewName() throws DataException { + try (final Repository repository = RepositoryManager.getRepository()) { + // Register-name + PrivateKeyAccount alice = Common.getTestAccount(repository, "alice"); + String name = "name"; + String reducedName = "name"; + String data = "{\"age\":30}"; + + TransactionData initialTransactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, data); + initialTransactionData.setFee(new RegisterNameTransaction(null, null).getUnitFee(initialTransactionData.getTimestamp())); + TransactionUtils.signAndMint(repository, initialTransactionData, alice); + + // Check name exists + assertTrue(repository.getNameRepository().nameExists(name)); + assertNotNull(repository.getNameRepository().fromReducedName(reducedName)); + + // Update name + TransactionData middleTransactionData = new UpdateNameTransactionData(TestTransaction.generateBase(alice), name, name, data); + TransactionUtils.signAndMint(repository, middleTransactionData, alice); + + // Check name still exists + assertTrue(repository.getNameRepository().nameExists(name)); + assertNotNull(repository.getNameRepository().fromReducedName(reducedName)); + + // Update name again + TransactionData newestTransactionData = new UpdateNameTransactionData(TestTransaction.generateBase(alice), name, name, data); + TransactionUtils.signAndMint(repository, newestTransactionData, alice); + + // Check name still exists + assertTrue(repository.getNameRepository().nameExists(name)); + assertNotNull(repository.getNameRepository().fromReducedName(reducedName)); + + // Check updated timestamp is correct + assertEquals((Long) newestTransactionData.getTimestamp(), repository.getNameRepository().fromName(name).getUpdated()); + + // orphan and recheck + BlockUtils.orphanLastBlock(repository); + + // Check name still exists + assertTrue(repository.getNameRepository().nameExists(name)); + assertNotNull(repository.getNameRepository().fromReducedName(reducedName)); + + // Check updated timestamp is correct + assertEquals((Long) middleTransactionData.getTimestamp(), repository.getNameRepository().fromName(name).getUpdated()); + + // orphan and recheck + BlockUtils.orphanLastBlock(repository); + + // Check name still exists + assertTrue(repository.getNameRepository().nameExists(name)); + assertNotNull(repository.getNameRepository().fromReducedName(reducedName)); + + // Check updated timestamp is empty + assertNull(repository.getNameRepository().fromName(name).getUpdated()); + } + } + // Test that reverting using previous UPDATE_NAME works as expected @Test public void testIntermediateUpdateName() throws DataException { From 466c727dee8b6a4e5077170bcc5e5de14c88bf43 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Wed, 22 Feb 2023 19:01:10 +0000 Subject: [PATCH 28/31] Bump version to 3.8.9 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f94e39b3..35c77bcc 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.qortal qortal - 3.8.8 + 3.8.9 jar true From 999e8b8aca2a817a56dec810b138cc07ae22db5d Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Fri, 24 Feb 2023 09:12:57 +0100 Subject: [PATCH 29/31] Update pom.xml --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 35c77bcc..efa84798 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 1.9 1.2.2 28.1-jre - 2.5.1 + 2.7.1 1.2.1 70.1 1.1 @@ -34,7 +34,7 @@ 1.1.0 1.13.1 4.10 - 1.45.1 + 1.53.0 3.19.4 From a3702ac6b08aed78f66a292c9a6da4a4f56363ab Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 26 Feb 2023 12:45:38 +0000 Subject: [PATCH 30/31] Revert "Merge pull request #111 from AlphaX-Projects/master" This reverts commit 69902f7f5b490257998a8a74cf9d26eece4a5680, reversing changes made to 466c727dee8b6a4e5077170bcc5e5de14c88bf43. --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index efa84798..35c77bcc 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 1.9 1.2.2 28.1-jre - 2.7.1 + 2.5.1 1.2.1 70.1 1.1 @@ -34,7 +34,7 @@ 1.1.0 1.13.1 4.10 - 1.53.0 + 1.45.1 3.19.4 From cc98abeffb797102446dfb6506afca64288a5959 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 26 Feb 2023 12:51:52 +0000 Subject: [PATCH 31/31] Reduced log spam --- .../controller/arbitrary/ArbitraryDataCleanupManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataCleanupManager.java b/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataCleanupManager.java index 39425b7e..34acf0cb 100644 --- a/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataCleanupManager.java +++ b/src/main/java/org/qortal/controller/arbitrary/ArbitraryDataCleanupManager.java @@ -204,7 +204,7 @@ public class ArbitraryDataCleanupManager extends Thread { if (completeFileExists && !allChunksExist) { // We have the complete file but not the chunks, so let's convert it - LOGGER.info(String.format("Transaction %s has complete file but no chunks", + LOGGER.debug(String.format("Transaction %s has complete file but no chunks", Base58.encode(arbitraryTransactionData.getSignature()))); ArbitraryTransactionUtils.convertFileToChunks(arbitraryTransactionData, now, STALE_FILE_TIMEOUT);