diff --git a/blockchain/src/main/java/org/ton/java/Blockchain.java b/blockchain/src/main/java/org/ton/java/Blockchain.java
index 7c76305e..3aa653e9 100644
--- a/blockchain/src/main/java/org/ton/java/Blockchain.java
+++ b/blockchain/src/main/java/org/ton/java/Blockchain.java
@@ -322,16 +322,44 @@ private void initializeTonlib() {
}
}
+ /**
+ * There is a huge difference between sendExternal(Cell body)
and sendExternal(Message message)
.
+ * The first one sends a body to itself, the second one - sends the message to a destination specified in a message.
+ * Basically, in the first method we construct MsgUtils.createExternalMessage()
with replaced destination address.
+ *
+ * @param body Cell
+ * @return SendExternalResult
+ */
+ public SendExternalResult sendExternal(Cell body) {
+ Address address;
+ if (nonNull(contract)) {
+ address = contract.getAddress();
+ } else {
+ address = stateInit.getAddress();
+ }
+ Message message = MsgUtils.createExternalMessage(address, null, body);
+ return sendExternal(message);
+ }
+
public SendExternalResult sendExternal(Message message) {
try {
+
+ Address address;
+ if (nonNull(contract)) {
+ address = contract.getAddress();
+ } else {
+ address = stateInit.getAddress();
+ }
+ String bounceableAddress =
+ (network == Network.TESTNET) ? address.toBounceableTestnet() : address.toBounceable();
+
if (network != Network.EMULATOR) {
- String bounceableAddress =
- (network == Network.TESTNET)
- ? contract.getAddress().toBounceableTestnet()
- : contract.getAddress().toBounceable();
+ String initialBalance = Utils.formatNanoValue(tonlib.getAccountBalance(address));
+ log.info("initialBalance {}", initialBalance);
log.info(
- "Sending external message to bounceable address {} on {}...",
+ "Sending external message (cell-hash: {}) to bounceable address {} on {}...",
+ message.toCell().getShortHash(),
bounceableAddress,
network);
ExtMessageInfo tonlibResult = tonlib.sendRawMessage(message.toCell().toBase64());
@@ -350,9 +378,9 @@ public SendExternalResult sendExternal(Message message) {
String initialBalance = Utils.formatNanoValue(customEmulatorShardAccount.getBalance());
log.info(
- "Sending external message to bounceable address {} on {}...",
- stateInit.getAddress().toBounceable(),
- network);
+ "Sending external message (cell-hash: {}) to bounceable address {} on {}...",
+ message.toCell().getShortHash(),
+ bounceableAddress, network);
EmulateTransactionResult emulateTransactionResult =
txEmulator.emulateTransaction(
customEmulatorShardAccount.toCell().toBase64(), message.toCell().toBase64());
diff --git a/blockchain/src/test/java/org/ton/java/BlockchainTest.java b/blockchain/src/test/java/org/ton/java/BlockchainTest.java
index 9086eab5..3772fa7f 100644
--- a/blockchain/src/test/java/org/ton/java/BlockchainTest.java
+++ b/blockchain/src/test/java/org/ton/java/BlockchainTest.java
@@ -11,12 +11,15 @@
import org.ton.java.address.Address;
import org.ton.java.cell.Cell;
import org.ton.java.cell.CellBuilder;
+import org.ton.java.emulator.tvm.TvmVerbosityLevel;
+import org.ton.java.emulator.tx.TxVerbosityLevel;
import org.ton.java.smartcontract.faucet.TestnetFaucet;
import org.ton.java.smartcontract.types.WalletV3Config;
import org.ton.java.smartcontract.utils.MsgUtils;
import org.ton.java.smartcontract.wallet.v3.WalletV3R2;
import org.ton.java.smartcontract.wallet.v5.WalletV5;
import org.ton.java.tlb.types.Message;
+import org.ton.java.tonlib.types.VerbosityLevel;
import org.ton.java.utils.Utils;
@Slf4j
@@ -288,20 +291,23 @@ public void testSendMessageCustomContractOnTestnetTolk() {
.storeUint(0, 32)
.storeInt(Utils.getRandomInt(), 32)
.endCell())
+ .tvmEmulatorVerbosityLevel(TvmVerbosityLevel.WITH_ALL_STACK_VALUES)
+ .txEmulatorVerbosityLevel(TxVerbosityLevel.WITH_ALL_STACK_VALUES)
+// .tonlibVerbosityLevel(VerbosityLevel.DEBUG)
.build();
+
assertThat(blockchain.deploy(30)).isTrue();
- GetterResult result = blockchain.runGetMethod("unique");
- System.out.printf("result %s\n", result);
+
+ blockchain.runGetMethod("unique");
System.out.printf("current seqno %s\n", blockchain.runGetSeqNo());
Cell bodyCell =
CellBuilder.beginCell()
- .storeUint(0, 32) // seqno
+ .storeUint(1, 32) // seqno
.endCell();
- Message extMsg = MsgUtils.createExternalMessage(dummyAddress, null, bodyCell);
-
- blockchain.sendExternal(extMsg);
+ blockchain.sendExternal(bodyCell);
+ //wait till delivered
System.out.printf("current seqno %s\n", blockchain.runGetSeqNo());
}
@@ -313,24 +319,24 @@ public void testSendMessageCustomContractOnEmulatorTolk() {
.customContractAsResource("simple.tolk")
.customContractDataCell(
CellBuilder.beginCell()
- .storeUint(0, 32)
+ .storeUint(1, 32)
.storeInt(Utils.getRandomInt(), 32)
.endCell())
// .tvmEmulatorVerbosityLevel(TvmVerbosityLevel.WITH_ALL_STACK_VALUES)
// .txEmulatorVerbosityLevel(TxVerbosityLevel.WITH_ALL_STACK_VALUES)
.build();
+
assertThat(blockchain.deploy(30)).isTrue();
+
blockchain.runGetMethod("unique");
System.out.printf("current seqno %s\n", blockchain.runGetSeqNo());
Cell bodyCell =
CellBuilder.beginCell()
- .storeUint(0, 32) // seqno
+ .storeUint(1, 32) // seqno
.endCell();
- Message extMsg = MsgUtils.createExternalMessage(dummyAddress, null, bodyCell);
-
- blockchain.sendExternal(extMsg);
+ blockchain.sendExternal(bodyCell);
System.out.printf("current seqno %s\n", blockchain.runGetSeqNo());
}
@@ -358,8 +364,7 @@ public void testSendMessagesChainCustomContractOnEmulatorTolk() {
.storeUint(0, 32) // seqno
.endCell();
- Message extMsg = MsgUtils.createExternalMessage(dummyAddress, null, bodyCell);
- blockchain.sendExternal(extMsg);
+ blockchain.sendExternal(bodyCell);
currentSeqno = blockchain.runGetSeqNo();
System.out.printf("current seqno %s\n", currentSeqno);
@@ -369,8 +374,45 @@ public void testSendMessagesChainCustomContractOnEmulatorTolk() {
.storeUint(1, 32) // seqno
.endCell();
- extMsg = MsgUtils.createExternalMessage(dummyAddress, null, bodyCell);
- blockchain.sendExternal(extMsg);
+ blockchain.sendExternal(bodyCell);
+ currentSeqno = blockchain.runGetSeqNo();
+ System.out.printf("current seqno %s\n", currentSeqno);
+ }
+
+
+ @Test
+ public void testSendMessagesChainCustomContractOnEmulatorFunc() {
+ Blockchain blockchain =
+ Blockchain.builder()
+ .network(Network.EMULATOR)
+ .customContractAsResource("simple.fc")
+ .customContractDataCell(
+ CellBuilder.beginCell()
+ .storeUint(0, 32)
+ .storeInt(Utils.getRandomInt(), 32)
+ .endCell())
+ .build();
+ assertThat(blockchain.deploy(30)).isTrue();
+ blockchain.runGetMethod("unique");
+ BigInteger currentSeqno = blockchain.runGetSeqNo();
+ System.out.printf("current seqno %s\n", currentSeqno);
+
+ Cell bodyCell =
+ CellBuilder.beginCell()
+ .storeUint(0, 32) // seqno
+ .endCell();
+
+ blockchain.sendExternal(bodyCell);
+
+ currentSeqno = blockchain.runGetSeqNo();
+ System.out.printf("current seqno %s\n", currentSeqno);
+
+ bodyCell =
+ CellBuilder.beginCell()
+ .storeUint(1, 32) // seqno
+ .endCell();
+
+ blockchain.sendExternal(bodyCell);
currentSeqno = blockchain.runGetSeqNo();
System.out.printf("current seqno %s\n", currentSeqno);
}
diff --git a/cell/src/main/java/org/ton/java/cell/Cell.java b/cell/src/main/java/org/ton/java/cell/Cell.java
index ad70d596..0f3bf5ec 100644
--- a/cell/src/main/java/org/ton/java/cell/Cell.java
+++ b/cell/src/main/java/org/ton/java/cell/Cell.java
@@ -669,6 +669,11 @@ public byte[] getHash() {
return getHash(levelMask.getLevel());
}
+ public String getShortHash() {
+ String hashHex = Utils.bytesToHex(getHash(levelMask.getLevel()));
+ return hashHex.substring(0, 4) + ".." + hashHex.substring(hashHex.length() - 5, hashHex.length() - 1);
+ }
+
public byte[] getHash(int lvl) {
int hashIndex = levelMask.apply(lvl).getHashIndex();
if (type == CellType.PRUNED_BRANCH) {
diff --git a/emulator/pom.xml b/emulator/pom.xml
index 33837d56..ce2dddba 100644
--- a/emulator/pom.xml
+++ b/emulator/pom.xml
@@ -108,11 +108,6 @@
0.7.1
compile
-
- net.java.dev.jna
- jna-platform
- 5.15.0
-
\ No newline at end of file
diff --git a/emulator/src/main/java/org/ton/java/emulator/tvm/TvmEmulator.java b/emulator/src/main/java/org/ton/java/emulator/tvm/TvmEmulator.java
index 38380f8f..713a8367 100644
--- a/emulator/src/main/java/org/ton/java/emulator/tvm/TvmEmulator.java
+++ b/emulator/src/main/java/org/ton/java/emulator/tvm/TvmEmulator.java
@@ -6,8 +6,7 @@
import com.google.gson.GsonBuilder;
import com.google.gson.ToNumberPolicy;
import com.sun.jna.Native;
-import com.sun.jna.platform.win32.Kernel32;
-import com.sun.jna.platform.win32.WinNT;
+
import java.math.BigInteger;
import java.util.Collections;
import lombok.Builder;
@@ -66,7 +65,7 @@ public TvmEmulator build() {
super.verbosityLevel = TvmVerbosityLevel.TRUNCATED;
}
- redirectNativeOutput();
+ Utils.disableNativeOutput();
if (isNull(super.codeBoc)) {
throw new Error("codeBoc is not set");
@@ -82,6 +81,8 @@ public TvmEmulator build() {
super.tvmEmulatorI.tvm_emulator_set_debug_enabled(super.tvmEmulator, true);
}
+ Utils.enableNativeOutput();
+
if (super.tvmEmulator == 0) {
throw new Error("Can't create emulator instance");
}
@@ -97,7 +98,9 @@ public TvmEmulator build() {
}
public void destroy() {
+ Utils.disableNativeOutput();
tvmEmulatorI.tvm_emulator_destroy(tvmEmulator);
+ Utils.enableNativeOutput();
}
/**
@@ -107,7 +110,10 @@ public void destroy() {
* @return true in case of success, false in case of error
*/
public boolean setLibs(String libsBoc) {
- return tvmEmulatorI.tvm_emulator_set_libraries(tvmEmulator, libsBoc);
+ Utils.disableNativeOutput();
+ boolean result = tvmEmulatorI.tvm_emulator_set_libraries(tvmEmulator, libsBoc);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -136,8 +142,11 @@ public boolean setLibs(String libsBoc) {
*/
public boolean setC7(
String address, long unixTime, long balance, String randSeedHex, String config) {
- return tvmEmulatorI.tvm_emulator_set_c7(
+ Utils.disableNativeOutput();
+ boolean result = tvmEmulatorI.tvm_emulator_set_c7(
tvmEmulator, address, unixTime, balance, randSeedHex, config);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -147,7 +156,10 @@ public boolean setC7(
* @return true in case of success, false in case of error
*/
public boolean setPrevBlockInfo(String infoBoc) {
- return tvmEmulatorI.tvm_emulator_set_prev_blocks_info(tvmEmulator, infoBoc);
+ Utils.disableNativeOutput();
+ boolean result = tvmEmulatorI.tvm_emulator_set_prev_blocks_info(tvmEmulator, infoBoc);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -157,7 +169,10 @@ public boolean setPrevBlockInfo(String infoBoc) {
* @return true in case of success, false in case of error
*/
public boolean setGasLimit(long gasLimit) {
- return tvmEmulatorI.tvm_emulator_set_gas_limit(tvmEmulator, gasLimit);
+ Utils.disableNativeOutput();
+ boolean result = tvmEmulatorI.tvm_emulator_set_gas_limit(tvmEmulator, gasLimit);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -167,7 +182,10 @@ public boolean setGasLimit(long gasLimit) {
* @return true in case of success, false in case of error
*/
public boolean setDebugEnabled(boolean debugEnabled) {
- return tvmEmulatorI.tvm_emulator_set_debug_enabled(tvmEmulator, debugEnabled);
+ Utils.disableNativeOutput();
+ boolean result = tvmEmulatorI.tvm_emulator_set_debug_enabled(tvmEmulator, debugEnabled);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -180,7 +198,9 @@ public boolean setDebugEnabled(boolean debugEnabled) {
* serialized stack (VmStack)", "missing_library": null, "gas_used": 1212 }
*/
public GetMethodResult runGetMethod(int methodId, String stackBoc) {
+ Utils.disableNativeOutput();
String result = tvmEmulatorI.tvm_emulator_run_get_method(tvmEmulator, methodId, stackBoc);
+ Utils.enableNativeOutput();
Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
return gson.fromJson(result, GetMethodResult.class);
}
@@ -194,6 +214,7 @@ public GetMethodResult runGetMethod(int methodId, String stackBoc) {
* serialized stack (VmStack)", "missing_library": null, "gas_used": 1212 }
*/
public GetMethodResult runGetMethod(int methodId) {
+ Utils.disableNativeOutput();
String result =
tvmEmulatorI.tvm_emulator_run_get_method(
tvmEmulator,
@@ -204,11 +225,13 @@ public GetMethodResult runGetMethod(int methodId) {
.build()
.toCell()
.toBase64());
+ Utils.enableNativeOutput();
Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
return gson.fromJson(result, GetMethodResult.class);
}
public GetMethodResult runGetMethod(String methodName) {
+ Utils.disableNativeOutput();
String result =
tvmEmulatorI.tvm_emulator_run_get_method(
tvmEmulator,
@@ -219,6 +242,7 @@ public GetMethodResult runGetMethod(String methodName) {
.build()
.toCell()
.toBase64());
+ Utils.enableNativeOutput();
Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
return gson.fromJson(result, GetMethodResult.class);
}
@@ -233,9 +257,11 @@ public GetMethodResult runGetMethod(String methodName) {
* serialized stack (VmStack)", "missing_library": null, "gas_used": 1212 }
*/
public GetMethodResult runGetMethod(String methodName, String stackBoc) {
+ Utils.disableNativeOutput();
String result =
tvmEmulatorI.tvm_emulator_run_get_method(
tvmEmulator, Utils.calculateMethodId(methodName), stackBoc);
+ Utils.enableNativeOutput();
Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
return gson.fromJson(result, GetMethodResult.class);
}
@@ -291,7 +317,10 @@ public String runGetPublicKey() {
* result$_ exit_code:(## 32) gas_used:(## 32) stack:^VmStack
*/
public String emulateRunMethod(int len, String paramsBoc, long gasLimit) {
- return tvmEmulatorI.tvm_emulator_emulate_run_method(len, paramsBoc, gasLimit);
+ Utils.disableNativeOutput();
+ String result = tvmEmulatorI.tvm_emulator_emulate_run_method(len, paramsBoc, gasLimit);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -305,7 +334,9 @@ public String emulateRunMethod(int len, String paramsBoc, long gasLimit) {
* type (OutList n)" }
*/
public SendExternalMessageResult sendExternalMessage(String messageBodyBoc) {
+ Utils.disableNativeOutput();
String result = tvmEmulatorI.tvm_emulator_send_external_message(tvmEmulator, messageBodyBoc);
+ Utils.enableNativeOutput();
Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
return gson.fromJson(result, SendExternalMessageResult.class);
}
@@ -322,39 +353,11 @@ public SendExternalMessageResult sendExternalMessage(String messageBodyBoc) {
* type (OutList n)" }
*/
public SendInternalMessageResult sendInternalMessage(String messageBodyBoc, long amount) {
+ Utils.disableNativeOutput();
String result =
tvmEmulatorI.tvm_emulator_send_internal_message(tvmEmulator, messageBodyBoc, amount);
+ Utils.enableNativeOutput();
Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
return gson.fromJson(result, SendInternalMessageResult.class);
}
-
- private static void redirectNativeOutput() {
-
- // Redirect native output on Windows
- WinNT.HANDLE originalOut = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_OUTPUT_HANDLE);
- WinNT.HANDLE originalErr = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_ERROR_HANDLE);
-
- // try (FileOutputStream nulStream = new FileOutputStream("NUL")) {
- WinNT.HANDLE hNul =
- Kernel32.INSTANCE.CreateFile(
- "NUL",
- Kernel32.GENERIC_WRITE,
- Kernel32.FILE_SHARE_WRITE,
- null,
- Kernel32.OPEN_EXISTING,
- 0,
- null);
-
- // Redirect stdout and stderr to NUL
- Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_OUTPUT_HANDLE, hNul);
- Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_ERROR_HANDLE, hNul);
-
- // // Close the handle to NUL
- // Kernel32.INSTANCE.CloseHandle(hNul);
- // } finally {
- // // Restore original stdout and stderr
- // Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_OUTPUT_HANDLE, originalOut);
- // Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_ERROR_HANDLE, originalErr);
- // }
- }
}
diff --git a/emulator/src/main/java/org/ton/java/emulator/tx/TxEmulator.java b/emulator/src/main/java/org/ton/java/emulator/tx/TxEmulator.java
index 5e8997c1..24c94be7 100644
--- a/emulator/src/main/java/org/ton/java/emulator/tx/TxEmulator.java
+++ b/emulator/src/main/java/org/ton/java/emulator/tx/TxEmulator.java
@@ -6,10 +6,7 @@
import com.google.gson.GsonBuilder;
import com.google.gson.ToNumberPolicy;
import com.sun.jna.Native;
-import com.sun.jna.platform.win32.Kernel32;
-import com.sun.jna.platform.win32.WinNT;
-import java.io.FileOutputStream;
-import java.io.IOException;
+
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
@@ -68,8 +65,6 @@ public TxEmulator build() {
super.verbosityLevel = TxVerbosityLevel.TRUNCATED;
}
- redirectNativeOutput();
-
if (isNull(super.configType)) {
super.configType = TxEmulatorConfig.MAINNET;
}
@@ -101,6 +96,8 @@ public TxEmulator build() {
}
}
+ Utils.disableNativeOutput();
+
super.txEmulator =
super.txEmulatorI.transaction_emulator_create(
configBoc, super.verbosityLevel.ordinal());
@@ -112,6 +109,8 @@ public TxEmulator build() {
super.txEmulatorI.transaction_emulator_set_debug_enabled(super.txEmulator, true);
}
+ Utils.enableNativeOutput();
+
if (super.txEmulator == 0) {
throw new Error("Can't create tx emulator instance");
}
@@ -134,43 +133,7 @@ public TxEmulator build() {
}
}
- private static void redirectNativeOutput() {
-
- if ((Utils.getOS() == Utils.OS.WINDOWS) || (Utils.getOS() == Utils.OS.WINDOWS_ARM)) {
- // Redirect native output on Windows
- WinNT.HANDLE originalOut = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_OUTPUT_HANDLE);
- WinNT.HANDLE originalErr = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_ERROR_HANDLE);
-
- try (FileOutputStream nulStream = new FileOutputStream("NUL")) {
- WinNT.HANDLE hNul =
- Kernel32.INSTANCE.CreateFile(
- "NUL",
- Kernel32.GENERIC_WRITE,
- Kernel32.FILE_SHARE_WRITE,
- null,
- Kernel32.OPEN_EXISTING,
- 0,
- null);
-
- // Redirect stdout and stderr to NUL
- Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_OUTPUT_HANDLE, hNul);
- Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_ERROR_HANDLE, hNul);
-
- // Close the handle to NUL
- Kernel32.INSTANCE.CloseHandle(hNul);
- } catch (IOException e) {
- throw new RuntimeException(e);
- } finally {
- // Restore original stdout and stderr
- Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_OUTPUT_HANDLE, originalOut);
- Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_ERROR_HANDLE, originalErr);
- }
- } else if ((Utils.getOS() == Utils.OS.LINUX) || (Utils.getOS() == Utils.OS.LINUX_ARM)) {
- // asdf
- } else if ((Utils.getOS() == Utils.OS.MAC) || (Utils.getOS() == Utils.OS.MAC_ARM64)) {
- // asdf
- }
- }
+
public void destroy() {
txEmulatorI.transaction_emulator_destroy(txEmulator);
@@ -189,9 +152,11 @@ public void destroy() {
* actions boc (OutList n)", "elapsed_time": 0.02 }
*/
public EmulateTransactionResult emulateTransaction(String shardAccountBoc, String messageBoc) {
+ Utils.disableNativeOutput();
String result =
txEmulatorI.transaction_emulator_emulate_transaction(
txEmulator, shardAccountBoc, messageBoc);
+ Utils.enableNativeOutput();
Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
return gson.fromJson(result, EmulateTransactionResult.class);
}
@@ -245,9 +210,11 @@ public EmulateTransactionResult emulateTransaction(
String shardAccountBocBase64 = shardAccount.toCell().toBase64();
+ Utils.disableNativeOutput();
String result =
txEmulatorI.transaction_emulator_emulate_transaction(
txEmulator, shardAccountBocBase64, messageBoc);
+ Utils.enableNativeOutput();
Gson gson = new GsonBuilder().setObjectToNumberStrategy(ToNumberPolicy.BIG_DECIMAL).create();
return gson.fromJson(result, EmulateTransactionResult.class);
}
@@ -259,7 +226,9 @@ public EmulateTransactionResult emulateTransaction(
* debug)
*/
public void setVerbosityLevel(int verbosityLevel) {
+ Utils.disableNativeOutput();
txEmulatorI.emulator_set_verbosity_level(txEmulator, verbosityLevel);
+ Utils.enableNativeOutput();
}
/**
@@ -269,7 +238,10 @@ public void setVerbosityLevel(int verbosityLevel) {
* @return true in case of success, false in case of error
*/
public boolean setDebugEnabled(boolean debugEnabled) {
- return txEmulatorI.transaction_emulator_set_debug_enabled(txEmulator, debugEnabled);
+ Utils.disableNativeOutput();
+ boolean result = txEmulatorI.transaction_emulator_set_debug_enabled(txEmulator, debugEnabled);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -279,7 +251,10 @@ public boolean setDebugEnabled(boolean debugEnabled) {
* @return true in case of success, false in case of error
*/
public boolean setLibs(String libsBoc) {
- return txEmulatorI.transaction_emulator_set_libs(txEmulator, libsBoc);
+ Utils.disableNativeOutput();
+ boolean result = txEmulatorI.transaction_emulator_set_libs(txEmulator, libsBoc);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -289,7 +264,10 @@ public boolean setLibs(String libsBoc) {
* @return true in case of success, false in case of error
*/
public boolean setPrevBlockInfo(String infoBoc) {
- return txEmulatorI.transaction_emulator_set_prev_blocks_info(txEmulator, infoBoc);
+ Utils.disableNativeOutput();
+ boolean result = txEmulatorI.transaction_emulator_set_prev_blocks_info(txEmulator, infoBoc);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -299,7 +277,10 @@ public boolean setPrevBlockInfo(String infoBoc) {
* @return true in case of success, false in case of error
*/
public boolean setRandSeed(String randSeedHex) {
- return txEmulatorI.transaction_emulator_set_rand_seed(txEmulator, randSeedHex);
+ Utils.disableNativeOutput();
+ boolean result = txEmulatorI.transaction_emulator_set_rand_seed(txEmulator, randSeedHex);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -309,6 +290,7 @@ public boolean setRandSeed(String randSeedHex) {
* @return true in case of success, false in case of error
*/
public boolean setUnixTime(long utime) {
+ Utils.disableNativeOutput();
return txEmulatorI.transaction_emulator_set_unixtime(txEmulator, utime);
}
@@ -319,7 +301,10 @@ public boolean setUnixTime(long utime) {
* @return true in case of success, false in case of error
*/
public boolean setConfig(String configBoc) {
- return txEmulatorI.transaction_emulator_set_config(txEmulator, configBoc);
+ Utils.disableNativeOutput();
+ boolean result = txEmulatorI.transaction_emulator_set_config(txEmulator, configBoc);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -329,7 +314,10 @@ public boolean setConfig(String configBoc) {
* @return Pointer to Config object or nullptr in case of error
*/
public long createConfig(String configBoc) {
- return txEmulatorI.emulator_config_create(configBoc);
+ Utils.disableNativeOutput();
+ long result = txEmulatorI.emulator_config_create(configBoc);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -338,7 +326,9 @@ public long createConfig(String configBoc) {
* @param config Pointer to Config object
*/
public void destroyConfig(long config) {
+ Utils.disableNativeOutput();
txEmulatorI.emulator_config_destroy(config);
+ Utils.enableNativeOutput();
}
/**
@@ -354,6 +344,7 @@ public void destroyConfig(long config) {
*/
public EmulateTransactionResult emulateTickTockTransaction(
String shardAccountBoc, boolean isTock) {
+ Utils.disableNativeOutput();
String result =
txEmulatorI.transaction_emulator_emulate_tick_tock_transaction(
txEmulator, shardAccountBoc, isTock);
@@ -368,7 +359,10 @@ public EmulateTransactionResult emulateTickTockTransaction(
* @return true in case of success, false in case of error
*/
public boolean setEmulatorLt(long lt) {
- return txEmulatorI.transaction_emulator_set_lt(txEmulator, lt);
+ Utils.disableNativeOutput();
+ boolean result = txEmulatorI.transaction_emulator_set_lt(txEmulator, lt);
+ Utils.enableNativeOutput();
+ return result;
}
/**
@@ -378,6 +372,9 @@ public boolean setEmulatorLt(long lt) {
* @return true in case of success, false in case of error
*/
public boolean setIgnoreCheckSignature(boolean ignoreChksig) {
- return txEmulatorI.transaction_emulator_set_ignore_chksig(txEmulator, ignoreChksig);
+ Utils.disableNativeOutput();
+ boolean result = txEmulatorI.transaction_emulator_set_ignore_chksig(txEmulator, ignoreChksig);
+ Utils.enableNativeOutput();
+ return result;
}
}
diff --git a/fift/src/main/java/org/ton/java/fift/FiftRunner.java b/fift/src/main/java/org/ton/java/fift/FiftRunner.java
index 396445b9..01a001bf 100644
--- a/fift/src/main/java/org/ton/java/fift/FiftRunner.java
+++ b/fift/src/main/java/org/ton/java/fift/FiftRunner.java
@@ -223,8 +223,12 @@ public Pair executeStdIn(
String.join(
" ", "powershell", "-c", "'" + stdin + "' | " + pathToBinary + " " + include);
} else { // linux & macos
- pb = null; // todo test
- cmd = String.join(" ", "echo", "'" + stdin + "' | " + pathToBinary + " " + include);
+ pb =
+ new ProcessBuilder(
+ "/bin/bash", "-c",
+ "echo", "\"" + stdin + "\" | " + pathToBinary + " " + include )
+ .redirectErrorStream(true);
+ cmd = String.join(" ", "/bin/bash", "-c", "\"echo", "'" , stdin , "'|", pathToBinary + " " + include + "\"");
}
if (printInfo) {
diff --git a/smartcontract/src/main/java/org/ton/java/smartcontract/SmartContractCompiler.java b/smartcontract/src/main/java/org/ton/java/smartcontract/SmartContractCompiler.java
index 14e3fee0..b0476bf0 100644
--- a/smartcontract/src/main/java/org/ton/java/smartcontract/SmartContractCompiler.java
+++ b/smartcontract/src/main/java/org/ton/java/smartcontract/SmartContractCompiler.java
@@ -8,6 +8,7 @@
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.ton.java.cell.Cell;
import org.ton.java.fift.FiftRunner;
@@ -83,39 +84,52 @@ public String compile() {
if (contractPath.contains(".func") || contractPath.contains(".fc")) {
outputFiftAsmFile = funcRunner.run(new File(contractPath).getParent(), contractPath);
// add missing includes, PROGRAM and to boc conversion
- outputFiftAsmFile =
- "\"\"\"\"TonUtil.fif\"\"\"\" include \"\"\"\"Asm.fif\"\"\"\" include PROGRAM{ "
- + outputFiftAsmFile
- + "}END>c 2 boc+>B dup Bx.";
- outputFiftAsmFile =
- outputFiftAsmFile
- .replaceAll("(?:/\\*(?:[^*]|(?:\\*+[^*/]))*\\*+/)|(?://.*)", "")
- .replaceAll("\n", " ")
- .replaceAll("\r", " ");
- } else { // told
+
+ outputFiftAsmFile =
+ "\"TonUtil.fif\" include \"Asm.fif\" include PROGRAM{ "
+ + outputFiftAsmFile
+ + "}END>c 2 boc+>B dup Bx.";
+ outputFiftAsmFile =
+ outputFiftAsmFile
+ .replaceAll("(?:/\\*(?:[^*]|(?:\\*+[^*/]))*\\*+/)|(?://.*)", "")
+ .replaceAll("\n", " ")
+ .replaceAll("\r", " ");
+
+ } else { // tolk
outputFiftAsmFile = tolkRunner.run(new File(contractPath).getParent(), contractPath);
- // add to boc conversion
+
outputFiftAsmFile =
- "\"\"\"\"TonUtil.fif\"\"\"\" include \"\"\"\"Asm.fif\"\"\"\" include "
- + outputFiftAsmFile
- + " 2 boc+>B dup Bx.";
+ "\"TonUtil.fif\" include "
+ +outputFiftAsmFile
+ +" 2 boc+>B dup Bx.";
+
outputFiftAsmFile =
outputFiftAsmFile
- .replaceAll("\"Asm.fif\" include", "")
.replaceAll("(?:/\\*(?:[^*]|(?:\\*+[^*/]))*\\*+/)|(?://.*)", "")
.replaceAll("\n", " ")
.replaceAll("\r", " ");
}
if (outputFiftAsmFile.contains("cannot generate code")
- || outputFiftAsmFile.contains("error: undefined function")) {
+ || outputFiftAsmFile.contains("error: undefined function") || outputFiftAsmFile.contains("Failed to discover")) {
throw new Error("Compile error: " + outputFiftAsmFile);
}
if (printFiftAsmOutput) {
log.info(outputFiftAsmFile);
}
- return fiftRunner.runStdIn(new File(contractPath).getParent(), outputFiftAsmFile);
+
+ String result;
+ try {
+ File fiftFile = new File(contractPath + ".fif");
+ FileUtils.writeStringToFile(fiftFile, outputFiftAsmFile);
+ result = fiftRunner.run(new File(contractPath).getParent(), "-s", fiftFile.getAbsolutePath());
+ FileUtils.deleteQuietly(fiftFile);
+ return result;
+ }
+ catch (Exception e) {
+ throw new Error("Cannot compile "+contractPath+ ", error " + e.getMessage());
+ }
}
/**
diff --git a/tonlib/pom.xml b/tonlib/pom.xml
index 7b9ae876..2e49ed07 100644
--- a/tonlib/pom.xml
+++ b/tonlib/pom.xml
@@ -101,11 +101,6 @@
ch.qos.logback
logback-classic
-
- net.java.dev.jna
- jna-platform
- 5.15.0
-
org.assertj
assertj-core
diff --git a/tonlib/src/main/java/org/ton/java/tonlib/Tonlib.java b/tonlib/src/main/java/org/ton/java/tonlib/Tonlib.java
index a72ce037..6c712f55 100644
--- a/tonlib/src/main/java/org/ton/java/tonlib/Tonlib.java
+++ b/tonlib/src/main/java/org/ton/java/tonlib/Tonlib.java
@@ -7,8 +7,7 @@
import com.google.gson.GsonBuilder;
import com.google.gson.ToNumberPolicy;
import com.sun.jna.Native;
-import com.sun.jna.platform.win32.Kernel32;
-import com.sun.jna.platform.win32.WinNT;
+
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.file.Files;
@@ -155,7 +154,6 @@ public Tonlib build() {
super.runResultParser = new RunResultParser();
super.libraryResultParser = new LibraryResultParser();
- // String originalGlobalConfigStr;
if (isNull(super.pathToGlobalConfig)) {
if (isNull(super.globalConfigAsString)) {
@@ -215,10 +213,12 @@ public Tonlib build() {
super.tonlibJson = Native.load(super.pathToTonlibSharedLib, TonlibJsonI.class);
- redirectNativeOutput();
+ Utils.disableNativeOutput();
super.tonlib = super.tonlibJson.tonlib_client_json_create();
+ Utils.enableNativeOutput();
+
if (super.printInfo) {
log.info(
String.format(
@@ -267,8 +267,11 @@ public Tonlib build() {
VerbosityLevelQuery.builder()
.new_verbosity_level(super.verbosityLevel.ordinal())
.build();
+
+ Utils.disableNativeOutput();
super.tonlibJson.tonlib_client_json_send(super.tonlib, gson.toJson(verbosityLevelQuery));
super.tonlibJson.tonlib_client_json_receive(super.tonlib, super.receiveTimeout);
+ Utils.enableNativeOutput();
initTonlibConfig(globalConfigCurrent);
@@ -315,8 +318,10 @@ private void initTonlibConfig(TonGlobalConfig tonGlobalConfig) {
.build())
.build();
+ Utils.disableNativeOutput();
super.tonlibJson.tonlib_client_json_send(super.tonlib, gson.toJson(tonlibSetup));
super.tonlibJson.tonlib_client_json_receive(super.tonlib, super.receiveTimeout);
+ Utils.enableNativeOutput();
}
}
@@ -325,7 +330,9 @@ private void reinitTonlibConfig(TonGlobalConfig tonGlobalConfig) {
// recreate tonlib instance
// tonlibJson.tonlib_client_json_destroy(tonlib);
destroy();
+
tonlibJson = Native.load(pathToTonlibSharedLib, TonlibJsonI.class);
+ Utils.disableNativeOutput();
tonlib = tonlibJson.tonlib_client_json_create();
// set verbosity
@@ -360,10 +367,14 @@ private void reinitTonlibConfig(TonGlobalConfig tonGlobalConfig) {
tonlibJson.tonlib_client_json_send(tonlib, gson.toJson(tonlibSetup));
tonlibJson.tonlib_client_json_receive(tonlib, receiveTimeout);
+
+ Utils.enableNativeOutput();
}
public void destroy() {
+ Utils.disableNativeOutput();
tonlibJson.tonlib_client_json_destroy(tonlib);
+ Utils.enableNativeOutput();
}
private String receive() {
@@ -371,7 +382,7 @@ private String receive() {
int retry = 0;
while (isNull(result)) {
if (retry > 0) {
- log.info("retry " + retry);
+// log.info("retry " + retry);
}
if (++retry > receiveRetryTimes) {
throw new Error(
@@ -379,7 +390,9 @@ private String receive() {
+ receiveRetryTimes
+ " times was not able retrieve result from lite-server.");
}
+// Utils.disableNativeOutput();
result = tonlibJson.tonlib_client_json_receive(tonlib, receiveTimeout);
+// Utils.enableNativeOutput();
}
return result;
}
@@ -387,9 +400,11 @@ private String receive() {
private String syncAndRead(String query) {
String response = null;
try {
+ Utils.disableNativeOutput();
tonlibJson.tonlib_client_json_send(tonlib, query);
TimeUnit.MILLISECONDS.sleep(200);
response = receive();
+ Utils.enableNativeOutput();
int retry = 0;
outterloop:
do {
@@ -430,7 +445,9 @@ private String syncAndRead(String query) {
reinitTonlibConfig(globalConfigCurrent);
// repeat request
+ Utils.disableNativeOutput();
tonlibJson.tonlib_client_json_send(tonlib, query);
+ Utils.enableNativeOutput();
}
} else if (response.contains("\"@type\":\"ok\"")) {
String queryExtraId = StringUtils.substringBetween(query, "@extra\":\"", "\"}");
@@ -445,9 +462,10 @@ private String syncAndRead(String query) {
if (response.contains(" : duplicate message\"")) {
break outterloop;
}
+ Utils.disableNativeOutput();
TimeUnit.MILLISECONDS.sleep(200);
response = receive();
-
+ Utils.enableNativeOutput();
UpdateSyncState sync = gson.fromJson(response, UpdateSyncState.class);
if (nonNull(sync)
&& nonNull(sync.getSync_state())
@@ -482,7 +500,9 @@ && nonNull(sync.getSync_state())
+ " times was not able retrieve result from lite-server.");
}
+ Utils.disableNativeOutput();
tonlibJson.tonlib_client_json_send(tonlib, query);
+ Utils.enableNativeOutput();
}
} while (response.contains("error") || response.contains("syncStateInProgress"));
@@ -1487,7 +1507,9 @@ public RawTransaction getRawTransaction(byte workchain, ShortTxId tx) {
.try_decode_message(false)
.build();
+ Utils.disableNativeOutput();
String result = syncAndRead(gson.toJson(getRawTransactionsQuery));
+ Utils.enableNativeOutput();
RawTransactions res = gson.fromJson(result, RawTransactions.class);
List t = res.getTransactions();
if (t.size() >= 1) {
@@ -1600,7 +1622,7 @@ public void waitForDeployment(Address address, int timeoutSeconds) {
public void waitForBalanceChange(Address address, int timeoutSeconds) {
log.info(
- "Waiting for balance change up to {}s - {} - ({})",
+ "Waiting for balance change (up to {}s) - {} - ({})",
timeoutSeconds,
testnet ? address.toBounceableTestnet() : address.toBounceable(),
address.toRaw());
@@ -1615,36 +1637,6 @@ public void waitForBalanceChange(Address address, int timeoutSeconds) {
} while (initialBalance.equals(getAccountBalance(address)));
}
- private static void redirectNativeOutput() {
-
- // Redirect native output on Windows
- WinNT.HANDLE originalOut = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_OUTPUT_HANDLE);
- WinNT.HANDLE originalErr = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_ERROR_HANDLE);
-
- // try (FileOutputStream nulStream = new FileOutputStream("NUL")) {
- WinNT.HANDLE hNul =
- Kernel32.INSTANCE.CreateFile(
- "NUL",
- Kernel32.GENERIC_WRITE,
- Kernel32.FILE_SHARE_WRITE,
- null,
- Kernel32.OPEN_EXISTING,
- 0,
- null);
-
- // Redirect stdout and stderr to NUL
- Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_OUTPUT_HANDLE, hNul);
- Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_ERROR_HANDLE, hNul);
-
- // // Close the handle to NUL
- // Kernel32.INSTANCE.CloseHandle(hNul);
- // } finally {
- // // Restore original stdout and stderr
- // Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_OUTPUT_HANDLE, originalOut);
- // Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_ERROR_HANDLE, originalErr);
- // }
- }
-
public boolean isTestnet() {
return testnet;
}
diff --git a/utils/pom.xml b/utils/pom.xml
index ed03219a..930a3ba3 100644
--- a/utils/pom.xml
+++ b/utils/pom.xml
@@ -55,6 +55,11 @@
0.4.7
compile
+
+ net.java.dev.jna
+ jna-platform
+ 5.15.0
+
junit
diff --git a/utils/src/main/java/org/ton/java/utils/Utils.java b/utils/src/main/java/org/ton/java/utils/Utils.java
index 99b53064..33ea9a24 100644
--- a/utils/src/main/java/org/ton/java/utils/Utils.java
+++ b/utils/src/main/java/org/ton/java/utils/Utils.java
@@ -1,9 +1,9 @@
package org.ton.java.utils;
import com.iwebpp.crypto.TweetNaclFast;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
+
+import java.io.*;
+import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
@@ -21,6 +21,11 @@
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
+
+import com.sun.jna.Library;
+import com.sun.jna.Native;
+import com.sun.jna.platform.win32.Kernel32;
+import com.sun.jna.platform.win32.WinNT;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.RandomStringUtils;
@@ -1037,4 +1042,126 @@ public static int getRandomInt() {
public static long getRandomLong() {
return new Random().nextLong();
}
+
+ public interface CStdLib extends Library {
+ int dup(int oldfd); // Duplicate a file descriptor
+ int dup2(int oldfd, int newfd); // Duplicate a file descriptor to a specified descriptor
+ int close(int fd); // Close a file descriptor
+ }
+
+ // Redirect native output on Windows
+ static WinNT.HANDLE originalOut;
+ static WinNT.HANDLE originalErr;
+ static int originalStdoutFD;
+ static int originalStderrFD;
+ static CStdLib cStdLib;
+
+ public static void disableNativeOutput() {
+// System.out.println("disable");
+ try {
+ if ((Utils.getOS() == Utils.OS.WINDOWS) || (Utils.getOS() == Utils.OS.WINDOWS_ARM)) {
+ // Redirect native output on Windows
+ originalOut = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_OUTPUT_HANDLE);
+ originalErr = Kernel32.INSTANCE.GetStdHandle(Kernel32.STD_ERROR_HANDLE);
+
+ try {
+ FileOutputStream nulStream = new FileOutputStream("NUL");
+
+ WinNT.HANDLE hNul =
+ Kernel32.INSTANCE.CreateFile(
+ "NUL",
+ Kernel32.GENERIC_WRITE,
+ Kernel32.FILE_SHARE_WRITE,
+ null,
+ Kernel32.OPEN_EXISTING,
+ 0,
+ null);
+
+ // Redirect stdout and stderr to NUL
+ Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_OUTPUT_HANDLE, hNul);
+ Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_ERROR_HANDLE, hNul);
+
+ // Close the handle to NUL
+ Kernel32.INSTANCE.CloseHandle(hNul);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ } else if ((Utils.getOS() == Utils.OS.LINUX) || (Utils.getOS() == Utils.OS.LINUX_ARM)) {
+ try {
+ // Load the native library
+ cStdLib = Native.load("c", CStdLib.class);
+
+ // Save original stdout and stderr file descriptors
+ originalStdoutFD = cStdLib.dup(1);
+ originalStderrFD = cStdLib.dup(2);
+
+ // Redirect stdout and stderr to /dev/null
+ try (FileOutputStream devNull = new FileOutputStream("/dev/null")) {
+ // Get the file descriptor for /dev/null
+ FileDescriptor fd = devNull.getFD();
+
+ // Get the file descriptor integer value by accessing the private field via reflection
+ // Retrieve the field that holds the actual fd (in a private field)
+ Field fdField = FileDescriptor.class.getDeclaredField("fd");
+ fdField.setAccessible(true);
+ int devNullFD = (int) fdField.get(fd);
+
+ cStdLib.dup2(devNullFD, 1);
+ cStdLib.dup2(devNullFD, 2);
+
+ } catch (IOException | NoSuchFieldException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ } catch (Exception e) {
+ System.out.println("error here " + e.getMessage());
+ }
+ } else if ((Utils.getOS() == Utils.OS.MAC) || (Utils.getOS() == Utils.OS.MAC_ARM64)) {
+ // Load the native library
+ CStdLib cStdLib = Native.load("c", CStdLib.class);
+
+ // Redirect stdout and stderr to /dev/null
+ try (FileOutputStream devNull = new FileOutputStream("/dev/null")) {
+ // Get the file descriptor for /dev/null
+ FileDescriptor fd = devNull.getFD();
+
+ // Get the file descriptor integer value by accessing the private field via reflection
+ // Retrieve the field that holds the actual fd (in a private field)
+ Field fdField = FileDescriptor.class.getDeclaredField("fd");
+ fdField.setAccessible(true);
+ int devNullFD = (int) fdField.get(fd);
+
+ // Duplicate and redirect stdout and stderr
+ int stdoutFD = 1; // File descriptor for stdout
+ int stderrFD = 2; // File descriptor for stderr
+ cStdLib.dup2(devNullFD, stdoutFD);
+ cStdLib.dup2(devNullFD, stderrFD);
+
+ } catch (IOException | NoSuchFieldException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ catch (Exception e) {
+ System.err.println("cannot disable native stdout");
+ }
+ }
+
+ public static void enableNativeOutput() {
+ try {
+ if ((Utils.getOS() == Utils.OS.WINDOWS) || (Utils.getOS() == Utils.OS.WINDOWS_ARM)) {
+ Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_OUTPUT_HANDLE, originalOut);
+ Kernel32.INSTANCE.SetStdHandle(Kernel32.STD_ERROR_HANDLE, originalErr);
+ } else if ((Utils.getOS() == Utils.OS.LINUX) || (Utils.getOS() == Utils.OS.LINUX_ARM)) {
+ cStdLib.dup2(originalStdoutFD, 1);
+ cStdLib.dup2(originalStderrFD, 2);
+ } else if ((Utils.getOS() == Utils.OS.MAC) || (Utils.getOS() == Utils.OS.MAC_ARM64)) {
+ cStdLib.dup2(originalStdoutFD, 1);
+ cStdLib.dup2(originalStderrFD, 2);
+ }
+ }
+ catch (Exception e) {
+ System.err.println("cannot enable native stdout");
+ }
+// System.out.println("enable");
+ }
}
diff --git a/utils/src/test/java/org/ton/java/utils/TestUtils.java b/utils/src/test/java/org/ton/java/utils/TestUtils.java
index 7d933a1b..3def24bd 100644
--- a/utils/src/test/java/org/ton/java/utils/TestUtils.java
+++ b/utils/src/test/java/org/ton/java/utils/TestUtils.java
@@ -2,6 +2,7 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.DecoderException;
+import org.apache.commons.lang3.SystemUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -432,6 +433,15 @@ public void testStringIpToInt() {
ip = "135.181.177.59"; // mainnet [2] - 135.181.177.59
log.info("ip {}", ip2int(ip));
assertThat(ip2int(ip)).isEqualTo(-2018135749);
+ }
+ @Test
+ public void testDisableEnableSystemOutput() {
+ long l = System.currentTimeMillis();
+ for (int i = 0; i < 10000; i++) {
+ Utils.disableNativeOutput();
+ Utils.enableNativeOutput();
+ }
+ log.info("10k switches took {}ms", System.currentTimeMillis() - l);
}
}