mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Compare commits
2 Commits
release-te
...
hook-tools
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bedde782c6 | ||
|
|
2dc5e670ac |
@@ -455,7 +455,6 @@ target_sources (rippled PRIVATE
|
||||
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/Remit.cpp
|
||||
src/ripple/app/tx/impl/SetSignerList.cpp
|
||||
src/ripple/app/tx/impl/SetTrust.cpp
|
||||
src/ripple/app/tx/impl/SignerEntries.cpp
|
||||
@@ -741,7 +740,6 @@ 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
|
||||
@@ -891,7 +889,6 @@ 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
|
||||
|
||||
127
hook/genesis/callback.c
Normal file
127
hook/genesis/callback.c
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* Payment Txn
|
||||
*/
|
||||
#include "hookapi.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// clang-format off
|
||||
uint8_t txn[305] =
|
||||
{
|
||||
/* size,upto */
|
||||
/* 3, 0 */ 0x12U, 0x00U, 0x00U, /* tt = Payment */
|
||||
/* 5, 3*/ 0x22U, 0x80U, 0x00U, 0x00U, 0x00U, /* flags = tfCanonical */
|
||||
/* 5, 8 */ 0x24U, 0x00U, 0x00U, 0x00U, 0x00U, /* sequence = 0 */
|
||||
/* 5, 13 */ 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, /* dtag, flipped */
|
||||
/* 6, 18 */ 0x20U, 0x1AU, 0x00U, 0x00U, 0x00U, 0x00U, /* first ledger seq */
|
||||
/* 6, 24 */ 0x20U, 0x1BU, 0x00U, 0x00U, 0x00U, 0x00U, /* last ledger seq */
|
||||
/* 49, 30 */ 0x61U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, /* amount field 9 or 49 bytes */
|
||||
0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U,
|
||||
0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U,
|
||||
0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U,
|
||||
0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U,
|
||||
0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99,
|
||||
/* 9, 79 */ 0x68U, 0x40U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, /* fee */
|
||||
/* 35, 88 */ 0x73U, 0x21U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* pubkey */
|
||||
/* 22,123 */ 0x81U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* src acc */
|
||||
/* 22,145 */ 0x83U, 0x14U, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* dst acc */
|
||||
/* 138,167 */ /* emit details */
|
||||
/* 0,305 */
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// TX BUILDER
|
||||
#define FLS_OUT (txn + 20U)
|
||||
#define LLS_OUT (txn + 26U)
|
||||
#define DTAG_OUT (txn + 14U)
|
||||
#define AMOUNT_OUT (txn + 30U)
|
||||
#define FEE_OUT (txn + 80U)
|
||||
#define HOOK_ACC (txn + 125U)
|
||||
#define OTX_ACC (txn + 147U)
|
||||
#define EMIT_OUT (txn + 167U)
|
||||
|
||||
int64_t cbak(uint32_t f)
|
||||
{
|
||||
uint8_t f_buf[4];
|
||||
UINT32_TO_BUF(f_buf, f);
|
||||
accept(SBUF(f_buf), __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t hook(uint32_t reserved)
|
||||
{
|
||||
|
||||
TRACESTR("callback.c: Called.");
|
||||
|
||||
// ACCOUNT: Hook Account
|
||||
uint8_t hook_acc[20];
|
||||
hook_account(HOOK_ACC, 20);
|
||||
|
||||
// TXN: PREPARE: Init
|
||||
etxn_reserve(2);
|
||||
|
||||
for (int64_t i = 0; GUARD(2), i < 2; i++)
|
||||
{
|
||||
TRACEVAR(i);
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
util_accid(OTX_ACC, 20, SBUF("rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK"));
|
||||
case 1:
|
||||
util_accid(OTX_ACC, 20, SBUF("rH4KEcG9dEwGwpn6AyoWK9cZPLL4RLSmWW"));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t fls = (uint32_t)ledger_seq() + 1;
|
||||
*((uint32_t *)(FLS_OUT)) = FLIP_ENDIAN(fls);
|
||||
|
||||
// TXN PREPARE: LastLedgerSequense
|
||||
uint32_t lls = fls + 4;
|
||||
*((uint32_t *)(LLS_OUT)) = FLIP_ENDIAN(lls);
|
||||
|
||||
// TXN PREPARE: Amount
|
||||
uint64_t drops = 1000000;
|
||||
uint8_t *b = AMOUNT_OUT + 1;
|
||||
*b++ = 0b01000000 + ((drops >> 56) & 0b00111111);
|
||||
*b++ = (drops >> 48) & 0xFFU;
|
||||
*b++ = (drops >> 40) & 0xFFU;
|
||||
*b++ = (drops >> 32) & 0xFFU;
|
||||
*b++ = (drops >> 24) & 0xFFU;
|
||||
*b++ = (drops >> 16) & 0xFFU;
|
||||
*b++ = (drops >> 8) & 0xFFU;
|
||||
*b++ = (drops >> 0) & 0xFFU;
|
||||
|
||||
// TXN PREPARE: Dest Tag <- Source Tag
|
||||
if (otxn_field(DTAG_OUT, 4, sfSourceTag) == 4)
|
||||
*(DTAG_OUT - 1) = 0x2EU;
|
||||
|
||||
// TXN PREPARE: Emit Metadata
|
||||
etxn_details(EMIT_OUT, 138U);
|
||||
|
||||
// TXN PREPARE: Fee
|
||||
{
|
||||
int64_t fee = etxn_fee_base(SBUF(txn));
|
||||
uint8_t *b = FEE_OUT;
|
||||
*b++ = 0b01000000 + ((fee >> 56) & 0b00111111);
|
||||
*b++ = (fee >> 48) & 0xFFU;
|
||||
*b++ = (fee >> 40) & 0xFFU;
|
||||
*b++ = (fee >> 32) & 0xFFU;
|
||||
*b++ = (fee >> 24) & 0xFFU;
|
||||
*b++ = (fee >> 16) & 0xFFU;
|
||||
*b++ = (fee >> 8) & 0xFFU;
|
||||
*b++ = (fee >> 0) & 0xFFU;
|
||||
}
|
||||
|
||||
TRACEHEX(txn); // <- final tx blob
|
||||
|
||||
// TXN: Emit/Send Txn
|
||||
uint8_t emithash[32];
|
||||
int64_t emit_result = emit(SBUF(emithash), SBUF(txn));
|
||||
TRACEVAR(emit_result);
|
||||
}
|
||||
|
||||
accept(SBUF("callback.c: Successful."), __LINE__);
|
||||
|
||||
// unreachable
|
||||
return 0;
|
||||
}
|
||||
32
hook/genesis/tsh.c
Normal file
32
hook/genesis/tsh.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "hookapi.h"
|
||||
|
||||
int64_t hook(uint32_t reserved) {
|
||||
TRACESTR("tsh.c: Start.");
|
||||
|
||||
uint8_t aaw_buffer[1];
|
||||
if (otxn_param(SBUF(aaw_buffer), "AAW", 3) == 1)
|
||||
hook_again();
|
||||
|
||||
switch (reserved)
|
||||
{
|
||||
case 0:
|
||||
TRACESTR("tsh.c: Strong. Execute BEFORE transaction is applied to ledger");
|
||||
break;
|
||||
case 1:
|
||||
TRACESTR("tsh.c: Weak. Execute AFTER transaction is applied to ledger");
|
||||
break;
|
||||
case 2:
|
||||
TRACESTR("tsh.c: Weak Again. Execute AFTER transaction is applied to ledger");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
TRACESTR("tsh.c: End.");
|
||||
uint8_t r_buf[4];
|
||||
UINT32_TO_BUF(r_buf, reserved);
|
||||
accept(SBUF(r_buf), __LINE__);
|
||||
_g(1,1);
|
||||
// unreachable
|
||||
return 0;
|
||||
}
|
||||
54
hook/macro.h
54
hook/macro.h
@@ -9,6 +9,34 @@
|
||||
#ifndef HOOKMACROS_INCLUDED
|
||||
#define HOOKMACROS_INCLUDED 1
|
||||
|
||||
#define DONEEMPTY()\
|
||||
accept(0,0,__LINE__)
|
||||
|
||||
#define DONEMSG(msg)\
|
||||
accept(msg, sizeof(msg),__LINE__)
|
||||
|
||||
#define DONE(x)\
|
||||
accept(SVAR(x),(uint32_t)__LINE__);
|
||||
|
||||
|
||||
#define SVAR(x) &x, sizeof(x)
|
||||
|
||||
#define ASSERT(x)\
|
||||
{\
|
||||
if (!(x))\
|
||||
rollback(0,0,__LINE__);\
|
||||
}
|
||||
|
||||
#define NOPE(x)\
|
||||
{\
|
||||
return rollback((x), sizeof(x), __LINE__);\
|
||||
}
|
||||
|
||||
#define FLIP_ENDIAN(n) ((uint32_t) (((n & 0xFFU) << 24U) | \
|
||||
((n & 0xFF00U) << 8U) | \
|
||||
((n & 0xFF0000U) >> 8U) | \
|
||||
((n & 0xFF000000U) >> 24U)))
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define DEBUG 0
|
||||
@@ -138,6 +166,18 @@ 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
|
||||
@@ -483,11 +523,16 @@ int out_len = 0;\
|
||||
#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_SIZE 35
|
||||
#define ENCODE_SIGNING_PUBKEY_NULL(buf_out )\
|
||||
{\
|
||||
*buf_out++ = 0x73U;\
|
||||
*buf_out++ = 0x00U;\
|
||||
buf_out[0] = 0x73U;\
|
||||
buf_out[1] = 0x21U;\
|
||||
*(uint64_t*)(buf_out+2) = 0;\
|
||||
*(uint64_t*)(buf_out+10) = 0;\
|
||||
*(uint64_t*)(buf_out+18) = 0;\
|
||||
*(uint64_t*)(buf_out+25) = 0;\
|
||||
buf_out += ENCODE_SIGNING_PUBKEY_NULL_SIZE;\
|
||||
}
|
||||
|
||||
#define _07_03_ENCODE_SIGNING_PUBKEY_NULL(buf_out )\
|
||||
@@ -516,8 +561,7 @@ int out_len = 0;\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
*buf_out++ = 0x50U; /* HookHash */\
|
||||
*buf_out++ = 0x1FU;\
|
||||
*buf_out++ = 0x1FU; /* HookHash */\
|
||||
uint64_t* d = (uint64_t*)buf_out;\
|
||||
uint64_t* s = (uint64_t*)hook0;\
|
||||
*d++ = *s++;\
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#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
|
||||
|
||||
35
hook/wasm_from_carray.py
Normal file
35
hook/wasm_from_carray.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Check if the file name is provided as a command-line argument
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python script.py <filename>")
|
||||
sys.exit(1)
|
||||
|
||||
# Read the .h file content
|
||||
file_name = sys.argv[1] # Get the file name from command-line arguments
|
||||
try:
|
||||
with open(file_name, "r") as file:
|
||||
content = file.read()
|
||||
|
||||
# Find the C array using a regular expression
|
||||
match = re.search(r'\{(.+?)\};', content, re.DOTALL)
|
||||
if match:
|
||||
c_array = match.group(1)
|
||||
|
||||
# Extract the hexadecimal values and remove the 'U' suffix
|
||||
hex_values = re.findall(r'0x([0-9A-F]+)U', c_array)
|
||||
|
||||
# Convert the list of hex values to a byte array
|
||||
byte_array = bytearray.fromhex(''.join(hex_values))
|
||||
|
||||
# Convert the byte array to a hex string
|
||||
hex_string = byte_array.hex().upper()
|
||||
|
||||
print(hex_string)
|
||||
else:
|
||||
print("C array not found in the file.")
|
||||
except FileNotFoundError:
|
||||
print(f"File not found: {file_name}")
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
33
hook/wasm_to_carray.py
Normal file
33
hook/wasm_to_carray.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import sys
|
||||
import binascii
|
||||
|
||||
# Check if the name is provided as a command-line argument
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: python script.py <name>")
|
||||
sys.exit(1)
|
||||
|
||||
name: str = sys.argv[1]
|
||||
|
||||
try:
|
||||
with open(f"build/{name}.wasm", "rb") as file:
|
||||
wasm = file.read()
|
||||
except FileNotFoundError:
|
||||
print(f"Error: File build/{name}.wasm not found.")
|
||||
sys.exit(1)
|
||||
|
||||
data = wasm.hex().upper()
|
||||
|
||||
# Convert hexadecimal data to bytes
|
||||
binary_data = binascii.unhexlify(data)
|
||||
|
||||
# Generate C array
|
||||
c_array = ', '.join([f"0x{b:02X}U" for b in binary_data])
|
||||
|
||||
try:
|
||||
with open(f"hook/{name}_a.h", "w") as file:
|
||||
file.write(f'static const std::vector<uint8_t> {name.capitalize()}Hook = {"{"}')
|
||||
file.write(c_array)
|
||||
file.write("};\n")
|
||||
except IOError as e:
|
||||
print(f"Error: Unable to write to file {name}_a.h. {e}")
|
||||
sys.exit(1)
|
||||
46
hook/wasm_verify.py
Normal file
46
hook/wasm_verify.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Function to extract hexadecimal values from a C array in a .h file
|
||||
def extract_hex_values(file_name):
|
||||
try:
|
||||
with open(file_name, "r") as file:
|
||||
content = file.read()
|
||||
except FileNotFoundError:
|
||||
print(f"File {file_name} not found.")
|
||||
return None
|
||||
|
||||
# Find the C array using a regular expression
|
||||
match = re.search(r'\{(.+?)\};', content, re.DOTALL)
|
||||
if match:
|
||||
c_array = match.group(1)
|
||||
|
||||
# Extract the hexadecimal values and remove the 'U' suffix
|
||||
hex_values = re.findall(r'0x([0-9A-F]+)U', c_array)
|
||||
return hex_values
|
||||
else:
|
||||
print(f"C array not found in the file {file_name}.")
|
||||
return None
|
||||
|
||||
# Check if the correct number of arguments are provided
|
||||
if len(sys.argv) != 3:
|
||||
print("Usage: python script.py <file1.h> <file2.h>")
|
||||
sys.exit(1)
|
||||
|
||||
# File names of the .h files to compare
|
||||
file_name1 = sys.argv[1]
|
||||
file_name2 = sys.argv[2]
|
||||
|
||||
# Extract hexadecimal values from both files
|
||||
hex_values1 = extract_hex_values(file_name1)
|
||||
hex_values2 = extract_hex_values(file_name2)
|
||||
|
||||
print(len(hex_values1))
|
||||
print(len(hex_values2))
|
||||
|
||||
# Compare the hexadecimal values if both files have been read successfully
|
||||
if hex_values1 is not None and hex_values2 is not None:
|
||||
if hex_values1 == hex_values2:
|
||||
print("The hexadecimal values in both files match.")
|
||||
else:
|
||||
print("The hexadecimal values in both files do not match.")
|
||||
@@ -318,7 +318,6 @@ getTransactionalStakeHolders(STTx const& tx, ReadView const& rv)
|
||||
}
|
||||
|
||||
// simple two party transactions
|
||||
case ttREMIT:
|
||||
case ttPAYMENT:
|
||||
case ttESCROW_CREATE:
|
||||
case ttCHECK_CREATE:
|
||||
|
||||
@@ -597,8 +597,7 @@ ValidNewAccountRoot::finalize(
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((tt == ttPAYMENT || tt == ttIMPORT || tt == ttGENESIS_MINT ||
|
||||
tt == ttREMIT) &&
|
||||
if ((tt == ttPAYMENT || tt == ttIMPORT || tt == ttGENESIS_MINT) &&
|
||||
result == tesSUCCESS)
|
||||
{
|
||||
std::uint32_t const startingSeq{
|
||||
|
||||
@@ -1,518 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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>
|
||||
namespace ripple {
|
||||
|
||||
TxConsequences
|
||||
Remit::makeTxConsequences(PreflightContext const& ctx)
|
||||
{
|
||||
return TxConsequences{ctx.tx, TxConsequences::normal};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// sanity check amounts
|
||||
if (ctx.tx.isFieldPresent(sfAmounts))
|
||||
{
|
||||
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>();
|
||||
// RH TODO: iterate mint fields detect any that shouldnt be there
|
||||
|
||||
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(mint.getFieldVL(sfURI)))
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "Malformed transaction: Invalid UTF8 inside MintURIToken.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (mint.isFieldPresent(sfFlags))
|
||||
{
|
||||
if (mint.getFieldU32(sfFlags) & tfURITokenMintMask)
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
// check uritokenids for duplicates
|
||||
if (ctx.tx.isFieldPresent(sfURITokenIDs))
|
||||
{
|
||||
STVector256 ids = ctx.tx.getFieldV256(sfURITokenIDs);
|
||||
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()
|
||||
{
|
||||
if (!view().rules().enabled(featureRemit))
|
||||
return temDISABLED;
|
||||
|
||||
Sandbox sb(&ctx_.view());
|
||||
|
||||
beast::Journal const& j = ctx_.journal;
|
||||
|
||||
auto const srcAccID = ctx_.tx[sfAccount];
|
||||
|
||||
auto sleSrcAcc = sb.peek(keylet::account(srcAccID));
|
||||
if (!sleSrcAcc)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
XRPAmount const accountReserve{sb.fees().accountReserve(0)};
|
||||
XRPAmount const objectReserve{sb.fees().accountReserve(1) - accountReserve};
|
||||
|
||||
// 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;
|
||||
|
||||
// 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
|
||||
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))
|
||||
{
|
||||
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 = view().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 tecUNFUNDED_PAYMENT;
|
||||
}
|
||||
|
||||
// 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
|
||||
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.
|
||||
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);
|
||||
canXfer != tesSUCCESS)
|
||||
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;
|
||||
|
||||
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(
|
||||
issuerAccID == dstAccID ? srcAccID : dstAccID,
|
||||
issuerAccID,
|
||||
amount.getCurrency())))
|
||||
nativeRemit += objectReserve;
|
||||
|
||||
// action the transfer
|
||||
if (TER result =
|
||||
accountSend(sb, srcAccID, dstAccID, amount, j, false);
|
||||
result != tesSUCCESS)
|
||||
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())};
|
||||
|
||||
// RH TODO: add fees
|
||||
|
||||
return Transactor::calculateBaseFee(view, tx) + extraFee;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -1,54 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TX_SIMPLE_PAYMENT_H_INCLUDED
|
||||
#define RIPPLE_TX_SIMPLE_PAYMENT_H_INCLUDED
|
||||
|
||||
#include <ripple/app/tx/impl/Transactor.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class Remit : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
|
||||
explicit Remit(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -577,14 +577,6 @@ 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)
|
||||
|
||||
@@ -164,8 +164,6 @@ 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:
|
||||
@@ -285,8 +283,6 @@ 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:
|
||||
@@ -368,8 +364,6 @@ 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:
|
||||
@@ -549,10 +543,6 @@ 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:
|
||||
|
||||
@@ -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 = 68;
|
||||
static constexpr std::size_t numFeatures = 67;
|
||||
|
||||
/** Amendments that this server supports and the default voting behavior.
|
||||
Whether they are enabled depends on the Rules defined in the validated
|
||||
@@ -355,7 +355,6 @@ extern uint256 const featureXahauGenesis;
|
||||
extern uint256 const featureHooksUpdate1;
|
||||
extern uint256 const fixXahauV1;
|
||||
extern uint256 const fixXahauV2;
|
||||
extern uint256 const featureRemit;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
|
||||
@@ -285,8 +285,6 @@ enum LedgerSpecificFlags {
|
||||
0x20000000, // True, reject new trustlines (only if no issued assets)
|
||||
lsfURITokenIssuer =
|
||||
0x40000000, // True, has minted tokens in the past
|
||||
lsfDisallowIncomingRemit = // True, no remits allowed to this account
|
||||
0x80000000,
|
||||
|
||||
// ltOFFER
|
||||
lsfPassive = 0x00010000,
|
||||
|
||||
@@ -552,7 +552,6 @@ 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;
|
||||
@@ -563,7 +562,6 @@ 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
|
||||
@@ -592,8 +590,6 @@ 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
|
||||
@@ -621,7 +617,6 @@ extern SField const sfGenesisMints;
|
||||
extern SField const sfActiveValidators;
|
||||
extern SField const sfImportVLKeys;
|
||||
extern SField const sfHookEmissions;
|
||||
extern SField const sfAmounts;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ constexpr std::uint32_t asfDisallowIncomingNFTokenOffer = 12;
|
||||
constexpr std::uint32_t asfDisallowIncomingCheck = 13;
|
||||
constexpr std::uint32_t asfDisallowIncomingPayChan = 14;
|
||||
constexpr std::uint32_t asfDisallowIncomingTrustline = 15;
|
||||
constexpr std::uint32_t asfDisallowIncomingRemit = 16;
|
||||
|
||||
// OfferCreate flags:
|
||||
constexpr std::uint32_t tfPassive = 0x00010000;
|
||||
|
||||
@@ -146,10 +146,6 @@ 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 */
|
||||
|
||||
@@ -461,7 +461,6 @@ REGISTER_FEATURE(XahauGenesis, Supported::yes, VoteBehavior::De
|
||||
REGISTER_FEATURE(HooksUpdate1, Supported::yes, VoteBehavior::DefaultYes);
|
||||
REGISTER_FIX (fixXahauV1, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX (fixXahauV2, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FEATURE(Remit, Supported::yes, VoteBehavior::DefaultNo);
|
||||
|
||||
// The following amendments are obsolete, but must remain supported
|
||||
// because they could potentially get enabled.
|
||||
|
||||
@@ -143,21 +143,6 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfPublicKey, soeREQUIRED},
|
||||
{sfAccount, soeOPTIONAL},
|
||||
});
|
||||
|
||||
add(sfAmountEntry.jsonName.c_str(),
|
||||
sfAmountEntry.getCode(),
|
||||
{
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfFlags, soeOPTIONAL},
|
||||
});
|
||||
|
||||
add(sfMintURIToken.jsonName.c_str(),
|
||||
sfMintURIToken.getCode(),
|
||||
{
|
||||
{sfURI, soeREQUIRED},
|
||||
{sfDigest, soeOPTIONAL},
|
||||
{sfFlags, soeOPTIONAL},
|
||||
});
|
||||
}
|
||||
|
||||
InnerObjectFormats const&
|
||||
|
||||
@@ -305,7 +305,6 @@ 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);
|
||||
@@ -313,7 +312,6 @@ 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);
|
||||
@@ -348,8 +346,6 @@ 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
|
||||
@@ -374,7 +370,6 @@ 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
|
||||
|
||||
|
||||
@@ -116,21 +116,6 @@ 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,
|
||||
{
|
||||
|
||||
@@ -117,7 +117,6 @@ 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.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -57,7 +57,6 @@
|
||||
#include <test/jtx/quality.h>
|
||||
#include <test/jtx/rate.h>
|
||||
#include <test/jtx/regkey.h>
|
||||
#include <test/jtx/remit.h>
|
||||
#include <test/jtx/require.h>
|
||||
#include <test/jtx/requires.h>
|
||||
#include <test/jtx/reward.h>
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2023 XRPL Labs
|
||||
|
||||
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/protocol/jss.h>
|
||||
#include <test/jtx/remit.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace jtx {
|
||||
namespace remit {
|
||||
|
||||
Json::Value
|
||||
remit(jtx::Account const& account, jtx::Account const& dest)
|
||||
{
|
||||
using namespace jtx;
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = jss::Remit;
|
||||
jv[jss::Account] = account.human();
|
||||
jv[jss::Destination] = dest.human();
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
amts::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
auto& ja = jt.jv[sfAmounts.getJsonName()];
|
||||
for (std::size_t i = 0; i < amts_.size(); ++i)
|
||||
{
|
||||
ja[i][sfAmountEntry.jsonName] = Json::Value{};
|
||||
ja[i][sfAmountEntry.jsonName][jss::Amount] =
|
||||
amts_[i].getJson(JsonOptions::none);
|
||||
}
|
||||
jt.jv[sfAmounts.jsonName] = ja;
|
||||
}
|
||||
|
||||
void
|
||||
blob::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
jt.jv[sfBlob.jsonName] = blob_;
|
||||
}
|
||||
|
||||
void
|
||||
inform::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
jt.jv[sfInform.jsonName] = inform_.human();
|
||||
}
|
||||
|
||||
void
|
||||
token_ids::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
for (std::size_t i = 0; i < token_ids_.size(); ++i)
|
||||
{
|
||||
jt.jv[sfURITokenIDs.jsonName] = Json::arrayValue;
|
||||
jt.jv[sfURITokenIDs.jsonName][i] = token_ids_[i];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uri::operator()(Env& env, JTx& jt) const
|
||||
{
|
||||
jt.jv[sfMintURIToken.jsonName] = Json::Value{};
|
||||
jt.jv[sfMintURIToken.jsonName][sfURI.jsonName] = strHex(uri_);
|
||||
;
|
||||
}
|
||||
|
||||
} // namespace remit
|
||||
} // namespace jtx
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
@@ -1,118 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2023 XRPL Labs
|
||||
|
||||
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_TEST_JTX_REMIT_H_INCLUDED
|
||||
#define RIPPLE_TEST_JTX_REMIT_H_INCLUDED
|
||||
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <test/jtx/Account.h>
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace jtx {
|
||||
|
||||
namespace remit {
|
||||
|
||||
Json::Value
|
||||
remit(jtx::Account const& account, jtx::Account const& dest);
|
||||
|
||||
/** Sets the optional Amount on a JTx. */
|
||||
class amts
|
||||
{
|
||||
private:
|
||||
std::vector<STAmount> amts_;
|
||||
|
||||
public:
|
||||
explicit amts(std::vector<STAmount> const& amts) : amts_(amts)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jtx) const;
|
||||
};
|
||||
|
||||
/** Set the optional "Blob" on a JTx */
|
||||
class blob
|
||||
{
|
||||
private:
|
||||
std::string blob_;
|
||||
|
||||
public:
|
||||
explicit blob(std::string const& blob) : blob_(blob)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jtx) const;
|
||||
};
|
||||
|
||||
/** Sets the optional "Inform" on a JTx. */
|
||||
class inform
|
||||
{
|
||||
private:
|
||||
jtx::Account inform_;
|
||||
|
||||
public:
|
||||
explicit inform(jtx::Account const& inform) : inform_(inform)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jtx) const;
|
||||
};
|
||||
|
||||
/** Sets the optional "URITokenIDs" on a JTx. */
|
||||
class token_ids
|
||||
{
|
||||
private:
|
||||
std::vector<std::string> token_ids_;
|
||||
|
||||
public:
|
||||
explicit token_ids(std::vector<std::string> const& token_ids) : token_ids_(token_ids)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jtx) const;
|
||||
};
|
||||
|
||||
/** Set the optional "sfMintURIToken" on a JTx */
|
||||
class uri
|
||||
{
|
||||
private:
|
||||
std::string uri_;
|
||||
|
||||
public:
|
||||
explicit uri(std::string const& uri) : uri_(uri)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jtx) const;
|
||||
};
|
||||
|
||||
} // namespace remit
|
||||
|
||||
} // namespace jtx
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_TEST_JTX_REMIT_H_INCLUDED
|
||||
@@ -98,7 +98,7 @@ public:
|
||||
auto vCurrent = BuildInfo::getEncodedVersion();
|
||||
BEAST_EXPECT(!BuildInfo::isNewerVersion(vCurrent));
|
||||
|
||||
auto vMax = BuildInfo::encodeSoftwareVersion("9999.12.30");
|
||||
auto vMax = BuildInfo::encodeSoftwareVersion("2100.12.30");
|
||||
BEAST_EXPECT(BuildInfo::isNewerVersion(vMax));
|
||||
|
||||
auto vRelease1 = BuildInfo::encodeSoftwareVersion("2023.1.1-release+1");
|
||||
|
||||
@@ -88,8 +88,7 @@ public:
|
||||
flag == asfDisallowIncomingPayChan ||
|
||||
flag == asfDisallowIncomingNFTokenOffer ||
|
||||
flag == asfDisallowIncomingTrustline ||
|
||||
flag == asfTshCollect ||
|
||||
flag == asfDisallowIncomingRemit)
|
||||
flag == asfTshCollect)
|
||||
{
|
||||
// These flags are part of the DisallowIncoming amendment
|
||||
// and are tested elsewhere
|
||||
|
||||
Reference in New Issue
Block a user