forked from Qortal/qortal
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
7e509f27fb
Binary file not shown.
@ -10,14 +10,13 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<skipTests>false</skipTests>
|
<skipTests>false</skipTests>
|
||||||
|
<bouncycastle.version>1.69</bouncycastle.version>
|
||||||
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
|
<junit.version>4.13.2</junit.version>
|
||||||
<maven-source-plugin.version>3.2.0</maven-source-plugin.version>
|
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
|
||||||
<maven-javadoc-plugin.version>3.3.1</maven-javadoc-plugin.version>
|
<maven-jar-plugin.version>3.3.0</maven-jar-plugin.version>
|
||||||
<maven-surefire-plugin.version>3.0.0-M4</maven-surefire-plugin.version>
|
<maven-javadoc-plugin.version>3.6.3</maven-javadoc-plugin.version>
|
||||||
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
|
<maven-source-plugin.version>3.3.0</maven-source-plugin.version>
|
||||||
|
<maven-surefire-plugin.version>3.2.2</maven-surefire-plugin.version>
|
||||||
<bouncycastle.version>1.64</bouncycastle.version>
|
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@ -117,7 +116,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.13</version>
|
<version>${junit.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -5,14 +5,11 @@
|
|||||||
<versioning>
|
<versioning>
|
||||||
<release>1.4.1</release>
|
<release>1.4.1</release>
|
||||||
<versions>
|
<versions>
|
||||||
<version>1.3.4</version>
|
|
||||||
<version>1.3.5</version>
|
|
||||||
<version>1.3.6</version>
|
|
||||||
<version>1.3.7</version>
|
<version>1.3.7</version>
|
||||||
<version>1.3.8</version>
|
<version>1.3.8</version>
|
||||||
<version>1.4.0</version>
|
<version>1.4.0</version>
|
||||||
<version>1.4.1</version>
|
<version>1.4.1</version>
|
||||||
</versions>
|
</versions>
|
||||||
<lastUpdated>20230821074325</lastUpdated>
|
<lastUpdated>20231212092227</lastUpdated>
|
||||||
</versioning>
|
</versioning>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
16
pom.xml
16
pom.xml
@ -10,18 +10,18 @@
|
|||||||
<altcoinj.version>7dc8c6f</altcoinj.version>
|
<altcoinj.version>7dc8c6f</altcoinj.version>
|
||||||
<bitcoinj.version>0.15.10</bitcoinj.version>
|
<bitcoinj.version>0.15.10</bitcoinj.version>
|
||||||
<bouncycastle.version>1.69</bouncycastle.version>
|
<bouncycastle.version>1.69</bouncycastle.version>
|
||||||
<build-helper-maven-plugin.version>3.4.0</build-helper-maven-plugin.version>
|
<build-helper-maven-plugin.version>3.5.0</build-helper-maven-plugin.version>
|
||||||
<build.timestamp>${maven.build.timestamp}</build.timestamp>
|
<build.timestamp>${maven.build.timestamp}</build.timestamp>
|
||||||
<ciyam-at.version>1.4.1</ciyam-at.version>
|
<ciyam-at.version>1.4.1</ciyam-at.version>
|
||||||
<commons-net.version>3.8.0</commons-net.version>
|
<commons-net.version>3.8.0</commons-net.version>
|
||||||
<commons-text.version>1.11.0</commons-text.version>
|
<commons-text.version>1.11.0</commons-text.version>
|
||||||
<commons-io.version>2.11.0</commons-io.version>
|
<commons-io.version>2.11.0</commons-io.version>
|
||||||
<commons-compress.version>1.24.0</commons-compress.version>
|
<commons-compress.version>1.25.0</commons-compress.version>
|
||||||
<commons-lang3.version>3.13.0</commons-lang3.version>
|
<commons-lang3.version>3.14.0</commons-lang3.version>
|
||||||
<dagger.version>1.2.2</dagger.version>
|
<dagger.version>1.2.2</dagger.version>
|
||||||
<extendedset.version>0.12.3</extendedset.version>
|
<extendedset.version>0.12.3</extendedset.version>
|
||||||
<git-commit-id-plugin.version>4.9.10</git-commit-id-plugin.version>
|
<git-commit-id-plugin.version>4.9.10</git-commit-id-plugin.version>
|
||||||
<grpc.version>1.59.0</grpc.version>
|
<grpc.version>1.60.0</grpc.version>
|
||||||
<guava.version>32.1.3-jre</guava.version>
|
<guava.version>32.1.3-jre</guava.version>
|
||||||
<hamcrest-library.version>2.2</hamcrest-library.version>
|
<hamcrest-library.version>2.2</hamcrest-library.version>
|
||||||
<homoglyph.version>1.2.1</homoglyph.version>
|
<homoglyph.version>1.2.1</homoglyph.version>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
<jetty.version>9.4.53.v20231009</jetty.version>
|
<jetty.version>9.4.53.v20231009</jetty.version>
|
||||||
<json-simple.version>1.1.1</json-simple.version>
|
<json-simple.version>1.1.1</json-simple.version>
|
||||||
<json.version>20231013</json.version>
|
<json.version>20231013</json.version>
|
||||||
<jsoup.version>1.16.2</jsoup.version>
|
<jsoup.version>1.17.1</jsoup.version>
|
||||||
<junit-jupiter-engine.version>5.10.0</junit-jupiter-engine.version>
|
<junit-jupiter-engine.version>5.10.0</junit-jupiter-engine.version>
|
||||||
<lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>
|
<lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>
|
||||||
<log4j.version>2.21.1</log4j.version>
|
<log4j.version>2.21.1</log4j.version>
|
||||||
@ -46,15 +46,15 @@
|
|||||||
<maven-surefire-plugin.version>3.2.2</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>3.2.2</maven-surefire-plugin.version>
|
||||||
<package-info-maven-plugin.version>1.1.0</package-info-maven-plugin.version>
|
<package-info-maven-plugin.version>1.1.0</package-info-maven-plugin.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<protobuf.version>3.24.4</protobuf.version>
|
<protobuf.version>3.25.0</protobuf.version>
|
||||||
<replacer.version>1.5.3</replacer.version>
|
<replacer.version>1.5.3</replacer.version>
|
||||||
<reproducible-build-maven-plugin.version>0.16</reproducible-build-maven-plugin.version>
|
<reproducible-build-maven-plugin.version>0.16</reproducible-build-maven-plugin.version>
|
||||||
<simplemagic.version>1.17</simplemagic.version>
|
<simplemagic.version>1.17</simplemagic.version>
|
||||||
<slf4j.version>1.7.36</slf4j.version>
|
<slf4j.version>1.7.36</slf4j.version>
|
||||||
<swagger-api.version>2.0.10</swagger-api.version>
|
<swagger-api.version>2.0.10</swagger-api.version>
|
||||||
<swagger-ui.version>5.9.0</swagger-ui.version>
|
<swagger-ui.version>5.10.3</swagger-ui.version>
|
||||||
<upnp.version>1.2</upnp.version>
|
<upnp.version>1.2</upnp.version>
|
||||||
<versions-maven-plugin.version>2.16.1</versions-maven-plugin.version>
|
<versions-maven-plugin.version>2.16.2</versions-maven-plugin.version>
|
||||||
<xz.version>1.9</xz.version>
|
<xz.version>1.9</xz.version>
|
||||||
</properties>
|
</properties>
|
||||||
<build>
|
<build>
|
||||||
|
@ -522,6 +522,10 @@ public class QortalATAPI extends API {
|
|||||||
|
|
||||||
/** Returns AT account's lastReference */
|
/** Returns AT account's lastReference */
|
||||||
private byte[] getLastReference() {
|
private byte[] getLastReference() {
|
||||||
|
// If we have transactions already, then use signature from last transaction
|
||||||
|
if (!this.transactions.isEmpty())
|
||||||
|
return this.transactions.get(this.transactions.size() - 1).getTransactionData().getSignature();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Look up AT's account's last reference from repository
|
// Look up AT's account's last reference from repository
|
||||||
Account atAccount = this.getATAccount();
|
Account atAccount = this.getATAccount();
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
package org.qortal.crypto;
|
package org.qortal.crypto;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.*;
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
public abstract class TrustlessSSLSocketFactory {
|
public abstract class TrustlessSSLSocketFactory {
|
||||||
|
|
||||||
// Create a trust manager that does not validate certificate chains
|
/**
|
||||||
|
* Creates a SSLSocketFactory that ignore certificate chain validation because ElectrumX servers use mostly
|
||||||
|
* self signed certificates.
|
||||||
|
*/
|
||||||
private static final TrustManager[] TRUSTLESS_MANAGER = new TrustManager[] {
|
private static final TrustManager[] TRUSTLESS_MANAGER = new TrustManager[] {
|
||||||
new X509TrustManager() {
|
new X509TrustManager() {
|
||||||
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
|
public X509Certificate[] getAcceptedIssuers() {
|
||||||
return new X509Certificate[0];
|
return null;
|
||||||
}
|
}
|
||||||
|
public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
||||||
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
|
|
||||||
}
|
}
|
||||||
|
public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||||
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Install the all-trusting trust manager
|
/**
|
||||||
|
* Install the all-trusting trust manager.
|
||||||
|
*/
|
||||||
private static final SSLContext sc;
|
private static final SSLContext sc;
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
sc = SSLContext.getInstance("TLSv1.3");
|
sc = SSLContext.getInstance("SSL");
|
||||||
sc.init(null, TRUSTLESS_MANAGER, new java.security.SecureRandom());
|
sc.init(null, TRUSTLESS_MANAGER, new java.security.SecureRandom());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@ -37,5 +37,4 @@ public abstract class TrustlessSSLSocketFactory {
|
|||||||
public static SSLSocketFactory getSocketFactory() {
|
public static SSLSocketFactory getSocketFactory() {
|
||||||
return sc.getSocketFactory();
|
return sc.getSocketFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ public class Settings {
|
|||||||
public long recoveryModeTimeout = 9999999999999L;
|
public long recoveryModeTimeout = 9999999999999L;
|
||||||
|
|
||||||
/** Minimum peer version number required in order to sync with them */
|
/** Minimum peer version number required in order to sync with them */
|
||||||
private String minPeerVersion = "4.3.2";
|
private String minPeerVersion = "4.4.0";
|
||||||
/** Whether to allow connections with peers below minPeerVersion
|
/** 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 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 */
|
* If false, sync will be blocked both ways, and they will not appear in the peers list */
|
||||||
|
83
src/main/resources/i18n/ApiError_he.properties
Normal file
83
src/main/resources/i18n/ApiError_he.properties
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||||
|
# Keys are from api.ApiError enum
|
||||||
|
|
||||||
|
# "localeLang": "he",
|
||||||
|
|
||||||
|
### Common ###
|
||||||
|
JSON = נכשל בניתוח הודעת JSON
|
||||||
|
|
||||||
|
INSUFFICIENT_BALANCE = יתרה לא מספקת
|
||||||
|
|
||||||
|
UNAUTHORIZED = קריאת API לא מורשית
|
||||||
|
|
||||||
|
REPOSITORY_ISSUE = שגיאת מאגר
|
||||||
|
|
||||||
|
NON_PRODUCTION = קריאת API זו אינה מותרת עבור מערכות ייצור
|
||||||
|
|
||||||
|
BLOCKCHAIN_NEEDS_SYNC = הבלוקצ'יין צריך להסתנכרן תחילה
|
||||||
|
|
||||||
|
NO_TIME_SYNC = עדיין אין סנכרון שעון
|
||||||
|
|
||||||
|
### Validation ###
|
||||||
|
INVALID_SIGNATURE = חתימה לא חוקית
|
||||||
|
|
||||||
|
INVALID_ADDRESS = כתובת לא חוקית
|
||||||
|
|
||||||
|
INVALID_PUBLIC_KEY = מפתח ציבורי לא חוקי
|
||||||
|
|
||||||
|
INVALID_DATA = נתונים לא חוקיים
|
||||||
|
|
||||||
|
INVALID_NETWORK_ADDRESS = כתובת רשת לא חוקית
|
||||||
|
|
||||||
|
ADDRESS_UNKNOWN = כתובת חשבון לא ידועה
|
||||||
|
|
||||||
|
INVALID_CRITERIA = קריטריוני חיפוש לא חוקיים
|
||||||
|
|
||||||
|
INVALID_REFERENCE = הפניה לא חוקית
|
||||||
|
|
||||||
|
TRANSFORMATION_ERROR = לא הצליח להפוך את JSON לעסקה
|
||||||
|
|
||||||
|
INVALID_PRIVATE_KEY = מפתח פרטי לא חוקי
|
||||||
|
|
||||||
|
INVALID_HEIGHT = גובה בלוק לא חוקי
|
||||||
|
|
||||||
|
CANNOT_MINT = החשבון לא יכול להטביע
|
||||||
|
|
||||||
|
### Blocks ###
|
||||||
|
BLOCK_UNKNOWN = בלוק לא ידוע
|
||||||
|
|
||||||
|
### Transactions ###
|
||||||
|
TRANSACTION_UNKNOWN = עסקה לא ידועה
|
||||||
|
|
||||||
|
PUBLIC_KEY_NOT_FOUND = מפתח ציבורי לא נמצא
|
||||||
|
|
||||||
|
# this one is special in that caller expected to pass two additional strings, hence the two %s
|
||||||
|
TRANSACTION_INVALID = עסקה לא חוקית: %s (%s)
|
||||||
|
|
||||||
|
### Naming ###
|
||||||
|
NAME_UNKNOWN = שם לא ידוע
|
||||||
|
|
||||||
|
### Asset ###
|
||||||
|
INVALID_ASSET_ID = מזהה נכס לא חוקי
|
||||||
|
|
||||||
|
INVALID_ORDER_ID = מזהה הזמנת נכס לא חוקי
|
||||||
|
|
||||||
|
ORDER_UNKNOWN = מזהה הזמנת נכס לא ידוע
|
||||||
|
|
||||||
|
### Groups ###
|
||||||
|
GROUP_UNKNOWN = קבוצה לא ידועה
|
||||||
|
|
||||||
|
### Foreign Blockchain ###
|
||||||
|
FOREIGN_BLOCKCHAIN_NETWORK_ISSUE = בעיה זרה בלוקצ'יין או ElectrumX ברשת
|
||||||
|
|
||||||
|
FOREIGN_BLOCKCHAIN_BALANCE_ISSUE = יתרה לא מספקת בבלוקצ'יין זר
|
||||||
|
|
||||||
|
FOREIGN_BLOCKCHAIN_TOO_SOON = מוקדם מדי לשדר עסקת בלוקצ'יין זרה (זמן נעילה/זמן חסימה חציוני)
|
||||||
|
|
||||||
|
### Trade Portal ###
|
||||||
|
ORDER_SIZE_TOO_SMALL = כמות ההזמנה נמוכה מדי
|
||||||
|
|
||||||
|
### Data ###
|
||||||
|
FILE_NOT_FOUND = הקובץ לא נמצא
|
||||||
|
|
||||||
|
NO_REPLY = עמית לא השיב בזמן המותר
|
48
src/main/resources/i18n/SysTray_he.properties
Normal file
48
src/main/resources/i18n/SysTray_he.properties
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
|
||||||
|
# SysTray pop-up menu
|
||||||
|
|
||||||
|
APPLYING_UPDATE_AND_RESTARTING = מחיל עדכון אוטומטי ומפעיל מחדש...
|
||||||
|
|
||||||
|
AUTO_UPDATE = עדכון אוטומטי
|
||||||
|
|
||||||
|
BLOCK_HEIGHT = גובה
|
||||||
|
|
||||||
|
BLOCKS_REMAINING = נותרו בלוקים
|
||||||
|
|
||||||
|
BUILD_VERSION = גרסת בנייה
|
||||||
|
|
||||||
|
CHECK_TIME_ACCURACY = בדוק את דיוק הזמן
|
||||||
|
|
||||||
|
CONNECTING = מתחבר
|
||||||
|
|
||||||
|
CONNECTION = חיבור
|
||||||
|
|
||||||
|
CONNECTIONS = חיבורים
|
||||||
|
|
||||||
|
CREATING_BACKUP_OF_DB_FILES = יוצר גיבוי של קבצי מסד נתונים...
|
||||||
|
|
||||||
|
DB_BACKUP = גיבוי מסד נתונים
|
||||||
|
|
||||||
|
DB_CHECKPOINT = נקודת ביקורת של מסד נתונים
|
||||||
|
|
||||||
|
DB_MAINTENANCE = תחזוקת מסד נתונים
|
||||||
|
|
||||||
|
EXIT = יציאה
|
||||||
|
|
||||||
|
LITE_NODE = Lite Node
|
||||||
|
|
||||||
|
MINTING_DISABLED = כרייה מבוטלת
|
||||||
|
|
||||||
|
MINTING_ENABLED = \u2714 הטבעה
|
||||||
|
|
||||||
|
OPEN_UI = ממשק משתמש פתוח
|
||||||
|
|
||||||
|
PERFORMING_DB_CHECKPOINT = שומר שינויים לא מחויבים במסד הנתונים...
|
||||||
|
|
||||||
|
PERFORMING_DB_MAINTENANCE = מבצע תחזוקה מתוזמנת...
|
||||||
|
|
||||||
|
SYNCHRONIZE_CLOCK = סנכרן שעון
|
||||||
|
|
||||||
|
SYNCHRONIZING_BLOCKCHAIN = מסנכרן
|
||||||
|
|
||||||
|
SYNCHRONIZING_CLOCK = מסנכרן שעון
|
195
src/main/resources/i18n/TransactionValidity_he.properties
Normal file
195
src/main/resources/i18n/TransactionValidity_he.properties
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
#
|
||||||
|
|
||||||
|
ACCOUNT_ALREADY_EXISTS = חשבון כבר קיים
|
||||||
|
|
||||||
|
ACCOUNT_CANNOT_REWARD_SHARE = חשבון לא יכול לחלוק תגמולים
|
||||||
|
|
||||||
|
ADDRESS_ABOVE_RATE_LIMIT = הכתובת הגיעה למגבלת התעריף שצוינה
|
||||||
|
|
||||||
|
ADDRESS_BLOCKED = כתובת זו חסומה
|
||||||
|
|
||||||
|
ALREADY_GROUP_ADMIN = כבר מנהל קבוצה
|
||||||
|
|
||||||
|
ALREADY_GROUP_MEMBER = כבר חבר בקבוצה
|
||||||
|
|
||||||
|
ALREADY_VOTED_FOR_THAT_OPTION = כבר הצביע עבור אפשרות זו
|
||||||
|
|
||||||
|
ASSET_ALREADY_EXISTS = הנכס כבר קיים
|
||||||
|
|
||||||
|
ASSET_DOES_NOT_EXIST = הנכס אינו קיים
|
||||||
|
|
||||||
|
ASSET_DOES_NOT_MATCH_AT = הנכס אינו תואם לנכס של AT
|
||||||
|
|
||||||
|
ASSET_NOT_SPENDABLE = הנכס אינו ניתן לבזבז
|
||||||
|
|
||||||
|
AT_ALREADY_EXISTS = AT כבר קיים
|
||||||
|
|
||||||
|
AT_IS_FINISHED = AT הסתיים
|
||||||
|
|
||||||
|
AT_UNKNOWN = AT לא ידוע
|
||||||
|
|
||||||
|
BAN_EXISTS = החסימה כבר קיימת
|
||||||
|
|
||||||
|
BAN_UNKNOWN = איסור לא ידוע
|
||||||
|
|
||||||
|
BANNED_FROM_GROUP = חסום מהקבוצה
|
||||||
|
|
||||||
|
BUYER_ALREADY_OWNER = הקונה כבר הבעלים
|
||||||
|
|
||||||
|
CLOCK_NOT_SYNCED = שעון לא מסונכרן
|
||||||
|
|
||||||
|
DUPLICATE_MESSAGE = כתובת שנשלחה הודעה כפולה
|
||||||
|
|
||||||
|
DUPLICATE_OPTION = אפשרות שכפול
|
||||||
|
|
||||||
|
GROUP_ALREADY_EXISTS = הקבוצה כבר קיימת
|
||||||
|
|
||||||
|
GROUP_APPROVAL_DECIDED = אישור הקבוצה כבר הוחלט
|
||||||
|
|
||||||
|
GROUP_APPROVAL_NOT_REQUIRED = אין צורך באישור קבוצתי
|
||||||
|
|
||||||
|
GROUP_DOES_NOT_EXIST = קבוצה לא קיימת
|
||||||
|
|
||||||
|
GROUP_ID_MISMATCH = אי התאמה של מזהה הקבוצה
|
||||||
|
|
||||||
|
GROUP_OWNER_CANNOT_LEAVE = בעל הקבוצה לא יכול לעזוב את הקבוצה
|
||||||
|
|
||||||
|
HAVE_EQUALS_WANT = have-asset זהה ל-want-asset
|
||||||
|
|
||||||
|
INCORRECT_NONCE = לא תקין של PoW
|
||||||
|
|
||||||
|
INSUFFICIENT_FEE = עמלה לא מספקת
|
||||||
|
|
||||||
|
INVALID_ADDRESS = כתובת לא חוקית
|
||||||
|
|
||||||
|
INVALID_AMOUNT = סכום לא חוקי
|
||||||
|
|
||||||
|
INVALID_ASSET_OWNER = בעל נכס לא חוקי
|
||||||
|
|
||||||
|
INVALID_AT_TRANSACTION = עסקת AT לא חוקית
|
||||||
|
|
||||||
|
INVALID_AT_TYPE_LENGTH = אורך AT 'סוג' לא חוקי
|
||||||
|
|
||||||
|
INVALID_BUT_OK = לא חוקי אבל בסדר
|
||||||
|
|
||||||
|
INVALID_CREATION_BYTES = בתים לא חוקיים של יצירה
|
||||||
|
|
||||||
|
INVALID_DATA_LENGTH = אורך נתונים לא חוקי
|
||||||
|
|
||||||
|
INVALID_DESCRIPTION_LENGTH = אורך תיאור לא חוקי
|
||||||
|
|
||||||
|
INVALID_GROUP_APPROVAL_THRESHOLD = סף לא חוקי לאישור קבוצה
|
||||||
|
|
||||||
|
INVALID_GROUP_BLOCK_DELAY = עיכוב חסימת אישור קבוצה לא חוקי
|
||||||
|
|
||||||
|
INVALID_GROUP_ID = מזהה קבוצה לא חוקי
|
||||||
|
|
||||||
|
INVALID_GROUP_OWNER = בעל קבוצה לא חוקי
|
||||||
|
|
||||||
|
INVALID_LIFETIME = משך חיים לא חוקי
|
||||||
|
|
||||||
|
INVALID_NAME_LENGTH = אורך שם לא חוקי
|
||||||
|
|
||||||
|
INVALID_NAME_OWNER = בעל שם לא חוקי
|
||||||
|
|
||||||
|
INVALID_OPTION_LENGTH = אורך אפשרויות לא חוקי
|
||||||
|
|
||||||
|
INVALID_OPTIONS_COUNT = ספירת אפשרויות לא חוקיות
|
||||||
|
|
||||||
|
INVALID_ORDER_CREATOR = יוצר הזמנה לא חוקי
|
||||||
|
|
||||||
|
INVALID_PAYMENTS_COUNT = ספירת תשלומים לא חוקיים
|
||||||
|
|
||||||
|
INVALID_PUBLIC_KEY = מפתח ציבורי לא חוקי
|
||||||
|
|
||||||
|
INVALID_QUANTITY = כמות לא חוקית
|
||||||
|
|
||||||
|
INVALID_REFERENCE = הפניה לא חוקית
|
||||||
|
|
||||||
|
INVALID_RETURN = החזרה לא חוקית
|
||||||
|
|
||||||
|
INVALID_REWARD_SHARE_PERCENT = אחוז חלוקת תגמולים לא חוקי
|
||||||
|
|
||||||
|
INVALID_SELLER = מוכר לא חוקי
|
||||||
|
|
||||||
|
INVALID_TAGS_LENGTH = אורך 'תגים' לא חוקי
|
||||||
|
|
||||||
|
INVALID_TIMESTAMP_SIGNATURE = חתימת חותמת זמן לא חוקית
|
||||||
|
|
||||||
|
INVALID_TX_GROUP_ID = מזהה קבוצת עסקאות לא חוקי
|
||||||
|
|
||||||
|
INVALID_VALUE_LENGTH = אורך 'ערך' לא חוקי
|
||||||
|
|
||||||
|
INVITE_UNKNOWN = הזמנה לקבוצה לא ידועה
|
||||||
|
|
||||||
|
JOIN_REQUEST_EXISTS = בקשת הצטרפות לקבוצה כבר קיימת
|
||||||
|
|
||||||
|
MAXIMUM_REWARD_SHARES = כבר במספר המרבי של שיתופי תגמול עבור חשבון זה
|
||||||
|
|
||||||
|
MISSING_CREATOR = חסר יוצר
|
||||||
|
|
||||||
|
MULTIPLE_NAMES_FORBIDDEN = אסור להשתמש במספר שמות רשומים לכל חשבון
|
||||||
|
|
||||||
|
NAME_ALREADY_FOR_SALE = שם כבר למכירה
|
||||||
|
|
||||||
|
NAME_ALREADY_REGISTERED = השם כבר רשום
|
||||||
|
|
||||||
|
NAME_BLOCKED = השם הזה חסום
|
||||||
|
|
||||||
|
NAME_DOES_NOT_EXIST = שם לא קיים
|
||||||
|
|
||||||
|
NAME_NOT_FOR_SALE = השם אינו למכירה
|
||||||
|
|
||||||
|
NAME_NOT_NORMALIZED = שם לא בצורת Unicode 'מנורמלת'
|
||||||
|
|
||||||
|
NEGATIVE_AMOUNT = סכום לא חוקי/שלילי
|
||||||
|
|
||||||
|
NEGATIVE_FEE = עמלה לא חוקית/שלילית
|
||||||
|
|
||||||
|
NEGATIVE_PRICE = מחיר לא חוקי/שלילי
|
||||||
|
|
||||||
|
NO_BALANCE = איזון לא מספיק
|
||||||
|
|
||||||
|
NO_BLOCKCHAIN_LOCK = הבלוקצ'יין של הצומת תפוס כעת
|
||||||
|
|
||||||
|
NO_FLAG_PERMISSION = לחשבון אין הרשאה זו
|
||||||
|
|
||||||
|
NOT_GROUP_ADMIN = החשבון אינו מנהל קבוצה
|
||||||
|
|
||||||
|
NOT_GROUP_MEMBER = החשבון אינו חבר בקבוצה
|
||||||
|
|
||||||
|
NOT_MINTING_ACCOUNT = החשבון אינו יכול להטביע
|
||||||
|
|
||||||
|
NOT_YET_RELEASED = תכונה עדיין לא שוחררה
|
||||||
|
|
||||||
|
OK = בסדר
|
||||||
|
|
||||||
|
ORDER_ALREADY_CLOSED = הזמנת סחר בנכס כבר סגורה
|
||||||
|
|
||||||
|
ORDER_DOES_NOT_EXIST = הוראת סחר בנכס לא קיימת
|
||||||
|
|
||||||
|
POLL_ALREADY_EXISTS = סקר כבר קיים
|
||||||
|
|
||||||
|
POLL_DOES_NOT_EXIST = סקר אינו קיים
|
||||||
|
|
||||||
|
POLL_OPTION_DOES_NOT_EXIST = אפשרות סקר לא קיימת
|
||||||
|
|
||||||
|
PUBLIC_KEY_UNKNOWN = מפתח ציבורי לא ידוע
|
||||||
|
|
||||||
|
REWARD_SHARE_UNKNOWN = חלוקת פרס לא ידוע
|
||||||
|
|
||||||
|
SELF_SHARE_EXISTS = שיתוף עצמי (שיתוף תגמול) כבר קיים
|
||||||
|
|
||||||
|
TIMESTAMP_TOO_NEW = חותמת זמן חדשה מדי
|
||||||
|
|
||||||
|
TIMESTAMP_TOO_OLD = חותמת זמן ישנה מדי
|
||||||
|
|
||||||
|
TOO_MANY_UNCONFIRMED = בחשבון יש יותר מדי עסקאות לא מאושרות בהמתנה
|
||||||
|
|
||||||
|
TRANSACTION_ALREADY_CONFIRMED = העסקה כבר אושרה
|
||||||
|
|
||||||
|
TRANSACTION_ALREADY_EXISTS = עסקה כבר קיימת
|
||||||
|
|
||||||
|
TRANSACTION_UNKNOWN = עסקה לא ידועה
|
||||||
|
|
||||||
|
TX_GROUP_ID_MISMATCH = מזהה הקבוצה של העסקה אינו תואם
|
425
src/test/java/org/qortal/test/at/CrowdfundTests.java
Normal file
425
src/test/java/org/qortal/test/at/CrowdfundTests.java
Normal file
@ -0,0 +1,425 @@
|
|||||||
|
package org.qortal.test.at;
|
||||||
|
|
||||||
|
import org.ciyam.at.*;
|
||||||
|
import org.junit.After;
|
||||||
|
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.at.AT;
|
||||||
|
import org.qortal.block.Block;
|
||||||
|
import org.qortal.data.at.ATData;
|
||||||
|
import org.qortal.data.at.ATStateData;
|
||||||
|
import org.qortal.data.block.BlockData;
|
||||||
|
import org.qortal.data.transaction.*;
|
||||||
|
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.*;
|
||||||
|
import org.qortal.transaction.*;
|
||||||
|
import org.qortal.utils.*;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class CrowdfundTests extends Common {
|
||||||
|
|
||||||
|
/*
|
||||||
|
"QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v", "amount": "1000000000"
|
||||||
|
"QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK", "amount": "1000000"
|
||||||
|
"QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL", "amount": "1000000"
|
||||||
|
"Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er", "amount": "1000000"
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static final String aliceAddress = "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v";
|
||||||
|
private static final String bobAddress = "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK";
|
||||||
|
private static final String chloeAddress = "QaUpHNhT3Ygx6avRiKobuLdusppR5biXjL";
|
||||||
|
private static final String dilbertAddress = "Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er";
|
||||||
|
|
||||||
|
// Creation bytes from: java -cp 'target/qrowdfund-1.0.0.jar:target/dependency/*' org.qortal.at.qrowdfund.Qrowdfund 50 12385 Qci5m9k4rcwe4ruKrZZQKka4FzUUMut3er
|
||||||
|
private static final String creationBytes58 = "1Pub6o13xyqfCZj8BMzmXsREVJR6h4xxpS2VPV1R2QwjP78r2ozxsNuvb28GWrT8FoTTQMGnVP7pNii6auUqYr2uunWfcxwhERbDgFdsJqtrJMpQNGB9GerAXYyiFiij35cP6eHw7BmALb3viT6VzqaXX9YB25iztekV5cTreJg7o2hRpFc9Rv8Z9dFXcD1Mm4WCaMaknUgchDi7qDnHA7JX8bn9EFD4WMG5nZHMsrmeqBHirURXr2dMxFprTBo187zztmw7izbv5KzMFP8aRP9uEqdTMhZJmvKqhapMK9UJkxMve3KnsxKn5yyaAeiZ4i9GNfrkjpz5T1VGomUaDmeatNti1bjQ2pwtcgZfFFbrnBFMU2kvcPx1UR53dArtRS7pFbNr3EFwnw2Yiu2xS3Z";
|
||||||
|
private static final byte[] creationBytes = Base58.decode(creationBytes58);
|
||||||
|
private static final long fundingAmount = 2_00000000L;
|
||||||
|
private static final long SLEEP_PERIOD = 50L;
|
||||||
|
|
||||||
|
private Repository repository = null;
|
||||||
|
private PrivateKeyAccount deployer;
|
||||||
|
private DeployAtTransaction deployAtTransaction;
|
||||||
|
private Account atAccount;
|
||||||
|
private String atAddress;
|
||||||
|
private byte[] rawLastTxnTimestamp = new byte[8];
|
||||||
|
private Transaction transaction;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() throws DataException {
|
||||||
|
Common.useDefaultSettings();
|
||||||
|
|
||||||
|
this.repository = RepositoryManager.getRepository();
|
||||||
|
this.deployer = Common.getTestAccount(repository, "alice");
|
||||||
|
|
||||||
|
this.deployAtTransaction = doDeploy(repository, deployer, creationBytes, fundingAmount);
|
||||||
|
this.atAccount = deployAtTransaction.getATAccount();
|
||||||
|
this.atAddress = deployAtTransaction.getATAccount().getAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() throws DataException {
|
||||||
|
if (this.repository != null)
|
||||||
|
this.repository.close();
|
||||||
|
|
||||||
|
this.repository = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeploy() throws DataException {
|
||||||
|
// Confirm initial value is zero
|
||||||
|
extractLastTxTimestamp(repository, atAddress, rawLastTxnTimestamp);
|
||||||
|
assertArrayEquals(new byte[8], rawLastTxnTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThresholdNotMet() throws DataException {
|
||||||
|
// AT deployment in block 2
|
||||||
|
|
||||||
|
// Mint block to allow AT to initialize and call SLEEP_UNTIL_MESSAGE_OR_HEIGHT
|
||||||
|
BlockUtils.mintBlock(repository); // height now 3
|
||||||
|
|
||||||
|
// Fetch AT's balance for this height
|
||||||
|
long preMintBalance = atAccount.getConfirmedBalance(Asset.QORT);
|
||||||
|
|
||||||
|
// Fetch AT's initial lastTxnTimestamp
|
||||||
|
byte[] creationTimestamp = new byte[8];
|
||||||
|
extractLastTxTimestamp(repository, atAddress, creationTimestamp);
|
||||||
|
|
||||||
|
// Mint several blocks
|
||||||
|
int i = repository.getBlockRepository().getBlockchainHeight();
|
||||||
|
long WAKE_HEIGHT = i + SLEEP_PERIOD;
|
||||||
|
for (; i < WAKE_HEIGHT; ++i)
|
||||||
|
BlockUtils.mintBlock(repository);
|
||||||
|
|
||||||
|
// We should now be at WAKE_HEIGHT
|
||||||
|
long height = repository.getBlockRepository().getBlockchainHeight();
|
||||||
|
assertEquals(WAKE_HEIGHT, height);
|
||||||
|
|
||||||
|
// AT should have woken and run at this height so balance should have changed
|
||||||
|
|
||||||
|
// Fetch new AT balance
|
||||||
|
long postMintBalance = atAccount.getConfirmedBalance(Asset.QORT);
|
||||||
|
|
||||||
|
assertNotSame(preMintBalance, postMintBalance);
|
||||||
|
|
||||||
|
// Confirm AT has found no payments
|
||||||
|
extractLastTxTimestamp(repository, atAddress, rawLastTxnTimestamp);
|
||||||
|
assertArrayEquals(creationTimestamp, rawLastTxnTimestamp);
|
||||||
|
|
||||||
|
// AT should have finished
|
||||||
|
ATData atData = repository.getATRepository().fromATAddress(atAddress);
|
||||||
|
assertTrue(atData.getIsFinished());
|
||||||
|
|
||||||
|
// AT should have sent balance back to creator
|
||||||
|
BlockData blockData = repository.getBlockRepository().getLastBlock();
|
||||||
|
Block block = new Block(repository, blockData);
|
||||||
|
List<Transaction> transactions = block.getTransactions();
|
||||||
|
|
||||||
|
assertEquals(1, transactions.size());
|
||||||
|
|
||||||
|
Transaction transaction = transactions.get(0);
|
||||||
|
AtTransaction atTransaction = (AtTransaction) transaction;
|
||||||
|
assertEquals(aliceAddress, atTransaction.getRecipient().getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThresholdNotMetWithOrphanage() throws DataException {
|
||||||
|
// AT deployment in block 2
|
||||||
|
|
||||||
|
// Mint block to allow AT to initialize and call SLEEP_UNTIL_MESSAGE_OR_HEIGHT
|
||||||
|
BlockUtils.mintBlock(repository); // height now 3
|
||||||
|
|
||||||
|
// Fetch AT's initial lastTxnTimestamp
|
||||||
|
byte[] creationTimestamp = new byte[8];
|
||||||
|
extractLastTxTimestamp(repository, atAddress, creationTimestamp);
|
||||||
|
|
||||||
|
// Mint several blocks
|
||||||
|
int i = repository.getBlockRepository().getBlockchainHeight();
|
||||||
|
long WAKE_HEIGHT = i + SLEEP_PERIOD;
|
||||||
|
for (; i < WAKE_HEIGHT; ++i)
|
||||||
|
BlockUtils.mintBlock(repository);
|
||||||
|
|
||||||
|
// AT should have finished
|
||||||
|
ATData atData = repository.getATRepository().fromATAddress(atAddress);
|
||||||
|
assertTrue(atData.getIsFinished());
|
||||||
|
|
||||||
|
// Orphan
|
||||||
|
BlockUtils.orphanBlocks(repository, 3);
|
||||||
|
|
||||||
|
// Mint several blocks
|
||||||
|
for (i = 0; i < 3; ++i)
|
||||||
|
BlockUtils.mintBlock(repository);
|
||||||
|
|
||||||
|
// Confirm AT has found no payments
|
||||||
|
extractLastTxTimestamp(repository, atAddress, rawLastTxnTimestamp);
|
||||||
|
assertArrayEquals(creationTimestamp, rawLastTxnTimestamp);
|
||||||
|
|
||||||
|
// AT should have finished
|
||||||
|
atData = repository.getATRepository().fromATAddress(atAddress);
|
||||||
|
assertTrue(atData.getIsFinished());
|
||||||
|
|
||||||
|
// AT should have sent balance back to creator
|
||||||
|
BlockData blockData = repository.getBlockRepository().getLastBlock();
|
||||||
|
Block block = new Block(repository, blockData);
|
||||||
|
List<Transaction> transactions = block.getTransactions();
|
||||||
|
|
||||||
|
assertEquals(1, transactions.size());
|
||||||
|
|
||||||
|
Transaction transaction = transactions.get(0);
|
||||||
|
AtTransaction atTransaction = (AtTransaction) transaction;
|
||||||
|
assertEquals(aliceAddress, atTransaction.getRecipient().getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThresholdNotMetWithPaymentsAndRefunds() throws DataException {
|
||||||
|
// AT deployment in block 2
|
||||||
|
|
||||||
|
// Mint block to allow AT to initialize and call SLEEP_UNTIL_MESSAGE_OR_HEIGHT
|
||||||
|
BlockUtils.mintBlock(repository); // height now 3
|
||||||
|
|
||||||
|
// Fetch AT's balance for this height
|
||||||
|
long preMintBalance = atAccount.getConfirmedBalance(Asset.QORT);
|
||||||
|
|
||||||
|
// Fetch AT's initial lastTxnTimestamp
|
||||||
|
byte[] creationTimestamp = new byte[8];
|
||||||
|
extractLastTxTimestamp(repository, atAddress, creationTimestamp);
|
||||||
|
|
||||||
|
int i = repository.getBlockRepository().getBlockchainHeight();
|
||||||
|
long WAKE_HEIGHT = i + SLEEP_PERIOD;
|
||||||
|
|
||||||
|
// Create some test accounts, based on donations
|
||||||
|
List<Pair<String,Long>> donations = List.of(
|
||||||
|
new Pair<>("QRt11DVBnLaSDxr2KHvx92LdPrjhbhJtkj", 500L),
|
||||||
|
new Pair<>("QRv7tHnaEpRtfovbTJqkJFmtnoahJrbPGg", 250L),
|
||||||
|
new Pair<>("QRv7tHnaEpRtfovbTJqkJFmtnoahJrbPGg", 250L),
|
||||||
|
new Pair<>("QczG8GXU5vPQLTZsJBASQd3fAKJzKwnubv", 250L),
|
||||||
|
new Pair<>("QNuYHyW4HJn7v3dYUxoTLiyS5tpGQAguMJ", 20L),
|
||||||
|
new Pair<>("QgVqcSZZ6HRhBvdUmpTvEonaQaH2oWfe58", 500L),
|
||||||
|
new Pair<>("QfDaxmD8jKi3TovWA1NA8RL5rWYXRC12uX", 10L),
|
||||||
|
new Pair<>("QSohMWUphRwtEuwAZKqoy8UGS13tk1bBDm", 15L),
|
||||||
|
new Pair<>("QiNKXRfnX9mTodSed1yRQexhL1HA42RHHo", 420L),
|
||||||
|
new Pair<>("Qgfh143pRJyxpS92JoazjXNMH1uZueQBZ2", 100L),
|
||||||
|
new Pair<>("Qgfh143pRJyxpS92JoazjXNMH1uZueQBZ2", 100L)
|
||||||
|
);
|
||||||
|
Map<String, TestAccount> donors = donations.stream()
|
||||||
|
.map(donation -> donation.getA())
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toMap(name -> name, name -> generateTestAccount(repository, name)));
|
||||||
|
|
||||||
|
// Give donors some QORT so they can donate
|
||||||
|
donors.values()
|
||||||
|
.stream()
|
||||||
|
.forEach(donorAccount -> {
|
||||||
|
try {
|
||||||
|
AccountUtils.pay(repository, Common.getTestAccount(repository, "alice"), donorAccount.getAddress(), 2000_00000000L);
|
||||||
|
} catch (DataException e) {
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Record balances
|
||||||
|
Map<String, Long> initialDonorBalances = donors.values()
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(account -> account.getAddress(), account -> {
|
||||||
|
try {
|
||||||
|
return account.getConfirmedBalance(Asset.QORT);
|
||||||
|
} catch (DataException e) {
|
||||||
|
fail(e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Now make donations
|
||||||
|
donations.stream()
|
||||||
|
.forEach(donation -> {
|
||||||
|
TestAccount donorAccount = donors.get(donation.getA());
|
||||||
|
try {
|
||||||
|
AccountUtils.pay(repository, donorAccount, atAddress, donation.getB() * 1_00000000L);
|
||||||
|
System.out.printf("AT balance at height %d is %s\n", repository.getBlockRepository().getBlockchainHeight(), Amounts.prettyAmount(atAccount.getConfirmedBalance(Asset.QORT)));
|
||||||
|
} catch (DataException e) {
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mint several blocks
|
||||||
|
i = repository.getBlockRepository().getBlockchainHeight();
|
||||||
|
for (; i < WAKE_HEIGHT; ++i) {
|
||||||
|
BlockUtils.mintBlock(repository);
|
||||||
|
System.out.printf("AT balance at height %d is %s\n", repository.getBlockRepository().getBlockchainHeight(), Amounts.prettyAmount(atAccount.getConfirmedBalance(Asset.QORT)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should now be at WAKE_HEIGHT
|
||||||
|
long height = repository.getBlockRepository().getBlockchainHeight();
|
||||||
|
assertEquals(WAKE_HEIGHT, height);
|
||||||
|
|
||||||
|
// AT should have woken and run at this height so balance should have changed
|
||||||
|
System.out.printf("AT balance at height %d is %s\n", repository.getBlockRepository().getBlockchainHeight(), Amounts.prettyAmount(atAccount.getConfirmedBalance(Asset.QORT)));
|
||||||
|
|
||||||
|
// Fetch new AT balance
|
||||||
|
long postMintBalance = atAccount.getConfirmedBalance(Asset.QORT);
|
||||||
|
|
||||||
|
assertNotSame(preMintBalance, postMintBalance);
|
||||||
|
|
||||||
|
|
||||||
|
// Payments might happen over multiple blocks!
|
||||||
|
Map<String, Long> expectedBalances = new HashMap<>(initialDonorBalances);
|
||||||
|
|
||||||
|
ATData atData;
|
||||||
|
do {
|
||||||
|
// Confirm AT has found payments
|
||||||
|
extractLastTxTimestamp(repository, atAddress, rawLastTxnTimestamp);
|
||||||
|
assertNotSame(ByteArray.wrap(creationTimestamp), ByteArray.copyOf(rawLastTxnTimestamp));
|
||||||
|
|
||||||
|
// AT should have sent refunds
|
||||||
|
BlockData blockData = repository.getBlockRepository().getLastBlock();
|
||||||
|
Block block = new Block(repository, blockData);
|
||||||
|
List<Transaction> transactions = block.getTransactions();
|
||||||
|
|
||||||
|
assertNotSame(0, transactions.size());
|
||||||
|
|
||||||
|
// Compute expected balances
|
||||||
|
for (var transaction : transactions) {
|
||||||
|
AtTransaction atTransaction = (AtTransaction) transaction;
|
||||||
|
ATTransactionData atTransactionData = (ATTransactionData) atTransaction.getTransactionData();
|
||||||
|
String recipient = atTransactionData.getRecipient();
|
||||||
|
|
||||||
|
// Skip if this is a refund to AT deployer
|
||||||
|
if (recipient.equals(aliceAddress))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
String donorName = donors.entrySet()
|
||||||
|
.stream()
|
||||||
|
.filter(donor -> donor.getValue().getAddress().equals(recipient))
|
||||||
|
.findFirst()
|
||||||
|
.get()
|
||||||
|
.getKey();
|
||||||
|
System.out.printf("AT paid %s to %s\n", Amounts.prettyAmount(atTransactionData.getAmount()), donorName);
|
||||||
|
|
||||||
|
expectedBalances.compute(atTransactionData.getRecipient(), (key, balance) -> balance - AccountUtils.fee);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AT should have finished
|
||||||
|
atData = repository.getATRepository().fromATAddress(atAddress);
|
||||||
|
|
||||||
|
// Mint new block in case we need to loop round again
|
||||||
|
BlockUtils.mintBlock(repository);
|
||||||
|
System.out.printf("AT balance at height %d is %s\n", repository.getBlockRepository().getBlockchainHeight(), Amounts.prettyAmount(atAccount.getConfirmedBalance(Asset.QORT)));
|
||||||
|
} while (!atData.getIsFinished());
|
||||||
|
|
||||||
|
// Compare expected balances
|
||||||
|
donors.entrySet()
|
||||||
|
.forEach(donor -> {
|
||||||
|
String donorName = donor.getKey();
|
||||||
|
TestAccount donorAccount = donor.getValue();
|
||||||
|
|
||||||
|
Long expectedBalance = expectedBalances.get(donorAccount.getAddress());
|
||||||
|
Long actualBalance = null;
|
||||||
|
try {
|
||||||
|
actualBalance = donorAccount.getConfirmedBalance(Asset.QORT);
|
||||||
|
} catch (DataException e) {
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(expectedBalance, actualBalance);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private DeployAtTransaction doDeploy(Repository repository, PrivateKeyAccount deployer, byte[] creationBytes, long fundingAmount) throws DataException {
|
||||||
|
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 = "Test AT";
|
||||||
|
String description = "Test AT";
|
||||||
|
String atType = "Test";
|
||||||
|
String tags = "TEST";
|
||||||
|
|
||||||
|
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 void extractLastTxTimestamp(Repository repository, String atAddress, byte[] rawLastTxnTimestamp) throws DataException {
|
||||||
|
// Check AT result
|
||||||
|
ATStateData atStateData = repository.getATRepository().getLatestATState(atAddress);
|
||||||
|
byte[] stateData = atStateData.getStateData();
|
||||||
|
|
||||||
|
byte[] dataBytes = MachineState.extractDataBytes(stateData);
|
||||||
|
|
||||||
|
System.arraycopy(dataBytes, 5 * MachineState.VALUE_SIZE, rawLastTxnTimestamp, 0, rawLastTxnTimestamp.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertTimestamp(Repository repository, String atAddress, Transaction transaction) throws DataException {
|
||||||
|
int height = transaction.getHeight();
|
||||||
|
byte[] transactionSignature = transaction.getTransactionData().getSignature();
|
||||||
|
|
||||||
|
BlockData blockData = repository.getBlockRepository().fromHeight(height);
|
||||||
|
assertNotNull(blockData);
|
||||||
|
|
||||||
|
Block block = new Block(repository, blockData);
|
||||||
|
|
||||||
|
List<Transaction> blockTransactions = block.getTransactions();
|
||||||
|
int sequence;
|
||||||
|
for (sequence = blockTransactions.size() - 1; sequence >= 0; --sequence)
|
||||||
|
if (Arrays.equals(blockTransactions.get(sequence).getTransactionData().getSignature(), transactionSignature))
|
||||||
|
break;
|
||||||
|
|
||||||
|
assertNotSame(-1, sequence);
|
||||||
|
|
||||||
|
byte[] rawLastTxTimestamp = new byte[8];
|
||||||
|
extractLastTxTimestamp(repository, atAddress, rawLastTxTimestamp);
|
||||||
|
|
||||||
|
Timestamp expectedTimestamp = new Timestamp(height, sequence);
|
||||||
|
Timestamp actualTimestamp = new Timestamp(BitTwiddling.longFromBEBytes(rawLastTxTimestamp, 0));
|
||||||
|
|
||||||
|
assertEquals(String.format("Expected height %d, seq %d but was height %d, seq %d",
|
||||||
|
height, sequence,
|
||||||
|
actualTimestamp.blockHeight, actualTimestamp.transactionSequence
|
||||||
|
),
|
||||||
|
expectedTimestamp.longValue(),
|
||||||
|
actualTimestamp.longValue());
|
||||||
|
|
||||||
|
byte[] expectedPartialSignature = new byte[24];
|
||||||
|
System.arraycopy(transactionSignature, 8, expectedPartialSignature, 0, expectedPartialSignature.length);
|
||||||
|
|
||||||
|
byte[] actualPartialSignature = new byte[24];
|
||||||
|
System.arraycopy(rawLastTxTimestamp, 8, actualPartialSignature, 0, actualPartialSignature.length);
|
||||||
|
|
||||||
|
assertArrayEquals(expectedPartialSignature, actualPartialSignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TestAccount generateTestAccount(Repository repository, String accountName) {
|
||||||
|
byte[] seed = new byte[32];
|
||||||
|
new SecureRandom().nextBytes(seed);
|
||||||
|
return new TestAccount(repository, accountName, Base58.encode(seed), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -27,6 +27,9 @@
|
|||||||
"onlineAccountsModulusV2Timestamp": 0,
|
"onlineAccountsModulusV2Timestamp": 0,
|
||||||
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
"selfSponsorshipAlgoV1SnapshotTimestamp": 9999999999999,
|
||||||
"mempowTransactionUpdatesTimestamp": 1692554400000,
|
"mempowTransactionUpdatesTimestamp": 1692554400000,
|
||||||
|
"blockRewardBatchStartHeight": 10000,
|
||||||
|
"blockRewardBatchSize": 1000,
|
||||||
|
"blockRewardBatchAccountsBlockCount": 25,
|
||||||
"rewardsByHeight": [
|
"rewardsByHeight": [
|
||||||
{ "height": 1, "reward": 5.00 },
|
{ "height": 1, "reward": 5.00 },
|
||||||
{ "height": 259201, "reward": 4.75 },
|
{ "height": 259201, "reward": 4.75 },
|
||||||
@ -69,8 +72,8 @@
|
|||||||
],
|
],
|
||||||
"ciyamAtSettings": {
|
"ciyamAtSettings": {
|
||||||
"feePerStep": "0.00000001",
|
"feePerStep": "0.00000001",
|
||||||
"maxStepsPerRound": 500,
|
"maxStepsPerRound": 1000,
|
||||||
"stepsPerFunctionCall": 10,
|
"stepsPerFunctionCall": 100,
|
||||||
"minutesPerBlock": 1
|
"minutesPerBlock": 1
|
||||||
},
|
},
|
||||||
"featureTriggers": {
|
"featureTriggers": {
|
||||||
@ -89,11 +92,11 @@
|
|||||||
"selfSponsorshipAlgoV1Height": 9999999,
|
"selfSponsorshipAlgoV1Height": 9999999,
|
||||||
"feeValidationFixTimestamp": 0,
|
"feeValidationFixTimestamp": 0,
|
||||||
"chatReferenceTimestamp": 0,
|
"chatReferenceTimestamp": 0,
|
||||||
"arbitraryOptionalFeeTimestamp": 1678622400000
|
"arbitraryOptionalFeeTimestamp": 0
|
||||||
},
|
},
|
||||||
"genesisInfo": {
|
"genesisInfo": {
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"timestamp": "1677572542000",
|
"timestamp": "1701874800000",
|
||||||
"transactions": [
|
"transactions": [
|
||||||
{ "type": "ISSUE_ASSET", "assetName": "QORT", "description": "QORTAL coin", "quantity": 0, "isDivisible": true, "data": "{}" },
|
{ "type": "ISSUE_ASSET", "assetName": "QORT", "description": "QORTAL coin", "quantity": 0, "isDivisible": true, "data": "{}" },
|
||||||
{ "type": "ISSUE_ASSET", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
|
{ "type": "ISSUE_ASSET", "assetName": "Legacy-QORA", "description": "Representative legacy QORA", "quantity": 0, "isDivisible": true, "data": "{}", "isUnspendable": true },
|
||||||
@ -2661,4 +2664,4 @@
|
|||||||
{ "type": "GENESIS", "recipient": "QU7EUWDZz7qJVPih3wL9RKTHRfPFy4ASHC", "amount": 10 }
|
{ "type": "GENESIS", "recipient": "QU7EUWDZz7qJVPih3wL9RKTHRfPFy4ASHC", "amount": 10 }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user