Merge branch 'dev' into duke
This commit is contained in:
@@ -2,8 +2,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N)
|
||||
AC_PREREQ([2.60])
|
||||
define(_CLIENT_VERSION_MAJOR, 3)
|
||||
dnl Must be kept in sync with src/clientversion.h , ugh!
|
||||
define(_CLIENT_VERSION_MINOR, 9)
|
||||
define(_CLIENT_VERSION_REVISION, 4)
|
||||
define(_CLIENT_VERSION_MINOR, 10)
|
||||
define(_CLIENT_VERSION_REVISION, 0)
|
||||
define(_CLIENT_VERSION_BUILD, 50)
|
||||
define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50)))
|
||||
define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1)))
|
||||
|
||||
@@ -14,7 +14,7 @@ ifneq ($(build_os),darwin)
|
||||
$(package)_config_opts_darwin=--disable-atomicsupport
|
||||
endif
|
||||
$(package)_config_opts_aarch64=--disable-atomicsupport
|
||||
$(package)_cxxflags=-std=c++11
|
||||
$(package)_cxxflags+=-std=c++11
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
|
||||
@@ -22,7 +22,7 @@ $(package)_archiver_$(host_os)=$($(package)_ar)
|
||||
$(package)_toolset_darwin=gcc
|
||||
$(package)_archiver_darwin=$($(package)_ar)
|
||||
$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test
|
||||
$(package)_cxxflags=-std=c++11 -fvisibility=hidden
|
||||
$(package)_cxxflags+=-std=c++11 -fvisibility=hidden
|
||||
$(package)_cxxflags_linux=-fPIC
|
||||
endef
|
||||
|
||||
|
||||
@@ -124,3 +124,9 @@ Install deps on Linux:
|
||||
Use `./util/build-mac.sh` to compile on Apple/Mac systems, use `./util/build-win.sh` to build on Windows and `./util/build-arm.sh` to build on ARMv8 systems.
|
||||
|
||||
Use `./util/build-debian-package.sh aarch64` to build a Debian package for aarch64 .
|
||||
|
||||
## Optional things
|
||||
|
||||
### Updating RandomX
|
||||
|
||||
If you need to update the source code of our in tree copy of RandomX, see issue https://git.hush.is/hush/hush3/issues/337#issuecomment-5114 for details. Currently we use RandomX v1.2.1 from the official repo at https://github.com/tevador/RandomX/releases/tag/v1.2.1
|
||||
@@ -10,6 +10,36 @@ and no longer on Github, since they banned Duke Leto and
|
||||
also because they censor many people around the world and work with
|
||||
evil organizations.
|
||||
|
||||
# Hush 3.10.0 ""
|
||||
|
||||
This is a MANDATORY release for Hush and nodes must upgrade by block height X, which will happen
|
||||
on approximately Y. This is an OPTIONAL release for DragonX but it is highly recommended for
|
||||
exchanges, solo miners and mining pools to update to this release.
|
||||
|
||||
|
||||
* Hush and all Hush Smart Chains now use less RAM https://git.hush.is/hush/hush3/issues/283
|
||||
* Hush full nodes will use ~2GB less RAM
|
||||
* DragonX full nodes will use ~30MB less RAM
|
||||
* Antispam defenses
|
||||
* Hush and all Hush Smart Chains now make it harder and more expensive for an attacker to send shielded spam. This raises the cost in CPU https://git.hush.is/hush/hush3/commit/14d3ae17851615a69c33cb7eed623b904b140e3d and transaction fees https://git.hush.is/hush/hush3/commit/2308db22eec78d0a10bde0f674243b2700d59e4a for Denial-of-Service attacks.
|
||||
* New RPC `z_getstats` which reports data about numer of shielded inputs (zins) and shielded outputs (zouts) in transactions. https://git.hush.is/hush/hush3/commit/96ae2d61ca5a392cb476da4c7f6ab1f638839a7f
|
||||
* Fix a bug where `hush-cli stop` would not stop the node during the "Building Witnesses" rescan phase https://git.hush.is/hush/hush3/issues/330
|
||||
* Fix bugs where `abortrescan` couldn't be used when node is start up (RPC warmup) and where it could not abort the rescan if it was in the "Building Witnesses" phase https://git.hush.is/hush/hush3/issues/331
|
||||
* Fix bug in `z_mergetoaddress` where docs said you could use `ANY_ZADDR` but you couldn't https://git.hush.is/hush/hush3/commit/7eb9d75b94469c3fc8c028f29b35be9ac764a10c
|
||||
* RPC `z_listunspent` now returns the text representation of a memo in `memoStr` key
|
||||
* Upgraded curl to 8.4.0 https://git.hush.is/hush/hush3/issues/325
|
||||
* This fixes CVE-2023-38545 which affects very few or potentially no Hush/DragonX users. It could only affect people who compile Hush full node software (not those who use binaries or packages) and who use a malicious SOCKS5 proxy for all network traffic via the operating system.
|
||||
* DragonX specific changes:
|
||||
* Updated to latest RandomX v1.2.1 which includes mining optimizations https://git.hush.is/hush/hush3/commit/6029b3d571009991ae9c4aea0397f4d00be6a817 https://git.hush.is/hush/hush3/issues/337
|
||||
* Fix RandomX mining memory leak and crash https://git.hush.is/hush/hush3/issues/324
|
||||
* This fixes the bug where stopping mining, making a transaction and then starting mining again
|
||||
* This also avoids an out-of-memory crash when miners change the number of threads of mining
|
||||
* Fixing this bug lead to a 10% hashrate increase vs the previous release
|
||||
* Fixed quoting bugs with dragonx-cli script
|
||||
* For instance, many RPCs such as `dragonx z_sendmany ...` would not previously work because the arguments to the RPC were not quoted correctly.
|
||||
|
||||
|
||||
|
||||
# Hush 3.9.4 "Maniacal Manticore"
|
||||
|
||||
```
|
||||
|
||||
@@ -39,7 +39,7 @@ src/bytecode_machine.cpp
|
||||
src/cpu.cpp
|
||||
src/dataset.cpp
|
||||
src/soft_aes.cpp
|
||||
src/virtual_memory.cpp
|
||||
src/virtual_memory.c
|
||||
src/vm_interpreted.cpp
|
||||
src/allocator.cpp
|
||||
src/assembly_generator_x86.cpp
|
||||
@@ -96,7 +96,7 @@ function(add_flag flag)
|
||||
endfunction()
|
||||
|
||||
# x86-64
|
||||
if(ARCH_ID STREQUAL "x86_64" OR ARCH_ID STREQUAL "x86-64" OR ARCH_ID STREQUAL "amd64")
|
||||
if ((CMAKE_SIZEOF_VOID_P EQUAL 8) AND (ARCH_ID STREQUAL "x86_64" OR ARCH_ID STREQUAL "x86-64" OR ARCH_ID STREQUAL "amd64"))
|
||||
list(APPEND randomx_sources
|
||||
src/jit_compiler_x86.cpp)
|
||||
|
||||
@@ -173,6 +173,42 @@ if(ARM_ID STREQUAL "aarch64" OR ARM_ID STREQUAL "arm64" OR ARM_ID STREQUAL "armv
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# RISC-V
|
||||
if(ARCH_ID STREQUAL "riscv64")
|
||||
list(APPEND randomx_sources
|
||||
src/jit_compiler_rv64_static.S
|
||||
src/jit_compiler_rv64.cpp)
|
||||
# cheat because cmake and ccache hate each other
|
||||
set_property(SOURCE src/jit_compiler_rv64_static.S PROPERTY LANGUAGE C)
|
||||
set_property(SOURCE src/jit_compiler_rv64_static.S PROPERTY XCODE_EXPLICIT_FILE_TYPE sourcecode.asm)
|
||||
|
||||
# default build uses the RV64GC baseline
|
||||
set(RVARCH "rv64gc")
|
||||
|
||||
# for native builds, enable Zba and Zbb if supported by the CPU
|
||||
if(ARCH STREQUAL "native")
|
||||
enable_language(ASM)
|
||||
try_run(RANDOMX_ZBA_RUN_FAIL
|
||||
RANDOMX_ZBA_COMPILE_OK
|
||||
${CMAKE_CURRENT_BINARY_DIR}/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/tests/riscv64_zba.s
|
||||
COMPILE_DEFINITIONS "-march=rv64gc_zba")
|
||||
if (RANDOMX_ZBA_COMPILE_OK AND NOT RANDOMX_ZBA_RUN_FAIL)
|
||||
set(RVARCH "${RVARCH}_zba")
|
||||
endif()
|
||||
try_run(RANDOMX_ZBB_RUN_FAIL
|
||||
RANDOMX_ZBB_COMPILE_OK
|
||||
${CMAKE_CURRENT_BINARY_DIR}/
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/tests/riscv64_zbb.s
|
||||
COMPILE_DEFINITIONS "-march=rv64gc_zbb")
|
||||
if (RANDOMX_ZBB_COMPILE_OK AND NOT RANDOMX_ZBB_RUN_FAIL)
|
||||
set(RVARCH "${RVARCH}_zbb")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_flag("-march=${RVARCH}")
|
||||
endif()
|
||||
|
||||
set(RANDOMX_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/src" CACHE STRING "RandomX Include path")
|
||||
|
||||
add_library(randomx ${randomx_sources})
|
||||
|
||||
@@ -37,7 +37,7 @@ RandomX is written in C++11 and builds a static library with a C API provided by
|
||||
|
||||
### Linux
|
||||
|
||||
Build dependencies: `cmake` (minimum 2.8.7) and `gcc` (minimum version 4.8, but version 7+ is recommended).
|
||||
Build dependencies: `cmake` (minimum 3.5) and `gcc` (minimum version 4.8, but version 7+ is recommended).
|
||||
|
||||
To build optimized binaries for your machine, run:
|
||||
```
|
||||
@@ -82,7 +82,7 @@ Intel Core i7-8550U|16G DDR4-2400|Windows 10|hw|200 (4T)|1700 (4T)|350 (8T)|
|
||||
Intel Core i3-3220|4G DDR3-1333|Ubuntu 16.04|soft|42 (4T)|510 (4T)|150 (4T)|
|
||||
Raspberry Pi 3|1G LPDDR2|Ubuntu 16.04|soft|3.5 (4T)|-|20 (4T)|
|
||||
|
||||
Note that RandomX currently includes a JIT compiler for x86-64 and ARM64. Other architectures have to use the portable interpreter, which is much slower.
|
||||
Note that RandomX currently includes a JIT compiler for x86-64, ARM64 and RISCV64. Other architectures have to use the portable interpreter, which is much slower.
|
||||
|
||||
### GPU performance
|
||||
|
||||
@@ -129,6 +129,7 @@ The reference implementation has been validated on the following platforms:
|
||||
* ARMv7+VFPv3 (32-bit, little-endian)
|
||||
* ARMv8 (64-bit, little-endian)
|
||||
* PPC64 (64-bit, big-endian)
|
||||
* RISCV64 (64-bit, little-endian)
|
||||
|
||||
### Can FPGAs mine RandomX?
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEXd+PeBYJKwYBBAHaRw8BAQdAZ0nqJ+nRYoScG2QLX62pl+WO1+Mkv6Yyt2Kb
|
||||
ntGUuLq0G3RldmFkb3IgPHRldmFkb3JAZ21haWwuY29tPoiWBBMWCAA+FiEEMoWj
|
||||
LVEwdmMs6CUQWijIaue9c6YFAl3fj3gCGwMFCQWnqDgFCwkIBwIGFQoJCAsCBBYC
|
||||
AwECHgECF4AACgkQWijIaue9c6YBFQD+N1XTUqSCZp9jB/yTHQ9ahSaIUMtmuvdT
|
||||
So2s+quudP4A/R5wLwukpfGN9UZ4cfpmKCJ9jO1HJ2udmlGMsJbQpDAIuDgEXd+P
|
||||
ntGUuLq0G3RldmFkb3IgPHRldmFkb3JAZ21haWwuY29tPoiWBBMWCAA+AhsDBQsJ
|
||||
CAcCBhUKCQgLAgQWAgMBAh4BAheAFiEEMoWjLVEwdmMs6CUQWijIaue9c6YFAmRP
|
||||
r8MFCQ/ZS2YACgkQWijIaue9c6bR5gEA0tnQ4Al+yOLoRUBQitAV8FU4FLy8Xx8U
|
||||
IyyivjJ0UhIA/2jwJfMXmJdMKtar8xfIA5mZLLofkEP6hug4knhitpkBuDgEXd+P
|
||||
eBIKKwYBBAGXVQEFAQEHQBNbQuPcDojMCkRb5B5u7Ld/AFLClOh+6ElL+u61rIY/
|
||||
AwEIB4h+BBgWCAAmFiEEMoWjLVEwdmMs6CUQWijIaue9c6YFAl3fj3gCGwwFCQWn
|
||||
qDgACgkQWijIaue9c6YJvgD+IY1Q9mCM1P1iZIoXuafRihXJ7UgVXpQqW2yoaUT3
|
||||
bfQA/RkisI2eElYoOjdwPszPP6VfL5+SViwDmDuJG2P5llgE
|
||||
=V4vd
|
||||
AwEIB4h+BBgWCAAmAhsMFiEEMoWjLVEwdmMs6CUQWijIaue9c6YFAmRQoAMFCQ/Z
|
||||
S2YACgkQWijIaue9c6bUfwD9Hw20kGCaZ8rWghz9W3bc645ys1vPQpQW28CD9w3B
|
||||
cTMBALsV1xpS2pGwTfn1PUimqESZfTrREmNvOjKSQwe0yicI
|
||||
=D4lm
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
@@ -29,7 +29,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <new>
|
||||
#include "allocator.hpp"
|
||||
#include "intrin_portable.h"
|
||||
#include "virtual_memory.hpp"
|
||||
#include "virtual_memory.h"
|
||||
#include "common.hpp"
|
||||
|
||||
namespace randomx {
|
||||
|
||||
@@ -445,7 +445,7 @@ namespace randomx {
|
||||
}
|
||||
|
||||
void AssemblyGeneratorX86::h_IMUL_RCP(Instruction& instr, int i) {
|
||||
uint64_t divisor = instr.getImm32();
|
||||
const uint32_t divisor = instr.getImm32();
|
||||
if (!isZeroOrPowerOf2(divisor)) {
|
||||
registerUsage[instr.dst] = i;
|
||||
asmCode << "\tmov rax, " << randomx_reciprocal(divisor) << std::endl;
|
||||
|
||||
@@ -243,7 +243,7 @@ namespace randomx {
|
||||
}
|
||||
|
||||
if (opcode < ceil_IMUL_RCP) {
|
||||
uint64_t divisor = instr.getImm32();
|
||||
const uint32_t divisor = instr.getImm32();
|
||||
if (!isZeroOrPowerOf2(divisor)) {
|
||||
auto dst = instr.dst % RegistersCount;
|
||||
ibc.type = InstructionType::IMUL_R;
|
||||
|
||||
@@ -116,12 +116,19 @@ namespace randomx {
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define RANDOMX_HAVE_COMPILER 1
|
||||
#define RANDOMX_COMPILER_X86
|
||||
class JitCompilerX86;
|
||||
using JitCompiler = JitCompilerX86;
|
||||
#elif defined(__aarch64__)
|
||||
#define RANDOMX_HAVE_COMPILER 1
|
||||
#define RANDOMX_COMPILER_A64
|
||||
class JitCompilerA64;
|
||||
using JitCompiler = JitCompilerA64;
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
#define RANDOMX_HAVE_COMPILER 1
|
||||
#define RANDOMX_COMPILER_RV64
|
||||
class JitCompilerRV64;
|
||||
using JitCompiler = JitCompilerRV64;
|
||||
#else
|
||||
#define RANDOMX_HAVE_COMPILER 0
|
||||
class JitCompilerFallback;
|
||||
|
||||
@@ -42,7 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "common.hpp"
|
||||
#include "dataset.hpp"
|
||||
#include "virtual_memory.hpp"
|
||||
#include "virtual_memory.h"
|
||||
#include "superscalar.hpp"
|
||||
#include "blake2_generator.hpp"
|
||||
#include "reciprocal.h"
|
||||
|
||||
@@ -349,7 +349,7 @@ FORCE_INLINE rx_vec_i128 rx_load_vec_i128(rx_vec_i128 const *p) {
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
return *p;
|
||||
#else
|
||||
uint32_t* ptr = (uint32_t*)p;
|
||||
const uint32_t* ptr = (const uint32_t*)p;
|
||||
vec_u c;
|
||||
c.u32[0] = load32(ptr + 0);
|
||||
c.u32[1] = load32(ptr + 1);
|
||||
@@ -375,8 +375,8 @@ FORCE_INLINE void rx_store_vec_i128(rx_vec_i128 *p, rx_vec_i128 b) {
|
||||
|
||||
FORCE_INLINE rx_vec_f128 rx_cvt_packed_int_vec_f128(const void* addr) {
|
||||
vec_u x;
|
||||
x.d64[0] = (double)unsigned32ToSigned2sCompl(load32((uint8_t*)addr + 0));
|
||||
x.d64[1] = (double)unsigned32ToSigned2sCompl(load32((uint8_t*)addr + 4));
|
||||
x.d64[0] = (double)unsigned32ToSigned2sCompl(load32((const uint8_t*)addr + 0));
|
||||
x.d64[1] = (double)unsigned32ToSigned2sCompl(load32((const uint8_t*)addr + 4));
|
||||
return (rx_vec_f128)x.d;
|
||||
}
|
||||
|
||||
@@ -684,7 +684,7 @@ FORCE_INLINE rx_vec_i128 rx_load_vec_i128(rx_vec_i128 const* p) {
|
||||
#if defined(NATIVE_LITTLE_ENDIAN)
|
||||
return *p;
|
||||
#else
|
||||
uint32_t* ptr = (uint32_t*)p;
|
||||
const uint32_t* ptr = (const uint32_t*)p;
|
||||
rx_vec_i128 c;
|
||||
c.u32[0] = load32(ptr + 0);
|
||||
c.u32[1] = load32(ptr + 1);
|
||||
@@ -708,8 +708,8 @@ FORCE_INLINE void rx_store_vec_i128(rx_vec_i128 *p, rx_vec_i128 b) {
|
||||
|
||||
FORCE_INLINE rx_vec_f128 rx_cvt_packed_int_vec_f128(const void* addr) {
|
||||
rx_vec_f128 x;
|
||||
x.lo = (double)unsigned32ToSigned2sCompl(load32((uint8_t*)addr + 0));
|
||||
x.hi = (double)unsigned32ToSigned2sCompl(load32((uint8_t*)addr + 4));
|
||||
x.lo = (double)unsigned32ToSigned2sCompl(load32((const uint8_t*)addr + 0));
|
||||
x.hi = (double)unsigned32ToSigned2sCompl(load32((const uint8_t*)addr + 4));
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,10 +28,48 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#include "common.hpp"
|
||||
|
||||
namespace randomx {
|
||||
|
||||
struct CodeBuffer {
|
||||
uint8_t* code;
|
||||
int32_t codePos;
|
||||
int32_t rcpCount;
|
||||
|
||||
void emit(const uint8_t* src, int32_t len) {
|
||||
memcpy(&code[codePos], src, len);
|
||||
codePos += len;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void emit(T src) {
|
||||
memcpy(&code[codePos], &src, sizeof(src));
|
||||
codePos += sizeof(src);
|
||||
}
|
||||
|
||||
void emitAt(int32_t codePos, const uint8_t* src, int32_t len) {
|
||||
memcpy(&code[codePos], src, len);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void emitAt(int32_t codePos, T src) {
|
||||
memcpy(&code[codePos], &src, sizeof(src));
|
||||
}
|
||||
};
|
||||
|
||||
struct CompilerState : public CodeBuffer {
|
||||
int32_t instructionOffsets[RANDOMX_PROGRAM_SIZE];
|
||||
int registerUsage[RegistersCount];
|
||||
};
|
||||
}
|
||||
|
||||
#if defined(RANDOMX_COMPILER_X86)
|
||||
#include "jit_compiler_x86.hpp"
|
||||
#elif defined(__aarch64__)
|
||||
#elif defined(RANDOMX_COMPILER_A64)
|
||||
#include "jit_compiler_a64.hpp"
|
||||
#elif defined(RANDOMX_COMPILER_RV64)
|
||||
#include "jit_compiler_rv64.hpp"
|
||||
#else
|
||||
#include "jit_compiler_fallback.hpp"
|
||||
#endif
|
||||
|
||||
@@ -31,7 +31,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "superscalar.hpp"
|
||||
#include "program.hpp"
|
||||
#include "reciprocal.h"
|
||||
#include "virtual_memory.hpp"
|
||||
#include "virtual_memory.h"
|
||||
|
||||
namespace ARMV8A {
|
||||
|
||||
@@ -130,8 +130,8 @@ void JitCompilerA64::generateProgram(Program& program, ProgramConfiguration& con
|
||||
// and w16, w10, ScratchpadL3Mask64
|
||||
emit32(0x121A0000 | 16 | (10 << 5) | ((Log2(RANDOMX_SCRATCHPAD_L3) - 7) << 10), code, codePos);
|
||||
|
||||
// and w17, w18, ScratchpadL3Mask64
|
||||
emit32(0x121A0000 | 17 | (18 << 5) | ((Log2(RANDOMX_SCRATCHPAD_L3) - 7) << 10), code, codePos);
|
||||
// and w17, w20, ScratchpadL3Mask64
|
||||
emit32(0x121A0000 | 17 | (20 << 5) | ((Log2(RANDOMX_SCRATCHPAD_L3) - 7) << 10), code, codePos);
|
||||
|
||||
codePos = PrologueSize;
|
||||
literalPos = ImulRcpLiteralsEnd;
|
||||
@@ -149,16 +149,16 @@ void JitCompilerA64::generateProgram(Program& program, ProgramConfiguration& con
|
||||
}
|
||||
|
||||
// Update spMix2
|
||||
// eor w18, config.readReg2, config.readReg3
|
||||
emit32(ARMV8A::EOR32 | 18 | (IntRegMap[config.readReg2] << 5) | (IntRegMap[config.readReg3] << 16), code, codePos);
|
||||
// eor w20, config.readReg2, config.readReg3
|
||||
emit32(ARMV8A::EOR32 | 20 | (IntRegMap[config.readReg2] << 5) | (IntRegMap[config.readReg3] << 16), code, codePos);
|
||||
|
||||
// Jump back to the main loop
|
||||
const uint32_t offset = (((uint8_t*)randomx_program_aarch64_vm_instructions_end) - ((uint8_t*)randomx_program_aarch64)) - codePos;
|
||||
emit32(ARMV8A::B | (offset / 4), code, codePos);
|
||||
|
||||
// and w18, w18, CacheLineAlignMask
|
||||
// and w20, w20, CacheLineAlignMask
|
||||
codePos = (((uint8_t*)randomx_program_aarch64_cacheline_align_mask1) - ((uint8_t*)randomx_program_aarch64));
|
||||
emit32(0x121A0000 | 18 | (18 << 5) | ((Log2(RANDOMX_DATASET_BASE_SIZE) - 7) << 10), code, codePos);
|
||||
emit32(0x121A0000 | 20 | (20 << 5) | ((Log2(RANDOMX_DATASET_BASE_SIZE) - 7) << 10), code, codePos);
|
||||
|
||||
// and w10, w10, CacheLineAlignMask
|
||||
codePos = (((uint8_t*)randomx_program_aarch64_cacheline_align_mask2) - ((uint8_t*)randomx_program_aarch64));
|
||||
@@ -181,8 +181,8 @@ void JitCompilerA64::generateProgramLight(Program& program, ProgramConfiguration
|
||||
// and w16, w10, ScratchpadL3Mask64
|
||||
emit32(0x121A0000 | 16 | (10 << 5) | ((Log2(RANDOMX_SCRATCHPAD_L3) - 7) << 10), code, codePos);
|
||||
|
||||
// and w17, w18, ScratchpadL3Mask64
|
||||
emit32(0x121A0000 | 17 | (18 << 5) | ((Log2(RANDOMX_SCRATCHPAD_L3) - 7) << 10), code, codePos);
|
||||
// and w17, w20, ScratchpadL3Mask64
|
||||
emit32(0x121A0000 | 17 | (20 << 5) | ((Log2(RANDOMX_SCRATCHPAD_L3) - 7) << 10), code, codePos);
|
||||
|
||||
codePos = PrologueSize;
|
||||
literalPos = ImulRcpLiteralsEnd;
|
||||
@@ -200,8 +200,8 @@ void JitCompilerA64::generateProgramLight(Program& program, ProgramConfiguration
|
||||
}
|
||||
|
||||
// Update spMix2
|
||||
// eor w18, config.readReg2, config.readReg3
|
||||
emit32(ARMV8A::EOR32 | 18 | (IntRegMap[config.readReg2] << 5) | (IntRegMap[config.readReg3] << 16), code, codePos);
|
||||
// eor w20, config.readReg2, config.readReg3
|
||||
emit32(ARMV8A::EOR32 | 20 | (IntRegMap[config.readReg2] << 5) | (IntRegMap[config.readReg3] << 16), code, codePos);
|
||||
|
||||
// Jump back to the main loop
|
||||
const uint32_t offset = (((uint8_t*)randomx_program_aarch64_vm_instructions_end_light) - ((uint8_t*)randomx_program_aarch64)) - codePos;
|
||||
@@ -434,7 +434,7 @@ void JitCompilerA64::emitAddImmediate(uint32_t dst, uint32_t src, uint32_t imm,
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
emitMovImmediate(tmp_reg, imm, code, k);
|
||||
|
||||
// add dst, src, tmp_reg
|
||||
@@ -483,7 +483,7 @@ void JitCompilerA64::emitMemLoadFP(uint32_t src, Instruction& instr, uint8_t* co
|
||||
uint32_t k = codePos;
|
||||
|
||||
uint32_t imm = instr.getImm32();
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 19;
|
||||
|
||||
imm &= instr.getModMem() ? (RANDOMX_SCRATCHPAD_L1 - 1) : (RANDOMX_SCRATCHPAD_L2 - 1);
|
||||
emitAddImmediate(tmp_reg, src, imm, code, k);
|
||||
@@ -537,7 +537,7 @@ void JitCompilerA64::h_IADD_M(Instruction& instr, uint32_t& codePos)
|
||||
const uint32_t src = IntRegMap[instr.src];
|
||||
const uint32_t dst = IntRegMap[instr.dst];
|
||||
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
emitMemLoad<tmp_reg>(dst, src, instr, code, k);
|
||||
|
||||
// add dst, dst, tmp_reg
|
||||
@@ -575,7 +575,7 @@ void JitCompilerA64::h_ISUB_M(Instruction& instr, uint32_t& codePos)
|
||||
const uint32_t src = IntRegMap[instr.src];
|
||||
const uint32_t dst = IntRegMap[instr.dst];
|
||||
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
emitMemLoad<tmp_reg>(dst, src, instr, code, k);
|
||||
|
||||
// sub dst, dst, tmp_reg
|
||||
@@ -594,7 +594,7 @@ void JitCompilerA64::h_IMUL_R(Instruction& instr, uint32_t& codePos)
|
||||
|
||||
if (src == dst)
|
||||
{
|
||||
src = 18;
|
||||
src = 20;
|
||||
emitMovImmediate(src, instr.getImm32(), code, k);
|
||||
}
|
||||
|
||||
@@ -612,7 +612,7 @@ void JitCompilerA64::h_IMUL_M(Instruction& instr, uint32_t& codePos)
|
||||
const uint32_t src = IntRegMap[instr.src];
|
||||
const uint32_t dst = IntRegMap[instr.dst];
|
||||
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
emitMemLoad<tmp_reg>(dst, src, instr, code, k);
|
||||
|
||||
// sub dst, dst, tmp_reg
|
||||
@@ -643,7 +643,7 @@ void JitCompilerA64::h_IMULH_M(Instruction& instr, uint32_t& codePos)
|
||||
const uint32_t src = IntRegMap[instr.src];
|
||||
const uint32_t dst = IntRegMap[instr.dst];
|
||||
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
emitMemLoad<tmp_reg>(dst, src, instr, code, k);
|
||||
|
||||
// umulh dst, dst, tmp_reg
|
||||
@@ -674,7 +674,7 @@ void JitCompilerA64::h_ISMULH_M(Instruction& instr, uint32_t& codePos)
|
||||
const uint32_t src = IntRegMap[instr.src];
|
||||
const uint32_t dst = IntRegMap[instr.dst];
|
||||
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
emitMemLoad<tmp_reg>(dst, src, instr, code, k);
|
||||
|
||||
// smulh dst, dst, tmp_reg
|
||||
@@ -686,34 +686,24 @@ void JitCompilerA64::h_ISMULH_M(Instruction& instr, uint32_t& codePos)
|
||||
|
||||
void JitCompilerA64::h_IMUL_RCP(Instruction& instr, uint32_t& codePos)
|
||||
{
|
||||
const uint64_t divisor = instr.getImm32();
|
||||
const uint32_t divisor = instr.getImm32();
|
||||
if (isZeroOrPowerOf2(divisor))
|
||||
return;
|
||||
|
||||
uint32_t k = codePos;
|
||||
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
const uint32_t dst = IntRegMap[instr.dst];
|
||||
|
||||
constexpr uint64_t N = 1ULL << 63;
|
||||
const uint64_t q = N / divisor;
|
||||
const uint64_t r = N % divisor;
|
||||
#ifdef __GNUC__
|
||||
const uint64_t shift = 64 - __builtin_clzll(divisor);
|
||||
#else
|
||||
uint64_t shift = 32;
|
||||
for (uint64_t k = 1U << 31; (k & divisor) == 0; k >>= 1)
|
||||
--shift;
|
||||
#endif
|
||||
|
||||
const uint32_t literal_id = (ImulRcpLiteralsEnd - literalPos) / sizeof(uint64_t);
|
||||
|
||||
literalPos -= sizeof(uint64_t);
|
||||
*(uint64_t*)(code + literalPos) = (q << shift) + ((r << shift) / divisor);
|
||||
|
||||
if (literal_id < 13)
|
||||
const uint64_t reciprocal = randomx_reciprocal_fast(divisor);
|
||||
memcpy(code + literalPos, &reciprocal, sizeof(reciprocal));
|
||||
|
||||
if (literal_id < 12)
|
||||
{
|
||||
static constexpr uint32_t literal_regs[13] = { 30 << 16, 29 << 16, 28 << 16, 27 << 16, 26 << 16, 25 << 16, 24 << 16, 23 << 16, 22 << 16, 21 << 16, 20 << 16, 11 << 16, 0 };
|
||||
static constexpr uint32_t literal_regs[12] = { 30 << 16, 29 << 16, 28 << 16, 27 << 16, 26 << 16, 25 << 16, 24 << 16, 23 << 16, 22 << 16, 21 << 16, 11 << 16, 0 };
|
||||
|
||||
// mul dst, dst, literal_reg
|
||||
emit32(ARMV8A::MUL | dst | (dst << 5) | literal_regs[literal_id], code, k);
|
||||
@@ -751,7 +741,7 @@ void JitCompilerA64::h_IXOR_R(Instruction& instr, uint32_t& codePos)
|
||||
|
||||
if (src == dst)
|
||||
{
|
||||
src = 18;
|
||||
src = 20;
|
||||
emitMovImmediate(src, instr.getImm32(), code, k);
|
||||
}
|
||||
|
||||
@@ -769,7 +759,7 @@ void JitCompilerA64::h_IXOR_M(Instruction& instr, uint32_t& codePos)
|
||||
const uint32_t src = IntRegMap[instr.src];
|
||||
const uint32_t dst = IntRegMap[instr.dst];
|
||||
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
emitMemLoad<tmp_reg>(dst, src, instr, code, k);
|
||||
|
||||
// eor dst, dst, tmp_reg
|
||||
@@ -807,7 +797,7 @@ void JitCompilerA64::h_IROL_R(Instruction& instr, uint32_t& codePos)
|
||||
|
||||
if (src != dst)
|
||||
{
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
|
||||
// sub tmp_reg, xzr, src
|
||||
emit32(ARMV8A::SUB | tmp_reg | (31 << 5) | (src << 16), code, k);
|
||||
@@ -835,7 +825,7 @@ void JitCompilerA64::h_ISWAP_R(Instruction& instr, uint32_t& codePos)
|
||||
|
||||
uint32_t k = codePos;
|
||||
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
emit32(ARMV8A::MOV_REG | tmp_reg | (dst << 16), code, k);
|
||||
emit32(ARMV8A::MOV_REG | dst | (src << 16), code, k);
|
||||
emit32(ARMV8A::MOV_REG | src | (tmp_reg << 16), code, k);
|
||||
@@ -984,7 +974,7 @@ void JitCompilerA64::h_CFROUND(Instruction& instr, uint32_t& codePos)
|
||||
|
||||
const uint32_t src = IntRegMap[instr.src];
|
||||
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
constexpr uint32_t fpcr_tmp_reg = 8;
|
||||
|
||||
// ror tmp_reg, src, imm
|
||||
@@ -1008,7 +998,7 @@ void JitCompilerA64::h_ISTORE(Instruction& instr, uint32_t& codePos)
|
||||
|
||||
const uint32_t src = IntRegMap[instr.src];
|
||||
const uint32_t dst = IntRegMap[instr.dst];
|
||||
constexpr uint32_t tmp_reg = 18;
|
||||
constexpr uint32_t tmp_reg = 20;
|
||||
|
||||
uint32_t imm = instr.getImm32();
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace randomx {
|
||||
|
||||
static void emit64(uint64_t val, uint8_t* code, uint32_t& codePos)
|
||||
{
|
||||
*(uint64_t*)(code + codePos) = val;
|
||||
memcpy(code + codePos, &val, sizeof(val));
|
||||
codePos += sizeof(val);
|
||||
}
|
||||
|
||||
|
||||
@@ -74,9 +74,9 @@
|
||||
# x15 -> "r7"
|
||||
# x16 -> spAddr0
|
||||
# x17 -> spAddr1
|
||||
# x18 -> temporary
|
||||
# x18 -> unused (platform register, don't touch it)
|
||||
# x19 -> temporary
|
||||
# x20 -> literal for IMUL_RCP
|
||||
# x20 -> temporary
|
||||
# x21 -> literal for IMUL_RCP
|
||||
# x22 -> literal for IMUL_RCP
|
||||
# x23 -> literal for IMUL_RCP
|
||||
@@ -111,7 +111,7 @@ DECL(randomx_program_aarch64):
|
||||
# Save callee-saved registers
|
||||
sub sp, sp, 192
|
||||
stp x16, x17, [sp]
|
||||
stp x18, x19, [sp, 16]
|
||||
str x19, [sp, 16]
|
||||
stp x20, x21, [sp, 32]
|
||||
stp x22, x23, [sp, 48]
|
||||
stp x24, x25, [sp, 64]
|
||||
@@ -166,7 +166,6 @@ DECL(randomx_program_aarch64):
|
||||
# Read literals
|
||||
ldr x0, literal_x0
|
||||
ldr x11, literal_x11
|
||||
ldr x20, literal_x20
|
||||
ldr x21, literal_x21
|
||||
ldr x22, literal_x22
|
||||
ldr x23, literal_x23
|
||||
@@ -198,11 +197,11 @@ DECL(randomx_program_aarch64):
|
||||
DECL(randomx_program_aarch64_main_loop):
|
||||
# spAddr0 = spMix1 & ScratchpadL3Mask64;
|
||||
# spAddr1 = (spMix1 >> 32) & ScratchpadL3Mask64;
|
||||
lsr x18, x10, 32
|
||||
lsr x20, x10, 32
|
||||
|
||||
# Actual mask will be inserted by JIT compiler
|
||||
and w16, w10, 1
|
||||
and w17, w18, 1
|
||||
and w17, w20, 1
|
||||
|
||||
# x16 = scratchpad + spAddr0
|
||||
# x17 = scratchpad + spAddr1
|
||||
@@ -210,31 +209,31 @@ DECL(randomx_program_aarch64_main_loop):
|
||||
add x17, x17, x2
|
||||
|
||||
# xor integer registers with scratchpad data (spAddr0)
|
||||
ldp x18, x19, [x16]
|
||||
eor x4, x4, x18
|
||||
ldp x20, x19, [x16]
|
||||
eor x4, x4, x20
|
||||
eor x5, x5, x19
|
||||
ldp x18, x19, [x16, 16]
|
||||
eor x6, x6, x18
|
||||
ldp x20, x19, [x16, 16]
|
||||
eor x6, x6, x20
|
||||
eor x7, x7, x19
|
||||
ldp x18, x19, [x16, 32]
|
||||
eor x12, x12, x18
|
||||
ldp x20, x19, [x16, 32]
|
||||
eor x12, x12, x20
|
||||
eor x13, x13, x19
|
||||
ldp x18, x19, [x16, 48]
|
||||
eor x14, x14, x18
|
||||
ldp x20, x19, [x16, 48]
|
||||
eor x14, x14, x20
|
||||
eor x15, x15, x19
|
||||
|
||||
# Load group F registers (spAddr1)
|
||||
ldpsw x18, x19, [x17]
|
||||
ins v16.d[0], x18
|
||||
ldpsw x20, x19, [x17]
|
||||
ins v16.d[0], x20
|
||||
ins v16.d[1], x19
|
||||
ldpsw x18, x19, [x17, 8]
|
||||
ins v17.d[0], x18
|
||||
ldpsw x20, x19, [x17, 8]
|
||||
ins v17.d[0], x20
|
||||
ins v17.d[1], x19
|
||||
ldpsw x18, x19, [x17, 16]
|
||||
ins v18.d[0], x18
|
||||
ldpsw x20, x19, [x17, 16]
|
||||
ins v18.d[0], x20
|
||||
ins v18.d[1], x19
|
||||
ldpsw x18, x19, [x17, 24]
|
||||
ins v19.d[0], x18
|
||||
ldpsw x20, x19, [x17, 24]
|
||||
ins v19.d[0], x20
|
||||
ins v19.d[1], x19
|
||||
scvtf v16.2d, v16.2d
|
||||
scvtf v17.2d, v17.2d
|
||||
@@ -242,17 +241,17 @@ DECL(randomx_program_aarch64_main_loop):
|
||||
scvtf v19.2d, v19.2d
|
||||
|
||||
# Load group E registers (spAddr1)
|
||||
ldpsw x18, x19, [x17, 32]
|
||||
ins v20.d[0], x18
|
||||
ldpsw x20, x19, [x17, 32]
|
||||
ins v20.d[0], x20
|
||||
ins v20.d[1], x19
|
||||
ldpsw x18, x19, [x17, 40]
|
||||
ins v21.d[0], x18
|
||||
ldpsw x20, x19, [x17, 40]
|
||||
ins v21.d[0], x20
|
||||
ins v21.d[1], x19
|
||||
ldpsw x18, x19, [x17, 48]
|
||||
ins v22.d[0], x18
|
||||
ldpsw x20, x19, [x17, 48]
|
||||
ins v22.d[0], x20
|
||||
ins v22.d[1], x19
|
||||
ldpsw x18, x19, [x17, 56]
|
||||
ins v23.d[0], x18
|
||||
ldpsw x20, x19, [x17, 56]
|
||||
ins v23.d[0], x20
|
||||
ins v23.d[1], x19
|
||||
scvtf v20.2d, v20.2d
|
||||
scvtf v21.2d, v21.2d
|
||||
@@ -276,7 +275,6 @@ DECL(randomx_program_aarch64_vm_instructions):
|
||||
|
||||
literal_x0: .fill 1,8,0
|
||||
literal_x11: .fill 1,8,0
|
||||
literal_x20: .fill 1,8,0
|
||||
literal_x21: .fill 1,8,0
|
||||
literal_x22: .fill 1,8,0
|
||||
literal_x23: .fill 1,8,0
|
||||
@@ -312,17 +310,17 @@ DECL(randomx_program_aarch64_vm_instructions_end):
|
||||
lsr x10, x9, 32
|
||||
|
||||
# mx ^= r[readReg2] ^ r[readReg3];
|
||||
eor x9, x9, x18
|
||||
eor x9, x9, x20
|
||||
|
||||
# Calculate dataset pointer for dataset prefetch
|
||||
mov w18, w9
|
||||
mov w20, w9
|
||||
DECL(randomx_program_aarch64_cacheline_align_mask1):
|
||||
# Actual mask will be inserted by JIT compiler
|
||||
and x18, x18, 1
|
||||
add x18, x18, x1
|
||||
and x20, x20, 1
|
||||
add x20, x20, x1
|
||||
|
||||
# Prefetch dataset data
|
||||
prfm pldl2strm, [x18]
|
||||
prfm pldl2strm, [x20]
|
||||
|
||||
# mx <-> ma
|
||||
ror x9, x9, 32
|
||||
@@ -335,17 +333,17 @@ DECL(randomx_program_aarch64_cacheline_align_mask2):
|
||||
DECL(randomx_program_aarch64_xor_with_dataset_line):
|
||||
rx_program_xor_with_dataset_line:
|
||||
# xor integer registers with dataset data
|
||||
ldp x18, x19, [x10]
|
||||
eor x4, x4, x18
|
||||
ldp x20, x19, [x10]
|
||||
eor x4, x4, x20
|
||||
eor x5, x5, x19
|
||||
ldp x18, x19, [x10, 16]
|
||||
eor x6, x6, x18
|
||||
ldp x20, x19, [x10, 16]
|
||||
eor x6, x6, x20
|
||||
eor x7, x7, x19
|
||||
ldp x18, x19, [x10, 32]
|
||||
eor x12, x12, x18
|
||||
ldp x20, x19, [x10, 32]
|
||||
eor x12, x12, x20
|
||||
eor x13, x13, x19
|
||||
ldp x18, x19, [x10, 48]
|
||||
eor x14, x14, x18
|
||||
ldp x20, x19, [x10, 48]
|
||||
eor x14, x14, x20
|
||||
eor x15, x15, x19
|
||||
|
||||
DECL(randomx_program_aarch64_update_spMix1):
|
||||
@@ -388,7 +386,7 @@ DECL(randomx_program_aarch64_update_spMix1):
|
||||
|
||||
# Restore callee-saved registers
|
||||
ldp x16, x17, [sp]
|
||||
ldp x18, x19, [sp, 16]
|
||||
ldr x19, [sp, 16]
|
||||
ldp x20, x21, [sp, 32]
|
||||
ldp x22, x23, [sp, 48]
|
||||
ldp x24, x25, [sp, 64]
|
||||
@@ -409,7 +407,7 @@ DECL(randomx_program_aarch64_vm_instructions_end_light):
|
||||
stp x2, x30, [sp, 80]
|
||||
|
||||
# mx ^= r[readReg2] ^ r[readReg3];
|
||||
eor x9, x9, x18
|
||||
eor x9, x9, x20
|
||||
|
||||
# mx <-> ma
|
||||
ror x9, x9, 32
|
||||
@@ -451,8 +449,8 @@ DECL(randomx_program_aarch64_light_dataset_offset):
|
||||
# x3 -> end item
|
||||
|
||||
DECL(randomx_init_dataset_aarch64):
|
||||
# Save x30 (return address)
|
||||
str x30, [sp, -16]!
|
||||
# Save x20 (used as temporary, but must be saved to not break ABI) and x30 (return address)
|
||||
stp x20, x30, [sp, -16]!
|
||||
|
||||
# Load pointer to cache memory
|
||||
ldr x0, [x0]
|
||||
@@ -464,8 +462,8 @@ DECL(randomx_init_dataset_aarch64_main_loop):
|
||||
cmp x2, x3
|
||||
bne DECL(randomx_init_dataset_aarch64_main_loop)
|
||||
|
||||
# Restore x30 (return address)
|
||||
ldr x30, [sp], 16
|
||||
# Restore x20 and x30
|
||||
ldp x20, x30, [sp], 16
|
||||
|
||||
ret
|
||||
|
||||
|
||||
1175
src/RandomX/src/jit_compiler_rv64.cpp
Normal file
1175
src/RandomX/src/jit_compiler_rv64.cpp
Normal file
File diff suppressed because it is too large
Load Diff
69
src/RandomX/src/jit_compiler_rv64.hpp
Normal file
69
src/RandomX/src/jit_compiler_rv64.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright (c) 2023 tevador <tevador@gmail.com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include "jit_compiler.hpp"
|
||||
|
||||
namespace randomx {
|
||||
|
||||
class Program;
|
||||
struct ProgramConfiguration;
|
||||
class SuperscalarProgram;
|
||||
class Instruction;
|
||||
|
||||
class JitCompilerRV64 {
|
||||
public:
|
||||
JitCompilerRV64();
|
||||
~JitCompilerRV64();
|
||||
void generateProgram(Program&, ProgramConfiguration&);
|
||||
void generateProgramLight(Program&, ProgramConfiguration&, uint32_t);
|
||||
void generateSuperscalarHash(SuperscalarProgram programs[RANDOMX_CACHE_ACCESSES], std::vector<uint64_t>&);
|
||||
void generateDatasetInitCode() {}
|
||||
ProgramFunc* getProgramFunc() {
|
||||
return (ProgramFunc*)entryProgram;
|
||||
}
|
||||
DatasetInitFunc* getDatasetInitFunc() {
|
||||
return (DatasetInitFunc*)entryDataInit;
|
||||
}
|
||||
uint8_t* getCode() {
|
||||
return state.code;
|
||||
}
|
||||
size_t getCodeSize();
|
||||
void enableWriting();
|
||||
void enableExecution();
|
||||
void enableAll();
|
||||
private:
|
||||
CompilerState state;
|
||||
void* entryDataInit;
|
||||
void* entryProgram;
|
||||
};
|
||||
}
|
||||
1235
src/RandomX/src/jit_compiler_rv64_static.S
Normal file
1235
src/RandomX/src/jit_compiler_rv64_static.S
Normal file
File diff suppressed because it is too large
Load Diff
53
src/RandomX/src/jit_compiler_rv64_static.hpp
Normal file
53
src/RandomX/src/jit_compiler_rv64_static.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
Copyright (c) 2023 tevador <tevador@gmail.com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
void randomx_riscv64_literals();
|
||||
void randomx_riscv64_literals_end();
|
||||
void randomx_riscv64_data_init();
|
||||
void randomx_riscv64_fix_data_call();
|
||||
void randomx_riscv64_prologue();
|
||||
void randomx_riscv64_loop_begin();
|
||||
void randomx_riscv64_data_read();
|
||||
void randomx_riscv64_data_read_light();
|
||||
void randomx_riscv64_fix_loop_call();
|
||||
void randomx_riscv64_spad_store();
|
||||
void randomx_riscv64_spad_store_hardaes();
|
||||
void randomx_riscv64_spad_store_softaes();
|
||||
void randomx_riscv64_loop_end();
|
||||
void randomx_riscv64_fix_continue_loop();
|
||||
void randomx_riscv64_epilogue();
|
||||
void randomx_riscv64_softaes();
|
||||
void randomx_riscv64_program_end();
|
||||
void randomx_riscv64_ssh_init();
|
||||
void randomx_riscv64_ssh_load();
|
||||
void randomx_riscv64_ssh_prefetch();
|
||||
void randomx_riscv64_ssh_end();
|
||||
}
|
||||
@@ -34,7 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "superscalar.hpp"
|
||||
#include "program.hpp"
|
||||
#include "reciprocal.h"
|
||||
#include "virtual_memory.hpp"
|
||||
#include "virtual_memory.h"
|
||||
|
||||
namespace randomx {
|
||||
/*
|
||||
@@ -618,7 +618,7 @@ namespace randomx {
|
||||
}
|
||||
|
||||
void JitCompilerX86::h_IMUL_RCP(Instruction& instr, int i) {
|
||||
uint64_t divisor = instr.getImm32();
|
||||
const uint32_t divisor = instr.getImm32();
|
||||
if (!isZeroOrPowerOf2(divisor)) {
|
||||
registerUsage[instr.dst] = i;
|
||||
emit(MOV_RAX_I);
|
||||
|
||||
@@ -36,7 +36,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "cpu.hpp"
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
#if defined(__SSE__) || defined(__SSE2__) || (defined(_M_IX86_FP) && (_M_IX86_FP > 0))
|
||||
#define USE_CSR_INTRINSICS
|
||||
#include <xmmintrin.h>
|
||||
#else
|
||||
#include <cfenv>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
@@ -356,8 +362,14 @@ extern "C" {
|
||||
assert(machine != nullptr);
|
||||
assert(inputSize == 0 || input != nullptr);
|
||||
assert(output != nullptr);
|
||||
|
||||
#ifdef USE_CSR_INTRINSICS
|
||||
const unsigned int fpstate = _mm_getcsr();
|
||||
#else
|
||||
fenv_t fpstate;
|
||||
fegetenv(&fpstate);
|
||||
#endif
|
||||
|
||||
alignas(16) uint64_t tempHash[8];
|
||||
int blakeResult = blake2b(tempHash, sizeof(tempHash), input, inputSize, nullptr, 0);
|
||||
assert(blakeResult == 0);
|
||||
@@ -370,7 +382,12 @@ extern "C" {
|
||||
}
|
||||
machine->run(&tempHash);
|
||||
machine->getFinalResult(output, RANDOMX_HASH_SIZE);
|
||||
|
||||
#ifdef USE_CSR_INTRINSICS
|
||||
_mm_setcsr(fpstate);
|
||||
#else
|
||||
fesetenv(&fpstate);
|
||||
#endif
|
||||
}
|
||||
|
||||
void randomx_calculate_hash_first(randomx_vm* machine, const void* input, size_t inputSize) {
|
||||
@@ -400,4 +417,15 @@ extern "C" {
|
||||
machine->run(machine->tempHash);
|
||||
machine->getFinalResult(output, RANDOMX_HASH_SIZE);
|
||||
}
|
||||
|
||||
void randomx_calculate_commitment(const void* input, size_t inputSize, const void* hash_in, void* com_out) {
|
||||
assert(inputSize == 0 || input != nullptr);
|
||||
assert(hash_in != nullptr);
|
||||
assert(com_out != nullptr);
|
||||
blake2b_state state;
|
||||
blake2b_init(&state, RANDOMX_HASH_SIZE);
|
||||
blake2b_update(&state, input, inputSize);
|
||||
blake2b_update(&state, hash_in, RANDOMX_HASH_SIZE);
|
||||
blake2b_final(&state, com_out, RANDOMX_HASH_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,6 +260,17 @@ RANDOMX_EXPORT void randomx_calculate_hash_first(randomx_vm* machine, const void
|
||||
RANDOMX_EXPORT void randomx_calculate_hash_next(randomx_vm* machine, const void* nextInput, size_t nextInputSize, void* output);
|
||||
RANDOMX_EXPORT void randomx_calculate_hash_last(randomx_vm* machine, void* output);
|
||||
|
||||
/**
|
||||
* Calculate a RandomX commitment from a RandomX hash and its input.
|
||||
*
|
||||
* @param input is a pointer to memory that was hashed. Must not be NULL.
|
||||
* @param inputSize is the number of bytes in the input.
|
||||
* @param hash_in is the output from randomx_calculate_hash* (RANDOMX_HASH_SIZE bytes).
|
||||
* @param com_out is a pointer to memory where the commitment will be stored. Must not
|
||||
* be NULL and at least RANDOMX_HASH_SIZE bytes must be available for writing.
|
||||
*/
|
||||
RANDOMX_EXPORT void randomx_calculate_commitment(const void* input, size_t inputSize, const void* hash_in, void* com_out);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -44,36 +44,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
ret
|
||||
|
||||
*/
|
||||
uint64_t randomx_reciprocal(uint64_t divisor) {
|
||||
uint64_t randomx_reciprocal(uint32_t divisor) {
|
||||
|
||||
assert(divisor != 0);
|
||||
|
||||
const uint64_t p2exp63 = 1ULL << 63;
|
||||
const uint64_t q = p2exp63 / divisor;
|
||||
const uint64_t r = p2exp63 % divisor;
|
||||
|
||||
uint64_t quotient = p2exp63 / divisor, remainder = p2exp63 % divisor;
|
||||
#ifdef __GNUC__
|
||||
const uint32_t shift = 64 - __builtin_clzll(divisor);
|
||||
#else
|
||||
uint32_t shift = 32;
|
||||
for (uint32_t k = 1U << 31; (k & divisor) == 0; k >>= 1)
|
||||
--shift;
|
||||
#endif
|
||||
|
||||
unsigned bsr = 0; //highest set bit in divisor
|
||||
|
||||
for (uint64_t bit = divisor; bit > 0; bit >>= 1)
|
||||
bsr++;
|
||||
|
||||
for (unsigned shift = 0; shift < bsr; shift++) {
|
||||
if (remainder >= divisor - remainder) {
|
||||
quotient = quotient * 2 + 1;
|
||||
remainder = remainder * 2 - divisor;
|
||||
}
|
||||
else {
|
||||
quotient = quotient * 2;
|
||||
remainder = remainder * 2;
|
||||
}
|
||||
}
|
||||
|
||||
return quotient;
|
||||
return (q << shift) + ((r << shift) / divisor);
|
||||
}
|
||||
|
||||
#if !RANDOMX_HAVE_FAST_RECIPROCAL
|
||||
|
||||
uint64_t randomx_reciprocal_fast(uint64_t divisor) {
|
||||
uint64_t randomx_reciprocal_fast(uint32_t divisor) {
|
||||
return randomx_reciprocal(divisor);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
uint64_t randomx_reciprocal(uint64_t);
|
||||
uint64_t randomx_reciprocal_fast(uint64_t);
|
||||
uint64_t randomx_reciprocal(uint32_t);
|
||||
uint64_t randomx_reciprocal_fast(uint32_t);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ void printUsage(const char* executable) {
|
||||
std::cout << " --avx2 use optimized Argon2 for AVX2 CPUs" << std::endl;
|
||||
std::cout << " --auto select the best options for the current CPU" << std::endl;
|
||||
std::cout << " --noBatch calculate hashes one by one (default: batch)" << std::endl;
|
||||
std::cout << " --commit calculate commitments instead of hashes (default: hashes)" << std::endl;
|
||||
}
|
||||
|
||||
struct MemoryException : public std::exception {
|
||||
@@ -113,7 +114,7 @@ struct DatasetAllocException : public MemoryException {
|
||||
|
||||
using MineFunc = void(randomx_vm * vm, std::atomic<uint32_t> & atomicNonce, AtomicHash & result, uint32_t noncesCount, int thread, int cpuid);
|
||||
|
||||
template<bool batch>
|
||||
template<bool batch, bool commit>
|
||||
void mine(randomx_vm* vm, std::atomic<uint32_t>& atomicNonce, AtomicHash& result, uint32_t noncesCount, int thread, int cpuid = -1) {
|
||||
if (cpuid >= 0) {
|
||||
int rc = set_thread_affinity(cpuid);
|
||||
@@ -138,6 +139,9 @@ void mine(randomx_vm* vm, std::atomic<uint32_t>& atomicNonce, AtomicHash& result
|
||||
}
|
||||
store32(noncePtr, nonce);
|
||||
(batch ? randomx_calculate_hash_next : randomx_calculate_hash)(vm, blockTemplate, sizeof(blockTemplate), &hash);
|
||||
if (commit) {
|
||||
randomx_calculate_commitment(blockTemplate, sizeof(blockTemplate), &hash, &hash);
|
||||
}
|
||||
result.xorWith(hash);
|
||||
if (!batch) {
|
||||
nonce = atomicNonce.fetch_add(1);
|
||||
@@ -146,7 +150,7 @@ void mine(randomx_vm* vm, std::atomic<uint32_t>& atomicNonce, AtomicHash& result
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
bool softAes, miningMode, verificationMode, help, largePages, jit, secure;
|
||||
bool softAes, miningMode, verificationMode, help, largePages, jit, secure, commit;
|
||||
bool ssse3, avx2, autoFlags, noBatch;
|
||||
int noncesCount, threadCount, initThreadCount;
|
||||
uint64_t threadAffinity;
|
||||
@@ -172,10 +176,11 @@ int main(int argc, char** argv) {
|
||||
readOption("--avx2", argc, argv, avx2);
|
||||
readOption("--auto", argc, argv, autoFlags);
|
||||
readOption("--noBatch", argc, argv, noBatch);
|
||||
readOption("--commit", argc, argv, commit);
|
||||
|
||||
store32(&seed, seedValue);
|
||||
|
||||
std::cout << "RandomX benchmark v1.1.11" << std::endl;
|
||||
std::cout << "RandomX benchmark v1.2.1" << std::endl;
|
||||
|
||||
if (help) {
|
||||
printUsage(argv[0]);
|
||||
@@ -280,11 +285,24 @@ int main(int argc, char** argv) {
|
||||
MineFunc* func;
|
||||
|
||||
if (noBatch) {
|
||||
func = &mine<false>;
|
||||
if (commit) {
|
||||
std::cout << " - hash commitments" << std::endl;
|
||||
func = &mine<false, true>;
|
||||
}
|
||||
else {
|
||||
func = &mine<false, false>;
|
||||
}
|
||||
}
|
||||
else {
|
||||
func = &mine<true>;
|
||||
std::cout << " - batch mode" << std::endl;
|
||||
if (commit) {
|
||||
//TODO: support batch mode with commitments
|
||||
std::cout << " - hash commitments" << std::endl;
|
||||
func = &mine<false, true>;
|
||||
}
|
||||
else {
|
||||
std::cout << " - batch mode" << std::endl;
|
||||
func = &mine<true, false>;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Initializing";
|
||||
@@ -376,7 +394,7 @@ int main(int argc, char** argv) {
|
||||
randomx_release_cache(cache);
|
||||
std::cout << "Calculated result: ";
|
||||
result.print(std::cout);
|
||||
if (noncesCount == 1000 && seedValue == 0)
|
||||
if (noncesCount == 1000 && seedValue == 0 && !commit)
|
||||
std::cout << "Reference result: 10b649a3f15c7c7f88277812f2e74b337a0f20ce909af09199cccb960771cfa1" << std::endl;
|
||||
if (!miningMode) {
|
||||
std::cout << "Performance: " << 1000 * elapsed / noncesCount << " ms per hash" << std::endl;
|
||||
|
||||
@@ -477,7 +477,7 @@ int analyze(randomx::Program& p) {
|
||||
}
|
||||
|
||||
if (opcode < randomx::ceil_IMUL_RCP) {
|
||||
uint64_t divisor = instr.getImm32();
|
||||
const uint32_t divisor = instr.getImm32();
|
||||
if (!randomx::isZeroOrPowerOf2(divisor)) {
|
||||
instr.dst = instr.dst % randomx::RegistersCount;
|
||||
instr.opcode |= DST_INT;
|
||||
|
||||
9
src/RandomX/src/tests/riscv64_zba.s
Normal file
9
src/RandomX/src/tests/riscv64_zba.s
Normal file
@@ -0,0 +1,9 @@
|
||||
/* RISC-V - test if the Zba extension is present */
|
||||
|
||||
.text
|
||||
.global main
|
||||
|
||||
main:
|
||||
sh1add x6, x6, x7
|
||||
li x10, 0
|
||||
ret
|
||||
9
src/RandomX/src/tests/riscv64_zbb.s
Normal file
9
src/RandomX/src/tests/riscv64_zbb.s
Normal file
@@ -0,0 +1,9 @@
|
||||
/* RISC-V - test if the Zbb extension is present */
|
||||
|
||||
.text
|
||||
.global main
|
||||
|
||||
main:
|
||||
ror x6, x6, x7
|
||||
li x10, 0
|
||||
ret
|
||||
@@ -34,6 +34,14 @@ void calcStringHash(const char(&key)[K], const char(&input)[H], void* output) {
|
||||
randomx_calculate_hash(vm, input, H - 1, output);
|
||||
}
|
||||
|
||||
template<size_t K, size_t H>
|
||||
void calcStringCommitment(const char(&key)[K], const char(&input)[H], void* output) {
|
||||
initCache(key);
|
||||
assert(vm != nullptr);
|
||||
randomx_calculate_hash(vm, input, H - 1, output);
|
||||
randomx_calculate_commitment(input, H - 1, output, output);
|
||||
}
|
||||
|
||||
template<size_t K, size_t H>
|
||||
void calcHexHash(const char(&key)[K], const char(&hex)[H], void* output) {
|
||||
initCache(key);
|
||||
@@ -1082,6 +1090,22 @@ int main() {
|
||||
assert(rx_get_rounding_mode() == RoundToNearest);
|
||||
});
|
||||
|
||||
if (RANDOMX_HAVE_COMPILER) {
|
||||
randomx_destroy_vm(vm);
|
||||
vm = nullptr;
|
||||
#ifdef RANDOMX_FORCE_SECURE
|
||||
vm = randomx_create_vm(RANDOMX_FLAG_DEFAULT | RANDOMX_FLAG_SECURE, cache, nullptr);
|
||||
#else
|
||||
vm = randomx_create_vm(RANDOMX_FLAG_DEFAULT, cache, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
runTest("Commitment test", stringsEqual(RANDOMX_ARGON_SALT, "RandomX\x03"), []() {
|
||||
char hash[RANDOMX_HASH_SIZE];
|
||||
calcStringCommitment("test key 000", "This is a test", &hash);
|
||||
assert(equalsHex(hash, "d53ccf348b75291b7be76f0a7ac8208bbced734b912f6fca60539ab6f86be919"));
|
||||
});
|
||||
|
||||
randomx_destroy_vm(vm);
|
||||
vm = nullptr;
|
||||
|
||||
|
||||
@@ -26,28 +26,24 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "virtual_memory.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#define _GNU_SOURCE 1 /* needed for MAP_ANONYMOUS on older platforms */
|
||||
#ifdef __APPLE__
|
||||
#include <mach/vm_statistics.h>
|
||||
#include <TargetConditionals.h>
|
||||
#include <AvailabilityMacros.h>
|
||||
# if TARGET_OS_OSX
|
||||
# if TARGET_CPU_ARM64
|
||||
# define USE_PTHREAD_JIT_WP 1
|
||||
# else
|
||||
# undef USE_PTHREAD_JIT_WP
|
||||
# endif
|
||||
# define USE_PTHREAD_JIT_WP 1
|
||||
# include <pthread.h>
|
||||
# include <sys/utsname.h>
|
||||
# include <stdio.h>
|
||||
# endif
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
#ifndef MAP_ANONYMOUS
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
@@ -57,27 +53,50 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#define PAGE_EXECUTE_READWRITE (PROT_READ | PROT_WRITE | PROT_EXEC)
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
std::string getErrorMessage(const char* function) {
|
||||
LPSTR messageBuffer = nullptr;
|
||||
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
|
||||
std::string message(messageBuffer, size);
|
||||
LocalFree(messageBuffer);
|
||||
return std::string(function) + std::string(": ") + message;
|
||||
}
|
||||
#include "virtual_memory.h"
|
||||
|
||||
void setPrivilege(const char* pszPrivilege, BOOL bEnable) {
|
||||
#if defined(USE_PTHREAD_JIT_WP) && defined(MAC_OS_VERSION_11_0) \
|
||||
&& MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0
|
||||
static int MacOSchecked, MacOSver;
|
||||
/* This function is used implicitly by clang's __builtin_available() checker.
|
||||
* When cross-compiling, the library containing this function doesn't exist,
|
||||
* and linking will fail because the symbol is unresolved. The function here
|
||||
* is a quick and dirty hack to get close enough to identify MacOSX 11.0.
|
||||
*/
|
||||
static int32_t __isOSVersionAtLeast(int32_t major, int32_t minor, int32_t subminor) {
|
||||
if (!MacOSchecked) {
|
||||
struct utsname ut;
|
||||
int mmaj, mmin;
|
||||
uname(&ut);
|
||||
sscanf(ut.release, "%d.%d", &mmaj, &mmin);
|
||||
// The utsname release version is 9 greater than the canonical OS version
|
||||
mmaj -= 9;
|
||||
MacOSver = (mmaj << 8) | mmin;
|
||||
MacOSchecked = 1;
|
||||
}
|
||||
return MacOSver >= ((major << 8) | minor);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#define Fail(func) do {*errfunc = func; return GetLastError();} while(0)
|
||||
int setPrivilege(const char* pszPrivilege, BOOL bEnable, char **errfunc) {
|
||||
HANDLE hToken;
|
||||
TOKEN_PRIVILEGES tp;
|
||||
BOOL status;
|
||||
DWORD error;
|
||||
DWORD error = 0;
|
||||
|
||||
*errfunc = NULL;
|
||||
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
||||
throw std::runtime_error(getErrorMessage("OpenProcessToken"));
|
||||
Fail("OpenProcessToken");
|
||||
|
||||
if (!LookupPrivilegeValue(NULL, pszPrivilege, &tp.Privileges[0].Luid))
|
||||
throw std::runtime_error(getErrorMessage("LookupPrivilegeValue"));
|
||||
if (!LookupPrivilegeValue(NULL, pszPrivilege, &tp.Privileges[0].Luid)) {
|
||||
*errfunc = "LookupPrivilegeValue";
|
||||
error = GetLastError();
|
||||
goto out;
|
||||
}
|
||||
|
||||
tp.PrivilegeCount = 1;
|
||||
|
||||
@@ -89,20 +108,28 @@ void setPrivilege(const char* pszPrivilege, BOOL bEnable) {
|
||||
status = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
|
||||
|
||||
error = GetLastError();
|
||||
if (!status || (error != ERROR_SUCCESS))
|
||||
throw std::runtime_error(getErrorMessage("AdjustTokenPrivileges"));
|
||||
if (!status || (error != ERROR_SUCCESS)) {
|
||||
*errfunc = "AdjustTokenPrivileges";
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!CloseHandle(hToken))
|
||||
throw std::runtime_error(getErrorMessage("CloseHandle"));
|
||||
out:
|
||||
if (!CloseHandle(hToken)) {
|
||||
if (*errfunc == NULL) {
|
||||
*errfunc = "CloseHandle";
|
||||
error = GetLastError();
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
#else
|
||||
#define Fail(func) do {*errfunc = func; return errno;} while(0)
|
||||
#endif
|
||||
|
||||
void* allocMemoryPages(std::size_t bytes) {
|
||||
void* allocMemoryPages(size_t bytes) {
|
||||
void* mem;
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
mem = VirtualAlloc(nullptr, bytes, MEM_COMMIT, PAGE_READWRITE);
|
||||
if (mem == nullptr)
|
||||
throw std::runtime_error(getErrorMessage("allocMemoryPages - VirtualAlloc"));
|
||||
mem = VirtualAlloc(NULL, bytes, MEM_COMMIT, PAGE_READWRITE);
|
||||
#else
|
||||
#if defined(__NetBSD__)
|
||||
#define RESERVED_FLAGS PROT_MPROTECT(PROT_EXEC)
|
||||
@@ -116,89 +143,95 @@ void* allocMemoryPages(std::size_t bytes) {
|
||||
#define MEXTRA 0
|
||||
#define PEXTRA 0
|
||||
#endif
|
||||
mem = mmap(nullptr, bytes, PAGE_READWRITE | RESERVED_FLAGS | PEXTRA, MAP_ANONYMOUS | MAP_PRIVATE | MEXTRA, -1, 0);
|
||||
mem = mmap(NULL, bytes, PAGE_READWRITE | RESERVED_FLAGS | PEXTRA, MAP_ANONYMOUS | MAP_PRIVATE | MEXTRA, -1, 0);
|
||||
if (mem == MAP_FAILED)
|
||||
throw std::runtime_error("allocMemoryPages - mmap failed");
|
||||
mem = NULL;
|
||||
#if defined(USE_PTHREAD_JIT_WP) && defined(MAC_OS_VERSION_11_0) \
|
||||
&& MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0
|
||||
if (__builtin_available(macOS 11.0, *)) {
|
||||
pthread_jit_write_protect_np(false);
|
||||
pthread_jit_write_protect_np(0);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return mem;
|
||||
}
|
||||
|
||||
static inline void pageProtect(void* ptr, std::size_t bytes, int rules) {
|
||||
static inline int pageProtect(void* ptr, size_t bytes, int rules, char **errfunc) {
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
DWORD oldp;
|
||||
if (!VirtualProtect(ptr, bytes, (DWORD)rules, &oldp)) {
|
||||
throw std::runtime_error(getErrorMessage("VirtualProtect"));
|
||||
Fail("VirtualProtect");
|
||||
}
|
||||
#else
|
||||
if (-1 == mprotect(ptr, bytes, rules))
|
||||
throw std::runtime_error("mprotect failed");
|
||||
Fail("mprotect");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setPagesRW(void* ptr, std::size_t bytes) {
|
||||
void setPagesRW(void* ptr, size_t bytes) {
|
||||
char *errfunc;
|
||||
#if defined(USE_PTHREAD_JIT_WP) && defined(MAC_OS_VERSION_11_0) \
|
||||
&& MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0
|
||||
if (__builtin_available(macOS 11.0, *)) {
|
||||
pthread_jit_write_protect_np(false);
|
||||
pthread_jit_write_protect_np(0);
|
||||
} else {
|
||||
pageProtect(ptr, bytes, PAGE_READWRITE);
|
||||
pageProtect(ptr, bytes, PAGE_READWRITE, &errfunc);
|
||||
}
|
||||
#else
|
||||
pageProtect(ptr, bytes, PAGE_READWRITE);
|
||||
pageProtect(ptr, bytes, PAGE_READWRITE, &errfunc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void setPagesRX(void* ptr, std::size_t bytes) {
|
||||
void setPagesRX(void* ptr, size_t bytes) {
|
||||
char *errfunc;
|
||||
#if defined(USE_PTHREAD_JIT_WP) && defined(MAC_OS_VERSION_11_0) \
|
||||
&& MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0
|
||||
if (__builtin_available(macOS 11.0, *)) {
|
||||
pthread_jit_write_protect_np(true);
|
||||
pthread_jit_write_protect_np(1);
|
||||
__builtin___clear_cache((char*)ptr, ((char*)ptr) + bytes);
|
||||
} else {
|
||||
pageProtect(ptr, bytes, PAGE_EXECUTE_READ);
|
||||
pageProtect(ptr, bytes, PAGE_EXECUTE_READ, &errfunc);
|
||||
}
|
||||
#else
|
||||
pageProtect(ptr, bytes, PAGE_EXECUTE_READ);
|
||||
pageProtect(ptr, bytes, PAGE_EXECUTE_READ, &errfunc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void setPagesRWX(void* ptr, std::size_t bytes) {
|
||||
pageProtect(ptr, bytes, PAGE_EXECUTE_READWRITE);
|
||||
void setPagesRWX(void* ptr, size_t bytes) {
|
||||
char *errfunc;
|
||||
pageProtect(ptr, bytes, PAGE_EXECUTE_READWRITE, &errfunc);
|
||||
}
|
||||
|
||||
void* allocLargePagesMemory(std::size_t bytes) {
|
||||
void* allocLargePagesMemory(size_t bytes) {
|
||||
void* mem;
|
||||
char *errfunc;
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
setPrivilege("SeLockMemoryPrivilege", 1);
|
||||
auto pageMinimum = GetLargePageMinimum();
|
||||
if (pageMinimum > 0)
|
||||
mem = VirtualAlloc(NULL, alignSize(bytes, pageMinimum), MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE);
|
||||
else
|
||||
throw std::runtime_error("allocLargePagesMemory - Large pages are not supported");
|
||||
if (mem == nullptr)
|
||||
throw std::runtime_error(getErrorMessage("allocLargePagesMemory - VirtualAlloc"));
|
||||
if (setPrivilege("SeLockMemoryPrivilege", 1, &errfunc))
|
||||
return NULL;
|
||||
size_t pageMinimum = GetLargePageMinimum();
|
||||
if (!pageMinimum) {
|
||||
errfunc = "No large pages";
|
||||
return NULL;
|
||||
}
|
||||
mem = VirtualAlloc(NULL, alignSize(bytes, pageMinimum), MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE);
|
||||
#else
|
||||
#ifdef __APPLE__
|
||||
mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
|
||||
mem = mmap(NULL, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, VM_FLAGS_SUPERPAGE_SIZE_2MB, 0);
|
||||
#elif defined(__FreeBSD__)
|
||||
mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER, -1, 0);
|
||||
mem = mmap(NULL, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED_SUPER, -1, 0);
|
||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
mem = MAP_FAILED; // OpenBSD does not support huge pages
|
||||
#else
|
||||
mem = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, -1, 0);
|
||||
mem = mmap(NULL, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, -1, 0);
|
||||
#endif
|
||||
if (mem == MAP_FAILED)
|
||||
throw std::runtime_error("allocLargePagesMemory - mmap failed");
|
||||
mem = NULL;
|
||||
#endif
|
||||
return mem;
|
||||
}
|
||||
|
||||
void freePagedMemory(void* ptr, std::size_t bytes) {
|
||||
void freePagedMemory(void* ptr, size_t bytes) {
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
VirtualFree(ptr, 0, MEM_RELEASE);
|
||||
#else
|
||||
@@ -28,15 +28,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
constexpr std::size_t alignSize(std::size_t pos, std::size_t align) {
|
||||
return ((pos - 1) / align + 1) * align;
|
||||
#include <stddef.h>
|
||||
|
||||
#define alignSize(pos, align) (((pos - 1) / align + 1) * align)
|
||||
|
||||
void* allocMemoryPages(size_t);
|
||||
void setPagesRW(void*, size_t);
|
||||
void setPagesRX(void*, size_t);
|
||||
void setPagesRWX(void*, size_t);
|
||||
void* allocLargePagesMemory(size_t);
|
||||
void freePagedMemory(void*, size_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
void* allocMemoryPages(std::size_t);
|
||||
void setPagesRW(void*, std::size_t);
|
||||
void setPagesRX(void*, std::size_t);
|
||||
void setPagesRWX(void*, std::size_t);
|
||||
void* allocLargePagesMemory(std::size_t);
|
||||
void freePagedMemory(void*, std::size_t);
|
||||
#endif
|
||||
@@ -43,7 +43,7 @@
|
||||
<ClInclude Include="..\src\superscalar.hpp" />
|
||||
<ClInclude Include="..\src\superscalar_program.hpp" />
|
||||
<ClInclude Include="..\src\virtual_machine.hpp" />
|
||||
<ClInclude Include="..\src\virtual_memory.hpp" />
|
||||
<ClInclude Include="..\src\virtual_memory.h" />
|
||||
<ClInclude Include="..\src\vm_compiled.hpp" />
|
||||
<ClInclude Include="..\src\vm_compiled_light.hpp" />
|
||||
<ClInclude Include="..\src\vm_interpreted.hpp" />
|
||||
@@ -74,7 +74,7 @@
|
||||
<ClCompile Include="..\src\soft_aes.cpp" />
|
||||
<ClCompile Include="..\src\superscalar.cpp" />
|
||||
<ClCompile Include="..\src\virtual_machine.cpp" />
|
||||
<ClCompile Include="..\src\virtual_memory.cpp" />
|
||||
<ClCompile Include="..\src\virtual_memory.c" />
|
||||
<ClCompile Include="..\src\vm_compiled.cpp" />
|
||||
<ClCompile Include="..\src\vm_compiled_light.cpp" />
|
||||
<ClCompile Include="..\src\vm_interpreted.cpp" />
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
<ClInclude Include="..\src\virtual_machine.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\virtual_memory.hpp">
|
||||
<ClInclude Include="..\src\virtual_memory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\vm_compiled.hpp">
|
||||
@@ -151,7 +151,7 @@
|
||||
<ClCompile Include="..\src\virtual_machine.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\virtual_memory.cpp">
|
||||
<ClCompile Include="..\src\virtual_memory.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\vm_compiled.cpp">
|
||||
|
||||
@@ -156,7 +156,7 @@ SET ERRORLEVEL = 0</Command>
|
||||
<ClCompile Include="..\src\reciprocal.c" />
|
||||
<ClCompile Include="..\src\soft_aes.cpp" />
|
||||
<ClCompile Include="..\src\virtual_machine.cpp" />
|
||||
<ClCompile Include="..\src\virtual_memory.cpp" />
|
||||
<ClCompile Include="..\src\virtual_memory.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="..\src\jit_compiler_x86_static.asm" />
|
||||
@@ -198,7 +198,7 @@ SET ERRORLEVEL = 0</Command>
|
||||
<ClInclude Include="..\src\soft_aes.h" />
|
||||
<ClInclude Include="..\src\superscalar_program.hpp" />
|
||||
<ClInclude Include="..\src\virtual_machine.hpp" />
|
||||
<ClInclude Include="..\src\virtual_memory.hpp" />
|
||||
<ClInclude Include="..\src\virtual_memory.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
<ClCompile Include="..\src\vm_interpreted.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\virtual_memory.cpp">
|
||||
<ClCompile Include="..\src\virtual_memory.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\blake2_generator.cpp">
|
||||
@@ -164,7 +164,7 @@
|
||||
<ClInclude Include="..\src\virtual_machine.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\virtual_memory.hpp">
|
||||
<ClInclude Include="..\src\virtual_memory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\superscalar.hpp">
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
|
||||
// Must be kept in sync with configure.ac , ugh!
|
||||
#define CLIENT_VERSION_MAJOR 3
|
||||
#define CLIENT_VERSION_MINOR 9
|
||||
#define CLIENT_VERSION_REVISION 4
|
||||
#define CLIENT_VERSION_MINOR 10
|
||||
#define CLIENT_VERSION_REVISION 0
|
||||
#define CLIENT_VERSION_BUILD 50
|
||||
|
||||
//! Set to true for release, false for prerelease or test build
|
||||
|
||||
@@ -2436,7 +2436,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
SetRPCWarmupFinished();
|
||||
if(fDebug)
|
||||
fprintf(stderr,"RPC warmump finished\n");
|
||||
uiInterface.InitMessage(_("Hush Full Node Done Loading! :)"));
|
||||
uiInterface.InitMessage(_("Full Node Done Loading! :)"));
|
||||
|
||||
#ifdef ENABLE_WALLET
|
||||
if (pwalletMain) {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#define HUSH_VERSION_H
|
||||
|
||||
// network protocol versioning
|
||||
static const int PROTOCOL_VERSION = 1987425;
|
||||
static const int PROTOCOL_VERSION = 1987426;
|
||||
//! initial proto version, to be increased after version/verack negotiation
|
||||
static const int INIT_PROTO_VERSION = 209;
|
||||
//! In this version, 'getheaders' was introduced.
|
||||
|
||||
@@ -3304,12 +3304,13 @@ UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey&
|
||||
if (!EnsureWalletIsAvailable(fHelp))
|
||||
return NullUniValue;
|
||||
|
||||
if (fHelp || params.size() > 5 || params.size() == 3)
|
||||
if (fHelp || params.size() > 5 || params.size() < 1)
|
||||
throw runtime_error(
|
||||
"z_listreceivedaddress\n"
|
||||
"\nReturns received outputs.\n"
|
||||
"\n"
|
||||
"This function only returns information on addresses with full spending keys."
|
||||
"This function is slow if no filters are given, use z_listreceivedbyaddress if you do not need filters."
|
||||
"\n"
|
||||
"\nArguments:\n"
|
||||
"1. \"hushaddress:\" (string, required) \n"
|
||||
@@ -3349,13 +3350,13 @@ UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey&
|
||||
" \"walletconflicts\": [conflicts], An array of wallet conflicts\n"
|
||||
" \"recieved\": { A list of receives from the transaction\n"
|
||||
" \"transparentReceived\": [{ An Array of txos received for transparent addresses\n"
|
||||
" \"address\": \"zeroaddress\", (string) Hush transparent address (t-address)\n"
|
||||
" \"address\": \"hushaddress\", (string) Hush transparent address (t-address)\n"
|
||||
" \"scriptPubKey\": \"script\", (string) Script for the transparent address (t-address)\n"
|
||||
" \"amount\": x.xxxx, (numeric) Value of output being received " + CURRENCY_UNIT + ", positive for receives\n"
|
||||
" \"vout\": : n, (numeric) the vout value\n"
|
||||
" }],\n"
|
||||
" \"saplingReceived\": [{ An Array of utxos/notes received for sapling addresses\n"
|
||||
" \"address\": \"zeroaddress\", (string) Shielded address (z-address)\n"
|
||||
" \"address\": \"hushaddress\", (string) Shielded address (z-address)\n"
|
||||
" \"amount\": x.xxxx, (numeric) Value of output being received " + CURRENCY_UNIT + ", positive for receives\n"
|
||||
" \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
|
||||
" \"memoStr\" : \"memo\", (string) Only returned if memo contains valid UTF-8 text.\n"
|
||||
@@ -3375,7 +3376,7 @@ UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey&
|
||||
|
||||
UniValue ret(UniValue::VARR);
|
||||
|
||||
//param values`
|
||||
//param values
|
||||
int64_t nMinConfirms = 0;
|
||||
int64_t nFilterType = 0;
|
||||
int64_t nFilter = 999999;
|
||||
@@ -4110,6 +4111,7 @@ UniValue z_listunspent(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
" \"address\" : \"address\", (string) the shielded address\n"
|
||||
" \"amount\": xxxxx, (numeric) the amount of value in the note\n"
|
||||
" \"memo\": xxxxx, (string) hexademical string representation of memo field\n"
|
||||
" \"memoStr\" : \"memo\", (string) Only returned if memo contains valid UTF-8 text.\n"
|
||||
" \"change\": true|false, (boolean) true if the address that received the note is also one of the sending addresses\n"
|
||||
" }\n"
|
||||
" ,...\n"
|
||||
@@ -4216,6 +4218,14 @@ UniValue z_listunspent(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||
obj.push_back(Pair("address", EncodePaymentAddress(entry.address)));
|
||||
obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value())))); // note.value() is equivalent to plaintext.value()
|
||||
obj.push_back(Pair("memo", HexStr(entry.memo)));
|
||||
auto memo = entry.memo;
|
||||
if (memo[0] <= 0xf4) {
|
||||
auto end = std::find_if(memo.rbegin(), memo.rend(), [](unsigned char v) { return v != 0; });
|
||||
std::string memoStr(memo.begin(), end.base());
|
||||
if (utf8::is_valid(memoStr)) {
|
||||
obj.push_back(Pair("memoStr", memoStr));
|
||||
}
|
||||
}
|
||||
if (hasSaplingSpendingKey) {
|
||||
obj.push_back(Pair("change", pwalletMain->IsNoteSaplingChange(nullifierSet, entry.address, entry.op)));
|
||||
}
|
||||
@@ -4470,6 +4480,7 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubK
|
||||
" \"txid\": xxxxx, (string) the transaction id\n"
|
||||
" \"amount\": xxxxx, (numeric) the amount of value in the note\n"
|
||||
" \"memo\": xxxxx, (string) hexadecimal string representation of memo field\n"
|
||||
" \"memoStr\" : \"memo\", (string) Only returned if memo contains valid UTF-8 text.\n"
|
||||
" \"confirmations\" : n, (numeric) the number of notarized confirmations (dpowconfs)\n"
|
||||
" \"rawconfirmations\" : n, (numeric) the number of raw confirmations\n"
|
||||
" \"outindex\" (sapling) : n, (numeric) the output index\n"
|
||||
|
||||
Reference in New Issue
Block a user