mirror of
https://github.com/Xahau/xahaud.git
synced 2026-10-22 11:47:09 +00:00
Compare commits
54
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e26fd326e0 | ||
|
|
4239124750 | ||
|
|
6fdb285d48 | ||
|
|
e2e0186b32 | ||
|
|
1e45d4120c | ||
|
|
9e446bcc85 | ||
|
|
376727d20c | ||
|
|
d921c87c88 | ||
|
|
7b94d3d99d | ||
|
|
79d83bd424 | ||
|
|
1a4d54f9d9 | ||
|
|
26cd629d28 | ||
|
|
2fb93f874b | ||
|
|
833df20fce | ||
|
|
5737c2b6e8 | ||
|
|
a15d0b2ecc | ||
|
|
18d76d3082 | ||
|
|
849a4435e0 | ||
|
|
247e9d98bf | ||
|
|
acd455f5df | ||
|
|
6636e3b6fd | ||
|
|
3c5f118b59 | ||
|
|
88308126cc | ||
|
|
497e52fcc6 | ||
|
|
a3852763e7 | ||
|
|
7cd8f0a03a | ||
|
|
d24c134612 | ||
|
|
cdac69a111 | ||
|
|
1500522427 | ||
|
|
75aba531d6 | ||
|
|
caa8b382d8 | ||
|
|
82e04073be | ||
|
|
e1b78f9682 | ||
|
|
901d1d4e8d | ||
|
|
aca5241515 | ||
|
|
780378c221 | ||
|
|
2dc5e670ac | ||
|
|
4dff5a5c8e | ||
|
|
f64e626a3f | ||
|
|
f21d3e1e97 | ||
|
|
858055c811 | ||
|
|
5d66f17574 | ||
|
|
00328cb782 | ||
|
|
fdf7ea4174 | ||
|
|
7877ed9704 | ||
|
|
17ccec9ac5 | ||
|
|
de522ac4ae | ||
|
|
74c83a9271 | ||
|
|
66ee96d456 | ||
|
|
b476aea55b | ||
|
|
4ad697069f | ||
|
|
97acfe9f97 | ||
|
|
475b6f7347 | ||
|
|
1b9373e220 |
No files matched your search
@@ -2,25 +2,37 @@ name: Build using Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "dev", "candidate", "release" ]
|
||||
branches: [ "dev", "candidate", "release", "jshooks" ]
|
||||
pull_request:
|
||||
branches: [ "dev", "candidate", "release" ]
|
||||
branches: [ "dev", "candidate", "release", "jshooks" ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
builder:
|
||||
checkout:
|
||||
runs-on: [self-hosted, vanity]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
clean: false
|
||||
checkpatterns:
|
||||
runs-on: [self-hosted, vanity]
|
||||
needs: checkout
|
||||
steps:
|
||||
- name: Check for suspicious patterns
|
||||
run: /bin/bash suspicious_patterns.sh
|
||||
build:
|
||||
runs-on: [self-hosted, vanity]
|
||||
needs: checkpatterns
|
||||
steps:
|
||||
- name: Build using Docker
|
||||
run: /bin/bash release-builder.sh
|
||||
tests:
|
||||
runs-on: [self-hosted, vanity]
|
||||
needs: build
|
||||
steps:
|
||||
- name: Unit tests
|
||||
run: /bin/bash docker-unit-tests.sh
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
git diff --exit-code | tee "clang-format.patch"
|
||||
- name: Upload patch
|
||||
if: failure() && steps.assert.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: clang-format.patch
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
git diff --exit-code | tee "levelization.patch"
|
||||
- name: Upload patch
|
||||
if: failure() && steps.assert.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
name: levelization.patch
|
||||
|
||||
@@ -433,13 +433,17 @@ target_sources (rippled PRIVATE
|
||||
src/ripple/app/tx/impl/CancelOffer.cpp
|
||||
src/ripple/app/tx/impl/CashCheck.cpp
|
||||
src/ripple/app/tx/impl/Change.cpp
|
||||
src/ripple/app/tx/impl/ClaimReward.cpp
|
||||
src/ripple/app/tx/impl/CreateCheck.cpp
|
||||
src/ripple/app/tx/impl/CreateOffer.cpp
|
||||
src/ripple/app/tx/impl/CreateTicket.cpp
|
||||
src/ripple/app/tx/impl/DeleteAccount.cpp
|
||||
src/ripple/app/tx/impl/DepositPreauth.cpp
|
||||
src/ripple/app/tx/impl/Escrow.cpp
|
||||
src/ripple/app/tx/impl/GenesisMint.cpp
|
||||
src/ripple/app/tx/impl/Import.cpp
|
||||
src/ripple/app/tx/impl/InvariantCheck.cpp
|
||||
src/ripple/app/tx/impl/Invoke.cpp
|
||||
src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp
|
||||
src/ripple/app/tx/impl/NFTokenBurn.cpp
|
||||
src/ripple/app/tx/impl/NFTokenCancelOffer.cpp
|
||||
@@ -448,13 +452,10 @@ target_sources (rippled PRIVATE
|
||||
src/ripple/app/tx/impl/OfferStream.cpp
|
||||
src/ripple/app/tx/impl/PayChan.cpp
|
||||
src/ripple/app/tx/impl/Payment.cpp
|
||||
src/ripple/app/tx/impl/Remit.cpp
|
||||
src/ripple/app/tx/impl/SetAccount.cpp
|
||||
src/ripple/app/tx/impl/SetRegularKey.cpp
|
||||
src/ripple/app/tx/impl/SetHook.cpp
|
||||
src/ripple/app/tx/impl/ClaimReward.cpp
|
||||
src/ripple/app/tx/impl/GenesisMint.cpp
|
||||
src/ripple/app/tx/impl/Import.cpp
|
||||
src/ripple/app/tx/impl/Invoke.cpp
|
||||
src/ripple/app/tx/impl/SetRegularKey.cpp
|
||||
src/ripple/app/tx/impl/SetSignerList.cpp
|
||||
src/ripple/app/tx/impl/SetTrust.cpp
|
||||
src/ripple/app/tx/impl/SignerEntries.cpp
|
||||
@@ -740,6 +741,7 @@ if (tests)
|
||||
src/test/app/RCLCensorshipDetector_test.cpp
|
||||
src/test/app/RCLValidations_test.cpp
|
||||
src/test/app/Regression_test.cpp
|
||||
src/test/app/Remit_test.cpp
|
||||
src/test/app/SHAMapStore_test.cpp
|
||||
src/test/app/SetAuth_test.cpp
|
||||
src/test/app/SetRegularKey_test.cpp
|
||||
@@ -889,6 +891,7 @@ if (tests)
|
||||
src/test/jtx/impl/rate.cpp
|
||||
src/test/jtx/impl/regkey.cpp
|
||||
src/test/jtx/impl/reward.cpp
|
||||
src/test/jtx/impl/remit.cpp
|
||||
src/test/jtx/impl/sendmax.cpp
|
||||
src/test/jtx/impl/seq.cpp
|
||||
src/test/jtx/impl/sig.cpp
|
||||
@@ -980,6 +983,7 @@ if (tests)
|
||||
src/test/rpc/AccountLinesRPC_test.cpp
|
||||
src/test/rpc/AccountObjects_test.cpp
|
||||
src/test/rpc/AccountOffers_test.cpp
|
||||
src/test/rpc/AccountNamespace_test.cpp
|
||||
src/test/rpc/AccountSet_test.cpp
|
||||
src/test/rpc/AccountTx_test.cpp
|
||||
src/test/rpc/AmendmentBlocked_test.cpp
|
||||
|
||||
@@ -44,7 +44,7 @@ else()
|
||||
endif()
|
||||
# TBD:
|
||||
# Boost_USE_DEBUG_RUNTIME: When ON, uses Boost libraries linked against the
|
||||
find_package(Boost 1.70 REQUIRED
|
||||
find_package(Boost 1.86 REQUIRED
|
||||
COMPONENTS
|
||||
chrono
|
||||
container
|
||||
|
||||
@@ -52,6 +52,9 @@ Loop: ripple.overlay ripple.rpc
|
||||
Loop: test.app test.jtx
|
||||
test.app > test.jtx
|
||||
|
||||
Loop: test.app test.rpc
|
||||
test.rpc ~= test.app
|
||||
|
||||
Loop: test.jtx test.toplevel
|
||||
test.toplevel > test.jtx
|
||||
|
||||
|
||||
@@ -90,7 +90,6 @@ test.app > ripple.overlay
|
||||
test.app > ripple.protocol
|
||||
test.app > ripple.resource
|
||||
test.app > ripple.rpc
|
||||
test.app > test.rpc
|
||||
test.app > test.toplevel
|
||||
test.app > test.unit_test
|
||||
test.basics > ripple.basics
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Xahau
|
||||
# Xahau
|
||||
|
||||
**Note:** Throughout this README, references to "we" or "our" pertain to the community and contributors involved in the Xahau network. It does not imply a legal entity or a specific collection of individuals.
|
||||
|
||||
@@ -68,4 +68,4 @@ git-subtree. See those directories' README files for more details.
|
||||
- **Testnet & Faucet**: Test applications and obtain test XAH at [xahau-test.net](https://xahau-test.net) and use the testnet explorer at [explorer.xahau.network](https://explorer.xahau.network).
|
||||
- **Supporting Wallets**: A list of wallets that support XAH and Xahau-based assets.
|
||||
- [Xumm](https://xumm.app)
|
||||
- [Crossmark](https://crossmark.io)
|
||||
- [Crossmark](https://crossmark.io)
|
||||
+15
-6
@@ -9,6 +9,15 @@ echo "-- GITHUB_RUN_NUMBER: $4"
|
||||
|
||||
umask 0000;
|
||||
|
||||
echo "Fixing CentOS 7 EOL"
|
||||
|
||||
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
|
||||
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
|
||||
yum clean all
|
||||
yum-config-manager --disable centos-sclo-sclo
|
||||
|
||||
####
|
||||
|
||||
cd /io;
|
||||
mkdir src/certs;
|
||||
curl --silent -k https://raw.githubusercontent.com/RichardAH/rippled-release-builder/main/ca-bundle/certbundle.h -o src/certs/certbundle.h;
|
||||
@@ -81,11 +90,11 @@ echo "-- Install Cmake 3.23.1 --" &&
|
||||
pwd &&
|
||||
( wget -nc -q https://github.com/Kitware/CMake/releases/download/v3.23.1/cmake-3.23.1-linux-x86_64.tar.gz; echo "" ) &&
|
||||
tar -xzf cmake-3.23.1-linux-x86_64.tar.gz -C /hbb/ &&
|
||||
echo "-- Install Boost 1.75.0 --" &&
|
||||
echo "-- Install Boost 1.86.0 --" &&
|
||||
pwd &&
|
||||
( wget -nc -q https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz; echo "" ) &&
|
||||
tar -xzf boost_1_75_0.tar.gz &&
|
||||
cd boost_1_75_0 && ./bootstrap.sh && ./b2 link=static -j$3 && ./b2 install &&
|
||||
( wget -nc -q https://boostorg.jfrog.io/artifactory/main/release/1.86.0/source/boost_1_86_0.tar.gz; echo "" ) &&
|
||||
tar -xzf boost_1_86_0.tar.gz &&
|
||||
cd boost_1_86_0 && ./bootstrap.sh && ./b2 link=static -j$3 && ./b2 install &&
|
||||
cd ../ &&
|
||||
echo "-- Install Protobuf 3.20.0 --" &&
|
||||
pwd &&
|
||||
@@ -118,9 +127,9 @@ echo "-- Build WasmEdge --" &&
|
||||
cd WasmEdge-0.11.2 &&
|
||||
( mkdir build; echo "" ) &&
|
||||
cd build &&
|
||||
export BOOST_ROOT="/usr/local/src/boost_1_75_0" &&
|
||||
export BOOST_ROOT="/usr/local/src/boost_1_86_0" &&
|
||||
export Boost_LIBRARY_DIRS="/usr/local/lib" &&
|
||||
export BOOST_INCLUDEDIR="/usr/local/src/boost_1_75_0" &&
|
||||
export BOOST_INCLUDEDIR="/usr/local/src/boost_1_86_0" &&
|
||||
export PATH=`echo $PATH | sed -E "s/devtoolset-7/devtoolset-9/g"` &&
|
||||
cmake .. \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
|
||||
@@ -144,4 +144,12 @@ D686F2538F410C9D0D856788E98E3579595DAF7B38D38887F81ECAC934B06040 HooksUpdate1
|
||||
86E83A7D2ECE3AD5FA87AB2195AE015C950469ABF0B72EAACED318F74886AE90 CryptoConditionsSuite
|
||||
3C43D9A973AA4443EF3FC38E42DD306160FBFFDAB901CD8BAA15D09F2597EB87 NonFungibleTokensV1
|
||||
0285B7E5E08E1A8E4C15636F0591D87F73CB6A7B6452A932AD72BBC8E5D1CBE3 fixNFTokenDirV1
|
||||
36799EA497B1369B170805C078AEFE6188345F9B3E324C21E9CA3FF574E3C3D6 fixNFTokenNegOffer
|
||||
36799EA497B1369B170805C078AEFE6188345F9B3E324C21E9CA3FF574E3C3D6 fixNFTokenNegOffer
|
||||
4C499D17719BB365B69010A436B64FD1A82AAB199FC1CEB06962EBD01059FB09 fixXahauV1
|
||||
215181D23BF5C173314B5FDB9C872C92DE6CC918483727DE037C0C13E7E6EE9D fixXahauV2
|
||||
0D8BF22FF7570D58598D1EF19EBB6E142AD46E59A223FD3816262FBB69345BEA Remit
|
||||
7CA0426E7F411D39BB014E57CD9E08F61DE1750F0D41FCD428D9FB80BB7596B0 ZeroB2M
|
||||
4B8466415FAB32FFA89D9DCBE166A42340115771DF611A7160F8D7439C87ECD8 fixNSDelete
|
||||
EDB4EE4C524E16BDD91D9A529332DED08DCAAA51CC6DC897ACFA1A0ED131C5B6 fix240819
|
||||
8063140E9260799D6716756B891CEC3E7006C4E4F277AB84670663A88F94B9C4 fixPageCap
|
||||
88693F108C3CD8A967F3F4253A32DEF5E35F9406ACD2A11B88B11D90865763A9 fix240911
|
||||
@@ -45,5 +45,7 @@
|
||||
#define INVALID_KEY -41
|
||||
#define NOT_A_STRING -42
|
||||
#define MEM_OVERLAP -43
|
||||
#define TOO_MANY_STATE_MODIFICATIONS -44
|
||||
#define TOO_MANY_NAMESPACES -45
|
||||
#define HOOK_ERROR_CODES
|
||||
#endif //HOOK_ERROR_CODES
|
||||
+103
-358
@@ -9,13 +9,32 @@
|
||||
#ifndef HOOKMACROS_INCLUDED
|
||||
#define HOOKMACROS_INCLUDED 1
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define DEBUG 0
|
||||
#else
|
||||
#define DEBUG 1
|
||||
#endif
|
||||
|
||||
#define DONEEMPTY()\
|
||||
accept(0,0,__LINE__)
|
||||
|
||||
#define DONEMSG(msg)\
|
||||
accept(msg, sizeof(msg),__LINE__)
|
||||
|
||||
#define DONE(x)\
|
||||
accept(SVAR(x),(uint32_t)__LINE__);
|
||||
|
||||
#define ASSERT(x)\
|
||||
{\
|
||||
if (!(x))\
|
||||
rollback(0,0,__LINE__);\
|
||||
}
|
||||
|
||||
#define NOPE(x)\
|
||||
{\
|
||||
return rollback((x), sizeof(x), __LINE__);\
|
||||
}
|
||||
|
||||
#define TRACEVAR(v) if (DEBUG) trace_num((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (int64_t)v);
|
||||
#define TRACEHEX(v) if (DEBUG) trace((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (uint32_t)(v), (uint32_t)(sizeof(v)), 1);
|
||||
#define TRACEXFL(v) if (DEBUG) trace_float((uint32_t)(#v), (uint32_t)(sizeof(#v) - 1), (int64_t)v);
|
||||
@@ -26,6 +45,7 @@
|
||||
#define GUARDM(maxiter, n) _g(( (1ULL << 31U) + (__LINE__ << 16) + n), (maxiter)+1)
|
||||
|
||||
#define SBUF(str) (uint32_t)(str), sizeof(str)
|
||||
#define SVAR(x) &x, sizeof(x)
|
||||
|
||||
#define REQUIRE(cond, str)\
|
||||
{\
|
||||
@@ -138,6 +158,17 @@ int out_len = 0;\
|
||||
*(((uint64_t*)(buf1)) + 2) == *(((uint64_t*)(buf2)) + 2) &&\
|
||||
*(((uint64_t*)(buf1)) + 3) == *(((uint64_t*)(buf2)) + 3))
|
||||
|
||||
#define BUFFER_EQUAL_64(buf1, buf2) \
|
||||
( \
|
||||
(*((uint64_t*)(buf1) + 0) == *((uint64_t*)(buf2) + 0)) && \
|
||||
(*((uint64_t*)(buf1) + 1) == *((uint64_t*)(buf2) + 1)) && \
|
||||
(*((uint64_t*)(buf1) + 2) == *((uint64_t*)(buf2) + 2)) && \
|
||||
(*((uint64_t*)(buf1) + 3) == *((uint64_t*)(buf2) + 3)) && \
|
||||
(*((uint64_t*)(buf1) + 4) == *((uint64_t*)(buf2) + 4)) && \
|
||||
(*((uint64_t*)(buf1) + 5) == *((uint64_t*)(buf2) + 5)) && \
|
||||
(*((uint64_t*)(buf1) + 6) == *((uint64_t*)(buf2) + 6)) && \
|
||||
(*((uint64_t*)(buf1) + 7) == *((uint64_t*)(buf2) + 7)) \
|
||||
)
|
||||
|
||||
// when using this macro buf1len may be dynamic but buf2len must be static
|
||||
// provide n >= 1 to indicate how many times the macro will be hit on the line of code
|
||||
@@ -185,6 +216,18 @@ int out_len = 0;\
|
||||
#define BUFFER_EQUAL(output, buf1, buf2, compare_len)\
|
||||
BUFFER_EQUAL_GUARD(output, buf1, compare_len, buf2, compare_len, 1)
|
||||
|
||||
|
||||
#define UINT8_TO_BUF(buf_raw, i)\
|
||||
{\
|
||||
unsigned char* buf = (unsigned char*)buf_raw;\
|
||||
buf[0] = (((uint8_t)i) >> 0) & 0xFFUL;\
|
||||
if (i < 0) buf[0] |= 0x80U;\
|
||||
}
|
||||
|
||||
#define UINT8_FROM_BUF(buf)\
|
||||
(((uint8_t)((buf)[0]) << 0))
|
||||
|
||||
|
||||
#define UINT16_TO_BUF(buf_raw, i)\
|
||||
{\
|
||||
unsigned char* buf = (unsigned char*)buf_raw;\
|
||||
@@ -205,7 +248,6 @@ int out_len = 0;\
|
||||
buf[3] = (((uint64_t)i) >> 0) & 0xFFUL;\
|
||||
}
|
||||
|
||||
|
||||
#define UINT32_FROM_BUF(buf)\
|
||||
(((uint64_t)((buf)[0]) << 24) +\
|
||||
((uint64_t)((buf)[1]) << 16) +\
|
||||
@@ -225,7 +267,6 @@ int out_len = 0;\
|
||||
buf[7] = (((uint64_t)i) >> 0) & 0xFFUL;\
|
||||
}
|
||||
|
||||
|
||||
#define UINT64_FROM_BUF(buf)\
|
||||
(((uint64_t)((buf)[0]) << 56) +\
|
||||
((uint64_t)((buf)[1]) << 48) +\
|
||||
@@ -236,17 +277,6 @@ int out_len = 0;\
|
||||
((uint64_t)((buf)[6]) << 8) +\
|
||||
((uint64_t)((buf)[7]) << 0))
|
||||
|
||||
|
||||
#define INT64_FROM_BUF(buf)\
|
||||
((((uint64_t)((buf)[0] & 0x7FU) << 56) +\
|
||||
((uint64_t)((buf)[1]) << 48) +\
|
||||
((uint64_t)((buf)[2]) << 40) +\
|
||||
((uint64_t)((buf)[3]) << 32) +\
|
||||
((uint64_t)((buf)[4]) << 24) +\
|
||||
((uint64_t)((buf)[5]) << 16) +\
|
||||
((uint64_t)((buf)[6]) << 8) +\
|
||||
((uint64_t)((buf)[7]) << 0)) * (buf[0] & 0x80U ? -1 : 1))
|
||||
|
||||
#define INT64_TO_BUF(buf_raw, i)\
|
||||
{\
|
||||
unsigned char* buf = (unsigned char*)buf_raw;\
|
||||
@@ -261,6 +291,65 @@ int out_len = 0;\
|
||||
if (i < 0) buf[0] |= 0x80U;\
|
||||
}
|
||||
|
||||
#define INT64_FROM_BUF(buf)\
|
||||
((((uint64_t)((buf)[0] & 0x7FU) << 56) +\
|
||||
((uint64_t)((buf)[1]) << 48) +\
|
||||
((uint64_t)((buf)[2]) << 40) +\
|
||||
((uint64_t)((buf)[3]) << 32) +\
|
||||
((uint64_t)((buf)[4]) << 24) +\
|
||||
((uint64_t)((buf)[5]) << 16) +\
|
||||
((uint64_t)((buf)[6]) << 8) +\
|
||||
((uint64_t)((buf)[7]) << 0)) * (buf[0] & 0x80U ? -1 : 1))
|
||||
|
||||
|
||||
#define BYTES20_TO_BUF(buf_raw, i)\
|
||||
{\
|
||||
unsigned char* buf = (unsigned char*)buf_raw;\
|
||||
*(uint64_t*)(buf + 0) = *(uint64_t*)(i + 0);\
|
||||
*(uint64_t*)(buf + 8) = *(uint64_t*)(i + 8);\
|
||||
*(uint32_t*)(buf + 16) = *(uint32_t*)(i + 16);\
|
||||
}
|
||||
|
||||
#define BYTES20_FROM_BUF(buf_raw, i)\
|
||||
{\
|
||||
const unsigned char* buf = (const unsigned char*)buf_raw;\
|
||||
*(uint64_t*)(i + 0) = *(const uint64_t*)(buf + 0);\
|
||||
*(uint64_t*)(i + 8) = *(const uint64_t*)(buf + 8);\
|
||||
*(uint32_t*)(i + 16) = *(const uint32_t*)(buf + 16);\
|
||||
}
|
||||
|
||||
#define BYTES32_TO_BUF(buf_raw, i)\
|
||||
{\
|
||||
unsigned char* buf = (unsigned char*)buf_raw;\
|
||||
*(uint64_t*)(buf + 0) = *(uint64_t*)(i + 0);\
|
||||
*(uint64_t*)(buf + 8) = *(uint64_t*)(i + 8);\
|
||||
*(uint64_t*)(buf + 16) = *(uint64_t*)(i + 16);\
|
||||
*(uint64_t*)(buf + 24) = *(uint64_t*)(i + 24);\
|
||||
}
|
||||
|
||||
#define BYTES32_FROM_BUF(buf_raw, i)\
|
||||
{\
|
||||
const unsigned char* buf = (const unsigned char*)buf_raw;\
|
||||
*(uint64_t*)(i + 0) = *(const uint64_t*)(buf + 0);\
|
||||
*(uint64_t*)(i + 8) = *(const uint64_t*)(buf + 8);\
|
||||
*(uint64_t*)(i + 16) = *(const uint64_t*)(buf + 16);\
|
||||
*(uint64_t*)(i + 24) = *(const uint64_t*)(buf + 24);\
|
||||
}
|
||||
|
||||
#define FLIP_ENDIAN_32(n) ((uint32_t) (((n & 0xFFU) << 24U) | \
|
||||
((n & 0xFF00U) << 8U) | \
|
||||
((n & 0xFF0000U) >> 8U) | \
|
||||
((n & 0xFF000000U) >> 24U)))
|
||||
|
||||
#define FLIP_ENDIAN_64(n) ((uint64_t)(((n & 0xFFULL) << 56ULL) | \
|
||||
((n & 0xFF00ULL) << 40ULL) | \
|
||||
((n & 0xFF0000ULL) << 24ULL) | \
|
||||
((n & 0xFF000000ULL) << 8ULL) | \
|
||||
((n & 0xFF00000000ULL) >> 8ULL) | \
|
||||
((n & 0xFF0000000000ULL) >> 24ULL) | \
|
||||
((n & 0xFF000000000000ULL) >> 40ULL) | \
|
||||
((n & 0xFF00000000000000ULL) >> 56ULL)))
|
||||
|
||||
#define tfCANONICAL 0x80000000UL
|
||||
|
||||
#define atACCOUNT 1U
|
||||
@@ -287,350 +376,6 @@ int out_len = 0;\
|
||||
#define amRIPPLEESCROW 17U
|
||||
#define amDELIVEREDAMOUNT 18U
|
||||
|
||||
/**
|
||||
* RH NOTE -- PAY ATTENTION
|
||||
*
|
||||
* ALL 'ENCODE' MACROS INCREMENT BUF_OUT
|
||||
* THIS IS TO MAKE CHAINING EASY
|
||||
* BUF_OUT IS A SACRIFICIAL POINTER
|
||||
*
|
||||
* 'ENCODE' MACROS WITH CONSTANTS HAVE
|
||||
* ALIASING TO ASSIST YOU WITH ORDER
|
||||
* _TYPECODE_FIELDCODE_ENCODE_MACRO
|
||||
* TO PRODUCE A SERIALIZED OBJECT
|
||||
* IN CANONICAL FORMAT YOU MUST ORDER
|
||||
* FIRST BY TYPE CODE THEN BY FIELD CODE
|
||||
*
|
||||
* ALL 'PREPARE' MACROS PRESERVE POINTERS
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
#define ENCODE_TL_SIZE 49
|
||||
#define ENCODE_TL(buf_out, tlamt, amount_type)\
|
||||
{\
|
||||
uint8_t uat = amount_type; \
|
||||
buf_out[0] = 0x60U +(uat & 0x0FU ); \
|
||||
for (int i = 1; GUARDM(48, 1), i < 49; ++i)\
|
||||
buf_out[i] = tlamt[i-1];\
|
||||
buf_out += ENCODE_TL_SIZE;\
|
||||
}
|
||||
#define _06_XX_ENCODE_TL(buf_out, drops, amount_type )\
|
||||
ENCODE_TL(buf_out, drops, amount_type );
|
||||
#define ENCODE_TL_AMOUNT(buf_out, drops )\
|
||||
ENCODE_TL(buf_out, drops, amAMOUNT );
|
||||
#define _06_01_ENCODE_TL_AMOUNT(buf_out, drops )\
|
||||
ENCODE_TL_AMOUNT(buf_out, drops );
|
||||
|
||||
|
||||
// Encode drops to serialization format
|
||||
// consumes 9 bytes
|
||||
#define ENCODE_DROPS_SIZE 9
|
||||
#define ENCODE_DROPS(buf_out, drops, amount_type ) \
|
||||
{\
|
||||
uint8_t uat = amount_type; \
|
||||
uint64_t udrops = drops; \
|
||||
buf_out[0] = 0x60U +(uat & 0x0FU ); \
|
||||
buf_out[1] = 0b01000000 + (( udrops >> 56 ) & 0b00111111 ); \
|
||||
buf_out[2] = (udrops >> 48) & 0xFFU; \
|
||||
buf_out[3] = (udrops >> 40) & 0xFFU; \
|
||||
buf_out[4] = (udrops >> 32) & 0xFFU; \
|
||||
buf_out[5] = (udrops >> 24) & 0xFFU; \
|
||||
buf_out[6] = (udrops >> 16) & 0xFFU; \
|
||||
buf_out[7] = (udrops >> 8) & 0xFFU; \
|
||||
buf_out[8] = (udrops >> 0) & 0xFFU; \
|
||||
buf_out += ENCODE_DROPS_SIZE; \
|
||||
}
|
||||
|
||||
#define _06_XX_ENCODE_DROPS(buf_out, drops, amount_type )\
|
||||
ENCODE_DROPS(buf_out, drops, amount_type );
|
||||
|
||||
#define ENCODE_DROPS_AMOUNT(buf_out, drops )\
|
||||
ENCODE_DROPS(buf_out, drops, amAMOUNT );
|
||||
#define _06_01_ENCODE_DROPS_AMOUNT(buf_out, drops )\
|
||||
ENCODE_DROPS_AMOUNT(buf_out, drops );
|
||||
|
||||
#define ENCODE_DROPS_FEE(buf_out, drops )\
|
||||
ENCODE_DROPS(buf_out, drops, amFEE );
|
||||
#define _06_08_ENCODE_DROPS_FEE(buf_out, drops )\
|
||||
ENCODE_DROPS_FEE(buf_out, drops );
|
||||
|
||||
#define ENCODE_TT_SIZE 3
|
||||
#define ENCODE_TT(buf_out, tt )\
|
||||
{\
|
||||
uint8_t utt = tt;\
|
||||
buf_out[0] = 0x12U;\
|
||||
buf_out[1] =(utt >> 8 ) & 0xFFU;\
|
||||
buf_out[2] =(utt >> 0 ) & 0xFFU;\
|
||||
buf_out += ENCODE_TT_SIZE; \
|
||||
}
|
||||
#define _01_02_ENCODE_TT(buf_out, tt)\
|
||||
ENCODE_TT(buf_out, tt);
|
||||
|
||||
|
||||
#define ENCODE_ACCOUNT_SIZE 22
|
||||
#define ENCODE_ACCOUNT(buf_out, account_id, account_type)\
|
||||
{\
|
||||
uint8_t uat = account_type;\
|
||||
buf_out[0] = 0x80U + uat;\
|
||||
buf_out[1] = 0x14U;\
|
||||
*(uint64_t*)(buf_out + 2) = *(uint64_t*)(account_id + 0);\
|
||||
*(uint64_t*)(buf_out + 10) = *(uint64_t*)(account_id + 8);\
|
||||
*(uint32_t*)(buf_out + 18) = *(uint32_t*)(account_id + 16);\
|
||||
buf_out += ENCODE_ACCOUNT_SIZE;\
|
||||
}
|
||||
#define _08_XX_ENCODE_ACCOUNT(buf_out, account_id, account_type)\
|
||||
ENCODE_ACCOUNT(buf_out, account_id, account_type);
|
||||
|
||||
#define ENCODE_ACCOUNT_SRC_SIZE 22
|
||||
#define ENCODE_ACCOUNT_SRC(buf_out, account_id)\
|
||||
ENCODE_ACCOUNT(buf_out, account_id, atACCOUNT);
|
||||
#define _08_01_ENCODE_ACCOUNT_SRC(buf_out, account_id)\
|
||||
ENCODE_ACCOUNT_SRC(buf_out, account_id);
|
||||
|
||||
#define ENCODE_ACCOUNT_DST_SIZE 22
|
||||
#define ENCODE_ACCOUNT_DST(buf_out, account_id)\
|
||||
ENCODE_ACCOUNT(buf_out, account_id, atDESTINATION);
|
||||
#define _08_03_ENCODE_ACCOUNT_DST(buf_out, account_id)\
|
||||
ENCODE_ACCOUNT_DST(buf_out, account_id);
|
||||
|
||||
#define ENCODE_ACCOUNT_OWNER_SIZE 22
|
||||
#define ENCODE_ACCOUNT_OWNER(buf_out, account_id) \
|
||||
ENCODE_ACCOUNT(buf_out, account_id, atOWNER);
|
||||
#define _08_02_ENCODE_ACCOUNT_OWNER(buf_out, account_id) \
|
||||
ENCODE_ACCOUNT_OWNER(buf_out, account_id);
|
||||
|
||||
#define ENCODE_UINT32_COMMON_SIZE 5U
|
||||
#define ENCODE_UINT32_COMMON(buf_out, i, field)\
|
||||
{\
|
||||
uint32_t ui = i; \
|
||||
uint8_t uf = field; \
|
||||
buf_out[0] = 0x20U +(uf & 0x0FU); \
|
||||
buf_out[1] =(ui >> 24 ) & 0xFFU; \
|
||||
buf_out[2] =(ui >> 16 ) & 0xFFU; \
|
||||
buf_out[3] =(ui >> 8 ) & 0xFFU; \
|
||||
buf_out[4] =(ui >> 0 ) & 0xFFU; \
|
||||
buf_out += ENCODE_UINT32_COMMON_SIZE; \
|
||||
}
|
||||
#define _02_XX_ENCODE_UINT32_COMMON(buf_out, i, field)\
|
||||
ENCODE_UINT32_COMMON(buf_out, i, field)\
|
||||
|
||||
#define ENCODE_UINT32_UNCOMMON_SIZE 6U
|
||||
#define ENCODE_UINT32_UNCOMMON(buf_out, i, field)\
|
||||
{\
|
||||
uint32_t ui = i; \
|
||||
uint8_t uf = field; \
|
||||
buf_out[0] = 0x20U; \
|
||||
buf_out[1] = uf; \
|
||||
buf_out[2] =(ui >> 24 ) & 0xFFU; \
|
||||
buf_out[3] =(ui >> 16 ) & 0xFFU; \
|
||||
buf_out[4] =(ui >> 8 ) & 0xFFU; \
|
||||
buf_out[5] =(ui >> 0 ) & 0xFFU; \
|
||||
buf_out += ENCODE_UINT32_UNCOMMON_SIZE; \
|
||||
}
|
||||
#define _02_XX_ENCODE_UINT32_UNCOMMON(buf_out, i, field)\
|
||||
ENCODE_UINT32_UNCOMMON(buf_out, i, field)\
|
||||
|
||||
#define ENCODE_LLS_SIZE 6U
|
||||
#define ENCODE_LLS(buf_out, lls )\
|
||||
ENCODE_UINT32_UNCOMMON(buf_out, lls, 0x1B );
|
||||
#define _02_27_ENCODE_LLS(buf_out, lls )\
|
||||
ENCODE_LLS(buf_out, lls );
|
||||
|
||||
#define ENCODE_FLS_SIZE 6U
|
||||
#define ENCODE_FLS(buf_out, fls )\
|
||||
ENCODE_UINT32_UNCOMMON(buf_out, fls, 0x1A );
|
||||
#define _02_26_ENCODE_FLS(buf_out, fls )\
|
||||
ENCODE_FLS(buf_out, fls );
|
||||
|
||||
#define ENCODE_TAG_SRC_SIZE 5
|
||||
#define ENCODE_TAG_SRC(buf_out, tag )\
|
||||
ENCODE_UINT32_COMMON(buf_out, tag, 0x3U );
|
||||
#define _02_03_ENCODE_TAG_SRC(buf_out, tag )\
|
||||
ENCODE_TAG_SRC(buf_out, tag );
|
||||
|
||||
#define ENCODE_TAG_DST_SIZE 5
|
||||
#define ENCODE_TAG_DST(buf_out, tag )\
|
||||
ENCODE_UINT32_COMMON(buf_out, tag, 0xEU );
|
||||
#define _02_14_ENCODE_TAG_DST(buf_out, tag )\
|
||||
ENCODE_TAG_DST(buf_out, tag );
|
||||
|
||||
#define ENCODE_SEQUENCE_SIZE 5
|
||||
#define ENCODE_SEQUENCE(buf_out, sequence )\
|
||||
ENCODE_UINT32_COMMON(buf_out, sequence, 0x4U );
|
||||
#define _02_04_ENCODE_SEQUENCE(buf_out, sequence )\
|
||||
ENCODE_SEQUENCE(buf_out, sequence );
|
||||
|
||||
#define ENCODE_FLAGS_SIZE 5
|
||||
#define ENCODE_FLAGS(buf_out, tag )\
|
||||
ENCODE_UINT32_COMMON(buf_out, tag, 0x2U );
|
||||
#define _02_02_ENCODE_FLAGS(buf_out, tag )\
|
||||
ENCODE_FLAGS(buf_out, tag );
|
||||
|
||||
#define ENCODE_SIGNING_PUBKEY_SIZE 35
|
||||
#define ENCODE_SIGNING_PUBKEY(buf_out, pkey )\
|
||||
{\
|
||||
buf_out[0] = 0x73U;\
|
||||
buf_out[1] = 0x21U;\
|
||||
*(uint64_t*)(buf_out + 2) = *(uint64_t*)(pkey + 0);\
|
||||
*(uint64_t*)(buf_out + 10) = *(uint64_t*)(pkey + 8);\
|
||||
*(uint64_t*)(buf_out + 18) = *(uint64_t*)(pkey + 16);\
|
||||
*(uint64_t*)(buf_out + 26) = *(uint64_t*)(pkey + 24);\
|
||||
buf[34] = pkey[32];\
|
||||
buf_out += ENCODE_SIGNING_PUBKEY_SIZE;\
|
||||
}
|
||||
|
||||
#define _07_03_ENCODE_SIGNING_PUBKEY(buf_out, pkey )\
|
||||
ENCODE_SIGNING_PUBKEY(buf_out, pkey );
|
||||
|
||||
#define ENCODE_SIGNING_PUBKEY_NULL_SIZE 2
|
||||
#define ENCODE_SIGNING_PUBKEY_NULL(buf_out )\
|
||||
{\
|
||||
*buf_out++ = 0x73U;\
|
||||
*buf_out++ = 0x00U;\
|
||||
}
|
||||
|
||||
#define _07_03_ENCODE_SIGNING_PUBKEY_NULL(buf_out )\
|
||||
ENCODE_SIGNING_PUBKEY_NULL(buf_out );
|
||||
|
||||
|
||||
#define _0E_0E_ENCODE_HOOKOBJ(buf_out, hhash)\
|
||||
{\
|
||||
uint8_t* hook0 = (hhash);\
|
||||
*buf_out++ = 0xEEU; /* hook obj start */ \
|
||||
if (hook0 == 0) /* noop */\
|
||||
{\
|
||||
/* do nothing */ \
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
*buf_out++ = 0x22U; /* flags = override */\
|
||||
*buf_out++ = 0x00U;\
|
||||
*buf_out++ = 0x00U;\
|
||||
*buf_out++ = 0x00U;\
|
||||
*buf_out++ = 0x01U;\
|
||||
if (hook0 == 0xFFFFFFFFUL) /* delete operation */ \
|
||||
{\
|
||||
*buf_out++ = 0x7BU; /* empty createcode */ \
|
||||
*buf_out++ = 0x00U;\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
*buf_out++ = 0x50U; /* HookHash */\
|
||||
*buf_out++ = 0x1FU;\
|
||||
uint64_t* d = (uint64_t*)buf_out;\
|
||||
uint64_t* s = (uint64_t*)hook0;\
|
||||
*d++ = *s++;\
|
||||
*d++ = *s++;\
|
||||
*d++ = *s++;\
|
||||
*d++ = *s++;\
|
||||
buf_out+=32;\
|
||||
}\
|
||||
}\
|
||||
*buf_out++ = 0xE1U;\
|
||||
}
|
||||
|
||||
#define PREPARE_HOOKSET(buf_out_master, maxlen, h, sizeout)\
|
||||
{\
|
||||
uint8_t* buf_out = (buf_out_master); \
|
||||
uint8_t acc[20]; \
|
||||
uint32_t cls = (uint32_t)ledger_seq(); \
|
||||
hook_account(SBUF(acc)); \
|
||||
_01_02_ENCODE_TT (buf_out, ttHOOK_SET ); \
|
||||
_02_02_ENCODE_FLAGS (buf_out, tfCANONICAL ); \
|
||||
_02_04_ENCODE_SEQUENCE (buf_out, 0 ); \
|
||||
_02_26_ENCODE_FLS (buf_out, cls + 1 ); \
|
||||
_02_27_ENCODE_LLS (buf_out, cls + 5 ); \
|
||||
uint8_t* fee_ptr = buf_out; \
|
||||
_06_08_ENCODE_DROPS_FEE (buf_out, 0 ); \
|
||||
_07_03_ENCODE_SIGNING_PUBKEY_NULL (buf_out ); \
|
||||
_08_01_ENCODE_ACCOUNT_SRC (buf_out, acc ); \
|
||||
uint32_t remaining_size = (maxlen) - (buf_out - (buf_out_master)); \
|
||||
int64_t edlen = etxn_details((uint32_t)buf_out, remaining_size); \
|
||||
buf_out += edlen; \
|
||||
*buf_out++ = 0xFBU; /* hook array start */ \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[0]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[1]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[2]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[3]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[4]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[5]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[6]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[7]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[8]); \
|
||||
_0E_0E_ENCODE_HOOKOBJ (buf_out, h[9]); \
|
||||
*buf_out++ = 0xF1U; /* hook array end */ \
|
||||
sizeout = (buf_out - (buf_out_master)); \
|
||||
int64_t fee = etxn_fee_base(buf_out_master, sizeout); \
|
||||
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
|
||||
}
|
||||
|
||||
#ifdef HAS_CALLBACK
|
||||
#define PREPARE_PAYMENT_SIMPLE_SIZE 270U
|
||||
#else
|
||||
#define PREPARE_PAYMENT_SIMPLE_SIZE 248U
|
||||
#endif
|
||||
|
||||
#define PREPARE_PAYMENT_SIMPLE(buf_out_master, drops_amount_raw, to_address, dest_tag_raw, src_tag_raw)\
|
||||
{\
|
||||
uint8_t* buf_out = buf_out_master;\
|
||||
uint8_t acc[20];\
|
||||
uint64_t drops_amount = (drops_amount_raw);\
|
||||
uint32_t dest_tag = (dest_tag_raw);\
|
||||
uint32_t src_tag = (src_tag_raw);\
|
||||
uint32_t cls = (uint32_t)ledger_seq();\
|
||||
hook_account(SBUF(acc));\
|
||||
_01_02_ENCODE_TT (buf_out, ttPAYMENT ); /* uint16 | size 3 */ \
|
||||
_02_02_ENCODE_FLAGS (buf_out, tfCANONICAL ); /* uint32 | size 5 */ \
|
||||
_02_03_ENCODE_TAG_SRC (buf_out, src_tag ); /* uint32 | size 5 */ \
|
||||
_02_04_ENCODE_SEQUENCE (buf_out, 0 ); /* uint32 | size 5 */ \
|
||||
_02_14_ENCODE_TAG_DST (buf_out, dest_tag ); /* uint32 | size 5 */ \
|
||||
_02_26_ENCODE_FLS (buf_out, cls + 1 ); /* uint32 | size 6 */ \
|
||||
_02_27_ENCODE_LLS (buf_out, cls + 5 ); /* uint32 | size 6 */ \
|
||||
_06_01_ENCODE_DROPS_AMOUNT (buf_out, drops_amount ); /* amount | size 9 */ \
|
||||
uint8_t* fee_ptr = buf_out;\
|
||||
_06_08_ENCODE_DROPS_FEE (buf_out, 0 ); /* amount | size 9 */ \
|
||||
_07_03_ENCODE_SIGNING_PUBKEY_NULL (buf_out ); /* pk | size 35 */ \
|
||||
_08_01_ENCODE_ACCOUNT_SRC (buf_out, acc ); /* account | size 22 */ \
|
||||
_08_03_ENCODE_ACCOUNT_DST (buf_out, to_address ); /* account | size 22 */ \
|
||||
int64_t edlen = etxn_details((uint32_t)buf_out, PREPARE_PAYMENT_SIMPLE_SIZE); /* emitdet | size 1?? */ \
|
||||
int64_t fee = etxn_fee_base(buf_out_master, PREPARE_PAYMENT_SIMPLE_SIZE); \
|
||||
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
|
||||
}
|
||||
|
||||
#ifdef HAS_CALLBACK
|
||||
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE 309
|
||||
#else
|
||||
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE 287
|
||||
#endif
|
||||
#define PREPARE_PAYMENT_SIMPLE_TRUSTLINE(buf_out_master, tlamt, to_address, dest_tag_raw, src_tag_raw)\
|
||||
{\
|
||||
uint8_t* buf_out = buf_out_master;\
|
||||
uint8_t acc[20];\
|
||||
uint32_t dest_tag = (dest_tag_raw);\
|
||||
uint32_t src_tag = (src_tag_raw);\
|
||||
uint32_t cls = (uint32_t)ledger_seq();\
|
||||
hook_account(SBUF(acc));\
|
||||
_01_02_ENCODE_TT (buf_out, ttPAYMENT ); /* uint16 | size 3 */ \
|
||||
_02_02_ENCODE_FLAGS (buf_out, tfCANONICAL ); /* uint32 | size 5 */ \
|
||||
_02_03_ENCODE_TAG_SRC (buf_out, src_tag ); /* uint32 | size 5 */ \
|
||||
_02_04_ENCODE_SEQUENCE (buf_out, 0 ); /* uint32 | size 5 */ \
|
||||
_02_14_ENCODE_TAG_DST (buf_out, dest_tag ); /* uint32 | size 5 */ \
|
||||
_02_26_ENCODE_FLS (buf_out, cls + 1 ); /* uint32 | size 6 */ \
|
||||
_02_27_ENCODE_LLS (buf_out, cls + 5 ); /* uint32 | size 6 */ \
|
||||
_06_01_ENCODE_TL_AMOUNT (buf_out, tlamt ); /* amount | size 48 */ \
|
||||
uint8_t* fee_ptr = buf_out;\
|
||||
_06_08_ENCODE_DROPS_FEE (buf_out, 0 ); /* amount | size 9 */ \
|
||||
_07_03_ENCODE_SIGNING_PUBKEY_NULL (buf_out ); /* pk | size 35 */ \
|
||||
_08_01_ENCODE_ACCOUNT_SRC (buf_out, acc ); /* account | size 22 */ \
|
||||
_08_03_ENCODE_ACCOUNT_DST (buf_out, to_address ); /* account | size 22 */ \
|
||||
etxn_details((uint32_t)buf_out, PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE); /* emitdet | size 1?? */ \
|
||||
int64_t fee = etxn_fee_base(buf_out_master, PREPARE_PAYMENT_SIMPLE_TRUSTLINE_SIZE); \
|
||||
_06_08_ENCODE_DROPS_FEE (fee_ptr, fee ); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#define ttURITOKEN_BUY 47
|
||||
#define ttURITOKEN_CREATE_SELL_OFFER 48
|
||||
#define ttURITOKEN_CANCEL_SELL_OFFER 49
|
||||
#define ttREMIT 95
|
||||
#define ttGENESIS_MINT 96
|
||||
#define ttIMPORT 97
|
||||
#define ttCLAIM_REWARD 98
|
||||
|
||||
+11
-8
@@ -12,10 +12,13 @@ if [[ "$GITHUB_REPOSITORY" == "" ]]; then
|
||||
BUILD_CORES=8
|
||||
fi
|
||||
|
||||
CONTAINER_NAME=xahaud_cached_builder_$(echo "$GITHUB_ACTOR" | awk '{print tolower($0)}')
|
||||
|
||||
echo "-- BUILD CORES: $BUILD_CORES"
|
||||
echo "-- GITHUB_REPOSITORY: $GITHUB_REPOSITORY"
|
||||
echo "-- GITHUB_SHA: $GITHUB_SHA"
|
||||
echo "-- GITHUB_RUN_NUMBER: $GITHUB_RUN_NUMBER"
|
||||
echo "-- CONTAINER_NAME: $CONTAINER_NAME"
|
||||
|
||||
which docker 2> /dev/null 2> /dev/null
|
||||
if [ "$?" -eq "1" ]
|
||||
@@ -31,13 +34,13 @@ then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
STATIC_CONTAINER=$(docker ps -a | grep xahaud_cached_builder |wc -l)
|
||||
STATIC_CONTAINER=$(docker ps -a | grep $CONTAINER_NAME |wc -l)
|
||||
|
||||
if [[ "$STATIC_CONTAINER" -gt "0" && "$GITHUB_REPOSITORY" != "" ]]; then
|
||||
echo "Static container, execute in static container to have max. cache"
|
||||
docker start xahaud_cached_builder
|
||||
docker exec -i xahaud_cached_builder /hbb_exe/activate-exec bash -x /io/build-core.sh "$GITHUB_REPOSITORY" "$GITHUB_SHA" "$BUILD_CORES" "$GITHUB_RUN_NUMBER"
|
||||
docker stop xahaud_cached_builder
|
||||
docker start $CONTAINER_NAME
|
||||
docker exec -i $CONTAINER_NAME /hbb_exe/activate-exec bash -x /io/build-core.sh "$GITHUB_REPOSITORY" "$GITHUB_SHA" "$BUILD_CORES" "$GITHUB_RUN_NUMBER"
|
||||
docker stop $CONTAINER_NAME
|
||||
else
|
||||
echo "No static container, build on temp container"
|
||||
rm -rf release-build;
|
||||
@@ -50,10 +53,10 @@ else
|
||||
else
|
||||
# GH Action, runner
|
||||
echo "GH Action, runner, clean & re-create create persistent container"
|
||||
docker rm -f xahaud_cached_builder
|
||||
docker run -di --user 0:$(id -g) --name xahaud_cached_builder -v /data/builds:/data/builds -v `pwd`:/io --network host ghcr.io/foobarwidget/holy-build-box-x64 /hbb_exe/activate-exec bash
|
||||
docker exec -i xahaud_cached_builder /hbb_exe/activate-exec bash -x /io/build-full.sh "$GITHUB_REPOSITORY" "$GITHUB_SHA" "$BUILD_CORES" "$GITHUB_RUN_NUMBER"
|
||||
docker stop xahaud_cached_builder
|
||||
docker rm -f $CONTAINER_NAME
|
||||
docker run -di --user 0:$(id -g) --name $CONTAINER_NAME -v /data/builds:/data/builds -v `pwd`:/io --network host ghcr.io/foobarwidget/holy-build-box-x64 /hbb_exe/activate-exec bash
|
||||
docker exec -i $CONTAINER_NAME /hbb_exe/activate-exec bash -x /io/build-full.sh "$GITHUB_REPOSITORY" "$GITHUB_SHA" "$BUILD_CORES" "$GITHUB_RUN_NUMBER"
|
||||
docker stop $CONTAINER_NAME
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
+98
-72
@@ -5,11 +5,11 @@
|
||||
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
|
||||
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
|
||||
// __/ | https://github.com/Neargye/magic_enum
|
||||
// |___/ version 0.9.3
|
||||
// |___/ version 0.9.5
|
||||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2023 Daniil Goncharov <[email protected]>.
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <[email protected]>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
#define MAGIC_ENUM_VERSION_MAJOR 0
|
||||
#define MAGIC_ENUM_VERSION_MINOR 9
|
||||
#define MAGIC_ENUM_VERSION_PATCH 3
|
||||
#define MAGIC_ENUM_VERSION_PATCH 5
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
#if defined(MAGIC_ENUM_NO_ASSERT)
|
||||
# define MAGIC_ENUM_ASSERT(...) static_cast<void>(0)
|
||||
#else
|
||||
#elif !defined(MAGIC_ENUM_ASSERT)
|
||||
# include <cassert>
|
||||
# define MAGIC_ENUM_ASSERT(...) assert((__VA_ARGS__))
|
||||
#endif
|
||||
@@ -69,9 +69,11 @@
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wunknown-warning-option"
|
||||
# pragma clang diagnostic ignored "-Wenum-constexpr-conversion"
|
||||
# pragma clang diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast<char_type>('\0')' for char_type = char (common on Linux).
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.
|
||||
# pragma GCC diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast<char_type>('\0')' for char_type = char (common on Linux).
|
||||
#elif defined(_MSC_VER)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 26495) // Variable 'static_str<N>::chars_' is uninitialized.
|
||||
@@ -164,14 +166,11 @@ namespace customize {
|
||||
// If need another range for specific enum type, add specialization enum_range for necessary enum type.
|
||||
template <typename E>
|
||||
struct enum_range {
|
||||
static_assert(std::is_enum_v<E>, "magic_enum::customize::enum_range requires enum type.");
|
||||
static constexpr int min = MAGIC_ENUM_RANGE_MIN;
|
||||
static constexpr int max = MAGIC_ENUM_RANGE_MAX;
|
||||
static_assert(max > min, "magic_enum::customize::enum_range requires max > min.");
|
||||
};
|
||||
|
||||
static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN.");
|
||||
static_assert((MAGIC_ENUM_RANGE_MAX - MAGIC_ENUM_RANGE_MIN) < (std::numeric_limits<std::uint16_t>::max)(), "MAGIC_ENUM_RANGE must be less than UINT16_MAX.");
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -216,9 +215,9 @@ namespace detail {
|
||||
template <typename T>
|
||||
struct supported
|
||||
#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT)
|
||||
: std::true_type {};
|
||||
: std::true_type {};
|
||||
#else
|
||||
: std::false_type {};
|
||||
: std::false_type {};
|
||||
#endif
|
||||
|
||||
template <auto V, typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>, int> = 0>
|
||||
@@ -423,10 +422,20 @@ constexpr auto n() noexcept {
|
||||
constexpr auto name_ptr = MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(E);
|
||||
constexpr auto name = name_ptr ? str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
|
||||
#elif defined(__clang__)
|
||||
auto name = str_view{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36};
|
||||
str_view name;
|
||||
if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
|
||||
static_assert(always_false_v<E>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
|
||||
return str_view{};
|
||||
} else {
|
||||
name.size_ = sizeof(__PRETTY_FUNCTION__) - 36;
|
||||
name.str_ = __PRETTY_FUNCTION__ + 34;
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1};
|
||||
if (name.str_[name.size_ - 1] == ']') {
|
||||
if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
|
||||
static_assert(always_false_v<E>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
|
||||
return str_view{};
|
||||
} else if (name.str_[name.size_ - 1] == ']') {
|
||||
name.size_ -= 50;
|
||||
name.str_ += 49;
|
||||
} else {
|
||||
@@ -489,7 +498,14 @@ constexpr auto n() noexcept {
|
||||
constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
|
||||
auto name = name_ptr ? str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
|
||||
#elif defined(__clang__)
|
||||
auto name = str_view{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36};
|
||||
str_view name;
|
||||
if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
|
||||
static_assert(always_false_v<decltype(V)>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
|
||||
return str_view{};
|
||||
} else {
|
||||
name.size_ = sizeof(__PRETTY_FUNCTION__) - 36;
|
||||
name.str_ = __PRETTY_FUNCTION__ + 34;
|
||||
}
|
||||
if (name.size_ > 22 && name.str_[0] == '(' && name.str_[1] == 'a' && name.str_[10] == ' ' && name.str_[22] == ':') {
|
||||
name.size_ -= 23;
|
||||
name.str_ += 23;
|
||||
@@ -499,7 +515,10 @@ constexpr auto n() noexcept {
|
||||
}
|
||||
#elif defined(__GNUC__)
|
||||
auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1};
|
||||
if (name.str_[name.size_ - 1] == ']') {
|
||||
if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
|
||||
static_assert(always_false_v<decltype(V)>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
|
||||
return str_view{};
|
||||
} else if (name.str_[name.size_ - 1] == ']') {
|
||||
name.size_ -= 55;
|
||||
name.str_ += 54;
|
||||
} else {
|
||||
@@ -698,7 +717,7 @@ constexpr void valid_count(bool* valid, std::size_t& count) noexcept {
|
||||
} \
|
||||
}
|
||||
|
||||
MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_V);
|
||||
MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_V)
|
||||
|
||||
if constexpr ((I + 256) < Size) {
|
||||
valid_count<E, S, Size, Min, I + 256>(valid, count);
|
||||
@@ -750,7 +769,6 @@ constexpr auto values() noexcept {
|
||||
constexpr auto max = reflected_max<E, S>();
|
||||
constexpr auto range_size = max - min + 1;
|
||||
static_assert(range_size > 0, "magic_enum::enum_range requires valid size.");
|
||||
static_assert(range_size < (std::numeric_limits<std::uint16_t>::max)(), "magic_enum::enum_range requires valid size.");
|
||||
|
||||
return values<E, S, range_size, min>();
|
||||
}
|
||||
@@ -807,7 +825,8 @@ inline constexpr auto max_v = (count_v<E, S> > 0) ? static_cast<U>(values_v<E, S
|
||||
|
||||
template <typename E, enum_subtype S, std::size_t... I>
|
||||
constexpr auto names(std::index_sequence<I...>) noexcept {
|
||||
return std::array<string_view, sizeof...(I)>{{enum_name_v<E, values_v<E, S>[I]>...}};
|
||||
constexpr auto names = std::array<string_view, sizeof...(I)>{{enum_name_v<E, values_v<E, S>[I]>...}};
|
||||
return names;
|
||||
}
|
||||
|
||||
template <typename E, enum_subtype S>
|
||||
@@ -818,7 +837,8 @@ using names_t = decltype((names_v<D, S>));
|
||||
|
||||
template <typename E, enum_subtype S, std::size_t... I>
|
||||
constexpr auto entries(std::index_sequence<I...>) noexcept {
|
||||
return std::array<std::pair<E, string_view>, sizeof...(I)>{{{values_v<E, S>[I], enum_name_v<E, values_v<E, S>[I]>}...}};
|
||||
constexpr auto entries = std::array<std::pair<E, string_view>, sizeof...(I)>{{{values_v<E, S>[I], enum_name_v<E, values_v<E, S>[I]>}...}};
|
||||
return entries;
|
||||
}
|
||||
|
||||
template <typename E, enum_subtype S>
|
||||
@@ -845,17 +865,16 @@ constexpr bool is_sparse() noexcept {
|
||||
template <typename E, enum_subtype S = subtype_v<E>>
|
||||
inline constexpr bool is_sparse_v = is_sparse<E, S>();
|
||||
|
||||
template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
|
||||
constexpr U values_ors() noexcept {
|
||||
static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype.");
|
||||
template <typename E, enum_subtype S>
|
||||
struct is_reflected
|
||||
#if defined(MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM)
|
||||
: std::true_type {};
|
||||
#else
|
||||
: std::bool_constant<std::is_enum_v<E> && (count_v<E, S> != 0)> {};
|
||||
#endif
|
||||
|
||||
auto ors = U{0};
|
||||
for (std::size_t i = 0; i < count_v<E, S>; ++i) {
|
||||
ors |= static_cast<U>(values_v<E, S>[i]);
|
||||
}
|
||||
|
||||
return ors;
|
||||
}
|
||||
template <typename E, enum_subtype S>
|
||||
inline constexpr bool is_reflected_v = is_reflected<std::decay_t<E>, S>{};
|
||||
|
||||
template <bool, typename R>
|
||||
struct enable_if_enum {};
|
||||
@@ -1156,6 +1175,7 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
|
||||
if constexpr (detail::is_sparse_v<D, S>) {
|
||||
return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::values_v<D, S>[index];
|
||||
@@ -1170,6 +1190,7 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
template <typename E, std::size_t I, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
static_assert(I < detail::count_v<D, S>, "magic_enum::enum_value out of range.");
|
||||
|
||||
return enum_value<D, S>(I);
|
||||
@@ -1178,7 +1199,10 @@ template <typename E, std::size_t I, detail::enum_subtype S = detail::subtype_v<
|
||||
// Returns std::array with enum values, sorted by enum value.
|
||||
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t<E, detail::values_t<E, S>> {
|
||||
return detail::values_v<std::decay_t<E>, S>;
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
|
||||
return detail::values_v<D, S>;
|
||||
}
|
||||
|
||||
// Returns integer value from enum value.
|
||||
@@ -1199,11 +1223,9 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
|
||||
using D = std::decay_t<E>;
|
||||
using U = underlying_type_t<D>;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
|
||||
if constexpr (detail::count_v<D, S> == 0) {
|
||||
static_cast<void>(value);
|
||||
return {}; // Empty enum.
|
||||
} else if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
|
||||
if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
|
||||
#if defined(MAGIC_ENUM_ENABLE_HASH)
|
||||
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::index>(
|
||||
[](std::size_t i) { return optional<std::size_t>{i}; },
|
||||
@@ -1231,14 +1253,17 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
template <detail::enum_subtype S, typename E>
|
||||
[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
|
||||
return enum_index<D, S>(value);
|
||||
}
|
||||
|
||||
// Obtains index in enum values from static storage enum variable.
|
||||
template <auto V, detail::enum_subtype S = detail::subtype_v<std::decay_t<decltype(V)>>>
|
||||
[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t<decltype(V), std::size_t> {
|
||||
constexpr auto index = enum_index<std::decay_t<decltype(V)>, S>(V);
|
||||
[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t<decltype(V), std::size_t> {\
|
||||
using D = std::decay_t<decltype(V)>;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
constexpr auto index = enum_index<D, S>(V);
|
||||
static_assert(index, "magic_enum::enum_index enum value does not have a index.");
|
||||
|
||||
return *index;
|
||||
@@ -1259,6 +1284,7 @@ template <auto V>
|
||||
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t<E, string_view> {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
|
||||
if (const auto i = enum_index<D, S>(value)) {
|
||||
return detail::names_v<D, S>[*i];
|
||||
@@ -1271,6 +1297,7 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
template <detail::enum_subtype S, typename E>
|
||||
[[nodiscard]] constexpr auto enum_name(E value) -> detail::enable_if_t<E, string_view> {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
|
||||
return enum_name<D, S>(value);
|
||||
}
|
||||
@@ -1278,13 +1305,19 @@ template <detail::enum_subtype S, typename E>
|
||||
// Returns std::array with names, sorted by enum value.
|
||||
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t<E, detail::names_t<E, S>> {
|
||||
return detail::names_v<std::decay_t<E>, S>;
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
|
||||
return detail::names_v<D, S>;
|
||||
}
|
||||
|
||||
// Returns std::array with pairs (value, name), sorted by enum value.
|
||||
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t<E, detail::entries_t<E, S>> {
|
||||
return detail::entries_v<std::decay_t<E>, S>;
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
|
||||
return detail::entries_v<D, S>;
|
||||
}
|
||||
|
||||
// Allows you to write magic_enum::enum_cast<foo>("bar", magic_enum::case_insensitive);
|
||||
@@ -1295,31 +1328,27 @@ inline constexpr auto case_insensitive = detail::case_insensitive<>{};
|
||||
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
|
||||
if constexpr (detail::count_v<D, S> == 0) {
|
||||
static_cast<void>(value);
|
||||
return {}; // Empty enum.
|
||||
} else {
|
||||
if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
|
||||
if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
|
||||
#if defined(MAGIC_ENUM_ENABLE_HASH)
|
||||
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
|
||||
[](D v) { return optional<D>{v}; },
|
||||
static_cast<D>(value),
|
||||
detail::default_result_type_lambda<optional<D>>);
|
||||
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
|
||||
[](D v) { return optional<D>{v}; },
|
||||
static_cast<D>(value),
|
||||
detail::default_result_type_lambda<optional<D>>);
|
||||
#else
|
||||
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
|
||||
if (value == static_cast<underlying_type_t<D>>(enum_value<D, S>(i))) {
|
||||
return static_cast<D>(value);
|
||||
}
|
||||
}
|
||||
return {}; // Invalid value or out of range.
|
||||
#endif
|
||||
} else {
|
||||
if (value >= detail::min_v<D, S> && value <= detail::max_v<D, S>) {
|
||||
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
|
||||
if (value == static_cast<underlying_type_t<D>>(enum_value<D, S>(i))) {
|
||||
return static_cast<D>(value);
|
||||
}
|
||||
return {}; // Invalid value or out of range.
|
||||
}
|
||||
return {}; // Invalid value or out of range.
|
||||
#endif
|
||||
} else {
|
||||
if (value >= detail::min_v<D, S> && value <= detail::max_v<D, S>) {
|
||||
return static_cast<D>(value);
|
||||
}
|
||||
return {}; // Invalid value or out of range.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1328,26 +1357,23 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
template <typename E, detail::enum_subtype S = detail::subtype_v<E>, typename BinaryPredicate = std::equal_to<>>
|
||||
[[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
|
||||
if constexpr (detail::count_v<D, S> == 0) {
|
||||
static_cast<void>(value);
|
||||
return {}; // Empty enum.
|
||||
#if defined(MAGIC_ENUM_ENABLE_HASH)
|
||||
} else if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
|
||||
return detail::constexpr_switch<&detail::names_v<D, S>, detail::case_call_t::index>(
|
||||
[](std::size_t i) { return optional<D>{detail::values_v<D, S>[i]}; },
|
||||
value,
|
||||
detail::default_result_type_lambda<optional<D>>,
|
||||
[&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); });
|
||||
#endif
|
||||
} else {
|
||||
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
|
||||
if (detail::cmp_equal(value, detail::names_v<D, S>[i], p)) {
|
||||
return enum_value<D, S>(i);
|
||||
}
|
||||
}
|
||||
return {}; // Invalid value or out of range.
|
||||
if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
|
||||
return detail::constexpr_switch<&detail::names_v<D, S>, detail::case_call_t::index>(
|
||||
[](std::size_t i) { return optional<D>{detail::values_v<D, S>[i]}; },
|
||||
value,
|
||||
detail::default_result_type_lambda<optional<D>>,
|
||||
[&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); });
|
||||
}
|
||||
#endif
|
||||
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
|
||||
if (detail::cmp_equal(value, detail::names_v<D, S>[i], p)) {
|
||||
return enum_value<D, S>(i);
|
||||
}
|
||||
}
|
||||
return {}; // Invalid value or out of range.
|
||||
}
|
||||
|
||||
// Checks whether enum contains value with such value.
|
||||
|
||||
@@ -134,8 +134,12 @@ RCLConsensus::Adaptor::acquireLedger(LedgerHash const& hash)
|
||||
acquiringLedger_ = hash;
|
||||
|
||||
app_.getJobQueue().addJob(
|
||||
jtADVANCE, "getConsensusLedger", [id = hash, &app = app_]() {
|
||||
app.getInboundLedgers().acquire(
|
||||
jtADVANCE,
|
||||
"getConsensusLedger1",
|
||||
[id = hash, &app = app_, this]() {
|
||||
JLOG(j_.debug())
|
||||
<< "JOB advanceLedger getConsensusLedger1 started";
|
||||
app.getInboundLedgers().acquireAsync(
|
||||
id, 0, InboundLedger::Reason::CONSENSUS);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -135,8 +135,10 @@ RCLValidationsAdaptor::acquire(LedgerHash const& hash)
|
||||
Application* pApp = &app_;
|
||||
|
||||
app_.getJobQueue().addJob(
|
||||
jtADVANCE, "getConsensusLedger", [pApp, hash]() {
|
||||
pApp->getInboundLedgers().acquire(
|
||||
jtADVANCE, "getConsensusLedger2", [pApp, hash, this]() {
|
||||
JLOG(j_.debug())
|
||||
<< "JOB advanceLedger getConsensusLedger2 started";
|
||||
pApp->getInboundLedgers().acquireAsync(
|
||||
hash, 0, InboundLedger::Reason::CONSENSUS);
|
||||
});
|
||||
return std::nullopt;
|
||||
@@ -152,7 +154,9 @@ void
|
||||
handleNewValidation(
|
||||
Application& app,
|
||||
std::shared_ptr<STValidation> const& val,
|
||||
std::string const& source)
|
||||
std::string const& source,
|
||||
BypassAccept const bypassAccept,
|
||||
std::optional<beast::Journal> j)
|
||||
{
|
||||
auto const& signingKey = val->getSignerPublic();
|
||||
auto const& hash = val->getLedgerHash();
|
||||
@@ -177,7 +181,23 @@ handleNewValidation(
|
||||
if (outcome == ValStatus::current)
|
||||
{
|
||||
if (val->isTrusted())
|
||||
app.getLedgerMaster().checkAccept(hash, seq);
|
||||
{
|
||||
// Was: app.getLedgerMaster().checkAccept(hash, seq);
|
||||
// https://github.com/XRPLF/rippled/commit/fbbea9e6e25795a8a6bd1bf64b780771933a9579
|
||||
if (bypassAccept == BypassAccept::yes)
|
||||
{
|
||||
assert(j.has_value());
|
||||
if (j.has_value())
|
||||
{
|
||||
JLOG(j->trace()) << "Bypassing checkAccept for validation "
|
||||
<< val->getLedgerHash();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
app.getLedgerMaster().checkAccept(hash, seq);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,12 +25,16 @@
|
||||
#include <ripple/protocol/Protocol.h>
|
||||
#include <ripple/protocol/RippleLedgerHash.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class Application;
|
||||
|
||||
enum class BypassAccept : bool { no = false, yes };
|
||||
|
||||
/** Wrapper over STValidation for generic Validation code
|
||||
|
||||
Wraps an STValidation for compatibility with the generic validation code.
|
||||
@@ -248,7 +252,9 @@ void
|
||||
handleNewValidation(
|
||||
Application& app,
|
||||
std::shared_ptr<STValidation> const& val,
|
||||
std::string const& source);
|
||||
std::string const& source,
|
||||
BypassAccept const bypassAccept = BypassAccept::no,
|
||||
std::optional<beast::Journal> j = std::nullopt);
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
|
||||
@@ -20,6 +20,12 @@ enum HookSetFlags : uint8_t {
|
||||
hsfNSDELETE = 0b00000010U, // delete namespace
|
||||
hsfCOLLECT = 0b00000100U, // allow collect calls on this hook
|
||||
};
|
||||
|
||||
enum HookEmissionFlags : uint16_t {
|
||||
hefSTRONG = 0x1,
|
||||
hefCALLBACK = 0x2,
|
||||
hefDOAAW = 0x4,
|
||||
};
|
||||
} // namespace ripple
|
||||
|
||||
namespace hook {
|
||||
@@ -54,6 +60,19 @@ maxHookChainLength(void)
|
||||
return 10;
|
||||
}
|
||||
|
||||
inline uint32_t
|
||||
maxNamespaces(void)
|
||||
{
|
||||
return 256;
|
||||
}
|
||||
|
||||
// maximum number of entires in a namespace to delete with ns delete
|
||||
inline uint32_t
|
||||
maxNamespaceDelete(void)
|
||||
{
|
||||
return 256;
|
||||
}
|
||||
|
||||
enum TSHFlags : uint8_t {
|
||||
tshNONE = 0b000,
|
||||
tshROLLBACK = 0b001,
|
||||
@@ -313,6 +332,7 @@ enum hook_return_code : int64_t {
|
||||
MEM_OVERLAP = -43, // one or more specified buffers are the same memory
|
||||
TOO_MANY_STATE_MODIFICATIONS = -44, // more than 5000 modified state
|
||||
// entires in the combined hook chains
|
||||
TOO_MANY_NAMESPACES = -45
|
||||
};
|
||||
|
||||
enum ExitType : uint8_t {
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
* were then used.
|
||||
*/
|
||||
|
||||
#define LPAREN (
|
||||
#define LPAREN (
|
||||
#define RPAREN )
|
||||
#define COMMA ,
|
||||
|
||||
@@ -29,8 +29,9 @@ isEmittedTxn(ripple::STTx const& tx);
|
||||
// only upon tesSuccess for the otxn.
|
||||
class HookStateMap : public std::map<
|
||||
ripple::AccountID, // account that owns the state
|
||||
std::pair<
|
||||
std::tuple<
|
||||
int64_t, // remaining available ownercount
|
||||
int64_t, // total namespace count
|
||||
std::map<
|
||||
ripple::uint256, // namespace
|
||||
std::map<
|
||||
@@ -44,43 +45,6 @@ public:
|
||||
};
|
||||
|
||||
using namespace ripple;
|
||||
static const std::map<uint16_t, uint8_t> TSHAllowances = {
|
||||
{ttPAYMENT, tshROLLBACK},
|
||||
{ttESCROW_CREATE, tshROLLBACK},
|
||||
{ttESCROW_FINISH, tshROLLBACK},
|
||||
{ttACCOUNT_SET, tshNONE},
|
||||
{ttESCROW_CANCEL, tshCOLLECT},
|
||||
{ttREGULAR_KEY_SET, tshROLLBACK},
|
||||
{ttOFFER_CREATE, tshCOLLECT},
|
||||
{ttOFFER_CANCEL, tshNONE},
|
||||
{ttTICKET_CREATE, tshNONE},
|
||||
{ttSIGNER_LIST_SET, tshROLLBACK},
|
||||
{ttPAYCHAN_CREATE, tshROLLBACK},
|
||||
{ttPAYCHAN_FUND, tshCOLLECT},
|
||||
{ttPAYCHAN_CLAIM, tshCOLLECT},
|
||||
{ttCHECK_CREATE, tshROLLBACK},
|
||||
{ttCHECK_CASH, tshROLLBACK},
|
||||
{ttCHECK_CANCEL, tshCOLLECT},
|
||||
{ttDEPOSIT_PREAUTH, tshROLLBACK},
|
||||
{ttTRUST_SET, tshCOLLECT},
|
||||
{ttACCOUNT_DELETE, tshROLLBACK},
|
||||
{ttHOOK_SET, tshNONE},
|
||||
{ttNFTOKEN_MINT, tshROLLBACK},
|
||||
{ttNFTOKEN_BURN, tshCOLLECT},
|
||||
{ttNFTOKEN_CREATE_OFFER, tshROLLBACK},
|
||||
{ttNFTOKEN_CANCEL_OFFER, tshCOLLECT},
|
||||
{ttNFTOKEN_ACCEPT_OFFER, tshROLLBACK},
|
||||
{ttCLAIM_REWARD, tshROLLBACK},
|
||||
{ttINVOKE, tshROLLBACK},
|
||||
{ttURITOKEN_MINT, tshNONE},
|
||||
{ttURITOKEN_BURN, tshROLLBACK},
|
||||
{ttURITOKEN_BUY, tshROLLBACK},
|
||||
{ttURITOKEN_CREATE_SELL_OFFER, tshROLLBACK},
|
||||
{ttURITOKEN_CANCEL_SELL_OFFER, tshNONE},
|
||||
{ttIMPORT, tshROLLBACK},
|
||||
{ttGENESIS_MINT, tshCOLLECT},
|
||||
};
|
||||
|
||||
std::vector<std::pair<AccountID, bool>>
|
||||
getTransactionalStakeHolders(STTx const& tx, ReadView const& rv);
|
||||
} // namespace hook
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
#include <ripple/app/hook/applyHook.h>
|
||||
#include <ripple/app/ledger/OpenLedger.h>
|
||||
#include <ripple/app/ledger/TransactionMaster.h>
|
||||
#include <ripple/app/misc/HashRouter.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
#include <ripple/app/misc/TxQ.h>
|
||||
#include <ripple/app/tx/impl/Import.h>
|
||||
#include <ripple/app/tx/impl/details/NFTokenUtils.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/Slice.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/protocol/st.h>
|
||||
#include <ripple/protocol/tokens.h>
|
||||
#include <boost/multiprecision/cpp_dec_float.hpp>
|
||||
#include <any>
|
||||
@@ -38,19 +43,10 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
|
||||
uint16_t tt = tx.getFieldU16(sfTransactionType);
|
||||
|
||||
uint8_t tsh = tshNONE;
|
||||
if (auto const& found = hook::TSHAllowances.find(tt);
|
||||
found != hook::TSHAllowances.end())
|
||||
tsh = found->second;
|
||||
else
|
||||
return {};
|
||||
|
||||
std::map<AccountID, std::pair<int, bool>> tshEntries;
|
||||
|
||||
int upto = 0;
|
||||
|
||||
bool canRollback = tsh & tshROLLBACK;
|
||||
|
||||
auto const ADD_TSH = [&otxnAcc, &tshEntries, &upto](
|
||||
const AccountID& acc_r, bool rb) {
|
||||
if (acc_r != *otxnAcc)
|
||||
@@ -62,6 +58,9 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
}
|
||||
};
|
||||
|
||||
bool const tshSTRONG = true; // tshROLLBACK
|
||||
bool const tshWEAK = false; // tshCOLLECT
|
||||
|
||||
auto const getNFTOffer =
|
||||
[](std::optional<uint256> id,
|
||||
ReadView const& rv) -> std::shared_ptr<const SLE> {
|
||||
@@ -71,11 +70,53 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
return rv.read(keylet::nftoffer(*id));
|
||||
};
|
||||
|
||||
bool const fixV1 = rv.rules().enabled(fixXahauV1);
|
||||
bool const fixV2 = rv.rules().enabled(fixXahauV2);
|
||||
|
||||
switch (tt)
|
||||
{
|
||||
case ttREMIT: {
|
||||
if (destAcc)
|
||||
ADD_TSH(*destAcc, tshSTRONG);
|
||||
|
||||
if (tx.isFieldPresent(sfInform))
|
||||
{
|
||||
auto const inform = tx.getAccountID(sfInform);
|
||||
if (*otxnAcc != inform && *destAcc != inform)
|
||||
ADD_TSH(inform, tshWEAK);
|
||||
}
|
||||
|
||||
if (tx.isFieldPresent(sfURITokenIDs))
|
||||
{
|
||||
STVector256 tokenIds = tx.getFieldV256(sfURITokenIDs);
|
||||
for (uint256 const klRaw : tokenIds)
|
||||
{
|
||||
Keylet const id{ltURI_TOKEN, klRaw};
|
||||
if (!rv.exists(id))
|
||||
continue;
|
||||
|
||||
auto const ut = rv.read(id);
|
||||
if (!ut ||
|
||||
ut->getFieldU16(sfLedgerEntryType) != ltURI_TOKEN)
|
||||
continue;
|
||||
|
||||
auto const owner = ut->getAccountID(sfOwner);
|
||||
auto const issuer = ut->getAccountID(sfIssuer);
|
||||
if (issuer != owner && issuer != *destAcc)
|
||||
{
|
||||
ADD_TSH(
|
||||
issuer,
|
||||
(ut->getFlags() & lsfBurnable) ? tshSTRONG
|
||||
: tshWEAK);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ttIMPORT: {
|
||||
if (tx.isFieldPresent(sfIssuer))
|
||||
ADD_TSH(tx.getAccountID(sfIssuer), canRollback);
|
||||
ADD_TSH(tx.getAccountID(sfIssuer), fixV2 ? tshWEAK : tshSTRONG);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -97,19 +138,36 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
// the burner is the issuer and not the owner of the token
|
||||
|
||||
if (issuer == owner)
|
||||
{
|
||||
// pass, already a TSH
|
||||
}
|
||||
else if (*otxnAcc == owner)
|
||||
break;
|
||||
// pass, already a TSH
|
||||
|
||||
// new logic
|
||||
if (fixV1)
|
||||
{
|
||||
// the owner burns their token, and the issuer is a weak TSH
|
||||
ADD_TSH(issuer, canRollback);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*otxnAcc == owner && rv.exists(keylet::account(issuer)))
|
||||
ADD_TSH(issuer, tshWEAK);
|
||||
// the issuer burns the owner's token, and the owner is a weak
|
||||
// TSH
|
||||
ADD_TSH(owner, canRollback);
|
||||
else if (rv.exists(keylet::account(owner)))
|
||||
ADD_TSH(owner, tshWEAK);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// old logic
|
||||
{
|
||||
if (*otxnAcc == owner)
|
||||
{
|
||||
// the owner burns their token, and the issuer is a weak TSH
|
||||
ADD_TSH(issuer, tshSTRONG);
|
||||
}
|
||||
else
|
||||
{
|
||||
// the issuer burns the owner's token, and the owner is a
|
||||
// weak TSH
|
||||
ADD_TSH(owner, tshSTRONG);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -129,17 +187,46 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
if (owner != tx.getAccountID(sfAccount))
|
||||
{
|
||||
// current owner is a strong TSH
|
||||
ADD_TSH(owner, canRollback);
|
||||
ADD_TSH(owner, tshSTRONG);
|
||||
}
|
||||
|
||||
// issuer is also a strong TSH if the burnable flag is set
|
||||
auto const issuer = ut->getAccountID(sfIssuer);
|
||||
if (issuer != owner)
|
||||
ADD_TSH(issuer, ut->getFlags() & lsfBurnable);
|
||||
ADD_TSH(
|
||||
issuer,
|
||||
(ut->getFlags() & lsfBurnable) ? tshSTRONG : tshWEAK);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ttURITOKEN_MINT: {
|
||||
// destination is a strong tsh
|
||||
if (fixV2 && tx.isFieldPresent(sfDestination))
|
||||
ADD_TSH(tx.getAccountID(sfDestination), tshSTRONG);
|
||||
break;
|
||||
}
|
||||
|
||||
case ttURITOKEN_CANCEL_SELL_OFFER: {
|
||||
if (!fixV2)
|
||||
break;
|
||||
|
||||
Keylet const id{ltURI_TOKEN, tx.getFieldH256(sfURITokenID)};
|
||||
if (!rv.exists(id))
|
||||
return {};
|
||||
|
||||
auto const ut = rv.read(id);
|
||||
if (!ut || ut->getFieldU16(sfLedgerEntryType) != ltURI_TOKEN)
|
||||
return {};
|
||||
|
||||
if (ut->isFieldPresent(sfDestination))
|
||||
{
|
||||
auto const dest = ut->getAccountID(sfDestination);
|
||||
ADD_TSH(dest, tshWEAK);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ttURITOKEN_CREATE_SELL_OFFER: {
|
||||
Keylet const id{ltURI_TOKEN, tx.getFieldH256(sfURITokenID)};
|
||||
if (!rv.exists(id))
|
||||
@@ -154,11 +241,13 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
|
||||
// issuer is a strong TSH if the burnable flag is set
|
||||
if (issuer != owner)
|
||||
ADD_TSH(issuer, ut->getFlags() & lsfBurnable);
|
||||
ADD_TSH(
|
||||
issuer,
|
||||
(ut->getFlags() & lsfBurnable) ? tshSTRONG : tshWEAK);
|
||||
|
||||
// destination is a strong tsh
|
||||
if (tx.isFieldPresent(sfDestination))
|
||||
ADD_TSH(tx.getAccountID(sfDestination), canRollback);
|
||||
ADD_TSH(tx.getAccountID(sfDestination), tshSTRONG);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -167,7 +256,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
case ttNFTOKEN_MINT:
|
||||
case ttCLAIM_REWARD: {
|
||||
if (tx.isFieldPresent(sfIssuer))
|
||||
ADD_TSH(tx.getAccountID(sfIssuer), canRollback);
|
||||
ADD_TSH(tx.getAccountID(sfIssuer), tshSTRONG);
|
||||
break;
|
||||
};
|
||||
|
||||
@@ -190,7 +279,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
|
||||
ADD_TSH(issuer, issuerCanRollback);
|
||||
if (hasOwner)
|
||||
ADD_TSH(owner, canRollback);
|
||||
ADD_TSH(owner, tshWEAK);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -209,16 +298,16 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
|
||||
if (bo)
|
||||
{
|
||||
ADD_TSH(bo->getAccountID(sfOwner), canRollback);
|
||||
ADD_TSH(bo->getAccountID(sfOwner), tshSTRONG);
|
||||
if (bo->isFieldPresent(sfDestination))
|
||||
ADD_TSH(bo->getAccountID(sfDestination), canRollback);
|
||||
ADD_TSH(bo->getAccountID(sfDestination), tshSTRONG);
|
||||
}
|
||||
|
||||
if (so)
|
||||
{
|
||||
ADD_TSH(so->getAccountID(sfOwner), canRollback);
|
||||
ADD_TSH(so->getAccountID(sfOwner), tshSTRONG);
|
||||
if (so->isFieldPresent(sfDestination))
|
||||
ADD_TSH(so->getAccountID(sfDestination), canRollback);
|
||||
ADD_TSH(so->getAccountID(sfDestination), tshSTRONG);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -234,24 +323,21 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
auto const offer = getNFTOffer(offerID, rv);
|
||||
if (offer)
|
||||
{
|
||||
ADD_TSH(offer->getAccountID(sfOwner), canRollback);
|
||||
ADD_TSH(offer->getAccountID(sfOwner), tshWEAK);
|
||||
if (offer->isFieldPresent(sfDestination))
|
||||
ADD_TSH(
|
||||
offer->getAccountID(sfDestination), canRollback);
|
||||
ADD_TSH(offer->getAccountID(sfDestination), tshWEAK);
|
||||
|
||||
// issuer can't stop people canceling their offers, but can
|
||||
// get weak executions
|
||||
uint256 nid = offer->getFieldH256(sfNFTokenID);
|
||||
auto const issuer = nft::getIssuer(nid);
|
||||
ADD_TSH(issuer, false);
|
||||
ADD_TSH(issuer, tshWEAK);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// self transactions
|
||||
case ttURITOKEN_MINT:
|
||||
case ttURITOKEN_CANCEL_SELL_OFFER:
|
||||
case ttACCOUNT_SET:
|
||||
case ttOFFER_CANCEL:
|
||||
case ttTICKET_CREATE:
|
||||
@@ -264,14 +350,14 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
case ttREGULAR_KEY_SET: {
|
||||
if (!tx.isFieldPresent(sfRegularKey))
|
||||
return {};
|
||||
ADD_TSH(tx.getAccountID(sfRegularKey), canRollback);
|
||||
ADD_TSH(tx.getAccountID(sfRegularKey), tshSTRONG);
|
||||
break;
|
||||
}
|
||||
|
||||
case ttDEPOSIT_PREAUTH: {
|
||||
if (!tx.isFieldPresent(sfAuthorize))
|
||||
return {};
|
||||
ADD_TSH(tx.getAccountID(sfAuthorize), canRollback);
|
||||
ADD_TSH(tx.getAccountID(sfAuthorize), tshSTRONG);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -283,7 +369,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
case ttPAYCHAN_CREATE:
|
||||
case ttINVOKE: {
|
||||
if (destAcc)
|
||||
ADD_TSH(*destAcc, canRollback);
|
||||
ADD_TSH(*destAcc, tshSTRONG);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -294,25 +380,67 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
auto const& lim = tx.getFieldAmount(sfLimitAmount);
|
||||
AccountID const& issuer = lim.getIssuer();
|
||||
|
||||
ADD_TSH(issuer, canRollback);
|
||||
ADD_TSH(issuer, tshWEAK);
|
||||
break;
|
||||
}
|
||||
|
||||
case ttESCROW_CANCEL:
|
||||
case ttESCROW_FINISH: {
|
||||
if (!tx.isFieldPresent(sfOwner) ||
|
||||
!tx.isFieldPresent(sfOfferSequence))
|
||||
return {};
|
||||
// new logic
|
||||
if (fixV1)
|
||||
{
|
||||
if (!tx.isFieldPresent(sfOwner))
|
||||
return {};
|
||||
|
||||
auto escrow = rv.read(keylet::escrow(
|
||||
tx.getAccountID(sfOwner), tx.getFieldU32(sfOfferSequence)));
|
||||
AccountID const owner = tx.getAccountID(sfOwner);
|
||||
|
||||
if (!escrow)
|
||||
return {};
|
||||
bool const hasSeq = tx.isFieldPresent(sfOfferSequence);
|
||||
bool const hasID = tx.isFieldPresent(sfEscrowID);
|
||||
if (!hasSeq && !hasID)
|
||||
return {};
|
||||
|
||||
ADD_TSH(escrow->getAccountID(sfAccount), true);
|
||||
ADD_TSH(escrow->getAccountID(sfDestination), canRollback);
|
||||
break;
|
||||
Keylet kl = hasSeq
|
||||
? keylet::escrow(owner, tx.getFieldU32(sfOfferSequence))
|
||||
: Keylet(ltESCROW, tx.getFieldH256(sfEscrowID));
|
||||
|
||||
auto escrow = rv.read(kl);
|
||||
|
||||
if (!escrow ||
|
||||
escrow->getFieldU16(sfLedgerEntryType) != ltESCROW)
|
||||
return {};
|
||||
|
||||
// this should always be the same as owner, but defensively...
|
||||
AccountID const src = escrow->getAccountID(sfAccount);
|
||||
AccountID const dst = escrow->getAccountID(sfDestination);
|
||||
|
||||
// the source account is a strong transacitonal stakeholder for
|
||||
// fin and can
|
||||
ADD_TSH(src, tshSTRONG);
|
||||
|
||||
// the dest acc is a strong tsh for fin and weak for can
|
||||
if (src != dst)
|
||||
ADD_TSH(dst, tt == ttESCROW_FINISH ? tshSTRONG : tshWEAK);
|
||||
|
||||
break;
|
||||
}
|
||||
// old logic
|
||||
{
|
||||
if (!tx.isFieldPresent(sfOwner) ||
|
||||
!tx.isFieldPresent(sfOfferSequence))
|
||||
return {};
|
||||
|
||||
auto escrow = rv.read(keylet::escrow(
|
||||
tx.getAccountID(sfOwner), tx.getFieldU32(sfOfferSequence)));
|
||||
|
||||
if (!escrow)
|
||||
return {};
|
||||
|
||||
ADD_TSH(escrow->getAccountID(sfAccount), tshSTRONG);
|
||||
ADD_TSH(
|
||||
escrow->getAccountID(sfDestination),
|
||||
tt == ttESCROW_FINISH ? tshSTRONG : tshWEAK);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case ttPAYCHAN_FUND:
|
||||
@@ -324,8 +452,8 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
if (!chan)
|
||||
return {};
|
||||
|
||||
ADD_TSH(chan->getAccountID(sfAccount), true);
|
||||
ADD_TSH(chan->getAccountID(sfDestination), canRollback);
|
||||
ADD_TSH(chan->getAccountID(sfAccount), tshSTRONG);
|
||||
ADD_TSH(chan->getAccountID(sfDestination), tshWEAK);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -338,8 +466,8 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
if (!check)
|
||||
return {};
|
||||
|
||||
ADD_TSH(check->getAccountID(sfAccount), true);
|
||||
ADD_TSH(check->getAccountID(sfDestination), canRollback);
|
||||
ADD_TSH(check->getAccountID(sfAccount), tshSTRONG);
|
||||
ADD_TSH(check->getAccountID(sfDestination), tshWEAK);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -349,7 +477,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
STArray const& signerEntries = tx.getFieldArray(sfSignerEntries);
|
||||
for (auto const& entryObj : signerEntries)
|
||||
if (entryObj.isFieldPresent(sfAccount))
|
||||
ADD_TSH(entryObj.getAccountID(sfAccount), canRollback);
|
||||
ADD_TSH(entryObj.getAccountID(sfAccount), tshSTRONG);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -361,7 +489,7 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
{
|
||||
if (mint.isFieldPresent(sfDestination))
|
||||
{
|
||||
ADD_TSH(mint.getAccountID(sfDestination), canRollback);
|
||||
ADD_TSH(mint.getAccountID(sfDestination), tshWEAK);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1287,7 +1415,7 @@ lookup_state_cache(
|
||||
if (stateMap.find(acc) == stateMap.end())
|
||||
return std::nullopt;
|
||||
|
||||
auto& stateMapAcc = stateMap[acc].second;
|
||||
auto& stateMapAcc = std::get<2>(stateMap[acc]);
|
||||
if (stateMapAcc.find(ns) == stateMapAcc.end())
|
||||
return std::nullopt;
|
||||
|
||||
@@ -1312,18 +1440,22 @@ set_state_cache(
|
||||
bool modified)
|
||||
{
|
||||
auto& stateMap = hookCtx.result.stateMap;
|
||||
auto& view = hookCtx.applyCtx.view();
|
||||
|
||||
if (modified && stateMap.modified_entry_count >= max_state_modifications)
|
||||
return TOO_MANY_STATE_MODIFICATIONS;
|
||||
|
||||
bool const createNamespace = view.rules().enabled(fixXahauV1) &&
|
||||
!view.exists(keylet::hookStateDir(acc, ns));
|
||||
|
||||
if (stateMap.find(acc) == stateMap.end())
|
||||
{
|
||||
// if this is the first time this account has been interacted with
|
||||
// we will compute how many available reserve positions there are
|
||||
auto const& fees = hookCtx.applyCtx.view().fees();
|
||||
|
||||
auto const accSLE =
|
||||
hookCtx.applyCtx.view().read(ripple::keylet::account(acc));
|
||||
auto const accSLE = view.read(ripple::keylet::account(acc));
|
||||
|
||||
if (!accSLE)
|
||||
return DOESNT_EXIST;
|
||||
|
||||
@@ -1342,15 +1474,32 @@ set_state_cache(
|
||||
if (availableForReserves < 1 && modified)
|
||||
return RESERVE_INSUFFICIENT;
|
||||
|
||||
int64_t namespaceCount = accSLE->isFieldPresent(sfHookNamespaces)
|
||||
? accSLE->getFieldV256(sfHookNamespaces).size()
|
||||
: 0;
|
||||
|
||||
if (createNamespace)
|
||||
{
|
||||
// overflow should never ever happen but check anyway
|
||||
if (namespaceCount + 1 < namespaceCount)
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
if (++namespaceCount > hook::maxNamespaces())
|
||||
return TOO_MANY_NAMESPACES;
|
||||
}
|
||||
|
||||
stateMap.modified_entry_count++;
|
||||
|
||||
stateMap[acc] = {
|
||||
availableForReserves - 1, {{ns, {{key, {modified, data}}}}}};
|
||||
availableForReserves - 1,
|
||||
namespaceCount,
|
||||
{{ns, {{key, {modified, data}}}}}};
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto& stateMapAcc = stateMap[acc].second;
|
||||
auto& availableForReserves = stateMap[acc].first;
|
||||
auto& availableForReserves = std::get<0>(stateMap[acc]);
|
||||
auto& namespaceCount = std::get<1>(stateMap[acc]);
|
||||
auto& stateMapAcc = std::get<2>(stateMap[acc]);
|
||||
bool const canReserveNew = availableForReserves > 0;
|
||||
|
||||
if (stateMapAcc.find(ns) == stateMapAcc.end())
|
||||
@@ -1360,6 +1509,18 @@ set_state_cache(
|
||||
if (!canReserveNew)
|
||||
return RESERVE_INSUFFICIENT;
|
||||
|
||||
if (createNamespace)
|
||||
{
|
||||
// overflow should never ever happen but check anyway
|
||||
if (namespaceCount + 1 < namespaceCount)
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
if (namespaceCount + 1 > hook::maxNamespaces())
|
||||
return TOO_MANY_NAMESPACES;
|
||||
|
||||
namespaceCount++;
|
||||
}
|
||||
|
||||
availableForReserves--;
|
||||
stateMap.modified_entry_count++;
|
||||
}
|
||||
@@ -1488,6 +1649,13 @@ DEFINE_HOOK_FUNCTION(
|
||||
auto const key = make_state_key(
|
||||
std::string_view{(const char*)(memory + kread_ptr), (size_t)kread_len});
|
||||
|
||||
if (view.rules().enabled(fixXahauV1))
|
||||
{
|
||||
auto const sleAccount = view.peek(hookCtx.result.accountKeylet);
|
||||
if (!sleAccount)
|
||||
return tefINTERNAL;
|
||||
}
|
||||
|
||||
if (!key)
|
||||
return INTERNAL_ERROR;
|
||||
|
||||
@@ -1610,7 +1778,7 @@ hook::finalizeHookState(
|
||||
for (const auto& accEntry : stateMap)
|
||||
{
|
||||
const auto& acc = accEntry.first;
|
||||
for (const auto& nsEntry : accEntry.second.second)
|
||||
for (const auto& nsEntry : std::get<2>(accEntry.second))
|
||||
{
|
||||
const auto& ns = nsEntry.first;
|
||||
for (const auto& cacheEntry : nsEntry.second)
|
||||
@@ -1635,7 +1803,7 @@ hook::finalizeHookState(
|
||||
|
||||
TER result = setHookState(applyCtx, acc, ns, key, slice);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "HookError[TX:" << txnID
|
||||
@@ -1733,7 +1901,8 @@ hook::finalizeHookResult(
|
||||
uint16_t exec_index = avi.nextHookExecutionIndex();
|
||||
// apply emitted transactions to the ledger (by adding them to the emitted
|
||||
// directory) if we are allowed to
|
||||
std::vector<uint256> emission_txnid;
|
||||
std::vector<std::pair<uint256 /* txnid */, uint256 /* emit nonce */>>
|
||||
emission_txnid;
|
||||
|
||||
if (doEmit)
|
||||
{
|
||||
@@ -1754,7 +1923,12 @@ hook::finalizeHookResult(
|
||||
|
||||
if (!sleEmitted)
|
||||
{
|
||||
emission_txnid.push_back(id);
|
||||
auto const& emitDetails = const_cast<ripple::STTx&>(*ptr)
|
||||
.getField(sfEmitDetails)
|
||||
.downcast<STObject>();
|
||||
|
||||
emission_txnid.emplace_back(
|
||||
id, emitDetails.getFieldH256(sfEmitNonce));
|
||||
sleEmitted = std::make_shared<SLE>(emittedId);
|
||||
|
||||
// RH TODO: add a new constructor to STObject to avoid this
|
||||
@@ -1786,6 +1960,7 @@ hook::finalizeHookResult(
|
||||
}
|
||||
}
|
||||
|
||||
bool const fixV2 = applyCtx.view().rules().enabled(fixXahauV2);
|
||||
// add a metadata entry for this hook execution result
|
||||
{
|
||||
STObject meta{sfHookExecution};
|
||||
@@ -1812,6 +1987,19 @@ hook::finalizeHookResult(
|
||||
meta.setFieldU16(sfHookExecutionIndex, exec_index);
|
||||
meta.setFieldU16(sfHookStateChangeCount, hookResult.changedStateCount);
|
||||
meta.setFieldH256(sfHookHash, hookResult.hookHash);
|
||||
|
||||
// add informational flags in fix2
|
||||
if (fixV2)
|
||||
{
|
||||
uint32_t flags = 0;
|
||||
if (hookResult.isStrong)
|
||||
flags |= hefSTRONG;
|
||||
if (hookResult.isCallback)
|
||||
flags |= hefCALLBACK;
|
||||
if (hookResult.executeAgainAsWeak)
|
||||
flags |= hefDOAAW;
|
||||
meta.setFieldU32(sfFlags, flags);
|
||||
}
|
||||
avi.addHookExecutionMetaData(std::move(meta));
|
||||
}
|
||||
|
||||
@@ -1819,12 +2007,14 @@ hook::finalizeHookResult(
|
||||
if (applyCtx.view().rules().enabled(featureHooksUpdate1) &&
|
||||
!emission_txnid.empty())
|
||||
{
|
||||
for (auto const& etxnid : emission_txnid)
|
||||
for (auto const& [etxnid, enonce] : emission_txnid)
|
||||
{
|
||||
STObject meta{sfHookEmission};
|
||||
meta.setFieldH256(sfHookHash, hookResult.hookHash);
|
||||
meta.setAccountID(sfHookAccount, hookResult.account);
|
||||
meta.setFieldH256(sfEmittedTxnID, etxnid);
|
||||
if (fixV2)
|
||||
meta.setFieldH256(sfEmitNonce, enonce);
|
||||
avi.addHookEmissionMetaData(std::move(meta));
|
||||
}
|
||||
}
|
||||
@@ -3342,7 +3532,7 @@ DEFINE_HOOK_FUNCTION(
|
||||
ripple::ApplyFlags::tapPREFLIGHT_EMIT,
|
||||
j);
|
||||
|
||||
if (preflightResult.ter != tesSUCCESS)
|
||||
if (!isTesSuccess(preflightResult.ter))
|
||||
{
|
||||
JLOG(j.trace()) << "HookEmit[" << HC_ACC()
|
||||
<< "]: Transaction preflight failure: "
|
||||
|
||||
@@ -38,10 +38,21 @@ public:
|
||||
virtual ~InboundLedgers() = default;
|
||||
|
||||
// VFALCO TODO Should this be called findOrAdd ?
|
||||
// Callers should use this if they possibly need an authoritative
|
||||
// response immediately.
|
||||
//
|
||||
virtual std::shared_ptr<Ledger const>
|
||||
acquire(uint256 const& hash, std::uint32_t seq, InboundLedger::Reason) = 0;
|
||||
|
||||
// Callers should use this if they are known to be executing on the Job
|
||||
// Queue. TODO review whether all callers of acquire() can use this
|
||||
// instead. Inbound ledger acquisition is asynchronous anyway.
|
||||
virtual void
|
||||
acquireAsync(
|
||||
uint256 const& hash,
|
||||
std::uint32_t seq,
|
||||
InboundLedger::Reason reason) = 0;
|
||||
|
||||
virtual std::shared_ptr<InboundLedger>
|
||||
find(LedgerHash const& hash) = 0;
|
||||
|
||||
|
||||
@@ -386,6 +386,17 @@ LedgerHistory::handleMismatch(
|
||||
JLOG(j_.error()) << "built\n" << getJson({*builtLedger, {}});
|
||||
JLOG(j_.error()) << "valid\n" << getJson({*validLedger, {}});
|
||||
|
||||
{
|
||||
auto b = builtTx.begin();
|
||||
auto v = validTx.begin();
|
||||
while (b != builtTx.end() && v != validTx.end())
|
||||
{
|
||||
log_one(*builtLedger, (*b)->key(), "validInfo", j_);
|
||||
log_one(*validLedger, (*v)->key(), "builtInfo", j_);
|
||||
++b;
|
||||
++v;
|
||||
}
|
||||
}
|
||||
// Log all differences between built and valid ledgers
|
||||
auto b = builtTx.begin();
|
||||
auto v = validTx.begin();
|
||||
|
||||
@@ -560,7 +560,7 @@ InboundLedger::trigger(std::shared_ptr<Peer> const& peer, TriggerReason reason)
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto stream = journal_.trace())
|
||||
if (auto stream = journal_.debug())
|
||||
{
|
||||
if (peer)
|
||||
stream << "Trigger acquiring ledger " << hash_ << " from " << peer;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <ripple/core/JobQueue.h>
|
||||
#include <ripple/nodestore/DatabaseShard.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
@@ -141,6 +142,37 @@ public:
|
||||
return inbound->getLedger();
|
||||
}
|
||||
|
||||
void
|
||||
acquireAsync(
|
||||
uint256 const& hash,
|
||||
std::uint32_t seq,
|
||||
InboundLedger::Reason reason) override
|
||||
{
|
||||
std::unique_lock lock(acquiresMutex_);
|
||||
try
|
||||
{
|
||||
if (pendingAcquires_.contains(hash))
|
||||
return;
|
||||
pendingAcquires_.insert(hash);
|
||||
lock.unlock();
|
||||
acquire(hash, seq, reason);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(j_.warn())
|
||||
<< "Exception thrown for acquiring new inbound ledger " << hash
|
||||
<< ": " << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
JLOG(j_.warn())
|
||||
<< "Unknown exception thrown for acquiring new inbound ledger "
|
||||
<< hash;
|
||||
}
|
||||
lock.lock();
|
||||
pendingAcquires_.erase(hash);
|
||||
}
|
||||
|
||||
std::shared_ptr<InboundLedger>
|
||||
find(uint256 const& hash) override
|
||||
{
|
||||
@@ -426,6 +458,9 @@ private:
|
||||
beast::insight::Counter mCounter;
|
||||
|
||||
std::unique_ptr<PeerSetBuilder> mPeerSetBuilder;
|
||||
|
||||
std::set<uint256> pendingAcquires_;
|
||||
std::mutex acquiresMutex_;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
|
||||
#include <ripple/app/consensus/RCLValidations.h>
|
||||
#include <ripple/app/ledger/Ledger.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/NegativeUNLVote.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
|
||||
@@ -70,7 +70,9 @@
|
||||
#include <boost/asio/ip/host_name.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
@@ -776,6 +778,9 @@ private:
|
||||
|
||||
StateAccounting accounting_{};
|
||||
|
||||
std::set<uint256> pendingValidations_;
|
||||
std::mutex validationsMutex_;
|
||||
|
||||
private:
|
||||
struct Stats
|
||||
{
|
||||
@@ -1142,8 +1147,12 @@ NetworkOPsImp::submitTransaction(std::shared_ptr<STTx const> const& iTrans)
|
||||
// Enforce Network bar for emitted txn
|
||||
if (view->rules().enabled(featureHooks) && hook::isEmittedTxn(*iTrans))
|
||||
{
|
||||
JLOG(m_journal.warn())
|
||||
<< "Submitted transaction invalid: EmitDetails present.";
|
||||
// RH NOTE: Warning removed here due to ConsesusSet using this function
|
||||
// which continually triggers this bar. Doesn't seem dangerous, just
|
||||
// annoying.
|
||||
|
||||
// JLOG(m_journal.warn())
|
||||
// << "Submitted transaction invalid: EmitDetails present.";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1155,7 +1164,11 @@ NetworkOPsImp::submitTransaction(std::shared_ptr<STTx const> const& iTrans)
|
||||
|
||||
if ((flags & SF_BAD) != 0)
|
||||
{
|
||||
JLOG(m_journal.warn()) << "Submitted transaction cached bad";
|
||||
// RH NOTE: Warning removed here due to ConsesusSet using this function
|
||||
// which continually triggers this bar. Doesn't seem dangerous, just
|
||||
// annoying.
|
||||
|
||||
// JLOG(m_journal.warn()) << "Submitted transaction cached bad";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1431,7 +1444,7 @@ NetworkOPsImp::apply(std::unique_lock<std::mutex>& batchLock)
|
||||
app_.getHashRouter().setFlags(e.transaction->getID(), SF_BAD);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (e.result != tesSUCCESS)
|
||||
if (!isTesSuccess(e.result))
|
||||
{
|
||||
std::string token, human;
|
||||
|
||||
@@ -1445,7 +1458,7 @@ NetworkOPsImp::apply(std::unique_lock<std::mutex>& batchLock)
|
||||
|
||||
bool addLocal = e.local;
|
||||
|
||||
if (e.result == tesSUCCESS)
|
||||
if (isTesSuccess(e.result))
|
||||
{
|
||||
JLOG(m_journal.debug())
|
||||
<< "Transaction is now included in open ledger";
|
||||
@@ -1783,7 +1796,8 @@ NetworkOPsImp::checkLastClosedLedger(
|
||||
}
|
||||
|
||||
JLOG(m_journal.warn()) << "We are not running on the consensus ledger";
|
||||
JLOG(m_journal.info()) << "Our LCL: " << getJson({*ourClosed, {}});
|
||||
JLOG(m_journal.info()) << "Our LCL: " << ourClosed->info().hash
|
||||
<< getJson({*ourClosed, {}});
|
||||
JLOG(m_journal.info()) << "Net LCL " << closedLedger;
|
||||
|
||||
if ((mMode == OperatingMode::TRACKING) || (mMode == OperatingMode::FULL))
|
||||
@@ -2337,7 +2351,37 @@ NetworkOPsImp::recvValidation(
|
||||
JLOG(m_journal.trace())
|
||||
<< "recvValidation " << val->getLedgerHash() << " from " << source;
|
||||
|
||||
handleNewValidation(app_, val, source);
|
||||
// handleNewValidation(app_, val, source);
|
||||
// https://github.com/XRPLF/rippled/commit/fbbea9e6e25795a8a6bd1bf64b780771933a9579
|
||||
std::unique_lock lock(validationsMutex_);
|
||||
BypassAccept bypassAccept = BypassAccept::no;
|
||||
try
|
||||
{
|
||||
if (pendingValidations_.contains(val->getLedgerHash()))
|
||||
bypassAccept = BypassAccept::yes;
|
||||
else
|
||||
pendingValidations_.insert(val->getLedgerHash());
|
||||
lock.unlock();
|
||||
handleNewValidation(app_, val, source, bypassAccept, m_journal);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
JLOG(m_journal.warn())
|
||||
<< "Exception thrown for handling new validation "
|
||||
<< val->getLedgerHash() << ": " << e.what();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
JLOG(m_journal.warn())
|
||||
<< "Unknown exception thrown for handling new validation "
|
||||
<< val->getLedgerHash();
|
||||
}
|
||||
if (bypassAccept == BypassAccept::no)
|
||||
{
|
||||
lock.lock();
|
||||
pendingValidations_.erase(val->getLedgerHash());
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
pubValidation(val);
|
||||
|
||||
@@ -3215,7 +3259,7 @@ NetworkOPsImp::pubValidatedTransaction(
|
||||
}
|
||||
}
|
||||
|
||||
if (transaction.getResult() == tesSUCCESS)
|
||||
if (isTesSuccess(transaction.getResult()))
|
||||
app_.getOrderBookDB().processTxn(ledger, transaction, jvObj);
|
||||
|
||||
pubAccountTransaction(ledger, transaction);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#include <boost/intrusive/set.hpp>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -56,7 +57,14 @@ class Config;
|
||||
*/
|
||||
class TxQ
|
||||
{
|
||||
private:
|
||||
std::mutex debugTxInjectMutex;
|
||||
std::vector<STTx> debugTxInjectQueue;
|
||||
|
||||
public:
|
||||
void
|
||||
debugTxInject(STTx const& txn);
|
||||
|
||||
/// Fee level for single-signed reference transaction.
|
||||
static constexpr FeeLevel64 baseLevel{256};
|
||||
|
||||
@@ -103,7 +111,7 @@ public:
|
||||
std::uint32_t minimumTxnInLedgerSA = 1000;
|
||||
/// Number of transactions per ledger that fee escalation "works
|
||||
/// towards".
|
||||
std::uint32_t targetTxnInLedger = 256;
|
||||
std::uint32_t targetTxnInLedger = 1000;
|
||||
/** Optional maximum allowed value of transactions per ledger before
|
||||
fee escalation kicks in. By default, the maximum is an emergent
|
||||
property of network, validator, and consensus performance. This
|
||||
|
||||
@@ -93,6 +93,13 @@ increase(FeeLevel64 level, std::uint32_t increasePercent)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
TxQ::debugTxInject(STTx const& txn)
|
||||
{
|
||||
const std::lock_guard<std::mutex> _(debugTxInjectMutex);
|
||||
debugTxInjectQueue.push_back(txn);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
TxQ::FeeMetrics::update(
|
||||
Application& app,
|
||||
@@ -748,7 +755,7 @@ TxQ::apply(
|
||||
// etc. before doing potentially expensive queue
|
||||
// replace and multi-transaction operations.
|
||||
auto const pfresult = preflight(app, view.rules(), *tx, flags, j);
|
||||
if (pfresult.ter != tesSUCCESS)
|
||||
if (!isTesSuccess(pfresult.ter))
|
||||
return {pfresult.ter, false};
|
||||
|
||||
// If the account is not currently in the ledger, don't queue its tx.
|
||||
@@ -1444,6 +1451,32 @@ TxQ::accept(Application& app, OpenView& view)
|
||||
|
||||
auto const metricsSnapshot = feeMetrics_.getSnapshot();
|
||||
|
||||
// try to inject any debug txns waiting in the debug queue
|
||||
{
|
||||
std::unique_lock<std::mutex> trylock(
|
||||
TxQ::debugTxInjectMutex, std::try_to_lock);
|
||||
if (trylock.owns_lock() && !debugTxInjectQueue.empty())
|
||||
{
|
||||
// pop everything
|
||||
for (STTx const& txn : debugTxInjectQueue)
|
||||
{
|
||||
auto txnHash = txn.getTransactionID();
|
||||
app.getHashRouter().setFlags(txnHash, SF_EMITTED | SF_PRIVATE2);
|
||||
|
||||
auto const& emitted =
|
||||
const_cast<ripple::STTx&>(txn).downcast<STObject>();
|
||||
|
||||
auto s = std::make_shared<ripple::Serializer>();
|
||||
emitted.add(*s);
|
||||
|
||||
view.rawTxInsert(txnHash, std::move(s), nullptr);
|
||||
ledgerChanged = true;
|
||||
}
|
||||
|
||||
debugTxInjectQueue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Inject emitted transactions if any
|
||||
if (view.rules().enabled(featureHooks))
|
||||
do
|
||||
@@ -2030,19 +2063,20 @@ TxQ::doRPC(Application& app, std::optional<XRPAmount> hookFeeUnits) const
|
||||
levels[jss::median_level] = to_string(metrics.medFeeLevel);
|
||||
levels[jss::open_ledger_level] = to_string(metrics.openLedgerFeeLevel);
|
||||
|
||||
auto const txFee = XRPAmount{hookFeeUnits->drops()};
|
||||
auto const baseFee = view->fees().base;
|
||||
auto const baseFee =
|
||||
hookFeeUnits ? XRPAmount{hookFeeUnits->drops()} : view->fees().base;
|
||||
// If the base fee is 0 drops, but escalation has kicked in, treat the
|
||||
// base fee as if it is 1 drop, which makes the rest of the math
|
||||
// work.
|
||||
auto const effectiveBaseFee = [&txFee, &metrics]() {
|
||||
if (!txFee && metrics.openLedgerFeeLevel != metrics.referenceFeeLevel)
|
||||
auto const effectiveBaseFee = [&baseFee, &metrics]() {
|
||||
if (!baseFee && metrics.openLedgerFeeLevel != metrics.referenceFeeLevel)
|
||||
return XRPAmount{1};
|
||||
return txFee;
|
||||
return baseFee;
|
||||
}();
|
||||
|
||||
auto& drops = ret[jss::drops] = Json::Value();
|
||||
|
||||
drops[jss::base_fee_no_hooks] = to_string(view->fees().base);
|
||||
drops[jss::base_fee] = to_string(baseFee);
|
||||
drops[jss::median_fee] = to_string(toDrops(metrics.medFeeLevel, baseFee));
|
||||
drops[jss::minimum_fee] = to_string(toDrops(
|
||||
|
||||
@@ -42,7 +42,7 @@ finishFlow(
|
||||
FlowResult&& f)
|
||||
{
|
||||
path::RippleCalc::Output result;
|
||||
if (f.ter == tesSUCCESS)
|
||||
if (isTesSuccess(f.ter))
|
||||
f.sandbox->apply(sb);
|
||||
else
|
||||
result.removableOffers = std::move(f.removableOffers);
|
||||
@@ -100,7 +100,7 @@ flow(
|
||||
offerCrossing,
|
||||
j);
|
||||
|
||||
if (toStrandsTer != tesSUCCESS)
|
||||
if (!isTesSuccess(toStrandsTer))
|
||||
{
|
||||
path::RippleCalc::Output result;
|
||||
result.setResult(toStrandsTer);
|
||||
|
||||
@@ -603,7 +603,7 @@ PathRequest::findPaths(
|
||||
ps, // --> Path set.
|
||||
app_.logs());
|
||||
|
||||
if (rc.result() != tesSUCCESS)
|
||||
if (!isTesSuccess(rc.result()))
|
||||
{
|
||||
JLOG(m_journal.warn())
|
||||
<< iIdentifier << " Failed with covering path "
|
||||
@@ -617,7 +617,7 @@ PathRequest::findPaths(
|
||||
}
|
||||
}
|
||||
|
||||
if (rc.result() == tesSUCCESS)
|
||||
if (isTesSuccess(rc.result()))
|
||||
{
|
||||
Json::Value jvEntry(Json::objectValue);
|
||||
rc.actualAmountIn.setIssuer(sourceAccount);
|
||||
|
||||
@@ -372,7 +372,7 @@ Pathfinder::getPathLiquidity(
|
||||
app_.logs(),
|
||||
&rcInput);
|
||||
// If we can't get even the minimum liquidity requested, we're done.
|
||||
if (rc.result() != tesSUCCESS)
|
||||
if (!isTesSuccess(rc.result()))
|
||||
return rc.result();
|
||||
|
||||
qualityOut = getRate(rc.actualAmountOut, rc.actualAmountIn);
|
||||
@@ -393,7 +393,7 @@ Pathfinder::getPathLiquidity(
|
||||
&rcInput);
|
||||
|
||||
// If we found further liquidity, add it into the result.
|
||||
if (rc.result() == tesSUCCESS)
|
||||
if (isTesSuccess(rc.result()))
|
||||
amountOut += rc.actualAmountOut;
|
||||
}
|
||||
|
||||
@@ -431,7 +431,7 @@ Pathfinder::computePathRanks(
|
||||
app_.logs(),
|
||||
&rcInput);
|
||||
|
||||
if (rc.result() == tesSUCCESS)
|
||||
if (isTesSuccess(rc.result()))
|
||||
{
|
||||
JLOG(j_.debug())
|
||||
<< "Default path contributes: " << rc.actualAmountIn;
|
||||
@@ -520,7 +520,7 @@ Pathfinder::rankPaths(
|
||||
uint64_t uQuality;
|
||||
auto const resultCode = getPathLiquidity(
|
||||
currentPath, saMinDstAmount, liquidity, uQuality);
|
||||
if (resultCode != tesSUCCESS)
|
||||
if (!isTesSuccess(resultCode))
|
||||
{
|
||||
JLOG(j_.debug())
|
||||
<< "findPaths: dropping : " << transToken(resultCode)
|
||||
|
||||
@@ -685,7 +685,7 @@ BookStep<TIn, TOut, TDerived>::consumeOffer(
|
||||
offer.owner(),
|
||||
toSTAmount(ofrAmt.in, book_.in),
|
||||
j_);
|
||||
if (dr != tesSUCCESS)
|
||||
if (!isTesSuccess(dr))
|
||||
Throw<FlowException>(dr);
|
||||
}
|
||||
|
||||
@@ -698,7 +698,7 @@ BookStep<TIn, TOut, TDerived>::consumeOffer(
|
||||
book_.out.account,
|
||||
toSTAmount(ownerGives, book_.out),
|
||||
j_);
|
||||
if (cr != tesSUCCESS)
|
||||
if (!isTesSuccess(cr))
|
||||
Throw<FlowException>(cr);
|
||||
}
|
||||
|
||||
@@ -1170,7 +1170,7 @@ make_BookStepHelper(StrandContext const& ctx, Issue const& in, Issue const& out)
|
||||
ter = paymentStep->check(ctx);
|
||||
r = std::move(paymentStep);
|
||||
}
|
||||
if (ter != tesSUCCESS)
|
||||
if (!isTesSuccess(ter))
|
||||
return {ter, nullptr};
|
||||
|
||||
return {tesSUCCESS, std::move(r)};
|
||||
|
||||
@@ -900,7 +900,7 @@ DirectStepI<TDerived>::check(StrandContext const& ctx) const
|
||||
if (!(ctx.isLast && ctx.isFirst))
|
||||
{
|
||||
auto const ter = checkFreeze(ctx.view, src_, dst_, currency_);
|
||||
if (ter != tesSUCCESS)
|
||||
if (!isTesSuccess(ter))
|
||||
return ter;
|
||||
}
|
||||
|
||||
@@ -912,7 +912,7 @@ DirectStepI<TDerived>::check(StrandContext const& ctx) const
|
||||
{
|
||||
auto const ter =
|
||||
checkNoRipple(ctx.view, *prevSrc, src_, dst_, currency_, j_);
|
||||
if (ter != tesSUCCESS)
|
||||
if (!isTesSuccess(ter))
|
||||
return ter;
|
||||
}
|
||||
}
|
||||
@@ -995,7 +995,7 @@ make_DirectStepI(
|
||||
ter = paymentStep->check(ctx);
|
||||
r = std::move(paymentStep);
|
||||
}
|
||||
if (ter != tesSUCCESS)
|
||||
if (!isTesSuccess(ter))
|
||||
return {ter, nullptr};
|
||||
|
||||
return {tesSUCCESS, std::move(r)};
|
||||
|
||||
@@ -318,7 +318,7 @@ toStrand(
|
||||
cur->getAccountID(),
|
||||
curIssue.account,
|
||||
curIssue.currency);
|
||||
if (msr.first != tesSUCCESS)
|
||||
if (!isTesSuccess(msr.first))
|
||||
return {msr.first, Strand{}};
|
||||
result.push_back(std::move(msr.second));
|
||||
impliedPE.emplace(
|
||||
@@ -339,7 +339,7 @@ toStrand(
|
||||
cur->getAccountID(),
|
||||
curIssue.account,
|
||||
curIssue.currency);
|
||||
if (msr.first != tesSUCCESS)
|
||||
if (!isTesSuccess(msr.first))
|
||||
return {msr.first, Strand{}};
|
||||
result.push_back(std::move(msr.second));
|
||||
impliedPE.emplace(
|
||||
@@ -364,7 +364,7 @@ toStrand(
|
||||
// Last step. insert xrp endpoint step
|
||||
auto msr =
|
||||
make_XRPEndpointStep(ctx(), next->getAccountID());
|
||||
if (msr.first != tesSUCCESS)
|
||||
if (!isTesSuccess(msr.first))
|
||||
return {msr.first, Strand{}};
|
||||
result.push_back(std::move(msr.second));
|
||||
}
|
||||
@@ -377,7 +377,7 @@ toStrand(
|
||||
curIssue.account,
|
||||
next->getAccountID(),
|
||||
curIssue.currency);
|
||||
if (msr.first != tesSUCCESS)
|
||||
if (!isTesSuccess(msr.first))
|
||||
return {msr.first, Strand{}};
|
||||
result.push_back(std::move(msr.second));
|
||||
}
|
||||
@@ -395,7 +395,7 @@ toStrand(
|
||||
|
||||
auto s = toStep(
|
||||
ctx(/*isLast*/ i == normPath.size() - 2), cur, next, curIssue);
|
||||
if (s.first == tesSUCCESS)
|
||||
if (isTesSuccess(s.first))
|
||||
result.emplace_back(std::move(s.second));
|
||||
else
|
||||
{
|
||||
@@ -503,7 +503,7 @@ toStrands(
|
||||
auto const ter = sp.first;
|
||||
auto& strand = sp.second;
|
||||
|
||||
if (ter != tesSUCCESS)
|
||||
if (!isTesSuccess(ter))
|
||||
{
|
||||
JLOG(j.trace()) << "failed to add default path";
|
||||
if (isTemMalformed(ter) || paths.empty())
|
||||
@@ -546,7 +546,7 @@ toStrands(
|
||||
auto ter = sp.first;
|
||||
auto& strand = sp.second;
|
||||
|
||||
if (ter != tesSUCCESS)
|
||||
if (!isTesSuccess(ter))
|
||||
{
|
||||
lastFailTer = ter;
|
||||
JLOG(j.trace()) << "failed to add path: ter: " << ter
|
||||
|
||||
@@ -267,7 +267,7 @@ XRPEndpointStep<TDerived>::revImp(
|
||||
auto& sender = isLast_ ? xrpAccount() : acc_;
|
||||
auto& receiver = isLast_ ? acc_ : xrpAccount();
|
||||
auto ter = accountSend(sb, sender, receiver, toSTAmount(result), j_);
|
||||
if (ter != tesSUCCESS)
|
||||
if (!isTesSuccess(ter))
|
||||
return {XRPAmount{beast::zero}, XRPAmount{beast::zero}};
|
||||
|
||||
cache_.emplace(result);
|
||||
@@ -290,7 +290,7 @@ XRPEndpointStep<TDerived>::fwdImp(
|
||||
auto& sender = isLast_ ? xrpAccount() : acc_;
|
||||
auto& receiver = isLast_ ? acc_ : xrpAccount();
|
||||
auto ter = accountSend(sb, sender, receiver, toSTAmount(result), j_);
|
||||
if (ter != tesSUCCESS)
|
||||
if (!isTesSuccess(ter))
|
||||
return {XRPAmount{beast::zero}, XRPAmount{beast::zero}};
|
||||
|
||||
cache_.emplace(result);
|
||||
@@ -359,7 +359,7 @@ XRPEndpointStep<TDerived>::check(StrandContext const& ctx) const
|
||||
auto& src = isLast_ ? xrpAccount() : acc_;
|
||||
auto& dst = isLast_ ? acc_ : xrpAccount();
|
||||
auto ter = checkFreeze(ctx.view, src, dst, xrpCurrency());
|
||||
if (ter != tesSUCCESS)
|
||||
if (!isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
if (ctx.view.rules().enabled(fix1781))
|
||||
@@ -413,7 +413,7 @@ make_XRPEndpointStep(StrandContext const& ctx, AccountID const& acc)
|
||||
ter = paymentStep->check(ctx);
|
||||
r = std::move(paymentStep);
|
||||
}
|
||||
if (ter != tesSUCCESS)
|
||||
if (!isTesSuccess(ter))
|
||||
return {ter, nullptr};
|
||||
|
||||
return {tesSUCCESS, std::move(r)};
|
||||
|
||||
@@ -173,6 +173,11 @@ updateLedgerDBs(
|
||||
|
||||
auto const sParentHash{to_string(ledger->info().parentHash)};
|
||||
auto const sDrops{to_string(ledger->info().drops)};
|
||||
auto const closingTime{
|
||||
ledger->info().closeTime.time_since_epoch().count()};
|
||||
auto const prevClosingTime{
|
||||
ledger->info().parentCloseTime.time_since_epoch().count()};
|
||||
auto const closeTimeRes{ledger->info().closeTimeResolution.count()};
|
||||
auto const sAccountHash{to_string(ledger->info().accountHash)};
|
||||
auto const sTxHash{to_string(ledger->info().txHash)};
|
||||
|
||||
@@ -188,11 +193,8 @@ updateLedgerDBs(
|
||||
":closingTime, :prevClosingTime, :closeTimeRes,"
|
||||
":closeFlags, :accountSetHash, :transSetHash);",
|
||||
soci::use(sHash), soci::use(ledgerSeq), soci::use(sParentHash),
|
||||
soci::use(sDrops),
|
||||
soci::use(ledger->info().closeTime.time_since_epoch().count()),
|
||||
soci::use(
|
||||
ledger->info().parentCloseTime.time_since_epoch().count()),
|
||||
soci::use(ledger->info().closeTimeResolution.count()),
|
||||
soci::use(sDrops), soci::use(closingTime),
|
||||
soci::use(prevClosingTime), soci::use(closeTimeRes),
|
||||
soci::use(ledger->info().closeFlags), soci::use(sAccountHash),
|
||||
soci::use(sTxHash);
|
||||
|
||||
|
||||
@@ -205,19 +205,20 @@ insertPeerReservation(
|
||||
PublicKey const& nodeId,
|
||||
std::string const& description)
|
||||
{
|
||||
auto const sNodeId = toBase58(TokenType::NodePublic, nodeId);
|
||||
session << "INSERT INTO PeerReservations (PublicKey, Description) "
|
||||
"VALUES (:nodeId, :desc) "
|
||||
"ON CONFLICT (PublicKey) DO UPDATE SET "
|
||||
"Description=excluded.Description",
|
||||
soci::use(toBase58(TokenType::NodePublic, nodeId)),
|
||||
soci::use(description);
|
||||
soci::use(sNodeId), soci::use(description);
|
||||
}
|
||||
|
||||
void
|
||||
deletePeerReservation(soci::session& session, PublicKey const& nodeId)
|
||||
{
|
||||
auto const sNodeId = toBase58(TokenType::NodePublic, nodeId);
|
||||
session << "DELETE FROM PeerReservations WHERE PublicKey = :nodeId",
|
||||
soci::use(toBase58(TokenType::NodePublic, nodeId));
|
||||
soci::use(sNodeId);
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -194,8 +194,14 @@ ETLSource::onResolve(
|
||||
{
|
||||
boost::beast::get_lowest_layer(*ws_).expires_after(
|
||||
std::chrono::seconds(30));
|
||||
|
||||
// Use async_connect with the entire results
|
||||
boost::beast::get_lowest_layer(*ws_).async_connect(
|
||||
results, [this](auto ec, auto ep) { onConnect(ec, ep); });
|
||||
results,
|
||||
[this](
|
||||
boost::beast::error_code ec,
|
||||
boost::asio::ip::tcp::resolver::results_type::endpoint_type
|
||||
ep) { onConnect(ec, ep); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ public:
|
||||
, flags(ctx_.flags)
|
||||
, j(ctx_.j)
|
||||
, ter(ter_)
|
||||
, likelyToClaimFee(ter == tesSUCCESS || isTecClaimHardFail(ter, flags))
|
||||
, likelyToClaimFee(isTesSuccess(ter) || isTecClaimHardFail(ter, flags))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -39,10 +39,26 @@ CancelOffer::preflight(PreflightContext const& ctx)
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
|
||||
if (!ctx.tx[sfOfferSequence])
|
||||
if (ctx.rules.enabled(fixXahauV1))
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "CancelOffer::preflight: missing sequence";
|
||||
return temBAD_SEQUENCE;
|
||||
if ((!ctx.tx.isFieldPresent(sfOfferSequence) &&
|
||||
!ctx.tx.isFieldPresent(sfOfferID)) ||
|
||||
(ctx.tx.isFieldPresent(sfOfferSequence) &&
|
||||
ctx.tx.isFieldPresent(sfOfferID)))
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "CancelOffer::preflight: invalid sequence or offer id";
|
||||
return temBAD_SEQUENCE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ctx.tx.isFieldPresent(sfOfferSequence) ||
|
||||
ctx.tx[sfOfferSequence] == 0)
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "CancelOffer::preflight: missing sequence";
|
||||
return temBAD_SEQUENCE;
|
||||
}
|
||||
}
|
||||
|
||||
return preflight2(ctx);
|
||||
@@ -54,29 +70,18 @@ TER
|
||||
CancelOffer::preclaim(PreclaimContext const& ctx)
|
||||
{
|
||||
auto const id = ctx.tx[sfAccount];
|
||||
auto const offerSequence = ctx.tx[sfOfferSequence];
|
||||
|
||||
auto const sle = ctx.view.read(keylet::account(id));
|
||||
if (!sle)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
bool hooksEnabled = ctx.view.rules().enabled(featureHooks);
|
||||
auto const offerSequence = ctx.tx[~sfOfferSequence];
|
||||
|
||||
auto const offerID = ctx.tx[~sfOfferID];
|
||||
|
||||
if ((*sle)[sfSequence] <= offerSequence)
|
||||
if (offerSequence && (*sle)[sfSequence] <= *offerSequence)
|
||||
{
|
||||
if (hooksEnabled && offerID && offerSequence == 0)
|
||||
{
|
||||
// pass, here the txn provides offerID instead of offerSequence
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(ctx.j.trace())
|
||||
<< "Malformed transaction: "
|
||||
<< "Sequence " << offerSequence << " is invalid.";
|
||||
return temBAD_SEQUENCE;
|
||||
}
|
||||
JLOG(ctx.j.trace()) << "Malformed transaction: "
|
||||
<< "Sequence " << *offerSequence << " is invalid.";
|
||||
return temBAD_SEQUENCE;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
@@ -87,36 +92,40 @@ CancelOffer::preclaim(PreclaimContext const& ctx)
|
||||
TER
|
||||
CancelOffer::doApply()
|
||||
{
|
||||
auto const offerSequence = ctx_.tx[sfOfferSequence];
|
||||
|
||||
auto const sle = view().read(keylet::account(account_));
|
||||
if (!sle)
|
||||
return tefINTERNAL;
|
||||
|
||||
auto const offerSequence = ctx_.tx[~sfOfferSequence];
|
||||
auto const offerID = ctx_.tx[~sfOfferID];
|
||||
|
||||
bool hooksEnabled = view().rules().enabled(featureHooks);
|
||||
|
||||
std::optional<uint256> offerID;
|
||||
|
||||
if (hooksEnabled)
|
||||
offerID = ctx_.tx[~sfOfferID];
|
||||
|
||||
Keylet cancel = hooksEnabled && offerID && offerSequence == 0
|
||||
Keylet cancel = hooksEnabled && offerID && !offerSequence
|
||||
? Keylet(ltOFFER, *offerID)
|
||||
: keylet::offer(account_, offerSequence);
|
||||
: keylet::offer(account_, *offerSequence);
|
||||
|
||||
if (auto sleOffer = view().peek(cancel))
|
||||
{
|
||||
if (offerID)
|
||||
JLOG(j_.debug()) << "Trying to cancel offer :" << *offerID;
|
||||
else
|
||||
JLOG(j_.debug()) << "Trying to cancel offer #" << offerSequence;
|
||||
JLOG(j_.debug()) << "Trying to cancel offer #" << *offerSequence;
|
||||
|
||||
bool const fixV1 = view().rules().enabled(fixXahauV1);
|
||||
if (fixV1 && sleOffer->getFieldU16(sfLedgerEntryType) != ltOFFER)
|
||||
{
|
||||
JLOG(j_.debug()) << "OfferCancel specified non-offer ledger object";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
return offerDelete(view(), sleOffer, ctx_.app.journal("View"));
|
||||
}
|
||||
|
||||
if (offerID)
|
||||
JLOG(j_.debug()) << "Offer :" << *offerID << " can't be found.";
|
||||
else
|
||||
JLOG(j_.debug()) << "Offer #" << offerSequence << " can't be found.";
|
||||
JLOG(j_.debug()) << "Offer #" << *offerSequence << " can't be found.";
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -326,7 +326,7 @@ CashCheck::doApply()
|
||||
// The source account has enough XRP so make the ledger change.
|
||||
if (TER const ter{
|
||||
transferXRP(psb, srcId, account_, xrpDeliver, viewJ)};
|
||||
ter != tesSUCCESS)
|
||||
!isTesSuccess(ter))
|
||||
{
|
||||
// The transfer failed. Return the error code.
|
||||
return ter;
|
||||
@@ -452,7 +452,7 @@ CashCheck::doApply()
|
||||
sleCheck->getFieldAmount(sfSendMax),
|
||||
viewJ);
|
||||
|
||||
if (result.result() != tesSUCCESS)
|
||||
if (!isTesSuccess(result.result()))
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "flow failed when cashing check.";
|
||||
return result.result();
|
||||
|
||||
@@ -212,7 +212,7 @@ CreateOffer::preclaim(PreclaimContext const& ctx)
|
||||
id,
|
||||
ctx.j,
|
||||
Issue(uPaysCurrency, uPaysIssuerID));
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -495,7 +495,7 @@ CreateOffer::bridged_cross(
|
||||
}
|
||||
}
|
||||
|
||||
if (cross_result != tesSUCCESS)
|
||||
if (!isTesSuccess(cross_result))
|
||||
{
|
||||
cross_result = tecFAILED_PROCESSING;
|
||||
break;
|
||||
@@ -585,7 +585,7 @@ CreateOffer::direct_cross(
|
||||
have_offer = step_account(offers, taker);
|
||||
}
|
||||
|
||||
if (cross_result != tesSUCCESS)
|
||||
if (!isTesSuccess(cross_result))
|
||||
{
|
||||
cross_result = tecFAILED_PROCESSING;
|
||||
break;
|
||||
@@ -989,7 +989,7 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel)
|
||||
bool const bOpenLedger = sb.open();
|
||||
bool crossed = false;
|
||||
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
{
|
||||
// If a tick size applies, round the offer to the tick size
|
||||
auto const& uPaysIssuerID = saTakerPays.getIssuer();
|
||||
@@ -1059,7 +1059,7 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel)
|
||||
|
||||
// We expect the implementation of cross to succeed
|
||||
// or give a tec.
|
||||
assert(result == tesSUCCESS || isTecClaim(result));
|
||||
assert(isTesSuccess(result) || isTecClaim(result));
|
||||
|
||||
if (auto stream = j_.trace())
|
||||
{
|
||||
@@ -1071,7 +1071,7 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel)
|
||||
if (result == tecFAILED_PROCESSING && bOpenLedger)
|
||||
result = telFAILED_PROCESSING;
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
{
|
||||
JLOG(j_.debug()) << "final result: " << transToken(result);
|
||||
return {result, true};
|
||||
@@ -1108,7 +1108,7 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel)
|
||||
|
||||
assert(saTakerPays > zero && saTakerGets > zero);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
{
|
||||
JLOG(j_.debug()) << "final result: " << transToken(result);
|
||||
return {result, true};
|
||||
@@ -1161,7 +1161,7 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel)
|
||||
if (!crossed)
|
||||
result = tecINSUF_RESERVE_OFFER;
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
{
|
||||
JLOG(j_.debug()) << "final result: " << transToken(result);
|
||||
}
|
||||
|
||||
@@ -431,6 +431,26 @@ EscrowFinish::preflight(PreflightContext const& ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// sfOfferSequence was changed to optional, so ensure the behaviour is the
|
||||
// same until amendment passes
|
||||
if (!ctx.rules.enabled(fixXahauV1))
|
||||
{
|
||||
if (!ctx.tx.isFieldPresent(sfOfferSequence))
|
||||
return temMALFORMED;
|
||||
|
||||
if (ctx.tx.isFieldPresent(sfEscrowID) &&
|
||||
ctx.tx.getFieldU32(sfOfferSequence) != 0)
|
||||
return temMALFORMED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((!ctx.tx.isFieldPresent(sfEscrowID) &&
|
||||
!ctx.tx.isFieldPresent(sfOfferSequence)) ||
|
||||
ctx.tx.isFieldPresent(sfEscrowID) &&
|
||||
ctx.tx.isFieldPresent(sfOfferSequence))
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -456,18 +476,20 @@ EscrowFinish::doApply()
|
||||
return temDISABLED;
|
||||
|
||||
std::optional<uint256> escrowID = ctx_.tx[~sfEscrowID];
|
||||
std::optional<std::uint32_t> offerSequence = ctx_.tx[~sfOfferSequence];
|
||||
|
||||
if (escrowID && ctx_.tx[sfOfferSequence] != 0)
|
||||
return temMALFORMED;
|
||||
bool const fixV1 = view().rules().enabled(fixXahauV1);
|
||||
|
||||
Keylet k = escrowID
|
||||
? Keylet(ltESCROW, *escrowID)
|
||||
: keylet::escrow(ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
|
||||
Keylet k = escrowID ? Keylet(ltESCROW, *escrowID)
|
||||
: keylet::escrow(ctx_.tx[sfOwner], *offerSequence);
|
||||
|
||||
auto const slep = ctx_.view().peek(k);
|
||||
if (!slep)
|
||||
return tecNO_TARGET;
|
||||
|
||||
if (fixV1 && slep->getFieldU16(sfLedgerEntryType) != ltESCROW)
|
||||
return tecINTERNAL;
|
||||
|
||||
AccountID const account = (*slep)[sfAccount];
|
||||
auto const sle = ctx_.view().peek(keylet::account(account));
|
||||
auto const amount = slep->getFieldAmount(sfAmount);
|
||||
@@ -692,6 +714,26 @@ EscrowCancel::preflight(PreflightContext const& ctx)
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
// sfOfferSequence was changed to optional, so ensure the behaviour is the
|
||||
// same until amendment passes
|
||||
if (!ctx.rules.enabled(fixXahauV1))
|
||||
{
|
||||
if (!ctx.tx.isFieldPresent(sfOfferSequence))
|
||||
return temMALFORMED;
|
||||
|
||||
if (ctx.tx.isFieldPresent(sfEscrowID) &&
|
||||
ctx.tx.getFieldU32(sfOfferSequence) != 0)
|
||||
return temMALFORMED;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((!ctx.tx.isFieldPresent(sfEscrowID) &&
|
||||
!ctx.tx.isFieldPresent(sfOfferSequence)) ||
|
||||
ctx.tx.isFieldPresent(sfEscrowID) &&
|
||||
ctx.tx.isFieldPresent(sfOfferSequence))
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
return preflight2(ctx);
|
||||
}
|
||||
|
||||
@@ -704,18 +746,20 @@ EscrowCancel::doApply()
|
||||
return temDISABLED;
|
||||
|
||||
std::optional<uint256> escrowID = ctx_.tx[~sfEscrowID];
|
||||
std::optional<std::uint32_t> offerSequence = ctx_.tx[~sfOfferSequence];
|
||||
|
||||
if (escrowID && ctx_.tx[sfOfferSequence] != 0)
|
||||
return temMALFORMED;
|
||||
bool const fixV1 = view().rules().enabled(fixXahauV1);
|
||||
|
||||
Keylet k = escrowID
|
||||
? Keylet(ltESCROW, *escrowID)
|
||||
: keylet::escrow(ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
|
||||
Keylet k = escrowID ? Keylet(ltESCROW, *escrowID)
|
||||
: keylet::escrow(ctx_.tx[sfOwner], *offerSequence);
|
||||
|
||||
auto const slep = ctx_.view().peek(k);
|
||||
if (!slep)
|
||||
return tecNO_TARGET;
|
||||
|
||||
if (fixV1 && slep->getFieldU16(sfLedgerEntryType) != ltESCROW)
|
||||
return tecINTERNAL;
|
||||
|
||||
if (ctx_.view().rules().enabled(fix1571))
|
||||
{
|
||||
auto const now = ctx_.view().info().parentCloseTime;
|
||||
@@ -758,7 +802,7 @@ EscrowCancel::doApply()
|
||||
// dry run before we make any changes to ledger
|
||||
if (TER const result = trustAdjustLockedBalance(
|
||||
ctx_.view(), sleLine, -amount, -1, ctx_.journal, DryRun);
|
||||
result != tesSUCCESS)
|
||||
!isTesSuccess(result))
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/st.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -74,6 +75,8 @@ GenesisMint::preflight(PreflightContext const& ctx)
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
bool const allowDuplicates = ctx.rules.enabled(fixXahauV1);
|
||||
|
||||
std::unordered_set<AccountID> alreadySeen;
|
||||
for (auto const& dest : dests)
|
||||
{
|
||||
@@ -137,6 +140,9 @@ GenesisMint::preflight(PreflightContext const& ctx)
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (allowDuplicates)
|
||||
continue;
|
||||
|
||||
if (alreadySeen.find(accid) != alreadySeen.end())
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "GenesisMint: duplicate in destinations.";
|
||||
@@ -171,7 +177,114 @@ GenesisMint::doApply()
|
||||
{
|
||||
auto const& dests = ctx_.tx.getFieldArray(sfGenesisMints);
|
||||
|
||||
if (!view().rules().enabled(fixXahauV1))
|
||||
{
|
||||
STAmount dropsAdded{0};
|
||||
for (auto const& dest : dests)
|
||||
{
|
||||
auto const amt = dest[~sfAmount];
|
||||
|
||||
if (amt && !isXRP(*amt))
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: Non-xrp amount.";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
auto const flags = dest[~sfGovernanceFlags];
|
||||
auto const marks = dest[~sfGovernanceMarks];
|
||||
|
||||
auto const id = dest.getAccountID(sfDestination);
|
||||
auto const k = keylet::account(id);
|
||||
auto sle = view().peek(k);
|
||||
|
||||
bool const created = !sle;
|
||||
|
||||
if (created)
|
||||
{
|
||||
// Create the account.
|
||||
std::uint32_t const seqno{
|
||||
view().info().parentCloseTime.time_since_epoch().count()};
|
||||
|
||||
sle = std::make_shared<SLE>(k);
|
||||
sle->setAccountID(sfAccount, id);
|
||||
|
||||
sle->setFieldU32(sfSequence, seqno);
|
||||
|
||||
if (amt)
|
||||
{
|
||||
sle->setFieldAmount(sfBalance, *amt);
|
||||
dropsAdded += *amt;
|
||||
}
|
||||
else // give them 2 XRP if the account didn't exist, same as
|
||||
// ttIMPORT
|
||||
{
|
||||
XRPAmount const initialXrp =
|
||||
Import::computeStartingBonus(ctx_.view());
|
||||
sle->setFieldAmount(sfBalance, initialXrp);
|
||||
dropsAdded += initialXrp;
|
||||
}
|
||||
}
|
||||
else if (amt)
|
||||
{
|
||||
// Credit the account
|
||||
STAmount startBal = sle->getFieldAmount(sfBalance);
|
||||
STAmount finalBal = startBal + *amt;
|
||||
if (finalBal <= startBal)
|
||||
{
|
||||
JLOG(ctx_.journal.warn())
|
||||
<< "GenesisMint: cannot credit " << dest
|
||||
<< " due to balance overflow";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
sle->setFieldAmount(sfBalance, finalBal);
|
||||
dropsAdded += *amt;
|
||||
}
|
||||
|
||||
// set flags and marks as applicable
|
||||
if (flags)
|
||||
sle->setFieldH256(sfGovernanceFlags, *flags);
|
||||
|
||||
if (marks)
|
||||
sle->setFieldH256(sfGovernanceMarks, *marks);
|
||||
|
||||
if (created)
|
||||
view().insert(sle);
|
||||
else
|
||||
view().update(sle);
|
||||
}
|
||||
|
||||
// update ledger header
|
||||
if (dropsAdded < beast::zero ||
|
||||
dropsAdded.xrp() + view().info().drops < view().info().drops)
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: dropsAdded overflowed\n";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
if (dropsAdded > beast::zero)
|
||||
ctx_.rawView().rawDestroyXRP(-dropsAdded.xrp());
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
// RH NOTE:
|
||||
// As of fixXahauV1, duplicate accounts are allowed
|
||||
// so we first do a summation loop then an actioning loop
|
||||
// if amendment is not active then there's exactly one entry per
|
||||
|
||||
std::map<
|
||||
AccountID, // account to credit
|
||||
std::tuple<
|
||||
XRPAmount, // amount to credit
|
||||
std::optional<uint256>, // gov flags
|
||||
std::optional<uint256>>> // gov marks
|
||||
|
||||
mints;
|
||||
|
||||
STAmount dropsAdded{0};
|
||||
|
||||
// sum loop
|
||||
for (auto const& dest : dests)
|
||||
{
|
||||
auto const amt = dest[~sfAmount];
|
||||
@@ -182,13 +295,53 @@ GenesisMint::doApply()
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
XRPAmount toCredit = amt ? amt->xrp() : XRPAmount{0};
|
||||
|
||||
auto const flags = dest[~sfGovernanceFlags];
|
||||
auto const marks = dest[~sfGovernanceMarks];
|
||||
|
||||
auto const id = dest.getAccountID(sfDestination);
|
||||
|
||||
bool const firstOccurance = mints.find(id) == mints.end();
|
||||
|
||||
dropsAdded += toCredit;
|
||||
|
||||
// if flags / marks appear more than once we just take the first
|
||||
// appearance
|
||||
if (firstOccurance)
|
||||
mints[id] = {toCredit, flags, marks};
|
||||
else
|
||||
{
|
||||
// duplicated entries accumulate in the map
|
||||
|
||||
auto& [accTotal, f, m] = mints[id];
|
||||
|
||||
// detect overflow
|
||||
if (accTotal + toCredit < accTotal)
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: cannot credit " << id
|
||||
<< " due to balance overflow";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
accTotal += toCredit;
|
||||
}
|
||||
}
|
||||
|
||||
// check for ledger header overflow
|
||||
if (dropsAdded < beast::zero ||
|
||||
dropsAdded.xrp() + view().info().drops < view().info().drops)
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: dropsAdded overflowed\n";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
// action loop
|
||||
for (auto const& [id, values] : mints)
|
||||
{
|
||||
auto const& [amt, flags, marks] = values;
|
||||
|
||||
auto const k = keylet::account(id);
|
||||
auto sle = view().peek(k);
|
||||
|
||||
bool const created = !sle;
|
||||
|
||||
if (created)
|
||||
@@ -202,34 +355,21 @@ GenesisMint::doApply()
|
||||
|
||||
sle->setFieldU32(sfSequence, seqno);
|
||||
|
||||
if (amt)
|
||||
{
|
||||
sle->setFieldAmount(sfBalance, *amt);
|
||||
dropsAdded += *amt;
|
||||
}
|
||||
else // give them 2 XRP if the account didn't exist, same as
|
||||
// ttIMPORT
|
||||
{
|
||||
XRPAmount const initialXrp =
|
||||
Import::computeStartingBonus(ctx_.view());
|
||||
sle->setFieldAmount(sfBalance, initialXrp);
|
||||
dropsAdded += initialXrp;
|
||||
}
|
||||
sle->setFieldAmount(sfBalance, amt);
|
||||
}
|
||||
else if (amt)
|
||||
else if (amt > beast::zero)
|
||||
{
|
||||
// Credit the account
|
||||
STAmount startBal = sle->getFieldAmount(sfBalance);
|
||||
STAmount finalBal = startBal + *amt;
|
||||
STAmount finalBal = startBal + amt;
|
||||
if (finalBal <= startBal)
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: cannot credit "
|
||||
<< dest << " due to balance overflow";
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: cannot credit " << id
|
||||
<< " due to balance overflow";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
sle->setFieldAmount(sfBalance, finalBal);
|
||||
dropsAdded += *amt;
|
||||
}
|
||||
|
||||
// set flags and marks as applicable
|
||||
@@ -245,14 +385,6 @@ GenesisMint::doApply()
|
||||
view().update(sle);
|
||||
}
|
||||
|
||||
// update ledger header
|
||||
if (dropsAdded < beast::zero ||
|
||||
dropsAdded.xrp() + view().info().drops < view().info().drops)
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "GenesisMint: dropsAdded overflowed\n";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
if (dropsAdded > beast::zero)
|
||||
ctx_.rawView().rawDestroyXRP(-dropsAdded.xrp());
|
||||
|
||||
|
||||
@@ -24,12 +24,15 @@
|
||||
#include <ripple/basics/base64.h>
|
||||
#include <ripple/json/json_reader.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Import.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/PublicKey.h>
|
||||
#include <ripple/protocol/STTx.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <ripple/protocol/st.h>
|
||||
#include <algorithm>
|
||||
#include <charconv>
|
||||
#include <iostream>
|
||||
@@ -49,7 +52,7 @@ Import::makeTxConsequences(PreflightContext const& ctx)
|
||||
return beast::zero;
|
||||
|
||||
auto const result = meta->getFieldU8(sfTransactionResult);
|
||||
if (result != tesSUCCESS &&
|
||||
if (!isTesSuccess(result) &&
|
||||
!(result >= tecCLAIM && result <= tecLAST_POSSIBLE_ENTRY))
|
||||
return beast::zero;
|
||||
|
||||
@@ -220,7 +223,7 @@ Import::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
uint8_t innerResult = meta->getFieldU8(sfTransactionResult);
|
||||
|
||||
if (innerResult == tesSUCCESS)
|
||||
if (isTesSuccess(innerResult))
|
||||
{
|
||||
// pass
|
||||
}
|
||||
@@ -710,7 +713,6 @@ Import::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
auto const& data = (*xpop)[jss::validation][jss::data];
|
||||
std::set<std::string> used_key;
|
||||
|
||||
for (const auto& key : data.getMemberNames())
|
||||
{
|
||||
auto nodepub = key;
|
||||
@@ -818,7 +820,18 @@ Import::preflight(PreflightContext const& ctx)
|
||||
<< " validation count: " << validationCount;
|
||||
|
||||
// check if the validation count is adequate
|
||||
if (quorum >= validationCount)
|
||||
auto hasInsufficientQuorum =
|
||||
[&ctx](uint64_t quorum, uint64_t validationCount) {
|
||||
if (ctx.rules.enabled(fixXahauV1))
|
||||
{
|
||||
return quorum > validationCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
return quorum >= validationCount;
|
||||
}
|
||||
};
|
||||
if (hasInsufficientQuorum(quorum, validationCount))
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Import: xpop did not contain an 80% quorum for "
|
||||
"the txn it purports to prove. "
|
||||
@@ -962,7 +975,7 @@ Import::doSignerList(std::shared_ptr<SLE>& sle, STTx const& stpTrans)
|
||||
|
||||
TER result =
|
||||
SetSignerList::removeFromLedger(ctx_.app, sb, id, ctx_.journal);
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
{
|
||||
JLOG(ctx_.journal.warn())
|
||||
<< "Import: successful destroy SignerListSet";
|
||||
@@ -1047,7 +1060,7 @@ Import::doSignerList(std::shared_ptr<SLE>& sle, STTx const& stpTrans)
|
||||
signers,
|
||||
sle->getFieldAmount(sfBalance).xrp());
|
||||
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
{
|
||||
JLOG(ctx_.journal.warn()) << "Import: successful set SignerListSet";
|
||||
sb.apply(ctx_.rawView());
|
||||
@@ -1214,7 +1227,13 @@ Import::doApply()
|
||||
create ? STAmount(bonusAmount) : STAmount(mSourceBalance);
|
||||
|
||||
uint64_t creditDrops = burn.xrp().drops();
|
||||
if (elapsed < 2'000'000)
|
||||
|
||||
if (view().rules().enabled(featureZeroB2M))
|
||||
{
|
||||
// B2M xrp is disabled by amendment
|
||||
creditDrops = 0;
|
||||
}
|
||||
else if (elapsed < 2'000'000)
|
||||
{
|
||||
// first 2MM ledgers
|
||||
// the ratio is 1:1
|
||||
@@ -1293,7 +1312,7 @@ Import::doApply()
|
||||
// Handle any key imports, but only if a tes code
|
||||
// these functions update the sle on their own
|
||||
//
|
||||
if (meta->getFieldU8(sfTransactionResult) == tesSUCCESS)
|
||||
if (isTesSuccess(meta->getFieldU8(sfTransactionResult)))
|
||||
{
|
||||
auto const tt = stpTrans->getTxnType();
|
||||
if (tt == ttSIGNER_LIST_SET)
|
||||
|
||||
@@ -155,7 +155,7 @@ XRPNotCreated::finalize(
|
||||
return true;
|
||||
|
||||
if (view.rules().enabled(featureImport) && tt == ttIMPORT &&
|
||||
res == tesSUCCESS)
|
||||
isTesSuccess(res))
|
||||
{
|
||||
// different rules for ttIMPORT
|
||||
auto const [inner, meta] = Import::getInnerTxn(tx, j);
|
||||
@@ -164,7 +164,7 @@ XRPNotCreated::finalize(
|
||||
|
||||
auto const result = meta->getFieldU8(sfTransactionResult);
|
||||
|
||||
XRPAmount maxDropsAdded = result == tesSUCCESS ||
|
||||
XRPAmount maxDropsAdded = isTesSuccess(result) ||
|
||||
(result >= tecCLAIM && result <= tecLAST_POSSIBLE_ENTRY)
|
||||
? inner->getFieldAmount(sfFee).xrp() // burned in PoB
|
||||
: beast::zero; // if the txn didnt burn a fee we add nothing
|
||||
@@ -203,7 +203,7 @@ XRPNotCreated::finalize(
|
||||
}
|
||||
|
||||
if (view.rules().enabled(featureXahauGenesis) && tt == ttGENESIS_MINT &&
|
||||
res == tesSUCCESS)
|
||||
isTesSuccess(res))
|
||||
{
|
||||
// different rules for ttGENESIS_MINT
|
||||
auto const& dests = tx.getFieldArray(sfGenesisMints);
|
||||
@@ -433,7 +433,7 @@ AccountRootsNotDeleted::finalize(
|
||||
ReadView const&,
|
||||
beast::Journal const& j)
|
||||
{
|
||||
if (tx.getTxnType() == ttACCOUNT_DELETE && result == tesSUCCESS)
|
||||
if (tx.getTxnType() == ttACCOUNT_DELETE && isTesSuccess(result))
|
||||
{
|
||||
if (accountsDeleted_ == 1)
|
||||
return true;
|
||||
@@ -597,8 +597,9 @@ ValidNewAccountRoot::finalize(
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((tt == ttPAYMENT || tt == ttIMPORT || tt == ttGENESIS_MINT) &&
|
||||
result == tesSUCCESS)
|
||||
if ((tt == ttPAYMENT || tt == ttIMPORT || tt == ttGENESIS_MINT ||
|
||||
tt == ttREMIT) &&
|
||||
isTesSuccess(result))
|
||||
{
|
||||
std::uint32_t const startingSeq{
|
||||
view.rules().enabled(featureXahauGenesis)
|
||||
@@ -790,7 +791,7 @@ NFTokenCountTracking::finalize(
|
||||
|
||||
if (tx.getTxnType() == ttNFTOKEN_MINT)
|
||||
{
|
||||
if (result == tesSUCCESS && beforeMintedTotal >= afterMintedTotal)
|
||||
if (isTesSuccess(result) && beforeMintedTotal >= afterMintedTotal)
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "Invariant failed: successful minting didn't increase "
|
||||
@@ -798,7 +799,7 @@ NFTokenCountTracking::finalize(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result != tesSUCCESS && beforeMintedTotal != afterMintedTotal)
|
||||
if (!isTesSuccess(result) && beforeMintedTotal != afterMintedTotal)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: failed minting changed the "
|
||||
"number of minted tokens.";
|
||||
@@ -816,7 +817,7 @@ NFTokenCountTracking::finalize(
|
||||
|
||||
if (tx.getTxnType() == ttNFTOKEN_BURN)
|
||||
{
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
{
|
||||
if (beforeBurnedTotal >= afterBurnedTotal)
|
||||
{
|
||||
@@ -827,7 +828,7 @@ NFTokenCountTracking::finalize(
|
||||
}
|
||||
}
|
||||
|
||||
if (result != tesSUCCESS && beforeBurnedTotal != afterBurnedTotal)
|
||||
if (!isTesSuccess(result) && beforeBurnedTotal != afterBurnedTotal)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: failed burning changed the "
|
||||
"number of burned tokens.";
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/st.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -86,6 +87,27 @@ Invoke::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
extraFee +=
|
||||
XRPAmount{static_cast<XRPAmount>(tx.getFieldVL(sfBlob).size())};
|
||||
|
||||
// old code (prior to fixXahauV1)
|
||||
if (!view.rules().enabled(fixXahauV1))
|
||||
{
|
||||
if (tx.isFieldPresent(sfHookParameters))
|
||||
{
|
||||
uint64_t paramBytes = 0;
|
||||
auto const& params = tx.getFieldArray(sfHookParameters);
|
||||
for (auto const& param : params)
|
||||
{
|
||||
paramBytes +=
|
||||
(param.isFieldPresent(sfHookParameterName)
|
||||
? param.getFieldVL(sfHookParameterName).size()
|
||||
: 0) +
|
||||
(param.isFieldPresent(sfHookParameterValue)
|
||||
? param.getFieldVL(sfHookParameterValue).size()
|
||||
: 0);
|
||||
}
|
||||
extraFee += XRPAmount{static_cast<XRPAmount>(paramBytes)};
|
||||
}
|
||||
}
|
||||
|
||||
return Transactor::calculateBaseFee(view, tx) + extraFee;
|
||||
}
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ NFTokenAcceptOffer::pay(
|
||||
// several payouts in this tx, just confirm that the end state is OK.
|
||||
if (!view().rules().enabled(fixNonFungibleTokensV1_2))
|
||||
return result;
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
return result;
|
||||
if (accountFunds(view(), from, amount, fhZERO_IF_FROZEN, j_).signum() < 0)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
@@ -257,7 +257,7 @@ NFTokenMint::doApply()
|
||||
|
||||
if (TER const ret =
|
||||
nft::insertToken(ctx_.view(), account_, std::move(newToken));
|
||||
ret != tesSUCCESS)
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
// Only check the reserve if the owner count actually changed. This
|
||||
|
||||
@@ -430,7 +430,7 @@ Payment::doApply()
|
||||
|
||||
// TODO: is this right? If the amount is the correct amount, was
|
||||
// the delivered amount previously set?
|
||||
if (rc.result() == tesSUCCESS && rc.actualAmountOut != saDstAmount)
|
||||
if (isTesSuccess(rc.result()) && rc.actualAmountOut != saDstAmount)
|
||||
{
|
||||
if (deliverMin && rc.actualAmountOut < *deliverMin)
|
||||
rc.setResult(tecPATH_PARTIAL);
|
||||
|
||||
@@ -0,0 +1,632 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/tx/impl/Remit.h>
|
||||
#include <ripple/app/tx/impl/URIToken.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/protocol/st.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
TxConsequences
|
||||
Remit::makeTxConsequences(PreflightContext const& ctx)
|
||||
{
|
||||
XRPAmount native = ([&ctx]() -> XRPAmount {
|
||||
if (!ctx.tx.isFieldPresent(sfAmounts))
|
||||
return beast::zero;
|
||||
|
||||
STArray const& sEntries(ctx.tx.getFieldArray(sfAmounts));
|
||||
for (STObject const& sEntry : sEntries)
|
||||
{
|
||||
if (!sEntry.isFieldPresent(sfAmount))
|
||||
continue;
|
||||
|
||||
STAmount const amount = sEntry.getFieldAmount(sfAmount);
|
||||
if (isXRP(amount))
|
||||
return amount.xrp();
|
||||
}
|
||||
return beast::zero;
|
||||
})();
|
||||
return TxConsequences{ctx.tx, native};
|
||||
}
|
||||
|
||||
NotTEC
|
||||
Remit::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (ctx.tx.getFlags() & tfUniversalMask)
|
||||
{
|
||||
// There are no flags (other than universal).
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: Invalid flags set.";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
|
||||
AccountID const dstID = ctx.tx.getAccountID(sfDestination);
|
||||
AccountID const srcID = ctx.tx.getAccountID(sfAccount);
|
||||
|
||||
if (dstID == srcID)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: Remit to self.";
|
||||
return temREDUNDANT;
|
||||
}
|
||||
|
||||
if (ctx.tx.isFieldPresent(sfInform))
|
||||
{
|
||||
AccountID const infID = ctx.tx.getAccountID(sfInform);
|
||||
if (infID == dstID || srcID == infID)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: sfInform is same as "
|
||||
"source or destination.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.tx.isFieldPresent(sfBlob) &&
|
||||
ctx.tx.getFieldVL(sfBlob).size() > (128 * 1024))
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Blob was more than 128kib "
|
||||
<< ctx.tx.getTransactionID();
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
// sanity check amounts
|
||||
if (ctx.tx.isFieldPresent(sfAmounts))
|
||||
{
|
||||
if (ctx.tx.getFieldArray(sfAmounts).size() > 32)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed: AmountEntry count exceeds `32`.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
std::map<Currency, std::set<AccountID>> already;
|
||||
bool nativeAlready = false;
|
||||
|
||||
STArray const& sEntries(ctx.tx.getFieldArray(sfAmounts));
|
||||
for (STObject const& sEntry : sEntries)
|
||||
{
|
||||
// Validate the AmountEntry.
|
||||
if (sEntry.getFName() != sfAmountEntry)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed: Expected AmountEntry.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
STAmount const amount = sEntry.getFieldAmount(sfAmount);
|
||||
if (!isLegalNet(amount) || amount.signum() <= 0)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: bad amount: "
|
||||
<< amount.getFullText();
|
||||
return temBAD_AMOUNT;
|
||||
}
|
||||
|
||||
if (isBadCurrency(amount.getCurrency()))
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: Bad currency.";
|
||||
return temBAD_CURRENCY;
|
||||
}
|
||||
|
||||
if (isXRP(amount))
|
||||
{
|
||||
if (nativeAlready)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: Native "
|
||||
"Currency appears more than once.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
nativeAlready = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto found = already.find(amount.getCurrency());
|
||||
if (found == already.end())
|
||||
{
|
||||
already.emplace(
|
||||
amount.getCurrency(),
|
||||
std::set<AccountID>{amount.getIssuer()});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (found->second.find(amount.getIssuer()) != found->second.end())
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: Issued Currency "
|
||||
"appears more than once.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
found->second.emplace(amount.getIssuer());
|
||||
}
|
||||
}
|
||||
|
||||
// sanity check minturitoken
|
||||
if (ctx.tx.isFieldPresent(sfMintURIToken))
|
||||
{
|
||||
STObject const& mint = const_cast<ripple::STTx&>(ctx.tx)
|
||||
.getField(sfMintURIToken)
|
||||
.downcast<STObject>();
|
||||
|
||||
for (auto const& mintElement : mint)
|
||||
{
|
||||
auto const& name = mintElement.getFName();
|
||||
if (name != sfURI && name != sfFlags && name != sfDigest)
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "Malformed transaction: sfMintURIToken "
|
||||
"contains invalid field.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
}
|
||||
if (!mint.isFieldPresent(sfURI))
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "Malformed transaction: URI was not provided.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
Blob const uri = mint.getFieldVL(sfURI);
|
||||
if (uri.size() < 1 || uri.size() > 256)
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "Malformed transaction: URI was too short/long.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (!URIToken::validateUTF8(uri))
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "Malformed transaction: Invalid UTF8 inside MintURIToken.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (mint.isFieldPresent(sfFlags))
|
||||
{
|
||||
if (mint.getFieldU32(sfFlags) & tfURITokenMintMask)
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
// sanity check uritokenids
|
||||
if (ctx.tx.isFieldPresent(sfURITokenIDs))
|
||||
{
|
||||
STVector256 ids = ctx.tx.getFieldV256(sfURITokenIDs);
|
||||
if (ids.size() < 1 || ids.size() > 32)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: URITokenIDs Invalid.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
std::sort(ids.begin(), ids.end());
|
||||
if (std::adjacent_find(ids.begin(), ids.end()) != ids.end())
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "Malformed transaction: Duplicate URITokenID.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
}
|
||||
|
||||
return preflight2(ctx);
|
||||
}
|
||||
|
||||
TER
|
||||
Remit::doApply()
|
||||
{
|
||||
Sandbox sb(&ctx_.view());
|
||||
|
||||
if (!sb.rules().enabled(featureRemit))
|
||||
return temDISABLED;
|
||||
|
||||
beast::Journal const& j = ctx_.journal;
|
||||
|
||||
auto const srcAccID = ctx_.tx[sfAccount];
|
||||
|
||||
auto sleSrcAcc = sb.peek(keylet::account(srcAccID));
|
||||
if (!sleSrcAcc)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
if (ctx_.tx.isFieldPresent(sfInform))
|
||||
{
|
||||
auto const informAcc = ctx_.tx.getAccountID(sfInform);
|
||||
if (!sb.exists(keylet::account(informAcc)))
|
||||
{
|
||||
JLOG(j.warn()) << "Remit: sfInform account does not exist.";
|
||||
return tecNO_TARGET;
|
||||
}
|
||||
}
|
||||
|
||||
XRPAmount const accountReserve{sb.fees().accountReserve(0)};
|
||||
XRPAmount const objectReserve{sb.fees().accountReserve(1) - accountReserve};
|
||||
|
||||
// sanity check
|
||||
if (accountReserve < beast::zero || objectReserve < beast::zero ||
|
||||
objectReserve > sb.fees().accountReserve(1))
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "Remit: account or object reserve calculation not sane.";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
// amount of native tokens we will transfer to cover reserves for the
|
||||
// tls/acc/uritokens created, and native tokens listed in amounts
|
||||
XRPAmount nativeRemit{0};
|
||||
|
||||
AccountID const dstAccID{ctx_.tx[sfDestination]};
|
||||
auto sleDstAcc = sb.peek(keylet::account(dstAccID));
|
||||
auto const flags = !sleDstAcc ? 0 : sleDstAcc->getFlags();
|
||||
|
||||
// Check if the destination has disallowed incoming
|
||||
if (sb.rules().enabled(featureDisallowIncoming) &&
|
||||
(flags & lsfDisallowIncomingRemit))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// Check if the destination account requires deposit authorization.
|
||||
bool const depositAuth{sb.rules().enabled(featureDepositAuth)};
|
||||
if (depositAuth && sleDstAcc && (flags & lsfDepositAuth))
|
||||
{
|
||||
if (!sb.exists(keylet::depositPreauth(dstAccID, srcAccID)))
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
// the destination may require a dest tag
|
||||
if ((flags & lsfRequireDestTag) &&
|
||||
!ctx_.tx.isFieldPresent(sfDestinationTag))
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "Remit: DestinationTag required for this destination.";
|
||||
return tecDST_TAG_NEEDED;
|
||||
}
|
||||
|
||||
// if the destination doesn't exist, create it.
|
||||
bool const createDst = !sleDstAcc;
|
||||
if (createDst)
|
||||
{
|
||||
// sender will pay the reserve
|
||||
if (nativeRemit + accountReserve < nativeRemit)
|
||||
return tecINTERNAL;
|
||||
|
||||
nativeRemit += accountReserve;
|
||||
|
||||
// Create the account.
|
||||
std::uint32_t const seqno{
|
||||
sb.rules().enabled(featureXahauGenesis)
|
||||
? sb.info().parentCloseTime.time_since_epoch().count()
|
||||
: sb.rules().enabled(featureDeletableAccounts) ? sb.seq() : 1};
|
||||
|
||||
sleDstAcc = std::make_shared<SLE>(keylet::account(dstAccID));
|
||||
sleDstAcc->setAccountID(sfAccount, dstAccID);
|
||||
|
||||
sleDstAcc->setFieldU32(sfSequence, seqno);
|
||||
sleDstAcc->setFieldU32(sfOwnerCount, 0);
|
||||
|
||||
if (sb.exists(keylet::fees()) &&
|
||||
sb.rules().enabled(featureXahauGenesis))
|
||||
{
|
||||
auto sleFees = sb.peek(keylet::fees());
|
||||
uint64_t accIdx = sleFees->isFieldPresent(sfAccountCount)
|
||||
? sleFees->getFieldU64(sfAccountCount)
|
||||
: 0;
|
||||
sleDstAcc->setFieldU64(sfAccountIndex, accIdx);
|
||||
sleFees->setFieldU64(sfAccountCount, accIdx + 1);
|
||||
sb.update(sleFees);
|
||||
}
|
||||
|
||||
// we'll fix this up at the end
|
||||
sleDstAcc->setFieldAmount(sfBalance, STAmount{XRPAmount{0}});
|
||||
sb.insert(sleDstAcc);
|
||||
}
|
||||
|
||||
// if theres a minted uritoken the sender pays for that
|
||||
if (ctx_.tx.isFieldPresent(sfMintURIToken))
|
||||
{
|
||||
if (nativeRemit + objectReserve < nativeRemit)
|
||||
return tecINTERNAL;
|
||||
|
||||
nativeRemit += objectReserve;
|
||||
STObject const& mint = const_cast<ripple::STTx&>(ctx_.tx)
|
||||
.getField(sfMintURIToken)
|
||||
.downcast<STObject>();
|
||||
|
||||
Blob const& mintURI = mint.getFieldVL(sfURI);
|
||||
|
||||
std::optional<uint256> mintDigest;
|
||||
if (mint.isFieldPresent(sfDigest))
|
||||
mintDigest = mint.getFieldH256(sfDigest);
|
||||
|
||||
Keylet kl = keylet::uritoken(srcAccID, mintURI);
|
||||
|
||||
// check that it doesn't already exist
|
||||
if (sb.exists(kl))
|
||||
{
|
||||
JLOG(j.trace()) << "Remit: tried to creat duplicate URIToken. Tx: "
|
||||
<< ctx_.tx.getTransactionID();
|
||||
return tecDUPLICATE;
|
||||
}
|
||||
|
||||
auto sleMint = std::make_shared<SLE>(kl);
|
||||
|
||||
sleMint->setAccountID(sfOwner, dstAccID);
|
||||
sleMint->setAccountID(sfIssuer, srcAccID);
|
||||
|
||||
sleMint->setFieldVL(sfURI, mintURI);
|
||||
|
||||
if (mint.isFieldPresent(sfDigest))
|
||||
sleMint->setFieldH256(sfDigest, mint.getFieldH256(sfDigest));
|
||||
|
||||
sleMint->setFieldU32(
|
||||
sfFlags,
|
||||
mint.isFieldPresent(sfFlags) ? mint.getFieldU32(sfFlags) : 0);
|
||||
|
||||
auto const page = sb.dirInsert(
|
||||
keylet::ownerDir(dstAccID), kl, describeOwnerDir(dstAccID));
|
||||
|
||||
JLOG(j_.trace()) << "Adding URIToken to owner directory "
|
||||
<< to_string(kl.key) << ": "
|
||||
<< (page ? "success" : "failure");
|
||||
|
||||
if (!page)
|
||||
return tecDIR_FULL;
|
||||
|
||||
sleMint->setFieldU64(sfOwnerNode, *page);
|
||||
sb.insert(sleMint);
|
||||
|
||||
// ensure there is a deletion blocker against the issuer now
|
||||
sleSrcAcc->setFieldU32(
|
||||
sfFlags, sleSrcAcc->getFlags() | lsfURITokenIssuer);
|
||||
|
||||
adjustOwnerCount(sb, sleDstAcc, 1, j);
|
||||
}
|
||||
|
||||
// iterate uritokens
|
||||
if (ctx_.tx.isFieldPresent(sfURITokenIDs))
|
||||
{
|
||||
STVector256 ids = ctx_.tx.getFieldV256(sfURITokenIDs);
|
||||
for (uint256 const klRaw : ids)
|
||||
{
|
||||
Keylet kl = keylet::unchecked(klRaw);
|
||||
auto sleU = sb.peek(kl);
|
||||
|
||||
// does it exist
|
||||
if (!sleU)
|
||||
{
|
||||
JLOG(j.warn()) << "Remit: one or more uritokens did not exist "
|
||||
"on the source account.";
|
||||
return tecNO_ENTRY;
|
||||
}
|
||||
|
||||
// is it a uritoken?
|
||||
if (sleU->getFieldU16(sfLedgerEntryType) != ltURI_TOKEN)
|
||||
{
|
||||
JLOG(j.warn()) << "Remit: one or more supplied URITokenIDs was "
|
||||
"not actually a uritoken.";
|
||||
return tecNO_ENTRY;
|
||||
}
|
||||
|
||||
// is it our uritoken?
|
||||
if (sleU->getAccountID(sfOwner) != srcAccID)
|
||||
{
|
||||
JLOG(j.warn()) << "Remit: one or more supplied URITokenIDs was "
|
||||
"not owned by sender.";
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
// erase current sale offers, if any
|
||||
if (sleU->isFieldPresent(sfAmount))
|
||||
sleU->makeFieldAbsent(sfAmount);
|
||||
if (sleU->isFieldPresent(sfDestination))
|
||||
sleU->makeFieldAbsent(sfDestination);
|
||||
|
||||
// pay the reserve
|
||||
if (nativeRemit + objectReserve < nativeRemit)
|
||||
return tecINTERNAL;
|
||||
|
||||
nativeRemit += objectReserve;
|
||||
|
||||
// remove from sender dir
|
||||
{
|
||||
auto const page = (*sleU)[sfOwnerNode];
|
||||
if (!sb.dirRemove(
|
||||
keylet::ownerDir(srcAccID), page, kl.key, true))
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "Could not remove URIToken from owner directory";
|
||||
return tefBAD_LEDGER;
|
||||
}
|
||||
|
||||
adjustOwnerCount(sb, sleSrcAcc, -1, j);
|
||||
}
|
||||
|
||||
// add to dest dir
|
||||
{
|
||||
auto const page = sb.dirInsert(
|
||||
keylet::ownerDir(dstAccID), kl, describeOwnerDir(dstAccID));
|
||||
|
||||
JLOG(j_.trace()) << "Adding URIToken to owner directory "
|
||||
<< to_string(kl.key) << ": "
|
||||
<< (page ? "success" : "failure");
|
||||
|
||||
if (!page)
|
||||
return tecDIR_FULL;
|
||||
|
||||
sleU->setFieldU64(sfOwnerNode, *page);
|
||||
|
||||
adjustOwnerCount(sb, sleDstAcc, 1, j);
|
||||
}
|
||||
|
||||
// change the owner
|
||||
sleU->setAccountID(sfOwner, dstAccID);
|
||||
|
||||
sb.update(sleU);
|
||||
}
|
||||
}
|
||||
|
||||
// iterate trustlines
|
||||
if (ctx_.tx.isFieldPresent(sfAmounts))
|
||||
{
|
||||
// process trustline remits
|
||||
STArray const& sEntries(ctx_.tx.getFieldArray(sfAmounts));
|
||||
for (STObject const& sEntry : sEntries)
|
||||
{
|
||||
STAmount const amount = sEntry.getFieldAmount(sfAmount);
|
||||
if (isXRP(amount))
|
||||
{
|
||||
// since we have to pay for all the created objects including
|
||||
// possibly the account itself this is paid right at the end,
|
||||
// and only if there is balance enough to cover.
|
||||
|
||||
// check for overflow
|
||||
if (nativeRemit + amount.xrp() < nativeRemit)
|
||||
return tecINTERNAL;
|
||||
|
||||
nativeRemit += amount.xrp();
|
||||
continue;
|
||||
}
|
||||
|
||||
AccountID const issuerAccID = amount.getIssuer();
|
||||
|
||||
// check permissions
|
||||
if (issuerAccID == srcAccID || issuerAccID == dstAccID)
|
||||
{
|
||||
// no permission check needed when the issuer sends out or a
|
||||
// subscriber sends back RH TODO: move this condition into
|
||||
// trustTransferAllowed, guarded by an amendment
|
||||
}
|
||||
else if (TER canXfer = trustTransferAllowed(
|
||||
sb,
|
||||
std::vector<AccountID>{srcAccID, dstAccID},
|
||||
amount.issue(),
|
||||
j);
|
||||
!isTesSuccess(canXfer))
|
||||
return canXfer;
|
||||
|
||||
// compute the amount the source will need to send
|
||||
// in remit the sender pays all transfer fees, so that
|
||||
// the destination can always be assured they got the exact amount
|
||||
// specified. therefore we need to compute the amount + transfer fee
|
||||
auto const srcAmt =
|
||||
issuerAccID != srcAccID && issuerAccID != dstAccID
|
||||
? multiply(amount, transferRate(sb, issuerAccID))
|
||||
: amount;
|
||||
|
||||
// sanity check this calculation
|
||||
if (srcAmt < amount || srcAmt > amount + amount)
|
||||
{
|
||||
JLOG(j.warn()) << "Remit: srcAmt calculation not sane.";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
STAmount availableFunds{
|
||||
accountFunds(sb, srcAccID, srcAmt, fhZERO_IF_FROZEN, j)};
|
||||
|
||||
if (availableFunds < srcAmt)
|
||||
return tecUNFUNDED_PAYMENT;
|
||||
|
||||
// if the target trustline doesn't exist we need to create it and
|
||||
// pay its reserve
|
||||
if (!sb.exists(
|
||||
keylet::line(dstAccID, issuerAccID, amount.getCurrency())))
|
||||
{
|
||||
if (nativeRemit + objectReserve < nativeRemit)
|
||||
return tecINTERNAL;
|
||||
|
||||
nativeRemit += objectReserve;
|
||||
}
|
||||
|
||||
// action the transfer
|
||||
if (TER result =
|
||||
accountSend(sb, srcAccID, dstAccID, amount, j, true);
|
||||
!isTesSuccess(result))
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (nativeRemit < beast::zero)
|
||||
return tecINTERNAL;
|
||||
|
||||
if (nativeRemit > beast::zero)
|
||||
{
|
||||
// ensure the account can cover the native remit
|
||||
if (mSourceBalance < nativeRemit)
|
||||
return tecUNFUNDED_PAYMENT;
|
||||
|
||||
// subtract the balance from the sender
|
||||
{
|
||||
STAmount bal = mSourceBalance;
|
||||
bal -= nativeRemit;
|
||||
if (bal < beast::zero || bal > mSourceBalance)
|
||||
return tecINTERNAL;
|
||||
sleSrcAcc->setFieldAmount(sfBalance, bal);
|
||||
}
|
||||
|
||||
// add the balance to the destination
|
||||
{
|
||||
STAmount bal = sleDstAcc->getFieldAmount(sfBalance);
|
||||
STAmount prior = bal;
|
||||
bal += nativeRemit;
|
||||
if (bal < beast::zero || bal < prior)
|
||||
return tecINTERNAL;
|
||||
sleDstAcc->setFieldAmount(sfBalance, bal);
|
||||
}
|
||||
}
|
||||
|
||||
auto hasSufficientReserve = [&](std::shared_ptr<SLE> const& sle) -> bool {
|
||||
std::uint32_t const uOwnerCount = sle->getFieldU32(sfOwnerCount);
|
||||
return sle->getFieldAmount(sfBalance) >=
|
||||
sb.fees().accountReserve(uOwnerCount);
|
||||
};
|
||||
|
||||
// sanity check reserves
|
||||
if (!hasSufficientReserve(sleSrcAcc))
|
||||
{
|
||||
JLOG(j.warn()) << "Remit: sender " << srcAccID
|
||||
<< " lacks reserves to cover send.";
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
|
||||
// this isn't actually an error but we will print a warning
|
||||
// this can occur if the destination was already below reserve level at the
|
||||
// time assets were sent
|
||||
if (!hasSufficientReserve(sleDstAcc))
|
||||
{
|
||||
JLOG(j.warn()) << "Remit: destination has insufficient reserves.";
|
||||
}
|
||||
|
||||
// apply
|
||||
sb.update(sleSrcAcc);
|
||||
sb.update(sleDstAcc);
|
||||
sb.apply(ctx_.rawView());
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
Remit::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
XRPAmount extraFee{0};
|
||||
|
||||
if (tx.isFieldPresent(sfBlob))
|
||||
extraFee +=
|
||||
XRPAmount{static_cast<XRPAmount>(tx.getFieldVL(sfBlob).size())};
|
||||
|
||||
return Transactor::calculateBaseFee(view, tx) + extraFee;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -0,0 +1,54 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TX_SIMPLE_PAYMENT_H_INCLUDED
|
||||
#define RIPPLE_TX_SIMPLE_PAYMENT_H_INCLUDED
|
||||
|
||||
#include <ripple/app/tx/impl/Transactor.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class Remit : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
|
||||
explicit Remit(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -577,6 +577,14 @@ SetAccount::doApply()
|
||||
uFlagsOut |= lsfDisallowIncomingTrustline;
|
||||
else if (uClearFlag == asfDisallowIncomingTrustline)
|
||||
uFlagsOut &= ~lsfDisallowIncomingTrustline;
|
||||
|
||||
if (ctx_.view().rules().enabled(featureRemit))
|
||||
{
|
||||
if (uSetFlag == asfDisallowIncomingRemit)
|
||||
uFlagsOut |= lsfDisallowIncomingRemit;
|
||||
else if (uClearFlag == asfDisallowIncomingRemit)
|
||||
uFlagsOut &= ~lsfDisallowIncomingRemit;
|
||||
}
|
||||
}
|
||||
|
||||
if (uFlagsIn != uFlagsOut)
|
||||
|
||||
@@ -794,21 +794,12 @@ SetHook::destroyNamespace(
|
||||
return tefBAD_LEDGER;
|
||||
}
|
||||
|
||||
bool sleAccChanged = false;
|
||||
|
||||
if (!sleAccount->isFieldPresent(sfHookNamespaces))
|
||||
{
|
||||
// NSDELETE is an opportunistic deleter, following "delete if exists"
|
||||
// logic this way the flag can't block the SetHook transaction just
|
||||
// because, for example, the namespace was deleted in the previous
|
||||
// transaction but the hsFlags have not changed. Thus this is not an
|
||||
// error. Allow fall through to below in case, for some reason, the
|
||||
// namespace directory *does* exist but does not appear in the vector.
|
||||
}
|
||||
else
|
||||
{
|
||||
sleAccChanged = hook::removeHookNamespaceEntry(*sleAccount, ns);
|
||||
}
|
||||
// NSDELETE is an opportunistic deleter, following "delete if exists"
|
||||
// logic this way the flag can't block the SetHook transaction just
|
||||
// because, for example, the namespace was deleted in the previous
|
||||
// transaction but the hsFlags have not changed. Thus this is not an
|
||||
// error. Allow fall through to below in case, for some reason, the
|
||||
// namespace directory *does* exist but does not appear in the vector.
|
||||
|
||||
Keylet dirKeylet = keylet::hookStateDir(account, ns);
|
||||
|
||||
@@ -818,21 +809,16 @@ SetHook::destroyNamespace(
|
||||
|
||||
auto sleDir = view.peek(dirKeylet);
|
||||
|
||||
if (!sleDir)
|
||||
{
|
||||
// directory doesn't exist, this is a success condition
|
||||
if (sleAccChanged)
|
||||
view.update(sleAccount);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
bool const dirExists = !!sleDir;
|
||||
bool const dirEmpty = dirExists && dirIsEmpty(view, dirKeylet);
|
||||
|
||||
if (dirIsEmpty(view, dirKeylet))
|
||||
if (!dirExists || dirEmpty)
|
||||
{
|
||||
// directory exists but is empty, so remove the root page
|
||||
if (sleAccChanged)
|
||||
// directory doesn't exist or is empty, this is a success condition
|
||||
if (hook::removeHookNamespaceEntry(*sleAccount, ns))
|
||||
view.update(sleAccount);
|
||||
|
||||
view.erase(sleDir);
|
||||
if (dirExists)
|
||||
view.erase(sleDir);
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -845,13 +831,20 @@ SetHook::destroyNamespace(
|
||||
return tefINTERNAL;
|
||||
}
|
||||
|
||||
uint32_t stateCount = sleAccount->getFieldU32(sfHookStateCount);
|
||||
uint32_t oldStateCount = stateCount;
|
||||
bool const fixEnabled = ctx.rules.enabled(fixNSDelete);
|
||||
bool partialDelete = false;
|
||||
uint32_t oldStateCount = sleAccount->getFieldU32(sfHookStateCount);
|
||||
|
||||
std::vector<uint256> toDelete;
|
||||
toDelete.reserve(sleDir->getFieldV256(sfIndexes).size());
|
||||
do
|
||||
{
|
||||
if (fixEnabled && toDelete.size() >= hook::maxNamespaceDelete())
|
||||
{
|
||||
partialDelete = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Make sure any directory node types that we find are the kind
|
||||
// we can delete.
|
||||
Keylet const itemKeylet{ltCHILD, dirEntry};
|
||||
@@ -910,9 +903,9 @@ SetHook::destroyNamespace(
|
||||
return tefBAD_LEDGER;
|
||||
}
|
||||
view.erase(sleItem);
|
||||
stateCount--;
|
||||
}
|
||||
|
||||
uint32_t stateCount = oldStateCount - toDelete.size();
|
||||
if (stateCount > oldStateCount)
|
||||
{
|
||||
JLOG(ctx.j.fatal()) << "HookSet(" << hook::log::NSDELETE_COUNT << ")["
|
||||
@@ -927,9 +920,14 @@ SetHook::destroyNamespace(
|
||||
else
|
||||
sleAccount->setFieldU32(sfHookStateCount, stateCount);
|
||||
|
||||
view.update(sleAccount);
|
||||
if (ctx.rules.enabled(fixNSDelete))
|
||||
adjustOwnerCount(view, sleAccount, -toDelete.size(), ctx.j);
|
||||
|
||||
return tesSUCCESS;
|
||||
if (!partialDelete && sleAccount->isFieldPresent(sfHookNamespaces))
|
||||
hook::removeHookNamespaceEntry(*sleAccount, ns);
|
||||
|
||||
view.update(sleAccount);
|
||||
return partialDelete ? tesPARTIAL : tesSUCCESS;
|
||||
}
|
||||
|
||||
// returns true if the reference counted ledger entry should be marked for
|
||||
@@ -1453,7 +1451,7 @@ SetHook::setHook()
|
||||
TER result = updateHookParameters(
|
||||
ctx, hookSetObj->get(), oldDefSLE, oldParams, newHook);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1696,7 +1694,7 @@ SetHook::setHook()
|
||||
STArray{sfHookParameters},
|
||||
newHook);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
return result;
|
||||
|
||||
// if grants are provided set them
|
||||
@@ -1790,6 +1788,7 @@ SetHook::setHook()
|
||||
if (mSourceBalance < requiredDrops)
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
}
|
||||
TER nsDeleteResult = tesSUCCESS;
|
||||
{
|
||||
// execution to here means we will enact changes to the ledger:
|
||||
|
||||
@@ -1804,7 +1803,9 @@ SetHook::setHook()
|
||||
// clean up any Namespace directories marked for deletion and any zero
|
||||
// reference Hook Definitions
|
||||
for (auto const& ns : namespacesToDestroy)
|
||||
destroyNamespace(ctx, view(), account_, ns);
|
||||
if (nsDeleteResult = destroyNamespace(ctx, view(), account_, ns);
|
||||
!isTesSuccess(nsDeleteResult))
|
||||
break;
|
||||
|
||||
// do any pending removals
|
||||
for (auto const& p : keyletsToDestroy)
|
||||
@@ -1856,6 +1857,10 @@ SetHook::setHook()
|
||||
else if (oldHookSLE && !newHooksEmpty)
|
||||
{
|
||||
// UPDATE ltHOOK
|
||||
if (view().rules().enabled(fixXahauV1))
|
||||
{
|
||||
(*newHookSLE)[sfOwnerNode] = (*oldHookSLE)[sfOwnerNode];
|
||||
}
|
||||
view().erase(oldHookSLE);
|
||||
view().insert(newHookSLE);
|
||||
}
|
||||
@@ -1891,7 +1896,7 @@ SetHook::setHook()
|
||||
view().update(accountSLE);
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
return nsDeleteResult;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -83,7 +83,7 @@ SetSignerList::preflight(PreflightContext const& ctx)
|
||||
|
||||
auto const result = determineOperation(ctx.tx, ctx.flags, ctx.j);
|
||||
|
||||
if (std::get<0>(result) != tesSUCCESS)
|
||||
if (!isTesSuccess(std::get<0>(result)))
|
||||
return std::get<0>(result);
|
||||
|
||||
if (std::get<3>(result) == unknown)
|
||||
@@ -104,7 +104,7 @@ SetSignerList::preflight(PreflightContext const& ctx)
|
||||
account,
|
||||
ctx.j,
|
||||
ctx.rules);
|
||||
if (ter != tesSUCCESS)
|
||||
if (!isTesSuccess(ter))
|
||||
{
|
||||
return ter;
|
||||
}
|
||||
@@ -137,7 +137,7 @@ SetSignerList::preCompute()
|
||||
{
|
||||
// Get the quorum and operation info.
|
||||
auto result = determineOperation(ctx_.tx, view().flags(), j_);
|
||||
assert(std::get<0>(result) == tesSUCCESS);
|
||||
assert(isTesSuccess(std::get<0>(result)));
|
||||
assert(std::get<3>(result) != unknown);
|
||||
|
||||
quorum_ = std::get<1>(result);
|
||||
@@ -153,8 +153,10 @@ SetSignerList::preCompute()
|
||||
// NOTE: This way of computing the OwnerCount associated with a SignerList
|
||||
// is valid until the featureMultiSignReserve amendment passes. Once it
|
||||
// passes then just 1 OwnerCount is associated with a SignerList.
|
||||
static int
|
||||
signerCountBasedOwnerCountDelta(std::size_t entryCount, Rules const& rules)
|
||||
int
|
||||
SetSignerList::signerCountBasedOwnerCountDelta(
|
||||
std::size_t entryCount,
|
||||
Rules const& rules)
|
||||
{
|
||||
// We always compute the full change in OwnerCount, taking into account:
|
||||
// o The fact that we're adding/removing a SignerList and
|
||||
@@ -176,8 +178,8 @@ signerCountBasedOwnerCountDelta(std::size_t entryCount, Rules const& rules)
|
||||
return 2 + static_cast<int>(entryCount);
|
||||
}
|
||||
|
||||
static TER
|
||||
removeSignersFromLedger(
|
||||
TER
|
||||
SetSignerList::removeSignersFromLedger(
|
||||
Application& app,
|
||||
ApplyView& view,
|
||||
Keylet const& accountKeylet,
|
||||
|
||||
@@ -71,6 +71,18 @@ public:
|
||||
AccountID const& account,
|
||||
beast::Journal j);
|
||||
|
||||
static TER
|
||||
removeSignersFromLedger(
|
||||
Application& app,
|
||||
ApplyView& view,
|
||||
Keylet const& accountKeylet,
|
||||
Keylet const& ownerDirKeylet,
|
||||
Keylet const& signerListKeylet,
|
||||
beast::Journal j);
|
||||
|
||||
static int
|
||||
signerCountBasedOwnerCountDelta(std::size_t entryCount, Rules const& rules);
|
||||
|
||||
private:
|
||||
static void
|
||||
writeSignersToSLE(
|
||||
|
||||
@@ -116,7 +116,7 @@ SignerEntries::determineOperation(
|
||||
// Rules const& rules)
|
||||
// {
|
||||
|
||||
// if (ter != tesSUCCESS)
|
||||
// if (!isTesSuccess(ter))
|
||||
// return ter;
|
||||
|
||||
// if (op == unknown)
|
||||
@@ -137,7 +137,7 @@ SignerEntries::determineOperation(
|
||||
// account,
|
||||
// j,
|
||||
// rules);
|
||||
// if (ter != tesSUCCESS)
|
||||
// if (!isTesSuccess(ter))
|
||||
// {
|
||||
// return ter;
|
||||
// }
|
||||
|
||||
@@ -691,11 +691,11 @@ Taker::fill(BasicTaker::Flow const& flow, Offer& offer)
|
||||
{
|
||||
assert(!isXRP(flow.order.in));
|
||||
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
result =
|
||||
redeemIOU(account(), flow.issuers.in, flow.issuers.in.issue());
|
||||
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
result =
|
||||
issueIOU(offer.owner(), flow.order.in, flow.order.in.issue());
|
||||
}
|
||||
@@ -703,7 +703,7 @@ Taker::fill(BasicTaker::Flow const& flow, Offer& offer)
|
||||
{
|
||||
assert(isXRP(flow.order.in));
|
||||
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
result = transferXRP(account(), offer.owner(), flow.order.in);
|
||||
}
|
||||
|
||||
@@ -712,11 +712,11 @@ Taker::fill(BasicTaker::Flow const& flow, Offer& offer)
|
||||
{
|
||||
assert(!isXRP(flow.order.out));
|
||||
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
result = redeemIOU(
|
||||
offer.owner(), flow.issuers.out, flow.issuers.out.issue());
|
||||
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
result =
|
||||
issueIOU(account(), flow.order.out, flow.order.out.issue());
|
||||
}
|
||||
@@ -724,11 +724,11 @@ Taker::fill(BasicTaker::Flow const& flow, Offer& offer)
|
||||
{
|
||||
assert(isXRP(flow.order.out));
|
||||
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
result = transferXRP(offer.owner(), account(), flow.order.out);
|
||||
}
|
||||
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
direct_crossings_++;
|
||||
|
||||
return result;
|
||||
@@ -751,32 +751,32 @@ Taker::fill(
|
||||
// Taker to leg1: IOU
|
||||
if (leg1.owner() != account())
|
||||
{
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
result = redeemIOU(
|
||||
account(), flow1.issuers.in, flow1.issuers.in.issue());
|
||||
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
result =
|
||||
issueIOU(leg1.owner(), flow1.order.in, flow1.order.in.issue());
|
||||
}
|
||||
|
||||
// leg1 to leg2: bridging over XRP
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
result = transferXRP(leg1.owner(), leg2.owner(), flow1.order.out);
|
||||
|
||||
// leg2 to Taker: IOU
|
||||
if (leg2.owner() != account())
|
||||
{
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
result = redeemIOU(
|
||||
leg2.owner(), flow2.issuers.out, flow2.issuers.out.issue());
|
||||
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
result =
|
||||
issueIOU(account(), flow2.order.out, flow2.order.out.issue());
|
||||
}
|
||||
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
{
|
||||
bridge_crossings_++;
|
||||
xrp_flow_ += flow1.order.out;
|
||||
|
||||
@@ -351,7 +351,7 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
XRPAmount accumulator = baseFee;
|
||||
|
||||
if (view.rules().enabled(featureHooks) &&
|
||||
tx.isFieldPresent(sfHookParameters))
|
||||
view.rules().enabled(fixXahauV1) && tx.isFieldPresent(sfHookParameters))
|
||||
{
|
||||
uint64_t paramBytes = 0;
|
||||
auto const& params = tx.getFieldArray(sfHookParameters);
|
||||
@@ -648,6 +648,43 @@ Transactor::checkPriorTxAndLastLedger(PreclaimContext const& ctx)
|
||||
if (ctx.view.txExists(ctx.tx.getTransactionID()))
|
||||
return tefALREADY;
|
||||
|
||||
if (hook::isEmittedTxn(ctx.tx) && ctx.view.rules().enabled(featureHooks) &&
|
||||
ctx.view.rules().enabled(fixXahauV2))
|
||||
{
|
||||
// check if the emitted txn exists on ledger and is in the emission
|
||||
// directory if not that's a re-apply so discard
|
||||
auto const kl = keylet::emittedTxn(ctx.tx.getTransactionID());
|
||||
auto const sleE = ctx.view.read(kl);
|
||||
if (!sleE)
|
||||
return tefNONDIR_EMIT;
|
||||
|
||||
// lookup the page
|
||||
uint64_t const page = sleE->getFieldU64(sfOwnerNode);
|
||||
auto node = ctx.view.read(keylet::page(keylet::emittedDir(), page));
|
||||
|
||||
if (!node)
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "applyTransaction: orphaned emitted txn detected. keylet="
|
||||
<< to_string(kl.key);
|
||||
|
||||
// RH TODO: work out how to safely delete the object
|
||||
return tefNONDIR_EMIT;
|
||||
}
|
||||
|
||||
auto entries = node->getFieldV256(sfIndexes);
|
||||
auto it = std::find(entries.begin(), entries.end(), kl.key);
|
||||
if (entries.end() == it)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "applyTransaction: orphaned emitted txn "
|
||||
"detected (2). keylet="
|
||||
<< to_string(kl.key);
|
||||
|
||||
// RH TODO: work out how to safely delete the object
|
||||
return tefNONDIR_EMIT;
|
||||
}
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -757,11 +794,11 @@ Transactor::apply()
|
||||
mSourceBalance = mPriorBalance;
|
||||
|
||||
TER result = consumeSeqProxy(sle);
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
return result;
|
||||
|
||||
result = payFee();
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
return result;
|
||||
|
||||
if (sle->isFieldPresent(sfAccountTxnID))
|
||||
@@ -1550,7 +1587,7 @@ Transactor::doTSH(
|
||||
TER tshResult = executeHookChain(
|
||||
tshHook, stateMap, results, tshAccountID, strong, provisionalMeta);
|
||||
|
||||
if (canRollback && (tshResult != tesSUCCESS))
|
||||
if (canRollback && (!isTesSuccess(tshResult)))
|
||||
return tshResult;
|
||||
}
|
||||
|
||||
@@ -1701,7 +1738,7 @@ Transactor::operator()()
|
||||
// Pre-application (Strong TSH) Hooks are executed here
|
||||
// These TSH have the right to rollback.
|
||||
// Weak TSH and callback are executed post-application.
|
||||
if (hooksEnabled && result == tesSUCCESS)
|
||||
if (hooksEnabled && isTesSuccess(result))
|
||||
{
|
||||
// this state map will be shared across all hooks in this execution
|
||||
// chain and any associated chains which are executed during this
|
||||
@@ -1752,7 +1789,7 @@ Transactor::operator()()
|
||||
}
|
||||
|
||||
// fall through allows normal apply
|
||||
if (result == tesSUCCESS)
|
||||
if (isTesSuccess(result))
|
||||
result = apply();
|
||||
|
||||
// No transaction can return temUNKNOWN from apply,
|
||||
@@ -1884,6 +1921,13 @@ Transactor::operator()()
|
||||
STObject const meta = metaRaw.getAsObject();
|
||||
|
||||
uint32_t lgrCur = view().seq();
|
||||
|
||||
bool const has240819 = view().rules().enabled(fix240819);
|
||||
bool const has240911 = view().rules().enabled(fix240911);
|
||||
|
||||
auto const& sfRewardFields =
|
||||
*(ripple::SField::knownCodeToField.at(917511 - has240819));
|
||||
|
||||
// iterate all affected balances
|
||||
for (auto const& node : meta.getFieldArray(sfAffectedNodes))
|
||||
{
|
||||
@@ -1895,7 +1939,7 @@ Transactor::operator()()
|
||||
if (nodeType != ltACCOUNT_ROOT || metaType == sfDeletedNode)
|
||||
continue;
|
||||
|
||||
if (!node.isFieldPresent(sfFinalFields) ||
|
||||
if (!node.isFieldPresent(sfRewardFields) ||
|
||||
!node.isFieldPresent(sfLedgerIndex))
|
||||
continue;
|
||||
|
||||
@@ -1911,7 +1955,7 @@ Transactor::operator()()
|
||||
continue;
|
||||
|
||||
STObject& finalFields = (const_cast<STObject&>(node))
|
||||
.getField(sfFinalFields)
|
||||
.getField(sfRewardFields)
|
||||
.downcast<STObject>();
|
||||
|
||||
if (!finalFields.isFieldPresent(sfBalance))
|
||||
@@ -1928,7 +1972,11 @@ Transactor::operator()()
|
||||
uint32_t lgrElapsed = lgrCur - lgrLast;
|
||||
|
||||
// overflow safety
|
||||
if (lgrElapsed > lgrCur || lgrElapsed > lgrLast || lgrElapsed == 0)
|
||||
if (!has240911 &&
|
||||
(lgrElapsed > lgrCur || lgrElapsed > lgrLast ||
|
||||
lgrElapsed == 0))
|
||||
continue;
|
||||
if (has240911 && (lgrElapsed > lgrCur || lgrElapsed == 0))
|
||||
continue;
|
||||
|
||||
uint64_t accum = sle->getFieldU64(sfRewardAccumulator);
|
||||
|
||||
+562
-339
File diff suppressed because it is too large.
Load diff
@@ -23,6 +23,7 @@
|
||||
#include <ripple/app/tx/impl/CancelOffer.h>
|
||||
#include <ripple/app/tx/impl/CashCheck.h>
|
||||
#include <ripple/app/tx/impl/Change.h>
|
||||
#include <ripple/app/tx/impl/ClaimReward.h>
|
||||
#include <ripple/app/tx/impl/CreateCheck.h>
|
||||
#include <ripple/app/tx/impl/CreateOffer.h>
|
||||
#include <ripple/app/tx/impl/CreateTicket.h>
|
||||
@@ -39,12 +40,14 @@
|
||||
#include <ripple/app/tx/impl/NFTokenMint.h>
|
||||
#include <ripple/app/tx/impl/PayChan.h>
|
||||
#include <ripple/app/tx/impl/Payment.h>
|
||||
#include <ripple/app/tx/impl/Remit.h>
|
||||
#include <ripple/app/tx/impl/SetAccount.h>
|
||||
#include <ripple/app/tx/impl/SetHook.h>
|
||||
#include <ripple/app/tx/impl/SetRegularKey.h>
|
||||
#include <ripple/app/tx/impl/SetSignerList.h>
|
||||
#include <ripple/app/tx/impl/SetTrust.h>
|
||||
#include <ripple/app/tx/impl/URIToken.h>
|
||||
#include <ripple/app/tx/impl/XahauGenesis.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -164,6 +167,8 @@ invoke_preflight(PreflightContext const& ctx)
|
||||
return invoke_preflight_helper<Import>(ctx);
|
||||
case ttINVOKE:
|
||||
return invoke_preflight_helper<Invoke>(ctx);
|
||||
case ttREMIT:
|
||||
return invoke_preflight_helper<Remit>(ctx);
|
||||
case ttURITOKEN_MINT:
|
||||
case ttURITOKEN_BURN:
|
||||
case ttURITOKEN_BUY:
|
||||
@@ -192,22 +197,22 @@ invoke_preclaim(PreclaimContext const& ctx)
|
||||
{
|
||||
TER result = T::checkSeqProxy(ctx.view, ctx.tx, ctx.j);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
return result;
|
||||
|
||||
result = T::checkPriorTxAndLastLedger(ctx);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
return result;
|
||||
|
||||
result = T::checkFee(ctx, calculateBaseFee(ctx.view, ctx.tx));
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
return result;
|
||||
|
||||
result = T::checkSign(ctx);
|
||||
|
||||
if (result != tesSUCCESS)
|
||||
if (!isTesSuccess(result))
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -283,6 +288,8 @@ invoke_preclaim(PreclaimContext const& ctx)
|
||||
return invoke_preclaim<Import>(ctx);
|
||||
case ttINVOKE:
|
||||
return invoke_preclaim<Invoke>(ctx);
|
||||
case ttREMIT:
|
||||
return invoke_preclaim<Remit>(ctx);
|
||||
case ttURITOKEN_MINT:
|
||||
case ttURITOKEN_BURN:
|
||||
case ttURITOKEN_BUY:
|
||||
@@ -364,6 +371,8 @@ invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
return Import::calculateBaseFee(view, tx);
|
||||
case ttINVOKE:
|
||||
return Invoke::calculateBaseFee(view, tx);
|
||||
case ttREMIT:
|
||||
return Remit::calculateBaseFee(view, tx);
|
||||
case ttURITOKEN_MINT:
|
||||
case ttURITOKEN_BURN:
|
||||
case ttURITOKEN_BUY:
|
||||
@@ -543,6 +552,10 @@ invoke_apply(ApplyContext& ctx)
|
||||
Invoke p(ctx);
|
||||
return p();
|
||||
}
|
||||
case ttREMIT: {
|
||||
Remit p(ctx);
|
||||
return p();
|
||||
}
|
||||
case ttURITOKEN_MINT:
|
||||
case ttURITOKEN_BURN:
|
||||
case ttURITOKEN_BUY:
|
||||
@@ -620,7 +633,7 @@ preclaim(
|
||||
try
|
||||
{
|
||||
#endif
|
||||
if (ctx->preflightResult != tesSUCCESS)
|
||||
if (!isTesSuccess(ctx->preflightResult))
|
||||
return {*ctx, ctx->preflightResult};
|
||||
return {*ctx, invoke_preclaim(*ctx)};
|
||||
#ifndef DEBUG
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
@@ -549,7 +549,8 @@ using uint128 = base_uint<128>;
|
||||
using uint160 = base_uint<160>;
|
||||
using uint256 = base_uint<256>;
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
/*
|
||||
* template <std::size_t Bits, class Tag>
|
||||
[[nodiscard]] inline constexpr std::strong_ordering
|
||||
operator<=>(base_uint<Bits, Tag> const& lhs, base_uint<Bits, Tag> const& rhs)
|
||||
{
|
||||
@@ -570,6 +571,19 @@ operator<=>(base_uint<Bits, Tag> const& lhs, base_uint<Bits, Tag> const& rhs)
|
||||
return (*ret.first > *ret.second) ? std::strong_ordering::greater
|
||||
: std::strong_ordering::less;
|
||||
}
|
||||
*/
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
[[nodiscard]] inline constexpr std::strong_ordering
|
||||
operator<=>(base_uint<Bits, Tag> const& lhs, base_uint<Bits, Tag> const& rhs)
|
||||
{
|
||||
return std::lexicographical_compare_three_way(
|
||||
lhs.cbegin(),
|
||||
lhs.cend(),
|
||||
rhs.cbegin(),
|
||||
rhs.cend(),
|
||||
std::compare_three_way{});
|
||||
}
|
||||
|
||||
template <std::size_t Bits, typename Tag>
|
||||
[[nodiscard]] inline constexpr bool
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/basics/FileUtilities.h>
|
||||
#include <fstream>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -41,7 +42,7 @@ getFileContents(
|
||||
return {};
|
||||
}
|
||||
|
||||
ifstream fileStream(fullPath, std::ios::in);
|
||||
std::ifstream fileStream(fullPath.string(), std::ios::in);
|
||||
|
||||
if (!fileStream)
|
||||
{
|
||||
@@ -71,7 +72,8 @@ writeFileContents(
|
||||
using namespace boost::filesystem;
|
||||
using namespace boost::system::errc;
|
||||
|
||||
ofstream fileStream(destPath, std::ios::out | std::ios::trunc);
|
||||
std::ofstream fileStream(
|
||||
destPath.string(), std::ios::out | std::ios::trunc);
|
||||
|
||||
if (!fileStream)
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@ mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div)
|
||||
{
|
||||
using namespace boost::multiprecision;
|
||||
|
||||
uint128_t result;
|
||||
boost::multiprecision::uint128_t result;
|
||||
result = multiply(result, value, mul);
|
||||
|
||||
result /= div;
|
||||
|
||||
@@ -240,7 +240,7 @@ public:
|
||||
bool LEDGER_REPLAY = false;
|
||||
|
||||
// Work queue limits
|
||||
int MAX_TRANSACTIONS = 250;
|
||||
int MAX_TRANSACTIONS = 1000;
|
||||
static constexpr int MAX_JOB_QUEUE_TX = 1000;
|
||||
static constexpr int MIN_JOB_QUEUE_TX = 100;
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ sizedItems
|
||||
{SizedItem::txnDBCache, {{ 4, 12, 24, 64, 128 }}},
|
||||
{SizedItem::lgrDBCache, {{ 4, 8, 16, 32, 128 }}},
|
||||
{SizedItem::openFinalLimit, {{ 8, 16, 32, 64, 128 }}},
|
||||
{SizedItem::burstSize, {{ 4, 8, 16, 32, 48 }}},
|
||||
{SizedItem::burstSize, {{ 4, 8, 16, 32, 64*1024*1024 }}},
|
||||
{SizedItem::ramSizeGB, {{ 8, 12, 16, 24, 32 }}},
|
||||
{SizedItem::accountIdCacheSize, {{ 20047, 50053, 77081, 150061, 300007 }}}
|
||||
}};
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <ripple/ledger/OpenView.h>
|
||||
#include <ripple/ledger/RawView.h>
|
||||
#include <ripple/ledger/ReadView.h>
|
||||
#include <ripple/ledger/Sandbox.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Protocol.h>
|
||||
#include <ripple/protocol/Rate.h>
|
||||
@@ -394,7 +395,8 @@ accountSend(
|
||||
AccountID const& from,
|
||||
AccountID const& to,
|
||||
const STAmount& saAmount,
|
||||
beast::Journal j);
|
||||
beast::Journal j,
|
||||
bool const senderPaysXferFees = true);
|
||||
|
||||
[[nodiscard]] TER
|
||||
issueIOU(
|
||||
@@ -627,7 +629,7 @@ trustTransferAllowed(
|
||||
{
|
||||
static_assert(
|
||||
std::is_same<V, ReadView const>::value ||
|
||||
std::is_same<V, ApplyView>::value);
|
||||
std::is_same<V, ApplyView>::value || std::is_same<V, Sandbox>::value);
|
||||
|
||||
typedef typename std::conditional<
|
||||
std::is_same<V, ApplyView>::value,
|
||||
|
||||
@@ -130,6 +130,8 @@ ApplyStateTable::generateTxMeta(
|
||||
if (!hookEmission.empty())
|
||||
meta.setHookEmissions(STArray{hookEmission, sfHookEmissions});
|
||||
|
||||
bool const recordDefaultAmounts = to.rules().enabled(fixXahauV1);
|
||||
|
||||
Mods newMod;
|
||||
for (auto& item : items_)
|
||||
{
|
||||
@@ -232,8 +234,12 @@ ApplyStateTable::generateTxMeta(
|
||||
STObject news(sfNewFields);
|
||||
for (auto const& obj : *curNode)
|
||||
{
|
||||
bool const shouldRecord =
|
||||
(obj.getSType() == STI_AMOUNT && recordDefaultAmounts) ||
|
||||
!obj.isDefault();
|
||||
|
||||
// save non-default values
|
||||
if (!obj.isDefault() &&
|
||||
if (shouldRecord &&
|
||||
obj.getFName().shouldMeta(
|
||||
SField::sMD_Create | SField::sMD_Always))
|
||||
news.emplace_back(obj);
|
||||
|
||||
@@ -91,8 +91,10 @@ ApplyView::dirAdd(
|
||||
return page;
|
||||
}
|
||||
|
||||
bool const capped = !rules().enabled(fixPageCap);
|
||||
|
||||
// Check whether we're out of pages.
|
||||
if (++page >= dirNodeMaxPages)
|
||||
if (++page >= dirNodeMaxPages && capped)
|
||||
return std::nullopt;
|
||||
|
||||
// We are about to create a new node; we'll link it to
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/ledger/detail/ApplyViewBase.h>
|
||||
#include <ripple/protocol/STAccount.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace detail {
|
||||
|
||||
@@ -1157,7 +1157,8 @@ rippleSend(
|
||||
AccountID const& uReceiverID,
|
||||
STAmount const& saAmount,
|
||||
STAmount& saActual,
|
||||
beast::Journal j)
|
||||
beast::Journal j,
|
||||
bool const senderPaysXferFees)
|
||||
{
|
||||
auto const issuer = saAmount.getIssuer();
|
||||
|
||||
@@ -1169,7 +1170,8 @@ rippleSend(
|
||||
// Direct send: redeeming IOUs and/or sending own IOUs.
|
||||
auto const ter =
|
||||
rippleCredit(view, uSenderID, uReceiverID, saAmount, false, j);
|
||||
if (view.rules().enabled(featureDeletableAccounts) && ter != tesSUCCESS)
|
||||
if (view.rules().enabled(featureDeletableAccounts) &&
|
||||
!isTesSuccess(ter))
|
||||
return ter;
|
||||
saActual = saAmount;
|
||||
return tesSUCCESS;
|
||||
@@ -1179,17 +1181,30 @@ rippleSend(
|
||||
|
||||
// Calculate the amount to transfer accounting
|
||||
// for any transfer fees:
|
||||
saActual = multiply(saAmount, transferRate(view, issuer));
|
||||
|
||||
STAmount senderPays = saAmount;
|
||||
STAmount destReceives = saAmount;
|
||||
if (senderPaysXferFees)
|
||||
{
|
||||
senderPays = multiply(saAmount, transferRate(view, issuer));
|
||||
saActual = senderPays;
|
||||
}
|
||||
else
|
||||
{
|
||||
destReceives = divide(saAmount, transferRate(view, issuer));
|
||||
saActual = destReceives;
|
||||
}
|
||||
|
||||
JLOG(j.debug()) << "rippleSend> " << to_string(uSenderID) << " - > "
|
||||
<< to_string(uReceiverID)
|
||||
<< " : deliver=" << saAmount.getFullText()
|
||||
<< " cost=" << saActual.getFullText();
|
||||
|
||||
TER terResult = rippleCredit(view, issuer, uReceiverID, saAmount, true, j);
|
||||
TER terResult =
|
||||
rippleCredit(view, issuer, uReceiverID, destReceives, true, j);
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
terResult = rippleCredit(view, uSenderID, issuer, saActual, true, j);
|
||||
if (isTesSuccess(terResult))
|
||||
terResult = rippleCredit(view, uSenderID, issuer, senderPays, true, j);
|
||||
|
||||
return terResult;
|
||||
}
|
||||
@@ -1200,7 +1215,8 @@ accountSend(
|
||||
AccountID const& uSenderID,
|
||||
AccountID const& uReceiverID,
|
||||
STAmount const& saAmount,
|
||||
beast::Journal j)
|
||||
beast::Journal j,
|
||||
bool const senderPaysXferFees)
|
||||
{
|
||||
assert(saAmount >= beast::zero);
|
||||
|
||||
@@ -1218,7 +1234,14 @@ accountSend(
|
||||
<< to_string(uReceiverID) << " : "
|
||||
<< saAmount.getFullText();
|
||||
|
||||
return rippleSend(view, uSenderID, uReceiverID, saAmount, saActual, j);
|
||||
return rippleSend(
|
||||
view,
|
||||
uSenderID,
|
||||
uReceiverID,
|
||||
saAmount,
|
||||
saActual,
|
||||
j,
|
||||
senderPaysXferFees);
|
||||
}
|
||||
|
||||
/* XRP send which does not check reserve and can do pure adjustment.
|
||||
@@ -1227,7 +1250,6 @@ accountSend(
|
||||
* ensure that transfers are balanced.
|
||||
*/
|
||||
TER terResult(tesSUCCESS);
|
||||
|
||||
SLE::pointer sender = uSenderID != beast::zero
|
||||
? view.peek(keylet::account(uSenderID))
|
||||
: SLE::pointer();
|
||||
@@ -1271,7 +1293,7 @@ accountSend(
|
||||
}
|
||||
}
|
||||
|
||||
if (tesSUCCESS == terResult && receiver)
|
||||
if (isTesSuccess(terResult) && receiver)
|
||||
{
|
||||
// Increment XRP balance.
|
||||
auto const rcvBal = receiver->getFieldAmount(sfBalance);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/rdb/Download.h>
|
||||
#include <fstream>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
|
||||
@@ -1894,7 +1894,9 @@ fromNetwork(
|
||||
constexpr auto RPC_REPLY_MAX_BYTES = megabytes(256);
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
auto constexpr RPC_NOTIFY = 10min;
|
||||
// auto constexpr RPC_NOTIFY = 10min; // Wietse: lolwut 10 minutes for one
|
||||
// HTTP call?
|
||||
auto constexpr RPC_NOTIFY = 30s;
|
||||
|
||||
HTTPClient::request(
|
||||
bSSL,
|
||||
|
||||
@@ -78,12 +78,14 @@ public:
|
||||
{
|
||||
std::lock_guard sl(mLock);
|
||||
|
||||
if (mDeque.size() >= eventQueueMax)
|
||||
{
|
||||
// Drop the previous event.
|
||||
JLOG(j_.warn()) << "RPCCall::fromNetwork drop";
|
||||
mDeque.pop_back();
|
||||
}
|
||||
// Wietse: we're not going to limit this, this is admin-port only, scale
|
||||
// accordingly Dropping events just like this results in inconsistent
|
||||
// data on the receiving end if (mDeque.size() >= eventQueueMax)
|
||||
// {
|
||||
// // Drop the previous event.
|
||||
// JLOG(j_.warn()) << "RPCCall::fromNetwork drop";
|
||||
// mDeque.pop_back();
|
||||
// }
|
||||
|
||||
auto jm = broadcast ? j_.debug() : j_.info();
|
||||
JLOG(jm) << "RPCCall::fromNetwork push: " << jvObj;
|
||||
@@ -182,7 +184,8 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
enum { eventQueueMax = 32 };
|
||||
// Wietse: we're not going to limit this, this is admin-port only, scale
|
||||
// accordingly enum { eventQueueMax = 32 };
|
||||
|
||||
boost::asio::io_service& m_io_service;
|
||||
JobQueue& m_jobQueue;
|
||||
|
||||
@@ -44,7 +44,7 @@ getFeatureValue(
|
||||
return {};
|
||||
boost::smatch match;
|
||||
boost::regex rx(feature + "=([^;\\s]+)");
|
||||
auto const value = header->value().to_string();
|
||||
auto const value = std::string(header->value());
|
||||
if (boost::regex_search(value, match, rx))
|
||||
return {match[1]};
|
||||
return {};
|
||||
@@ -233,7 +233,7 @@ verifyHandshake(
|
||||
{
|
||||
if (auto const iter = headers.find("Server-Domain"); iter != headers.end())
|
||||
{
|
||||
if (!isProperlyFormedTomlDomain(iter->value().to_string()))
|
||||
if (!isProperlyFormedTomlDomain(std::string(iter->value())))
|
||||
throw std::runtime_error("Invalid server domain");
|
||||
}
|
||||
|
||||
@@ -243,7 +243,8 @@ verifyHandshake(
|
||||
uint32_t peer_nid = 0;
|
||||
if (auto const iter = headers.find("Network-ID"); iter != headers.end())
|
||||
{
|
||||
if (!beast::lexicalCastChecked(peer_nid, iter->value().to_string()))
|
||||
if (!beast::lexicalCastChecked(
|
||||
peer_nid, std::string(iter->value())))
|
||||
throw std::runtime_error("Invalid peer network identifier");
|
||||
}
|
||||
|
||||
@@ -255,7 +256,7 @@ verifyHandshake(
|
||||
if (auto const iter = headers.find("Network-Time"); iter != headers.end())
|
||||
{
|
||||
auto const netTime =
|
||||
[str = iter->value().to_string()]() -> TimeKeeper::time_point {
|
||||
[str = std::string(iter->value())]() -> TimeKeeper::time_point {
|
||||
TimeKeeper::duration::rep val;
|
||||
|
||||
if (beast::lexicalCastChecked(val, str))
|
||||
@@ -291,7 +292,7 @@ verifyHandshake(
|
||||
if (auto const iter = headers.find("Public-Key"); iter != headers.end())
|
||||
{
|
||||
auto pk = parseBase58<PublicKey>(
|
||||
TokenType::NodePublic, iter->value().to_string());
|
||||
TokenType::NodePublic, std::string(iter->value()));
|
||||
|
||||
if (pk)
|
||||
{
|
||||
@@ -317,7 +318,7 @@ verifyHandshake(
|
||||
if (iter == headers.end())
|
||||
throw std::runtime_error("No session signature specified");
|
||||
|
||||
auto sig = base64_decode(iter->value().to_string());
|
||||
auto sig = base64_decode(std::string(iter->value()));
|
||||
|
||||
if (!verifyDigest(publicKey, sharedValue, makeSlice(sig), false))
|
||||
throw std::runtime_error("Failed to verify session");
|
||||
@@ -330,7 +331,7 @@ verifyHandshake(
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto const local_ip = boost::asio::ip::address::from_string(
|
||||
iter->value().to_string(), ec);
|
||||
std::string(iter->value()), ec);
|
||||
|
||||
if (ec)
|
||||
throw std::runtime_error("Invalid Local-IP");
|
||||
@@ -345,7 +346,7 @@ verifyHandshake(
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
auto const remote_ip = boost::asio::ip::address::from_string(
|
||||
iter->value().to_string(), ec);
|
||||
std::string(iter->value()), ec);
|
||||
|
||||
if (ec)
|
||||
throw std::runtime_error("Invalid Remote-IP");
|
||||
|
||||
@@ -176,7 +176,7 @@ PeerImp::run()
|
||||
if (auto const iter = headers_.find("Closed-Ledger");
|
||||
iter != headers_.end())
|
||||
{
|
||||
closed = parseLedgerHash(iter->value().to_string());
|
||||
closed = parseLedgerHash(std::string(iter->value()));
|
||||
|
||||
if (!closed)
|
||||
fail("Malformed handshake data (1)");
|
||||
@@ -185,7 +185,7 @@ PeerImp::run()
|
||||
if (auto const iter = headers_.find("Previous-Ledger");
|
||||
iter != headers_.end())
|
||||
{
|
||||
previous = parseLedgerHash(iter->value().to_string());
|
||||
previous = parseLedgerHash(std::string(iter->value()));
|
||||
|
||||
if (!previous)
|
||||
fail("Malformed handshake data (2)");
|
||||
@@ -372,8 +372,8 @@ std::string
|
||||
PeerImp::getVersion() const
|
||||
{
|
||||
if (inbound_)
|
||||
return headers_["User-Agent"].to_string();
|
||||
return headers_["Server"].to_string();
|
||||
return std::string(headers_["User-Agent"]);
|
||||
return std::string(headers_["Server"]);
|
||||
}
|
||||
|
||||
Json::Value
|
||||
@@ -399,7 +399,7 @@ PeerImp::json()
|
||||
if (auto const d = domain(); !d.empty())
|
||||
ret[jss::server_domain] = domain();
|
||||
|
||||
if (auto const nid = headers_["Network-ID"].to_string(); !nid.empty())
|
||||
if (auto const nid = std::string(headers_["Network-ID"]); !nid.empty())
|
||||
ret[jss::network_id] = nid;
|
||||
|
||||
ret[jss::load] = usage_.balance();
|
||||
@@ -839,7 +839,7 @@ PeerImp::name() const
|
||||
std::string
|
||||
PeerImp::domain() const
|
||||
{
|
||||
return headers_["Server-Domain"].to_string();
|
||||
return std::string(headers_["Server-Domain"]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#define RIPPLE_PEERFINDER_CHECKER_H_INCLUDED
|
||||
|
||||
#include <ripple/beast/net/IPAddressConversion.h>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace detail {
|
||||
// Feature.cpp. Because it's only used to reserve storage, and determine how
|
||||
// large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than
|
||||
// the actual number of amendments. A LogicError on startup will verify this.
|
||||
static constexpr std::size_t numFeatures = 66;
|
||||
static constexpr std::size_t numFeatures = 73;
|
||||
|
||||
/** Amendments that this server supports and the default voting behavior.
|
||||
Whether they are enabled depends on the Rules defined in the validated
|
||||
@@ -353,7 +353,14 @@ extern uint256 const fixNFTokenRemint;
|
||||
extern uint256 const featureImport;
|
||||
extern uint256 const featureXahauGenesis;
|
||||
extern uint256 const featureHooksUpdate1;
|
||||
extern uint256 const fixURITokenV1;
|
||||
extern uint256 const fixXahauV1;
|
||||
extern uint256 const fixXahauV2;
|
||||
extern uint256 const featureRemit;
|
||||
extern uint256 const featureZeroB2M;
|
||||
extern uint256 const fixNSDelete;
|
||||
extern uint256 const fix240819;
|
||||
extern uint256 const fixPageCap;
|
||||
extern uint256 const fix240911;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
|
||||
@@ -285,6 +285,8 @@ enum LedgerSpecificFlags {
|
||||
0x20000000, // True, reject new trustlines (only if no issued assets)
|
||||
lsfURITokenIssuer =
|
||||
0x40000000, // True, has minted tokens in the past
|
||||
lsfDisallowIncomingRemit = // True, no remits allowed to this account
|
||||
0x80000000,
|
||||
|
||||
// ltOFFER
|
||||
lsfPassive = 0x00010000,
|
||||
|
||||
@@ -552,6 +552,7 @@ extern SF_ACCOUNT const sfEmitCallback;
|
||||
// account (uncommon)
|
||||
extern SF_ACCOUNT const sfHookAccount;
|
||||
extern SF_ACCOUNT const sfNFTokenMinter;
|
||||
extern SF_ACCOUNT const sfInform;
|
||||
|
||||
// path set
|
||||
extern SField const sfPaths;
|
||||
@@ -562,6 +563,7 @@ extern SF_VECTOR256 const sfHashes;
|
||||
extern SF_VECTOR256 const sfAmendments;
|
||||
extern SF_VECTOR256 const sfNFTokenOffers;
|
||||
extern SF_VECTOR256 const sfHookNamespaces;
|
||||
extern SF_VECTOR256 const sfURITokenIDs;
|
||||
|
||||
// inner object
|
||||
// OBJECT/1 is reserved for end of object
|
||||
@@ -590,6 +592,8 @@ extern SField const sfHookGrant;
|
||||
extern SField const sfActiveValidator;
|
||||
extern SField const sfImportVLKey;
|
||||
extern SField const sfHookEmission;
|
||||
extern SField const sfMintURIToken;
|
||||
extern SField const sfAmountEntry;
|
||||
|
||||
// array of objects (common)
|
||||
// ARRAY/1 is reserved for end of array
|
||||
@@ -617,6 +621,7 @@ extern SField const sfGenesisMints;
|
||||
extern SField const sfActiveValidators;
|
||||
extern SField const sfImportVLKeys;
|
||||
extern SField const sfHookEmissions;
|
||||
extern SField const sfAmounts;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -183,6 +183,7 @@ enum TEFcodes : TERUnderlyingType {
|
||||
tefNFTOKEN_IS_NOT_TRANSFERABLE,
|
||||
tefPAST_IMPORT_SEQ,
|
||||
tefPAST_IMPORT_VL_SEQ,
|
||||
tefNONDIR_EMIT,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -239,7 +240,8 @@ enum TEScodes : TERUnderlyingType {
|
||||
// Implications:
|
||||
// - Applied
|
||||
// - Forwarded
|
||||
tesSUCCESS = 0
|
||||
tesSUCCESS = 0,
|
||||
tesPARTIAL = 1,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -337,6 +339,7 @@ enum TECcodes : TERUnderlyingType {
|
||||
tecXCHAIN_PAYMENT_FAILED = 184, // RESERVED - XCHAIN
|
||||
tecXCHAIN_SELF_COMMIT = 185, // RESERVED - XCHAIN
|
||||
tecXCHAIN_BAD_PUBLIC_KEY_ACCOUNT_PAIR = 186, // RESERVED - XCHAIN
|
||||
tecINSUF_RESERVE_SELLER = 187,
|
||||
tecLAST_POSSIBLE_ENTRY = 255,
|
||||
};
|
||||
|
||||
@@ -434,7 +437,7 @@ public:
|
||||
// Conversion to bool.
|
||||
explicit operator bool() const
|
||||
{
|
||||
return code_ != tesSUCCESS;
|
||||
return code_ < tesSUCCESS || code_ >= tecCLAIM;
|
||||
}
|
||||
|
||||
// Conversion to Json::Value allows assignment to Json::Objects
|
||||
@@ -639,10 +642,17 @@ isTerRetry(TER x)
|
||||
return ((x) >= terRETRY && (x) < tesSUCCESS);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool
|
||||
isTesSuccess(T x)
|
||||
{
|
||||
return ((x) >= tesSUCCESS) && (x) < tecCLAIM;
|
||||
}
|
||||
|
||||
inline bool
|
||||
isTesSuccess(TER x)
|
||||
{
|
||||
return ((x) == tesSUCCESS);
|
||||
return ((x) >= tesSUCCESS) && (x) < tecCLAIM;
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
||||
@@ -55,79 +55,98 @@ namespace ripple {
|
||||
// wrapped lines
|
||||
// clang-format off
|
||||
// Universal Transaction flags:
|
||||
constexpr std::uint32_t tfFullyCanonicalSig = 0x80000000;
|
||||
enum UniversalFlags : uint32_t {
|
||||
tfFullyCanonicalSig = 0x80000000,
|
||||
};
|
||||
constexpr std::uint32_t tfUniversal = tfFullyCanonicalSig;
|
||||
constexpr std::uint32_t tfUniversalMask = ~tfUniversal;
|
||||
|
||||
// AccountSet flags:
|
||||
constexpr std::uint32_t tfRequireDestTag = 0x00010000;
|
||||
constexpr std::uint32_t tfOptionalDestTag = 0x00020000;
|
||||
constexpr std::uint32_t tfRequireAuth = 0x00040000;
|
||||
constexpr std::uint32_t tfOptionalAuth = 0x00080000;
|
||||
constexpr std::uint32_t tfDisallowXRP = 0x00100000;
|
||||
constexpr std::uint32_t tfAllowXRP = 0x00200000;
|
||||
enum AccountSetFlags : uint32_t {
|
||||
tfRequireDestTag = 0x00010000,
|
||||
tfOptionalDestTag = 0x00020000,
|
||||
tfRequireAuth = 0x00040000,
|
||||
tfOptionalAuth = 0x00080000,
|
||||
tfDisallowXRP = 0x00100000,
|
||||
tfAllowXRP = 0x00200000,
|
||||
};
|
||||
constexpr std::uint32_t tfAccountSetMask =
|
||||
~(tfUniversal | tfRequireDestTag | tfOptionalDestTag | tfRequireAuth |
|
||||
tfOptionalAuth | tfDisallowXRP | tfAllowXRP);
|
||||
|
||||
// AccountSet SetFlag/ClearFlag values
|
||||
constexpr std::uint32_t asfRequireDest = 1;
|
||||
constexpr std::uint32_t asfRequireAuth = 2;
|
||||
constexpr std::uint32_t asfDisallowXRP = 3;
|
||||
constexpr std::uint32_t asfDisableMaster = 4;
|
||||
constexpr std::uint32_t asfAccountTxnID = 5;
|
||||
constexpr std::uint32_t asfNoFreeze = 6;
|
||||
constexpr std::uint32_t asfGlobalFreeze = 7;
|
||||
constexpr std::uint32_t asfDefaultRipple = 8;
|
||||
constexpr std::uint32_t asfDepositAuth = 9;
|
||||
constexpr std::uint32_t asfAuthorizedNFTokenMinter = 10;
|
||||
constexpr std::uint32_t asfTshCollect = 11;
|
||||
constexpr std::uint32_t asfDisallowIncomingNFTokenOffer = 12;
|
||||
constexpr std::uint32_t asfDisallowIncomingCheck = 13;
|
||||
constexpr std::uint32_t asfDisallowIncomingPayChan = 14;
|
||||
constexpr std::uint32_t asfDisallowIncomingTrustline = 15;
|
||||
enum AccountFlags : uint32_t {
|
||||
asfRequireDest = 1,
|
||||
asfRequireAuth = 2,
|
||||
asfDisallowXRP = 3,
|
||||
asfDisableMaster = 4,
|
||||
asfAccountTxnID = 5,
|
||||
asfNoFreeze = 6,
|
||||
asfGlobalFreeze = 7,
|
||||
asfDefaultRipple = 8,
|
||||
asfDepositAuth = 9,
|
||||
asfAuthorizedNFTokenMinter = 10,
|
||||
asfTshCollect = 11,
|
||||
asfDisallowIncomingNFTokenOffer = 12,
|
||||
asfDisallowIncomingCheck = 13,
|
||||
asfDisallowIncomingPayChan = 14,
|
||||
asfDisallowIncomingTrustline = 15,
|
||||
asfDisallowIncomingRemit = 16,
|
||||
};
|
||||
|
||||
// OfferCreate flags:
|
||||
constexpr std::uint32_t tfPassive = 0x00010000;
|
||||
constexpr std::uint32_t tfImmediateOrCancel = 0x00020000;
|
||||
constexpr std::uint32_t tfFillOrKill = 0x00040000;
|
||||
constexpr std::uint32_t tfSell = 0x00080000;
|
||||
enum OfferCreateFlags : uint32_t {
|
||||
tfPassive = 0x00010000,
|
||||
tfImmediateOrCancel = 0x00020000,
|
||||
tfFillOrKill = 0x00040000,
|
||||
tfSell = 0x00080000,
|
||||
};
|
||||
constexpr std::uint32_t tfOfferCreateMask =
|
||||
~(tfUniversal | tfPassive | tfImmediateOrCancel | tfFillOrKill | tfSell);
|
||||
|
||||
// Payment flags:
|
||||
constexpr std::uint32_t tfNoRippleDirect = 0x00010000;
|
||||
constexpr std::uint32_t tfPartialPayment = 0x00020000;
|
||||
constexpr std::uint32_t tfLimitQuality = 0x00040000;
|
||||
enum PaymentFlags : uint32_t {
|
||||
tfNoRippleDirect = 0x00010000,
|
||||
tfPartialPayment = 0x00020000,
|
||||
tfLimitQuality = 0x00040000,
|
||||
};
|
||||
constexpr std::uint32_t tfPaymentMask =
|
||||
~(tfUniversal | tfPartialPayment | tfLimitQuality | tfNoRippleDirect);
|
||||
|
||||
// TrustSet flags:
|
||||
constexpr std::uint32_t tfSetfAuth = 0x00010000;
|
||||
constexpr std::uint32_t tfSetNoRipple = 0x00020000;
|
||||
constexpr std::uint32_t tfClearNoRipple = 0x00040000;
|
||||
constexpr std::uint32_t tfSetFreeze = 0x00100000;
|
||||
constexpr std::uint32_t tfClearFreeze = 0x00200000;
|
||||
enum TrustSetFlags : uint32_t {
|
||||
tfSetfAuth = 0x00010000,
|
||||
tfSetNoRipple = 0x00020000,
|
||||
tfClearNoRipple = 0x00040000,
|
||||
tfSetFreeze = 0x00100000,
|
||||
tfClearFreeze = 0x00200000,
|
||||
};
|
||||
constexpr std::uint32_t tfTrustSetMask =
|
||||
~(tfUniversal | tfSetfAuth | tfSetNoRipple | tfClearNoRipple | tfSetFreeze |
|
||||
tfClearFreeze);
|
||||
|
||||
// EnableAmendment flags:
|
||||
constexpr std::uint32_t tfGotMajority = 0x00010000;
|
||||
constexpr std::uint32_t tfLostMajority = 0x00020000;
|
||||
constexpr std::uint32_t tfTestSuite = 0x80000000;
|
||||
enum EnableAmendmentFlags : std::uint32_t {
|
||||
tfGotMajority = 0x00010000,
|
||||
tfLostMajority = 0x00020000,
|
||||
tfTestSuite = 0x80000000,
|
||||
};
|
||||
|
||||
// PaymentChannelClaim flags:
|
||||
constexpr std::uint32_t tfRenew = 0x00010000;
|
||||
constexpr std::uint32_t tfClose = 0x00020000;
|
||||
enum PaymentChannelClaimFlags : uint32_t {
|
||||
tfRenew = 0x00010000,
|
||||
tfClose = 0x00020000,
|
||||
};
|
||||
constexpr std::uint32_t tfPayChanClaimMask = ~(tfUniversal | tfRenew | tfClose);
|
||||
|
||||
// NFTokenMint flags:
|
||||
constexpr std::uint32_t const tfBurnable = 0x00000001;
|
||||
constexpr std::uint32_t const tfOnlyXRP = 0x00000002;
|
||||
constexpr std::uint32_t const tfTrustLine = 0x00000004;
|
||||
constexpr std::uint32_t const tfTransferable = 0x00000008;
|
||||
constexpr std::uint32_t const tfStrongTSH = 0x00008000;
|
||||
enum NFTokenMintFlags : uint32_t {
|
||||
tfBurnable = 0x00000001,
|
||||
tfOnlyXRP = 0x00000002,
|
||||
tfTrustLine = 0x00000004,
|
||||
tfTransferable = 0x00000008,
|
||||
tfStrongTSH = 0x00008000,
|
||||
};
|
||||
|
||||
constexpr std::uint32_t const tfNFTokenMintOldMask =
|
||||
~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable | tfStrongTSH);
|
||||
@@ -150,7 +169,9 @@ constexpr std::uint32_t const tfNFTokenMintMask =
|
||||
~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable | tfStrongTSH);
|
||||
|
||||
// NFTokenCreateOffer flags:
|
||||
constexpr std::uint32_t const tfSellNFToken = 0x00000001;
|
||||
enum NFTokenCreateOfferFlags : uint32_t {
|
||||
tfSellNFToken = 0x00000001,
|
||||
};
|
||||
constexpr std::uint32_t const tfNFTokenCreateOfferMask =
|
||||
~(tfUniversal | tfSellNFToken);
|
||||
|
||||
@@ -165,7 +186,9 @@ constexpr std::uint32_t const tfURITokenMintMask = ~(tfUniversal | tfBurnable);
|
||||
constexpr std::uint32_t const tfURITokenNonMintMask = ~tfUniversal;
|
||||
|
||||
// ClaimReward flags:
|
||||
constexpr std::uint32_t const tfOptOut = 0x00000001;
|
||||
enum ClaimRewardFlags : uint32_t {
|
||||
tfOptOut = 0x00000001,
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -146,6 +146,10 @@ enum TxType : std::uint16_t
|
||||
ttURITOKEN_CREATE_SELL_OFFER = 48,
|
||||
ttURITOKEN_CANCEL_SELL_OFFER = 49,
|
||||
|
||||
/* A payment transactor that delivers only the exact amounts specified, creating accounts and TLs as needed
|
||||
* that the sender pays for. */
|
||||
ttREMIT = 95,
|
||||
|
||||
/** This transaction can only be used by the genesis account, which is controlled exclusively by
|
||||
* rewards/governance hooks, to print new XRP to be delivered directly to an array of destinations,
|
||||
* according to reward schedule */
|
||||
|
||||
@@ -108,6 +108,7 @@ constexpr static ErrorInfo unorderedErrorInfos[]{
|
||||
{rpcSTREAM_MALFORMED, "malformedStream", "Stream malformed.", 400},
|
||||
{rpcTOO_BUSY, "tooBusy", "The server is too busy to help you now.", 503},
|
||||
{rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found.", 404},
|
||||
{rpcNAMESPACE_NOT_FOUND, "namespaceNotFound", "Namespace not found.", 404},
|
||||
{rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown method.", 405}};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -459,8 +459,14 @@ REGISTER_FEATURE(URIToken, Supported::yes, VoteBehavior::De
|
||||
REGISTER_FEATURE(Import, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FEATURE(XahauGenesis, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FEATURE(HooksUpdate1, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fixURITokenV1, Supported::yes, VoteBehavior::DefaultNo);
|
||||
|
||||
REGISTER_FIX (fixXahauV1, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX (fixXahauV2, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FEATURE(Remit, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FEATURE(ZeroB2M, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX (fixNSDelete, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX (fix240819, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fixPageCap, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fix240911, Supported::yes, VoteBehavior::DefaultYes);
|
||||
|
||||
// The following amendments are obsolete, but must remain supported
|
||||
// because they could potentially get enabled.
|
||||
|
||||
@@ -72,13 +72,15 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfHookInstructionCount, soeREQUIRED},
|
||||
{sfHookExecutionIndex, soeREQUIRED},
|
||||
{sfHookStateChangeCount, soeREQUIRED},
|
||||
{sfHookEmitCount, soeREQUIRED}});
|
||||
{sfHookEmitCount, soeREQUIRED},
|
||||
{sfFlags, soeOPTIONAL}});
|
||||
|
||||
add(sfHookEmission.jsonName.c_str(),
|
||||
sfHookEmission.getCode(),
|
||||
{{sfHookHash, soeREQUIRED},
|
||||
{sfHookAccount, soeREQUIRED},
|
||||
{sfEmittedTxnID, soeREQUIRED}});
|
||||
{sfEmittedTxnID, soeREQUIRED},
|
||||
{sfEmitNonce, soeOPTIONAL}});
|
||||
|
||||
add(sfHookDefinition.jsonName.c_str(),
|
||||
sfHookDefinition.getCode(),
|
||||
@@ -141,6 +143,20 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfPublicKey, soeREQUIRED},
|
||||
{sfAccount, soeOPTIONAL},
|
||||
});
|
||||
|
||||
add(sfAmountEntry.jsonName.c_str(),
|
||||
sfAmountEntry.getCode(),
|
||||
{
|
||||
{sfAmount, soeREQUIRED},
|
||||
});
|
||||
|
||||
add(sfMintURIToken.jsonName.c_str(),
|
||||
sfMintURIToken.getCode(),
|
||||
{
|
||||
{sfURI, soeREQUIRED},
|
||||
{sfDigest, soeOPTIONAL},
|
||||
{sfFlags, soeOPTIONAL},
|
||||
});
|
||||
}
|
||||
|
||||
InnerObjectFormats const&
|
||||
|
||||
@@ -305,6 +305,7 @@ CONSTRUCT_TYPED_SFIELD(sfEmitCallback, "EmitCallback", ACCOUNT,
|
||||
|
||||
// account (uncommon)
|
||||
CONSTRUCT_TYPED_SFIELD(sfHookAccount, "HookAccount", ACCOUNT, 16);
|
||||
CONSTRUCT_TYPED_SFIELD(sfInform, "Inform", ACCOUNT, 99);
|
||||
|
||||
// vector of 256-bit
|
||||
CONSTRUCT_TYPED_SFIELD(sfIndexes, "Indexes", VECTOR256, 1, SField::sMD_Never);
|
||||
@@ -312,6 +313,7 @@ CONSTRUCT_TYPED_SFIELD(sfHashes, "Hashes", VECTOR25
|
||||
CONSTRUCT_TYPED_SFIELD(sfAmendments, "Amendments", VECTOR256, 3);
|
||||
CONSTRUCT_TYPED_SFIELD(sfNFTokenOffers, "NFTokenOffers", VECTOR256, 4);
|
||||
CONSTRUCT_TYPED_SFIELD(sfHookNamespaces, "HookNamespaces", VECTOR256, 5);
|
||||
CONSTRUCT_TYPED_SFIELD(sfURITokenIDs, "URITokenIDs", VECTOR256, 99);
|
||||
|
||||
// path set
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfPaths, "Paths", PATHSET, 1);
|
||||
@@ -346,6 +348,8 @@ CONSTRUCT_UNTYPED_SFIELD(sfGenesisMint, "GenesisMint", OBJECT,
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfActiveValidator, "ActiveValidator", OBJECT, 95);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfImportVLKey, "ImportVLKey", OBJECT, 94);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfHookEmission, "HookEmission", OBJECT, 93);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfMintURIToken, "MintURIToken", OBJECT, 92);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfAmountEntry, "AmountEntry", OBJECT, 91);
|
||||
|
||||
// array of objects
|
||||
// ARRAY/1 is reserved for end of array
|
||||
@@ -370,6 +374,7 @@ CONSTRUCT_UNTYPED_SFIELD(sfGenesisMints, "GenesisMints", ARRAY,
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfActiveValidators, "ActiveValidators", ARRAY, 95);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfImportVLKeys, "ImportVLKeys", ARRAY, 94);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfHookEmissions, "HookEmissions", ARRAY, 93);
|
||||
CONSTRUCT_UNTYPED_SFIELD(sfAmounts, "Amounts", ARRAY, 92);
|
||||
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ transResults()
|
||||
MAKE_ERROR(tecHOOK_REJECTED, "Rejected by hook on sending or receiving account."),
|
||||
MAKE_ERROR(tecREQUIRES_FLAG, "The transaction or part-thereof requires a flag that wasn't set."),
|
||||
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),
|
||||
MAKE_ERROR(tecINSUF_RESERVE_SELLER, "The seller of an object has insufficient reserves, and thus cannot complete the sale."),
|
||||
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
|
||||
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
|
||||
MAKE_ERROR(tefBAD_AUTH, "Transaction's public key is not authorized."),
|
||||
@@ -114,6 +115,7 @@ transResults()
|
||||
MAKE_ERROR(tefTOO_BIG, "Transaction affects too many items."),
|
||||
MAKE_ERROR(tefNO_TICKET, "Ticket is not in ledger."),
|
||||
MAKE_ERROR(tefNFTOKEN_IS_NOT_TRANSFERABLE, "The specified NFToken is not transferable."),
|
||||
MAKE_ERROR(tefNONDIR_EMIT, "An emitted txn was injected into the ledger without a corresponding directory entry."),
|
||||
|
||||
MAKE_ERROR(telLOCAL_ERROR, "Local failure."),
|
||||
MAKE_ERROR(telBAD_DOMAIN, "Domain too long."),
|
||||
@@ -190,6 +192,7 @@ transResults()
|
||||
MAKE_ERROR(terNO_HOOK, "No hook with that hash exists on the ledger."),
|
||||
|
||||
MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."),
|
||||
MAKE_ERROR(tesPARTIAL, "The transaction was applied but should be submitted again until returning tesSUCCESS."),
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ TxFormats::TxFormats()
|
||||
add(jss::OfferCancel,
|
||||
ttOFFER_CANCEL,
|
||||
{
|
||||
{sfOfferSequence, soeREQUIRED},
|
||||
{sfOfferSequence, soeOPTIONAL},
|
||||
{sfOfferID, soeOPTIONAL}, // keylet as alternative to offerseq
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
},
|
||||
@@ -116,6 +116,21 @@ TxFormats::TxFormats()
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::Remit,
|
||||
ttREMIT,
|
||||
{
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfAmounts, soeOPTIONAL},
|
||||
{sfURITokenIDs, soeOPTIONAL},
|
||||
{sfMintURIToken, soeOPTIONAL},
|
||||
{sfInvoiceID, soeOPTIONAL},
|
||||
{sfDestinationTag, soeOPTIONAL},
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
{sfBlob, soeOPTIONAL},
|
||||
{sfInform, soeOPTIONAL},
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::EscrowCreate,
|
||||
ttESCROW_CREATE,
|
||||
{
|
||||
@@ -133,7 +148,7 @@ TxFormats::TxFormats()
|
||||
ttESCROW_FINISH,
|
||||
{
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOfferSequence, soeREQUIRED},
|
||||
{sfOfferSequence, soeOPTIONAL},
|
||||
{sfEscrowID, soeOPTIONAL}, // keylet as alternative to offerseq
|
||||
{sfFulfillment, soeOPTIONAL},
|
||||
{sfCondition, soeOPTIONAL},
|
||||
@@ -145,7 +160,7 @@ TxFormats::TxFormats()
|
||||
ttESCROW_CANCEL,
|
||||
{
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOfferSequence, soeREQUIRED},
|
||||
{sfOfferSequence, soeOPTIONAL},
|
||||
{sfEscrowID, soeOPTIONAL}, // keylet as alternative to offerseq
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
},
|
||||
|
||||
+80
-72
@@ -117,6 +117,7 @@ JSS(Payment); // transaction type.
|
||||
JSS(PaymentChannelClaim); // transaction type.
|
||||
JSS(PaymentChannelCreate); // transaction type.
|
||||
JSS(PaymentChannelFund); // transaction type.
|
||||
JSS(Remit); // transaction type.
|
||||
JSS(RippleState); // ledger type.
|
||||
JSS(SLE_hit_rate); // out: GetCounts.
|
||||
JSS(SetFee); // transaction type.
|
||||
@@ -160,6 +161,7 @@ JSS(account_data); // out: AccountInfo
|
||||
JSS(account_flags); // out: AccountInfo
|
||||
JSS(account_hash); // out: LedgerToJson
|
||||
JSS(account_id); // out: WalletPropose
|
||||
JSS(account_namespace); // out: AccountNamespace
|
||||
JSS(account_nfts); // out: AccountNFTs
|
||||
JSS(account_objects); // out: AccountObjects
|
||||
JSS(account_root); // in: LedgerEntry
|
||||
@@ -173,29 +175,30 @@ JSS(accounts); // in: LedgerEntry, Subscribe,
|
||||
JSS(accounts_proposed); // in: Subscribe, Unsubscribe
|
||||
JSS(acroot);
|
||||
JSS(action);
|
||||
JSS(acquiring); // out: LedgerRequest
|
||||
JSS(address); // out: PeerImp
|
||||
JSS(affected); // out: AcceptedLedgerTx
|
||||
JSS(age); // out: NetworkOPs, Peers
|
||||
JSS(alternatives); // out: PathRequest, RipplePathFind
|
||||
JSS(amendment_blocked); // out: NetworkOPs
|
||||
JSS(amendments); // in: AccountObjects, out: NetworkOPs
|
||||
JSS(amount); // out: AccountChannels
|
||||
JSS(api_version); // in: many, out: Version
|
||||
JSS(api_version_low); // out: Version
|
||||
JSS(applied); // out: SubmitTransaction
|
||||
JSS(asks); // out: Subscribe
|
||||
JSS(assets); // out: GatewayBalances
|
||||
JSS(authorized); // out: AccountLines
|
||||
JSS(auth_change); // out: AccountInfo
|
||||
JSS(auth_change_queued); // out: AccountInfo
|
||||
JSS(available); // out: ValidatorList
|
||||
JSS(avg_bps_recv); // out: Peers
|
||||
JSS(avg_bps_sent); // out: Peers
|
||||
JSS(balance); // out: AccountLines
|
||||
JSS(balances); // out: GatewayBalances
|
||||
JSS(base); // out: LogLevel
|
||||
JSS(base_fee); // out: NetworkOPs
|
||||
JSS(acquiring); // out: LedgerRequest
|
||||
JSS(address); // out: PeerImp
|
||||
JSS(affected); // out: AcceptedLedgerTx
|
||||
JSS(age); // out: NetworkOPs, Peers
|
||||
JSS(alternatives); // out: PathRequest, RipplePathFind
|
||||
JSS(amendment_blocked); // out: NetworkOPs
|
||||
JSS(amendments); // in: AccountObjects, out: NetworkOPs
|
||||
JSS(amount); // out: AccountChannels
|
||||
JSS(api_version); // in: many, out: Version
|
||||
JSS(api_version_low); // out: Version
|
||||
JSS(applied); // out: SubmitTransaction
|
||||
JSS(asks); // out: Subscribe
|
||||
JSS(assets); // out: GatewayBalances
|
||||
JSS(authorized); // out: AccountLines
|
||||
JSS(auth_change); // out: AccountInfo
|
||||
JSS(auth_change_queued); // out: AccountInfo
|
||||
JSS(available); // out: ValidatorList
|
||||
JSS(avg_bps_recv); // out: Peers
|
||||
JSS(avg_bps_sent); // out: Peers
|
||||
JSS(balance); // out: AccountLines
|
||||
JSS(balances); // out: GatewayBalances
|
||||
JSS(base); // out: LogLevel
|
||||
JSS(base_fee); // out: NetworkOPs
|
||||
JSS(base_fee_no_hooks);
|
||||
JSS(base_fee_xrp); // out: NetworkOPs
|
||||
JSS(base_fee_native); // out: NetworkOPs
|
||||
JSS(bids); // out: Subscribe
|
||||
@@ -351,12 +354,14 @@ JSS(id); // websocket.
|
||||
JSS(ident); // in: AccountCurrencies, AccountInfo,
|
||||
// OwnerInfo
|
||||
JSS(ignore_default); // in: AccountLines
|
||||
JSS(import_vlseq); // in: LedgerEntry
|
||||
JSS(inLedger); // out: tx/Transaction
|
||||
JSS(inbound); // out: PeerImp
|
||||
JSS(index); // in: LedgerEntry, DownloadShard
|
||||
// out: STLedgerEntry,
|
||||
// LedgerEntry, TxHistory, LedgerData
|
||||
JSS(info); // out: ServerInfo, ConsensusInfo, FetchInfo
|
||||
JSS(in_queue);
|
||||
JSS(inbound); // out: PeerImp
|
||||
JSS(index); // in: LedgerEntry, DownloadShard
|
||||
// out: STLedgerEntry,
|
||||
// LedgerEntry, TxHistory, LedgerData
|
||||
JSS(info); // out: ServerInfo, ConsensusInfo, FetchInfo
|
||||
JSS(initial_sync_duration_us);
|
||||
JSS(internal_command); // in: Internal
|
||||
JSS(invalid_API_version); // out: Many, when a request has an invalid
|
||||
@@ -662,50 +667,53 @@ JSS(trusted); // out: UnlList
|
||||
JSS(trusted_validator_keys); // out: ValidatorList
|
||||
JSS(tx); // out: STTx, AccountTx*
|
||||
JSS(txroot);
|
||||
JSS(tx_blob); // in/out: Submit,
|
||||
// in: TransactionSign, AccountTx*
|
||||
JSS(tx_hash); // in: TransactionEntry
|
||||
JSS(tx_json); // in/out: TransactionSign
|
||||
// out: TransactionEntry
|
||||
JSS(tx_signing_hash); // out: TransactionSign
|
||||
JSS(tx_unsigned); // out: TransactionSign
|
||||
JSS(txn_count); // out: NetworkOPs
|
||||
JSS(txr_tx_cnt); // out: protocol message tx's count
|
||||
JSS(txr_tx_sz); // out: protocol message tx's size
|
||||
JSS(txr_have_txs_cnt); // out: protocol message have tx count
|
||||
JSS(txr_have_txs_sz); // out: protocol message have tx size
|
||||
JSS(txr_get_ledger_cnt); // out: protocol message get ledger count
|
||||
JSS(txr_get_ledger_sz); // out: protocol message get ledger size
|
||||
JSS(txr_ledger_data_cnt); // out: protocol message ledger data count
|
||||
JSS(txr_ledger_data_sz); // out: protocol message ledger data size
|
||||
JSS(txr_transactions_cnt); // out: protocol message get object count
|
||||
JSS(txr_transactions_sz); // out: protocol message get object size
|
||||
JSS(txr_selected_cnt); // out: selected peers count
|
||||
JSS(txr_suppressed_cnt); // out: suppressed peers count
|
||||
JSS(txr_not_enabled_cnt); // out: peers with tx reduce-relay disabled count
|
||||
JSS(txr_missing_tx_freq); // out: missing tx frequency average
|
||||
JSS(txs); // out: TxHistory
|
||||
JSS(type); // in: AccountObjects
|
||||
// out: NetworkOPs RPC server_definitions
|
||||
// OverlayImpl, Logic
|
||||
JSS(TRANSACTION_RESULTS); // out: RPC server_definitions
|
||||
JSS(TRANSACTION_TYPES); // out: RPC server_definitions
|
||||
JSS(TYPES); // out: RPC server_definitions
|
||||
JSS(type_hex); // out: STPathSet
|
||||
JSS(unl); // out: UnlList
|
||||
JSS(unlimited); // out: Connection.h
|
||||
JSS(uptime); // out: GetCounts
|
||||
JSS(uri); // out: ValidatorSites
|
||||
JSS(uri_token); // in: LedgerEntry
|
||||
JSS(url); // in/out: Subscribe, Unsubscribe
|
||||
JSS(url_password); // in: Subscribe
|
||||
JSS(url_username); // in: Subscribe
|
||||
JSS(urlgravatar); //
|
||||
JSS(username); // in: Subscribe
|
||||
JSS(validated); // out: NetworkOPs, RPCHelpers, AccountTx*
|
||||
// Tx
|
||||
JSS(validator_list_expires); // out: NetworkOps, ValidatorList
|
||||
JSS(validator_list); // out: NetworkOps, ValidatorList
|
||||
JSS(tx_blob); // in/out: Submit,
|
||||
// in: TransactionSign, AccountTx*
|
||||
JSS(tx_hash); // in: TransactionEntry
|
||||
JSS(tx_json); // in/out: TransactionSign
|
||||
// out: TransactionEntry
|
||||
JSS(tx_signing_hash); // out: TransactionSign
|
||||
JSS(tx_unsigned); // out: TransactionSign
|
||||
JSS(txn_count); // out: NetworkOPs
|
||||
JSS(txr_tx_cnt); // out: protocol message tx's count
|
||||
JSS(txr_tx_sz); // out: protocol message tx's size
|
||||
JSS(txr_have_txs_cnt); // out: protocol message have tx count
|
||||
JSS(txr_have_txs_sz); // out: protocol message have tx size
|
||||
JSS(txr_get_ledger_cnt); // out: protocol message get ledger count
|
||||
JSS(txr_get_ledger_sz); // out: protocol message get ledger size
|
||||
JSS(txr_ledger_data_cnt); // out: protocol message ledger data count
|
||||
JSS(txr_ledger_data_sz); // out: protocol message ledger data size
|
||||
JSS(txr_transactions_cnt); // out: protocol message get object count
|
||||
JSS(txr_transactions_sz); // out: protocol message get object size
|
||||
JSS(txr_selected_cnt); // out: selected peers count
|
||||
JSS(txr_suppressed_cnt); // out: suppressed peers count
|
||||
JSS(txr_not_enabled_cnt); // out: peers with tx reduce-relay disabled count
|
||||
JSS(txr_missing_tx_freq); // out: missing tx frequency average
|
||||
JSS(txs); // out: TxHistory
|
||||
JSS(type); // in: AccountObjects
|
||||
// out: NetworkOPs RPC server_definitions
|
||||
// OverlayImpl, Logic
|
||||
JSS(TRANSACTION_RESULTS); // out: RPC server_definitions
|
||||
JSS(TRANSACTION_TYPES); // out: RPC server_definitions
|
||||
JSS(TYPES); // out: RPC server_definitions
|
||||
JSS(TRANSACTION_FLAGS); // out: RPC server_definitions
|
||||
JSS(TRANSACTION_FLAGS_INDICES); // out: RPC server_definitions
|
||||
JSS(type_hex); // out: STPathSet
|
||||
JSS(unl); // out: UnlList
|
||||
JSS(unlimited); // out: Connection.h
|
||||
JSS(unl_report); // in: LedgerEntry
|
||||
JSS(uptime); // out: GetCounts
|
||||
JSS(uri); // out: ValidatorSites
|
||||
JSS(uri_token); // in: LedgerEntry
|
||||
JSS(url); // in/out: Subscribe, Unsubscribe
|
||||
JSS(url_password); // in: Subscribe
|
||||
JSS(url_username); // in: Subscribe
|
||||
JSS(urlgravatar); //
|
||||
JSS(username); // in: Subscribe
|
||||
JSS(validated); // out: NetworkOPs, RPCHelpers, AccountTx*
|
||||
// Tx
|
||||
JSS(validator_list_expires); // out: NetworkOps, ValidatorList
|
||||
JSS(validator_list); // out: NetworkOps, ValidatorList
|
||||
JSS(validators);
|
||||
JSS(validated_hash); // out: NetworkOPs
|
||||
JSS(validated_ledger); // out: NetworkOPs
|
||||
|
||||
@@ -78,7 +78,7 @@ doAccountInfo(RPC::JsonContext& context)
|
||||
return jvAccepted;
|
||||
|
||||
static constexpr std::
|
||||
array<std::pair<std::string_view, LedgerSpecificFlags>, 9>
|
||||
array<std::pair<std::string_view, LedgerSpecificFlags>, 10>
|
||||
lsFlags{
|
||||
{{"defaultRipple", lsfDefaultRipple},
|
||||
{"depositAuth", lsfDepositAuth},
|
||||
@@ -88,16 +88,18 @@ doAccountInfo(RPC::JsonContext& context)
|
||||
{"noFreeze", lsfNoFreeze},
|
||||
{"passwordSpent", lsfPasswordSpent},
|
||||
{"requireAuthorization", lsfRequireAuth},
|
||||
{"tshCollect", lsfTshCollect},
|
||||
{"requireDestinationTag", lsfRequireDestTag}}};
|
||||
|
||||
static constexpr std::
|
||||
array<std::pair<std::string_view, LedgerSpecificFlags>, 4>
|
||||
array<std::pair<std::string_view, LedgerSpecificFlags>, 5>
|
||||
disallowIncomingFlags{
|
||||
{{"disallowIncomingNFTokenOffer",
|
||||
lsfDisallowIncomingNFTokenOffer},
|
||||
{"disallowIncomingCheck", lsfDisallowIncomingCheck},
|
||||
{"disallowIncomingPayChan", lsfDisallowIncomingPayChan},
|
||||
{"disallowIncomingTrustline", lsfDisallowIncomingTrustline}}};
|
||||
{"disallowIncomingTrustline", lsfDisallowIncomingTrustline},
|
||||
{"disallowIncomingRemit", lsfDisallowIncomingRemit}}};
|
||||
|
||||
auto const sleAccepted = ledger->read(keylet::account(accountID));
|
||||
if (sleAccepted)
|
||||
|
||||
@@ -42,7 +42,6 @@ namespace ripple {
|
||||
namespace_id: <namespace hex>
|
||||
ledger_hash: <string> // optional
|
||||
ledger_index: <string | unsigned integer> // optional
|
||||
type: <string> // optional, defaults to all account objects types
|
||||
limit: <integer> // optional
|
||||
marker: <opaque> // optional, resume previous query
|
||||
}
|
||||
|
||||
@@ -141,6 +141,8 @@ doCrawlShards(RPC::JsonContext&);
|
||||
Json::Value
|
||||
doStop(RPC::JsonContext&);
|
||||
Json::Value
|
||||
doInject(RPC::JsonContext&);
|
||||
Json::Value
|
||||
doSubmit(RPC::JsonContext&);
|
||||
Json::Value
|
||||
doSubmitMultiSigned(RPC::JsonContext&);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <ripple/net/RPCErr.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/PublicKey.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/rpc/Context.h>
|
||||
#include <ripple/rpc/GRPCHandlers.h>
|
||||
@@ -231,6 +232,41 @@ doLedgerEntry(RPC::JsonContext& context)
|
||||
uNodeIndex = keylet::emittedTxn(uNodeIndex).key;
|
||||
}
|
||||
}
|
||||
else if (context.params.isMember(jss::import_vlseq))
|
||||
{
|
||||
expectedType = ltIMPORT_VLSEQ;
|
||||
if (!context.params[jss::import_vlseq].isObject())
|
||||
{
|
||||
if (!uNodeIndex.parseHex(
|
||||
context.params[jss::import_vlseq].asString()))
|
||||
{
|
||||
uNodeIndex = beast::zero;
|
||||
jvResult[jss::error] = "malformedRequest";
|
||||
}
|
||||
}
|
||||
else if (
|
||||
!context.params[jss::import_vlseq].isMember(jss::public_key) ||
|
||||
!context.params[jss::import_vlseq][jss::public_key].isString())
|
||||
{
|
||||
jvResult[jss::error] = "malformedRequest";
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const pkHex = strUnHex(
|
||||
context.params[jss::import_vlseq][jss::public_key].asString());
|
||||
auto const pkSlice = makeSlice(*pkHex);
|
||||
if (!publicKeyType(pkSlice))
|
||||
{
|
||||
uNodeIndex = beast::zero;
|
||||
jvResult[jss::error] = "malformedRequest";
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const pk = PublicKey(pkSlice);
|
||||
uNodeIndex = keylet::import_vlseq(pk).key;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (context.params.isMember(jss::offer))
|
||||
{
|
||||
expectedType = ltOFFER;
|
||||
@@ -277,11 +313,32 @@ doLedgerEntry(RPC::JsonContext& context)
|
||||
{
|
||||
expectedType = ltURI_TOKEN;
|
||||
|
||||
if (!uNodeIndex.parseHex(context.params[jss::uri_token].asString()))
|
||||
if (!context.params[jss::uri_token].isObject())
|
||||
{
|
||||
if (!uNodeIndex.parseHex(context.params[jss::uri_token].asString()))
|
||||
{
|
||||
uNodeIndex = beast::zero;
|
||||
jvResult[jss::error] = "malformedRequest";
|
||||
}
|
||||
}
|
||||
else if (
|
||||
!context.params[jss::uri_token].isMember(jss::account) ||
|
||||
!context.params[jss::uri_token].isMember(jss::uri))
|
||||
{
|
||||
uNodeIndex = beast::zero;
|
||||
jvResult[jss::error] = "malformedRequest";
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const id = parseBase58<AccountID>(
|
||||
context.params[jss::uri_token][jss::account].asString());
|
||||
auto const strUri =
|
||||
context.params[jss::uri_token][jss::uri].asString();
|
||||
Blob raw = Blob(strUri.begin(), strUri.end());
|
||||
if (!id)
|
||||
jvResult[jss::error] = "malformedAddress";
|
||||
else
|
||||
uNodeIndex = keylet::uritoken(*id, raw).key;
|
||||
}
|
||||
}
|
||||
else if (context.params.isMember(jss::ripple_state))
|
||||
{
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#define MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM
|
||||
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/AmendmentTable.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
@@ -26,6 +28,7 @@
|
||||
#include <ripple/net/RPCErr.h>
|
||||
#include <ripple/protocol/LedgerFormats.h>
|
||||
#include <ripple/protocol/SField.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/rpc/impl/TransactionSign.h>
|
||||
@@ -41,6 +44,21 @@
|
||||
static constexpr int max = 20000; \
|
||||
};
|
||||
|
||||
#define MAGIC_ENUM_16(x) \
|
||||
template <> \
|
||||
struct magic_enum::customize::enum_range<x> \
|
||||
{ \
|
||||
static constexpr int min = -128; \
|
||||
static constexpr int max = 127; \
|
||||
};
|
||||
|
||||
#define MAGIC_ENUM_FLAG(x) \
|
||||
template <> \
|
||||
struct magic_enum::customize::enum_range<x> \
|
||||
{ \
|
||||
static constexpr bool is_flags = true; \
|
||||
};
|
||||
|
||||
MAGIC_ENUM(ripple::SerializedTypeID);
|
||||
MAGIC_ENUM(ripple::LedgerEntryType);
|
||||
MAGIC_ENUM(ripple::TELcodes);
|
||||
@@ -49,22 +67,45 @@ MAGIC_ENUM(ripple::TEFcodes);
|
||||
MAGIC_ENUM(ripple::TERcodes);
|
||||
MAGIC_ENUM(ripple::TEScodes);
|
||||
MAGIC_ENUM(ripple::TECcodes);
|
||||
MAGIC_ENUM_16(ripple::TxType);
|
||||
MAGIC_ENUM_FLAG(ripple::UniversalFlags);
|
||||
MAGIC_ENUM_FLAG(ripple::AccountSetFlags);
|
||||
MAGIC_ENUM_FLAG(ripple::OfferCreateFlags);
|
||||
MAGIC_ENUM_FLAG(ripple::PaymentFlags);
|
||||
MAGIC_ENUM_FLAG(ripple::TrustSetFlags);
|
||||
MAGIC_ENUM_FLAG(ripple::EnableAmendmentFlags);
|
||||
MAGIC_ENUM_FLAG(ripple::PaymentChannelClaimFlags);
|
||||
MAGIC_ENUM_FLAG(ripple::NFTokenMintFlags);
|
||||
MAGIC_ENUM_FLAG(ripple::NFTokenCreateOfferFlags);
|
||||
MAGIC_ENUM_FLAG(ripple::ClaimRewardFlags);
|
||||
MAGIC_ENUM_16(ripple::AccountFlags);
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class Definitions
|
||||
{
|
||||
private:
|
||||
Json::Value
|
||||
generate()
|
||||
{
|
||||
// RH TODO: probably a better way to do this?
|
||||
#define STR(x) \
|
||||
([&] { \
|
||||
std::ostringstream ss; \
|
||||
return ss << (x), ss.str(); \
|
||||
}())
|
||||
|
||||
template <typename EnumType>
|
||||
void
|
||||
addFlagsToJson(Json::Value& json, std::string const& key)
|
||||
{
|
||||
for (auto const& entry : magic_enum::enum_entries<EnumType>())
|
||||
{
|
||||
const auto name = entry.second;
|
||||
json[jss::TRANSACTION_FLAGS][key][STR(name)] =
|
||||
static_cast<uint32_t>(entry.first);
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value
|
||||
generate()
|
||||
{
|
||||
Json::Value ret{Json::objectValue};
|
||||
ret[jss::TYPES] = Json::objectValue;
|
||||
|
||||
@@ -368,6 +409,39 @@ private:
|
||||
ret[jss::TRANSACTION_TYPES][type_name] = type_value;
|
||||
}
|
||||
|
||||
// Transaction Flags:
|
||||
ret[jss::TRANSACTION_FLAGS] = Json::objectValue;
|
||||
addFlagsToJson<UniversalFlags>(ret, "Universal");
|
||||
addFlagsToJson<AccountSetFlags>(ret, "AccountSet");
|
||||
addFlagsToJson<OfferCreateFlags>(ret, "OfferCreate");
|
||||
addFlagsToJson<PaymentFlags>(ret, "Payment");
|
||||
addFlagsToJson<TrustSetFlags>(ret, "TrustSet");
|
||||
addFlagsToJson<EnableAmendmentFlags>(ret, "EnableAmendment");
|
||||
addFlagsToJson<PaymentChannelClaimFlags>(ret, "PaymentChannelClaim");
|
||||
addFlagsToJson<NFTokenMintFlags>(ret, "NFTokenMint");
|
||||
addFlagsToJson<NFTokenCreateOfferFlags>(ret, "NFTokenCreateOffer");
|
||||
addFlagsToJson<ClaimRewardFlags>(ret, "ClaimReward");
|
||||
struct FlagData
|
||||
{
|
||||
std::string name;
|
||||
std::uint32_t value;
|
||||
};
|
||||
std::array<FlagData, 1> uriTokenMintFlags{{{"tfBurnable", tfBurnable}}};
|
||||
for (auto const& entry : uriTokenMintFlags)
|
||||
{
|
||||
ret[jss::TRANSACTION_FLAGS]["URITokenMint"][entry.name] =
|
||||
static_cast<uint32_t>(entry.value);
|
||||
}
|
||||
|
||||
// Transaction Indicies Flags:
|
||||
ret[jss::TRANSACTION_FLAGS_INDICES] = Json::objectValue;
|
||||
for (auto const& entry : magic_enum::enum_entries<AccountFlags>())
|
||||
{
|
||||
const auto name = entry.second;
|
||||
ret[jss::TRANSACTION_FLAGS_INDICES]["AccountSet"][STR(name)] =
|
||||
static_cast<uint32_t>(entry.first);
|
||||
}
|
||||
|
||||
ret[jss::native_currency_code] = systemCurrencyCode();
|
||||
|
||||
// generate hash
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/app/reporting/P2pProxy.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/rpc/Context.h>
|
||||
#include <ripple/rpc/Role.h>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <ripple/app/ledger/LedgerMaster.h>
|
||||
#include <ripple/app/misc/HashRouter.h>
|
||||
#include <ripple/app/misc/Transaction.h>
|
||||
#include <ripple/app/misc/TxQ.h>
|
||||
#include <ripple/app/tx/apply.h>
|
||||
#include <ripple/net/RPCErr.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
@@ -39,6 +40,48 @@ getFailHard(RPC::JsonContext const& context)
|
||||
context.params["fail_hard"].asBool());
|
||||
}
|
||||
|
||||
// {
|
||||
// tx_blob: serialized tx
|
||||
// }
|
||||
// Only for debug use!!!!
|
||||
Json::Value
|
||||
doInject(RPC::JsonContext& context)
|
||||
{
|
||||
if (context.role != Role::ADMIN)
|
||||
return rpcError(rpcNO_PERMISSION);
|
||||
|
||||
Json::Value jvResult;
|
||||
|
||||
auto ret = strUnHex(context.params[jss::tx_blob].asString());
|
||||
|
||||
if (!ret || !ret->size())
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
|
||||
SerialIter sitTrans(makeSlice(*ret));
|
||||
|
||||
std::shared_ptr<STTx const> stpTrans;
|
||||
|
||||
try
|
||||
{
|
||||
stpTrans = std::make_shared<STTx const>(std::ref(sitTrans));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
jvResult[jss::error] = "invalidTransaction";
|
||||
jvResult[jss::error_exception] = e.what();
|
||||
jvResult[jss::in_queue] = false;
|
||||
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
context.app.getTxQ().debugTxInject(*stpTrans);
|
||||
|
||||
jvResult[jss::tx_json] = stpTrans->getJson(JsonOptions::none);
|
||||
jvResult[jss::in_queue] = true;
|
||||
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
// {
|
||||
// tx_json: <object>,
|
||||
// secret: <secret>
|
||||
|
||||
Loaded 100 of 146 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user