Compare commits

...
Author SHA1 Message Date
RichardAH e26fd326e0 Merge branch 'dev' into fix/rpc-queue-limit 2024-10-25 09:11:19 +10:00
tequ 4239124750 Update amendments for rippled-standalone.cfg (#385) 2024-10-25 09:10:45 +10:00
Wietse Wind 6fdb285d48 clang again 2024-10-24 02:32:15 +02:00
Wietse Wind e2e0186b32 Improve ADMIN HTTP POST RPC notifications: no queue limit, shorter HTTP call TTL 2024-10-24 02:29:02 +02:00
RichardAHandDenis Angell 1e45d4120c Update to boost186 (#377)
Co-Authored-By: Denis Angell <[email protected]>
2024-10-17 01:29:17 +02:00
Denis Angell 9e446bcc85 Fix: Missing Headers - Linker Errors (#300) 2024-10-16 18:19:21 +10:00
RichardAH 376727d20c use std::lexicographical_compare_three_way for uint spaceship operator (#374)
* use std::lexicographical_compare_three_way for uint spaceship operator

* clang
2024-10-16 11:37:26 +10:00
Richard Holland d921c87c88 also update max transactions for tx queue 2024-10-11 09:59:04 +11:00
RichardAH 7b94d3d99d increase txn in ledger target to 1000 (#372) 2024-10-11 08:21:23 +10:00
Denis Angell 79d83bd424 fix240911 (#363) 2024-09-11 13:43:03 +10:00
Richard Holland 1a4d54f9d9 force build 2024-09-07 15:41:00 +10:00
Wietse WindandWietse Wind 26cd629d28 Merge/2.2.2 jobqueue (#360)
* Merge https://github.com/XRPLF/rippled/commit/fbbea9e6e25795a8a6bd1bf64b780771933a9579

* Merge https://github.com/XRPLF/rippled/commit/774148389467781aca7c01bac90af2fba870570c

* clang-format

* Oops

---------

Co-authored-by: Wietse Wind <[email protected]>
2024-09-07 15:22:15 +10:00
RichardAHandDenis Angell 2fb93f874b fixPageCap (#359)
* page cap fix

---------

Co-authored-by: Denis Angell <[email protected]>
2024-09-07 11:39:24 +10:00
RichardAHandDenis Angell 833df20fce Fix240819 (#350)
fix240918
---------

Co-authored-by: Denis Angell <[email protected]>
2024-08-20 09:40:31 +10:00
Wietse Wind 5737c2b6e8 Workaround CentOS7 EOL 2024-08-18 01:50:44 +02:00
Richard Holland a15d0b2ecc set huge mode nudb cache to 64mib 2024-08-14 16:40:07 +10:00
Denis Angell 18d76d3082 fix delivered amount (#310)
* fix delivered amount
2024-07-16 08:56:30 +10:00
Wietse WindandDenis Angell 849a4435e0 CI Split jobs with prev job dependency & CI on jshooks (#320)
* CI on `jshooks` branch

* CI Split jobs with prev job dependency

* No multi branch worker in parallel

---------

Co-authored-by: Denis Angell <[email protected]>
2024-05-29 13:45:59 +02:00
Wietse Wind 247e9d98bf CI on jshooks branch (#317) 2024-05-24 10:10:40 +10:00
Denis Angell acd455f5df Fix: Server Definitions Typo (#306) 2024-04-19 07:39:21 +10:00
Denis AngellandRichardAH 6636e3b6fd Add RPC Tests (#295)
Co-authored-by: RichardAH <[email protected]>
2024-04-18 18:22:46 +10:00
Denis Angell 3c5f118b59 Fix: Add Tx Flags To Server Definitions (#304) 2024-04-18 15:43:48 +10:00
Vasu 88308126cc Removing duplicate macro #define LPAREN ( (#233) 2024-03-25 09:11:21 +11:00
Denis Angell 497e52fcc6 Update Macros (#279)
* add common macros
* remove old/unused macros
2024-03-25 08:43:46 +11:00
Denis AngellandRichard Holland a3852763e7 Fix: Namespace Delete (OwnerCount) (#296)
* fix ns delete owner count
* add a new success code and refactor success checks, limit ns delete operations to 256 entries per txn
---------
Co-authored-by: Richard Holland <[email protected]>
2024-03-25 08:37:08 +11:00
RichardAHandDenis Angell 7cd8f0a03a ZeroB2M amendment (#293)
* ZeroB2M amendment

Co-authored-by: Denis Angell <[email protected]>
2024-03-22 10:49:35 +11:00
Denis Angell d24c134612 add emitted order test (#273) 2024-03-11 11:46:03 +11:00
Denis Angell cdac69a111 Fix: URIToken Test (#254)
* update tests for fixXahauV1
2024-03-11 10:06:15 +11:00
Denis Angell 1500522427 fix tsh on nftoken (#269) 2024-03-11 09:38:45 +11:00
Denis AngellandRichard Holland 75aba531d6 Amendment: featureRemit (#278)
* Remit Amendment

Co-authored-by: Denis Angell <[email protected]>

Co-authored-by: Richard Holland <[email protected]>
2024-03-11 09:29:39 +11:00
Wietse Wind caa8b382d8 🤦 2024-02-22 23:28:19 +01:00
Wietse Wind 82e04073be Revert checkout v3 2024-02-14 15:21:43 +01:00
Wietse Wind e1b78f9682 Do clean 2024-02-14 15:20:24 +01:00
Wietse Wind 901d1d4e8d Update checkout CI to v4 2024-02-14 15:17:45 +01:00
Wietse Wind aca5241515 Build Container per user 2024-02-14 15:15:12 +01:00
RichardAH 780378c221 fix hook emission ordering (#270) 2024-01-24 19:55:28 +01:00
RichardAH 2dc5e670ac fix buildinfo test (#266) 2024-01-22 12:34:13 +01:00
RichardAH 4dff5a5c8e fix permisisons on inject (#264) 2024-01-22 10:48:01 +01:00
Denis AngellandRichard Holland f64e626a3f Fix: TSH Updates & Emitted Txn (#261)
fixXahauV2
* refactor tsh
* add uritoken mint/cancel tsh
* add flags to hookexections meta and nonce to hookemissions meta

Co-authored-by: Richard Holland <[email protected]>
2024-01-22 10:25:36 +01:00
RichardAH f21d3e1e97 Merge pull request #260 from Xahau/emit_guard
Fix: EmittedTxn Reliability
2024-01-19 14:05:06 +01:00
Denis Angell 858055c811 clang-format 2024-01-19 11:07:22 +01:00
Denis Angell 5d66f17574 add test 2024-01-19 11:05:45 +01:00
Denis Angell 00328cb782 Merge branch 'dev' into emit_guard 2024-01-19 10:24:34 +01:00
Richard Holland fdf7ea4174 dbg inject clang + permission check 2024-01-17 18:15:17 +00:00
Richard Holland 7877ed9704 debug txn injector 2024-01-17 18:07:05 +00:00
Richard Holland 17ccec9ac5 Add additional checks for emitted txns 2024-01-17 15:39:02 +00:00
RichardAH de522ac4ae Merge pull request #255 from Xahau/candidate
Candidate/release/sync
2023-12-29 22:18:04 +01:00
RichardAH 74c83a9271 Merge branch 'release' into candidate 2023-12-29 21:56:05 +01:00
Wietse Wind 66ee96d456 Build on release after all 2023-12-29 15:43:33 +01:00
Wietse Wind b476aea55b Do not auto build on release 2023-12-29 15:39:48 +01:00
RichardAH 4ad697069f Fix xahau v1audit (#250) 2023-12-27 14:53:38 +01:00
Denis Angell 97acfe9f97 Fix: URIToken Test (#247) 2023-12-22 11:54:54 +01:00
Denis AngellandRichardAH 475b6f7347 Amendment: Fix Xahau v1 (#231)
* FXV1: Meta Amount (#225)

* FXV1: Optional Offer Sequence (#224)

* FXV1: Patch Hooks OwnerDir (#236)

* FXV1:  Fix `Import` Quorum (#235)

* FXV1: Namespace Limit (#220)

* FXV1: allow duplicate entries in genesis mint transactor (#239)

* FXV1: Fix URIToken (#243)

* lite fixes for tsh issues (#244)

Co-authored-by: RichardAH <[email protected]>
2023-12-21 16:21:17 +01:00
Denis Angell 1b9373e220 add array xpop path 2023-10-30 15:53:48 +01:00
146 changed files with 11822 additions and 3971 deletions

No files matched your search

+17 -5
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+9 -5
View File
@@ -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
+1 -1
View File
@@ -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
+3
View File
@@ -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
-1
View File
@@ -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
+2 -2
View File
@@ -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
View File
@@ -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 \
+9 -1
View File
@@ -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
+2
View File
@@ -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
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+6 -2
View File
@@ -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);
});
}
+24 -4
View File
@@ -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;
}
+7 -1
View File
@@ -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
View File
@@ -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 {
-1
View File
@@ -10,7 +10,6 @@
* were then used.
*/
#define LPAREN (
#define LPAREN (
#define RPAREN )
#define COMMA ,
+2 -38
View File
@@ -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
+257 -67
View File
@@ -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: "
+11
View File
@@ -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;
+11
View File
@@ -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();
+1 -1
View File
@@ -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_;
};
//------------------------------------------------------------------------------
+2
View File
@@ -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 {
+52 -8
View File
@@ -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);
+9 -1
View File
@@ -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
+40 -6
View File
@@ -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(
+2 -2
View File
@@ -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);
+2 -2
View File
@@ -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);
+4 -4
View File
@@ -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)
+3 -3
View File
@@ -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)};
+3 -3
View File
@@ -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)};
+7 -7
View File
@@ -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)};
+7 -5
View File
@@ -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);
+4 -3
View File
@@ -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
+7 -1
View File
@@ -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); });
}
}
+1 -1
View File
@@ -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 -30
View File
@@ -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;
}
+2 -2
View File
@@ -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();
+8 -8
View File
@@ -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);
}
+55 -11
View File
@@ -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;
}
}
+160 -28
View File
@@ -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());
+27 -8
View File
@@ -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)
+11 -10
View File
@@ -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
View File
@@ -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;
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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);
+632
View File
@@ -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
+54
View File
@@ -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
+8
View File
@@ -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)
+41 -36
View File
@@ -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
+9 -7
View File
@@ -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,
+12
View File
@@ -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(
+2 -2
View File
@@ -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;
// }
+13 -13
View File
@@ -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;
+57 -9
View File
@@ -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);
File diff suppressed because it is too large. Load diff
+18 -5
View File
@@ -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
+1
View File
@@ -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>
+15 -1
View File
@@ -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
+4 -2
View File
@@ -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)
{
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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 }}}
}};
+4 -2
View File
@@ -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,
+7 -1
View File
@@ -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);
+3 -1
View File
@@ -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
+1
View File
@@ -19,6 +19,7 @@
#include <ripple/basics/contract.h>
#include <ripple/ledger/detail/ApplyViewBase.h>
#include <ripple/protocol/STAccount.h>
namespace ripple {
namespace detail {
+32 -10
View File
@@ -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);
+1
View File
@@ -18,6 +18,7 @@
//==============================================================================
#include <ripple/app/rdb/Download.h>
#include <fstream>
namespace ripple {
+3 -1
View File
@@ -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,
+10 -7
View File
@@ -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;
+9 -8
View File
@@ -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");
+6 -6
View File
@@ -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"]);
}
//------------------------------------------------------------------------------
-1
View File
@@ -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>
+9 -2
View File
@@ -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
+2
View File
@@ -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,
+5
View File
@@ -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;
//------------------------------------------------------------------------------
+13 -3
View File
@@ -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
+69 -46
View File
@@ -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
+4
View File
@@ -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 */
+1
View File
@@ -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
+8 -2
View File
@@ -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&
+5
View File
@@ -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
+3
View File
@@ -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
+18 -3
View File
@@ -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
View File
@@ -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
+5 -3
View File
@@ -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
}
+2
View File
@@ -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&);
+59 -2
View File
@@ -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))
{
+78 -4
View File
@@ -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
+1
View File
@@ -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>
+43
View File
@@ -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