From 598a0e31a491b93b0908ea24522151c4b64d3b51 Mon Sep 17 00:00:00 2001 From: xVet Date: Mon, 27 Nov 2023 16:30:45 +0100 Subject: [PATCH 01/26] XLS-46 dNFTs PR first --- cfg/rippled-example.cfg | 1742 ----------------- cfg/validators-example.txt | 72 - src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp | 1 + src/ripple/app/tx/impl/NFTokenModify.cpp | 88 + src/ripple/app/tx/impl/NFTokenModify.h | 48 + .../app/tx/impl/details/NFTokenUtils.cpp | 16 + src/ripple/protocol/TxFlags.h | 3 +- 7 files changed, 155 insertions(+), 1815 deletions(-) delete mode 100644 cfg/rippled-example.cfg delete mode 100644 cfg/validators-example.txt create mode 100644 src/ripple/app/tx/impl/NFTokenModify.cpp create mode 100644 src/ripple/app/tx/impl/NFTokenModify.h diff --git a/cfg/rippled-example.cfg b/cfg/rippled-example.cfg deleted file mode 100644 index a3bcf0056be..00000000000 --- a/cfg/rippled-example.cfg +++ /dev/null @@ -1,1742 +0,0 @@ -#------------------------------------------------------------------------------- -# -# -#------------------------------------------------------------------------------- -# -# Contents -# -# 1. Server -# -# 2. Peer Protocol -# -# 3. Ripple Protocol -# -# 4. HTTPS Client -# -# 5. Reporting Mode -# -# 6. Database -# -# 7. Diagnostics -# -# 8. Voting -# -# 9. Misc Settings -# -# 10. Example Settings -# -#------------------------------------------------------------------------------- -# -# Purpose -# -# This file documents and provides examples of all rippled server process -# configuration options. When the rippled server instance is launched, it -# looks for a file with the following name: -# -# rippled.cfg -# -# For more information on where the rippled server instance searches for the -# file, visit: -# -# https://xrpl.org/commandline-usage.html#generic-options -# -# This file should be named rippled.cfg. This file is UTF-8 with DOS, UNIX, -# or Mac style end of lines. Blank lines and lines beginning with '#' are -# ignored. Undefined sections are reserved. No escapes are currently defined. -# -# Notation -# -# In this document a simple BNF notation is used. Angle brackets denote -# required elements, square brackets denote optional elements, and single -# quotes indicate string literals. A vertical bar separating 1 or more -# elements is a logical "or"; any one of the elements may be chosen. -# Parentheses are notational only, and used to group elements; they are not -# part of the syntax unless they appear in quotes. White space may always -# appear between elements, it has no effect on values. -# -# A required identifier -# '=' The equals sign character -# | Logical "or" -# ( ) Used for grouping -# -# -# An identifier is a string of upper or lower case letters, digits, or -# underscores subject to the requirement that the first character of an -# identifier must be a letter. Identifiers are not case sensitive (but -# values may be). -# -# Some configuration sections contain key/value pairs. A line containing -# a key/value pair has this syntax: -# -# '=' -# -# Depending on the section and key, different value types are possible: -# -# A signed integer -# An unsigned integer -# A boolean. 1 = true/yes/on, 0 = false/no/off. -# -# Consult the documentation on the key in question to determine the possible -# value types. -# -# -# -#------------------------------------------------------------------------------- -# -# 1. Server -# -#---------- -# -# -# -# rippled offers various server protocols to clients making inbound -# connections. The listening ports rippled uses are "universal" ports -# which may be configured to handshake in one or more of the available -# supported protocols. These universal ports simplify administration: -# A single open port can be used for multiple protocols. -# -# NOTE At least one server port must be defined in order -# to accept incoming network connections. -# -# -# [server] -# -# A list of port names and key/value pairs. A port name must start with a -# letter and contain only letters and numbers. The name is not case-sensitive. -# For each name in this list, rippled will look for a configuration file -# section with the same name and use it to create a listening port. The -# name is informational only; the choice of name does not affect the function -# of the listening port. -# -# Key/value pairs specified in this section are optional, and apply to all -# listening ports unless the port overrides the value in its section. They -# may be considered default values. -# -# Suggestion: -# -# To avoid a conflict with port names and future configuration sections, -# we recommend prepending "port_" to the port name. This prefix is not -# required, but suggested. -# -# This example defines two ports with different port numbers and settings: -# -# [server] -# port_public -# port_private -# port = 80 -# -# [port_public] -# ip = 0.0.0.0 -# port = 443 -# protocol = peer,https -# -# [port_private] -# ip = 127.0.0.1 -# protocol = http -# -# When rippled is used as a command line client (for example, issuing a -# server stop command), the first port advertising the http or https -# protocol will be used to make the connection. -# -# -# -# [] -# -# A series of key/value pairs that define the settings for the port with -# the corresponding name. These keys are possible: -# -# ip = -# -# Required. Determines the IP address of the network interface to bind -# to. To bind to all available IPv4 interfaces, use 0.0.0.0 -# To binding to all IPv4 and IPv6 interfaces, use :: -# -# NOTE if the ip value is ::, then any incoming IPv4 connections will -# be made as mapped IPv4 addresses. -# -# port = -# -# Required. Sets the port number to use for this port. -# -# protocol = [ http, https, peer ] -# -# Required. A comma-separated list of protocols to support: -# -# http JSON-RPC over HTTP -# https JSON-RPC over HTTPS -# ws Websockets -# wss Secure Websockets -# peer Peer Protocol -# -# Restrictions: -# -# Only one port may be configured to support the peer protocol. -# A port cannot have websocket and non websocket protocols at the -# same time. It is possible have both Websockets and Secure Websockets -# together in one port. -# -# NOTE If no ports support the peer protocol, rippled cannot -# receive incoming peer connections or become a superpeer. -# -# limit = -# -# Optional. An integer value that will limit the number of connected -# clients that the port will accept. Once the limit is reached, new -# connections will be refused until other clients disconnect. -# Omit or set to 0 to allow unlimited numbers of clients. -# -# user = -# password = -# -# When set, these credentials will be required on HTTP/S requests. -# The credentials must be provided using HTTP's Basic Authentication -# headers. If either or both fields are empty, then no credentials are -# required. IP address restrictions, if any, will be checked in addition -# to the credentials specified here. -# -# When acting in the client role, rippled will supply these credentials -# using HTTP's Basic Authentication headers when making outbound HTTP/S -# requests. -# -# admin = [ IP, IP, IP, ... ] -# -# A comma-separated list of IP addresses or subnets. Subnets -# should be represented in "slash" notation, such as: -# 10.0.0.0/8 -# 172.16.0.0/12 -# 192.168.0.0/16 -# Those examples are ipv4, but ipv6 is also supported. -# When configuring subnets, the address must match the -# underlying network address. Otherwise, the desired IP range is -# ambiguous. For example, 10.1.2.3/24 has a network address of -# 10.1.2.0. Therefore, that subnet should be configured as -# 10.1.2.0/24. -# -# When set, grants administrative command access to the specified -# addresses. These commands may be issued over http, https, ws, or wss -# if configured on the port. If not provided, the default is to not allow -# administrative commands. -# -# NOTE A common configuration value for the admin field is "localhost". -# If you are listening on all IPv4/IPv6 addresses by specifing -# ip = :: then you can use admin = ::ffff:127.0.0.1,::1 to allow -# administrative access from both IPv4 and IPv6 localhost -# connections. -# -# *SECURITY WARNING* -# 0.0.0.0 or :: may be used to allow access from any IP address. It must -# be the only address specified and cannot be combined with other IPs. -# Use of this address can compromise server security, please consider its -# use carefully. -# -# admin_user = -# admin_password = -# -# When set, clients must provide these credentials in the submitted -# JSON for any administrative command requests submitted to the HTTP/S, -# WS, or WSS protocol interfaces. If administrative commands are -# disabled for a port, these credentials have no effect. -# -# When acting in the client role, rippled will supply these credentials -# in the submitted JSON for any administrative command requests when -# invoking JSON-RPC commands on remote servers. -# -# secure_gateway = [ IP, IP, IP, ... ] -# -# A comma-separated list of IP addresses or subnets. See the -# details for the "admin" option above. -# -# When set, allows the specified addresses to pass HTTP headers -# containing username and remote IP address for each session. If a -# non-empty username is passed in this way, then resource controls -# such as often resulting in "tooBusy" errors will be lifted. However, -# administrative RPC commands such as "stop" will not be allowed. -# The HTTP headers that secure_gateway hosts can set are X-User and -# X-Forwarded-For. Only the X-User header affects resource controls. -# However, both header values are logged to help identify user activity. -# If no X-User header is passed, or if its value is empty, then -# resource controls will default to those for non-administrative users. -# -# The secure_gateway IP addresses are intended to represent -# proxies. Since rippled trusts these hosts, they must be -# responsible for properly authenticating the remote user. -# -# If some IP addresses are included for both "admin" and -# "secure_gateway" connections, then they will be treated as -# "admin" addresses. -# -# ssl_key = -# ssl_cert = -# ssl_chain = -# -# Use the specified files when configuring SSL on the port. -# -# NOTE If no files are specified and secure protocols are selected, -# rippled will generate an internal self-signed certificate. -# -# The files have these meanings: -# -# ssl_key -# -# Specifies the filename holding the SSL key in PEM format. -# -# ssl_cert -# -# Specifies the path to the SSL certificate file in PEM format. -# This is not needed if the chain includes it. Use ssl_chain if -# your certificate includes one or more intermediates. -# -# ssl_chain -# -# If you need a certificate chain, specify the path to the -# certificate chain here. The chain may include the end certificate. -# This must be used if the certificate includes intermediates. -# -# ssl_ciphers = -# -# Control the ciphers which the server will support over SSL on the port, -# specified using the OpenSSL "cipher list format". -# -# NOTE If unspecified, rippled will automatically configure a modern -# cipher suite. This default suite should be widely supported. -# -# You should not modify this string unless you have a specific -# reason and cryptographic expertise. Incorrect modification may -# keep rippled from connecting to other instances of rippled or -# prevent RPC and WebSocket clients from connecting. -# -# send_queue_limit = [1..65535] -# -# A Websocket will disconnect when its send queue exceeds this limit. -# The default is 100. A larger value may help with erratic disconnects but -# may adversely affect server performance. -# -# WebSocket permessage-deflate extension options -# -# These settings configure the optional permessage-deflate extension -# options and may appear on any port configuration entry. They are meaningful -# only to ports which have enabled a WebSocket protocol. -# -# permessage_deflate = -# -# Determines if permessage_deflate extension negotiations are enabled. -# When enabled, clients may request the extension and the server will -# offer the enabled extension in response. -# -# client_max_window_bits = [9..15] -# server_max_window_bits = [9..15] -# client_no_context_takeover = -# server_no_context_takeover = -# -# These optional settings control options related to the permessage-deflate -# extension negotiation. For precise definitions of these fields please see -# the RFC 7692, "Compression Extensions for WebSocket": -# https://tools.ietf.org/html/rfc7692 -# -# compress_level = [0..9] -# -# When set, determines the amount of compression attempted, where 0 is -# the least amount and 9 is the most amount. Higher levels require more -# CPU resources. Levels 1 through 3 use a fast compression algorithm, -# while levels 4 through 9 use a more compact algorithm which uses more -# CPU resources. If unspecified, a default of 3 is used. -# -# memory_level = [1..9] -# -# When set, determines the relative amount of memory used to hold -# intermediate compression data. Higher numbers can give better compression -# ratios at the cost of higher memory and CPU resources. -# -# [rpc_startup] -# -# Specify a list of RPC commands to run at startup. -# -# Examples: -# { "command" : "server_info" } -# { "command" : "log_level", "partition" : "ripplecalc", "severity" : "trace" } -# -# -# -# [websocket_ping_frequency] -# -# -# -# The amount of time to wait in seconds, before sending a websocket 'ping' -# message. Ping messages are used to determine if the remote end of the -# connection is no longer available. -# -# -# [server_domain] -# -# domain name -# -# The domain under which a TOML file applicable to this server can be -# found. A server may lie about its domain so the TOML should contain -# a reference to this server by pubkey in the [nodes] array. -# -# -#------------------------------------------------------------------------------- -# -# 2. Peer Protocol -# -#----------------- -# -# These settings control security and access attributes of the Peer to Peer -# server section of the rippled process. Peer Protocol implements the -# Ripple Payment protocol. It is over peer connections that transactions -# and validations are passed from to machine to machine, to determine the -# contents of validated ledgers. -# -# -# -# [compression] -# -# true or false -# -# true - enables compression -# false - disables compression [default]. -# -# The rippled server can save bandwidth by compressing its peer-to-peer communications, -# at a cost of greater CPU usage. If you enable link compression, -# the server automatically compresses communications with peer servers -# that also have link compression enabled. -# https://xrpl.org/enable-link-compression.html -# -# -# -# [ips] -# -# List of hostnames or ips where the Ripple protocol is served. A default -# starter list is included in the code and used if no other hostnames are -# available. -# -# One address or domain name per line is allowed. A port may must be -# specified after adding a space to the address. The ordering of entries -# does not generally matter. -# -# The default list of entries is: -# - r.ripple.com 51235 -# - zaphod.alloy.ee 51235 -# - sahyadri.isrdc.in 51235 -# -# Examples: -# -# [ips] -# 192.168.0.1 -# 192.168.0.1 2459 -# r.ripple.com 51235 -# -# -# [ips_fixed] -# -# List of IP addresses or hostnames to which rippled should always attempt to -# maintain peer connections with. This is useful for manually forming private -# networks, for example to configure a validation server that connects to the -# Ripple network through a public-facing server, or for building a set -# of cluster peers. -# -# One address or domain names per line is allowed. A port must be specified -# after adding a space to the address. -# -# -# -# [peer_private] -# -# 0 or 1. -# -# 0: Request peers to broadcast your address. Normal outbound peer connections [default] -# 1: Request peers not broadcast your address. Only connect to configured peers. -# -# -# -# [peers_max] -# -# The largest number of desired peer connections (incoming or outgoing). -# Cluster and fixed peers do not count towards this total. There are -# implementation-defined lower limits imposed on this value for security -# purposes. -# -# -# -# [node_seed] -# -# This is used for clustering. To force a particular node seed or key, the -# key can be set here. The format is the same as the validation_seed field. -# To obtain a validation seed, use the validation_create command. -# -# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE -# shfArahZT9Q9ckTf3s1psJ7C7qzVN -# -# -# -# [cluster_nodes] -# -# To extend full trust to other nodes, place their node public keys here. -# Generally, you should only do this for nodes under common administration. -# Node public keys start with an 'n'. To give a node a name for identification -# place a space after the public key and then the name. -# -# -# -# [max_transactions] -# -# Configure the maximum number of transactions to have in the job queue -# -# Must be a number between 1000 and 100000, defaults to 10000 -# -# -# [overlay] -# -# Controls settings related to the peer to peer overlay. -# -# A set of key/value pair parameters to configure the overlay. -# -# public_ip = -# -# If the server has a known, fixed public IPv4 address, -# specify that IP address here in dotted decimal notation. -# Peers will use this information to reject attempt to proxy -# connections to or from this server. -# -# ip_limit = -# -# The maximum number of incoming peer connections allowed by a single -# IP that isn't classified as "private" in RFC1918. The implementation -# imposes some hard and soft upper limits on this value to prevent a -# single host from consuming all inbound slots. If the value is not -# present the server will autoconfigure an appropriate limit. -# -# max_unknown_time = -# -# The maximum amount of time, in seconds, that an outbound connection -# is allowed to stay in the "unknown" tracking state. This option can -# take any value between 300 and 1800 seconds, inclusive. If the option -# is not present the server will autoconfigure an appropriate limit. -# -# The current default (which is subject to change) is 600 seconds. -# -# max_diverged_time = -# -# The maximum amount of time, in seconds, that an outbound connection -# is allowed to stay in the "diverged" tracking state. The option can -# take any value between 60 and 900 seconds, inclusive. If the option -# is not present the server will autoconfigure an appropriate limit. -# -# The current default (which is subject to change) is 300 seconds. -# -# -# [transaction_queue] EXPERIMENTAL -# -# This section is EXPERIMENTAL, and should not be -# present for production configuration settings. -# -# A set of key/value pair parameters to tune the performance of the -# transaction queue. -# -# ledgers_in_queue = -# -# The queue will be limited to this of average ledgers' -# worth of transactions. If the queue fills up, the transactions -# with the lowest fee levels will be dropped from the queue any -# time a transaction with a higher fee level is added. -# Default: 20. -# -# minimum_queue_size = -# -# The queue will always be able to hold at least this of -# transactions, regardless of recent ledger sizes or the value of -# ledgers_in_queue. Default: 2000. -# -# retry_sequence_percent = -# -# If a client replaces a transaction in the queue (same sequence -# number as a transaction already in the queue), the new -# transaction's fee must be more than percent higher -# than the original transaction's fee, or meet the current open -# ledger fee to be considered. Default: 25. -# -# minimum_escalation_multiplier = -# -# At ledger close time, the median fee level of the transactions -# in that ledger is used as a multiplier in escalation -# calculations of the next ledger. This minimum value ensures that -# the escalation is significant. Default: 500. -# -# minimum_txn_in_ledger = -# -# Minimum number of transactions that must be allowed into the -# ledger at the minimum required fee before the required fee -# escalates. Default: 5. -# -# minimum_txn_in_ledger_standalone = -# -# Like minimum_txn_in_ledger when rippled is running in standalone -# mode. Default: 1000. -# -# target_txn_in_ledger = -# -# Number of transactions allowed into the ledger at the minimum -# required fee that the queue will "work toward" as long as -# consensus stays healthy. The limit will grow quickly until it -# reaches or exceeds this number. After that the limit may still -# change, but will stay above the target. If consensus is not -# healthy, the limit will be clamped to this value or lower. -# Default: 50. -# -# maximum_txn_in_ledger = -# -# (Optional) Maximum number of transactions that will be allowed -# into the ledger at the minimum required fee before the required -# fee escalates. Default: no maximum. -# -# normal_consensus_increase_percent = -# -# (Optional) When the ledger has more transactions than "expected", -# and performance is humming along nicely, the expected ledger size -# is updated to the previous ledger size plus this percentage. -# Default: 20 -# -# slow_consensus_decrease_percent = -# -# (Optional) When consensus takes longer than appropriate, the -# expected ledger size is updated to the minimum of the previous -# ledger size or the "expected" ledger size minus this percentage. -# Default: 50 -# -# maximum_txn_per_account = -# -# Maximum number of transactions that one account can have in the -# queue at any given time. Default: 10. -# -# minimum_last_ledger_buffer = -# -# If a transaction has a LastLedgerSequence, it must be at least -# this much larger than the current open ledger sequence number. -# Default: 2. -# -# zero_basefee_transaction_feelevel = -# -# So we don't deal with infinite fee levels, treat any transaction -# with a 0 base fee (ie. SetRegularKey password recovery) as -# having this fee level. -# Default: 256000. -# -# -#------------------------------------------------------------------------------- -# -# 3. Protocol -# -#------------------- -# -# These settings affect the behavior of the server instance with respect -# to protocol level activities such as validating and closing ledgers -# adjusting fees in response to server overloads. -# -# -# -# -# [relay_proposals] -# -# Controls the relay and processing behavior for proposals received by this -# server that are issued by validators that are not on the server's UNL. -# -# Legal values are: -# "all" - Relay and process all incoming proposals -# "trusted" - Relay only trusted proposals, but locally process all -# "drop_untrusted" - Relay only trusted proposals, do not process untrusted -# -# The default is "trusted". -# -# -# [relay_validations] -# -# Controls the relay and processing behavior for validations received by this -# server that are issued by validators that are not on the server's UNL. -# -# Legal values are: -# "all" - Relay and process all incoming validations -# "trusted" - Relay only trusted validations, but locally process all -# "drop_untrusted" - Relay only trusted validations, do not process untrusted -# -# The default is "all". -# -# -# -# -# -# [ledger_history] -# -# The number of past ledgers to acquire on server startup and the minimum to -# maintain while running. -# -# To serve clients, servers need historical ledger data. Servers that don't -# need to serve clients can set this to "none". Servers that want complete -# history can set this to "full". -# -# This must be less than or equal to online_delete (if online_delete is used) -# -# The default is: 256 -# -# -# -# [fetch_depth] -# -# The number of past ledgers to serve to other peers that request historical -# ledger data (or "full" for no limit). -# -# Servers that require low latency and high local performance may wish to -# restrict the historical ledgers they are willing to serve. Setting this -# below 32 can harm network stability as servers require easy access to -# recent history to stay in sync. Values below 128 are not recommended. -# -# The default is: full -# -# -# -# [validation_seed] -# -# To perform validation, this section should contain either a validation seed -# or key. The validation seed is used to generate the validation -# public/private key pair. To obtain a validation seed, use the -# validation_create command. -# -# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE -# shfArahZT9Q9ckTf3s1psJ7C7qzVN -# -# -# -# [validator_token] -# -# This is an alternative to [validation_seed] that allows rippled to perform -# validation without having to store the validator keys on the network -# connected server. The field should contain a single token in the form of a -# base64-encoded blob. -# An external tool is available for generating validator keys and tokens. -# -# -# -# [validator_key_revocation] -# -# If a validator's secret key has been compromised, a revocation must be -# generated and added to this field. The revocation notifies peers that it is -# no longer safe to trust the revoked key. The field should contain a single -# revocation in the form of a base64-encoded blob. -# An external tool is available for generating and revoking validator keys. -# -# -# -# [validators_file] -# -# Path or name of a file that determines the nodes to always accept as validators. -# -# The contents of the file should include a [validators] and/or -# [validator_list_sites] and [validator_list_keys] entries. -# [validators] should be followed by a list of validation public keys of -# nodes, one per line. -# [validator_list_sites] should be followed by a list of URIs each serving a -# list of recommended validators. -# [validator_list_keys] should be followed by a list of keys belonging to -# trusted validator list publishers. Validator lists fetched from configured -# sites will only be considered if the list is accompanied by a valid -# signature from a trusted publisher key. -# -# Specify the file by its name or path. -# Unless an absolute path is specified, it will be considered relative to -# the folder in which the rippled.cfg file is located. -# -# Examples: -# /home/ripple/validators.txt -# C:/home/ripple/validators.txt -# -# Example content: -# [validators] -# n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 -# n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj -# n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C -# n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS -# n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA -# -# -# -# [path_search] -# When searching for paths, the default search aggressiveness. This can take -# exponentially more resources as the size is increased. -# -# The recommended value to support advanced pathfinding is: 7 -# -# The default is: 2 -# -# [path_search_fast] -# [path_search_max] -# When searching for paths, the minimum and maximum search aggressiveness. -# -# If you do not need pathfinding, you can set path_search_max to zero to -# disable it and avoid some expensive bookkeeping. -# -# To support advanced pathfinding the recommended value for -# 'path_search_fast' is 2, and for 'path_search_max' is 10. -# -# The default for 'path_search_fast' is 2. The default for 'path_search_max' is 3. -# -# [path_search_old] -# -# For clients that use the legacy path finding interfaces, the search -# aggressiveness to use. -# -# The recommended value to support advanced pathfinding is: 7. -# -# The default is: 2 -# -# -# -# [fee_default] -# -# Sets the base cost of a transaction in drops. Used when the server has -# no other source of fee information, such as signing transactions offline. -# -# -# -# [workers] -# -# Configures the number of threads for processing work submitted by peers -# and clients. If not specified, then the value is automatically set to the -# number of processor threads plus 2 for networked nodes. Nodes running in -# stand alone mode default to 1 worker. -# -# [io_workers] -# -# Configures the number of threads for processing raw inbound and outbound IO. -# -# [prefetch_workers] -# -# Configures the number of threads for performing nodestore prefetching. -# -# -# -# [network_id] -# -# Specify the network which this server is configured to connect to and -# track. If set, the server will not establish connections with servers -# that are explicitly configured to track another network. -# -# Network identifiers are usually unsigned integers in the range 0 to -# 4294967295 inclusive. The server also maps the following well-known -# names to the corresponding numerical identifier: -# -# main -> 0 -# testnet -> 1 -# devnet -> 2 -# -# If this value is not specified the server is not explicitly configured -# to track a particular network. -# -# -# [ledger_replay] -# -# 0 or 1. -# -# 0: Disable the ledger replay feature [default] -# 1: Enable the ledger replay feature. With this feature enabled, when -# acquiring a ledger from the network, a rippled node only downloads -# the ledger header and the transactions instead of the whole ledger. -# And the ledger is built by applying the transactions to the parent -# ledger. -# -#------------------------------------------------------------------------------- -# -# 4. HTTPS Client -# -#---------------- -# -# The rippled server instance uses HTTPS GET requests in a variety of -# circumstances, including but not limited to contacting trusted domains to -# fetch information such as mapping an email address to a Ripple Payment -# Network address. -# -# [ssl_verify] -# -# 0 or 1. -# -# 0. HTTPS client connections will not verify certificates. -# 1. Certificates will be checked for HTTPS client connections. -# -# If not specified, this parameter defaults to 1. -# -# -# -# [ssl_verify_file] -# -# -# -# A file system path leading to the certificate verification file for -# HTTPS client requests. -# -# -# -# [ssl_verify_dir] -# -# -# -# -# A file system path leading to a file or directory containing the root -# certificates that the server will accept for verifying HTTP servers. -# Used only for outbound HTTPS client connections. -# -#------------------------------------------------------------------------------- -# -# 5. Reporting Mode -# -#------------ -# -# rippled has an optional operating mode called Reporting Mode. In Reporting -# Mode, rippled does not connect to the peer to peer network. Instead, rippled -# will continuously extract data from one or more rippled servers that are -# connected to the peer to peer network (referred to as an ETL source). -# Reporting mode servers will forward RPC requests that require access to the -# peer to peer network (submit, fee, etc) to an ETL source. -# -# [reporting] Settings for Reporting Mode. If and only if this section is -# present, rippled will start in reporting mode. This section -# contains a list of ETL source names, and key-value pairs. The -# ETL source names each correspond to a configuration file -# section; the names must match exactly. The key-value pairs are -# optional. -# -# -# [] -# -# A series of key/value pairs that specify an ETL source. -# -# source_ip = -# -# Required. IP address of the ETL source. Can also be a DNS record. -# -# source_ws_port = -# -# Required. Port on which ETL source is accepting unencrypted websocket -# connections. -# -# source_grpc_port = -# -# Required for ETL. Port on which ETL source is accepting gRPC requests. -# If this option is ommitted, this ETL source cannot actually be used for -# ETL; the Reporting Mode server can still forward RPCs to this ETL -# source, but cannot extract data from this ETL source. -# -# -# Key-value pairs (all optional): -# -# read_only Valid values: 0, 1. Default is 0. If set to 1, the server -# will start in strict read-only mode, and will not perform -# ETL. The server will still handle RPC requests, and will -# still forward RPC requests that require access to the p2p -# network. -# -# start_sequence -# Sequence of first ledger to extract if the database is empty. -# ETL extracts ledgers in order. If this setting is absent and -# the database is empty, ETL will start with the next ledger -# validated by the network. If this setting is present and the -# database is not empty, an exception is thrown. -# -# num_markers Degree of parallelism used during the initial ledger -# download. Only used if the database is empty. Valid values -# are 1-256. A higher degree of parallelism results in a -# faster download, but puts more load on the ETL source. -# Default is 2. -# -# Example: -# -# [reporting] -# etl_source1 -# etl_source2 -# read_only=0 -# start_sequence=32570 -# num_markers=8 -# -# [etl_source1] -# source_ip=1.2.3.4 -# source_ws_port=6005 -# source_grpc_port=50051 -# -# [etl_source2] -# source_ip=5.6.7.8 -# source_ws_port=6005 -# source_grpc_port=50051 -# -# Minimal Example: -# -# [reporting] -# etl_source1 -# -# [etl_source1] -# source_ip=1.2.3.4 -# source_ws_port=6005 -# source_grpc_port=50051 -# -# -# Notes: -# -# Reporting Mode requires Postgres (instead of SQLite). The Postgres -# connection info is specified under the [ledger_tx_tables] config section; -# see the Database section for further documentation. -# -# Each ETL source specified must have gRPC enabled (by adding a [port_grpc] -# section to the config). It is recommended to add a secure_gateway entry to -# the gRPC section, in order to bypass the server's rate limiting. -# This section needs to be added to the config of the ETL source, not -# the config of the reporting node. In the example below, the -# reporting server is running at 127.0.0.1. Multiple IPs can be -# specified in secure_gateway via a comma separated list. -# -# [port_grpc] -# ip = 0.0.0.0 -# port = 50051 -# secure_gateway = 127.0.0.1 -# -# -#------------------------------------------------------------------------------- -# -# 6. Database -# -#------------ -# -# rippled creates 4 SQLite database to hold bookkeeping information -# about transactions, local credentials, and various other things. -# It also creates the NodeDB, which holds all the objects that -# make up the current and historical ledgers. In Reporting Mode, rippled -# uses a Postgres database instead of SQLite. -# -# The simplest way to work with Postgres is to install it locally. -# When it is running, execute the initdb.sh script in the current -# directory as: sudo -u postgres ./initdb.sh -# This will create the rippled user and an empty database of the same name. -# -# The size of the NodeDB grows in proportion to the amount of new data and the -# amount of historical data (a configurable setting) so the performance of the -# underlying storage media where the NodeDB is placed can significantly affect -# the performance of the server. -# -# Partial pathnames will be considered relative to the location of -# the rippled.cfg file. -# -# [node_db] Settings for the Node Database (required) -# -# Format (without spaces): -# One or more lines of case-insensitive key / value pairs: -# '=' -# ... -# -# Example: -# type=nudb -# path=db/nudb -# -# The "type" field must be present and controls the choice of backend: -# -# type = NuDB -# -# NuDB is a high-performance database written by Ripple Labs and optimized -# for rippled and solid-state drives. -# -# NuDB maintains its high speed regardless of the amount of history -# stored. Online delete may be selected, but is not required. NuDB is -# available on all platforms that rippled runs on. -# -# type = RocksDB -# -# RocksDB is an open-source, general-purpose key/value store - see -# http://rocksdb.org/ for more details. -# -# RocksDB is an alternative backend for systems that don't use solid-state -# drives. Because RocksDB's performance degrades as it stores more data, -# keeping full history is not advised, and using online delete is -# recommended. -# -# type = Cassandra -# -# Apache Cassandra is an open-source, distributed key-value store - see -# https://cassandra.apache.org/ for more details. -# -# Cassandra is an alternative backend to be used only with Reporting Mode. -# See the Reporting Mode section for more details about Reporting Mode. -# -# Required keys for NuDB and RocksDB: -# -# path Location to store the database -# -# Required keys for Cassandra: -# -# contact_points IP of a node in the Cassandra cluster -# -# port CQL Native Transport Port -# -# secure_connect_bundle -# Absolute path to a secure connect bundle. When using -# a secure connect bundle, contact_points and port are -# not required. -# -# keyspace Name of Cassandra keyspace to use -# -# table_name Name of table in above keyspace to use -# -# Optional keys -# -# cache_size Size of cache for database records. Default is 16384. -# Setting this value to 0 will use the default value. -# -# cache_age Length of time in minutes to keep database records -# cached. Default is 5 minutes. Setting this value to -# 0 will use the default value. -# -# Note: if neither cache_size nor cache_age is -# specified, the cache for database records will not -# be created. If only one of cache_size or cache_age -# is specified, the cache will be created using the -# default value for the unspecified parameter. -# -# Note: the cache will not be created if online_delete -# is specified, or if shards are used. -# -# fast_load Boolean. If set, load the last persisted ledger -# from disk upon process start before syncing to -# the network. This is likely to improve performance -# if sufficient IOPS capacity is available. -# Default 0. -# -# Optional keys for NuDB or RocksDB: -# -# earliest_seq The default is 32570 to match the XRP ledger -# network's earliest allowed sequence. Alternate -# networks may set this value. Minimum value of 1. -# If a [shard_db] section is defined, and this -# value is present either [node_db] or [shard_db], -# it must be defined with the same value in both -# sections. -# -# online_delete Minimum value of 256. Enable automatic purging -# of older ledger information. Maintain at least this -# number of ledger records online. Must be greater -# than or equal to ledger_history. -# -# These keys modify the behavior of online_delete, and thus are only -# relevant if online_delete is defined and non-zero: -# -# advisory_delete 0 for disabled, 1 for enabled. If set, the -# administrative RPC call "can_delete" is required -# to enable online deletion of ledger records. -# Online deletion does not run automatically if -# non-zero and the last deletion was on a ledger -# greater than the current "can_delete" setting. -# Default is 0. -# -# delete_batch When automatically purging, SQLite database -# records are deleted in batches. This value -# controls the maximum size of each batch. Larger -# batches keep the databases locked for more time, -# which may cause other functions to fall behind, -# and thus cause the node to lose sync. -# Default is 100. -# -# back_off_milliseconds -# Number of milliseconds to wait between -# online_delete batches to allow other functions -# to catch up. -# Default is 100. -# -# age_threshold_seconds -# The online delete process will only run if the -# latest validated ledger is younger than this -# number of seconds. -# Default is 60. -# -# recovery_wait_seconds -# The online delete process checks periodically -# that rippled is still in sync with the network, -# and that the validated ledger is less than -# 'age_threshold_seconds' old. If not, then continue -# sleeping for this number of seconds and -# checking until healthy. -# Default is 5. -# -# Optional keys for Cassandra: -# -# username Username to use if Cassandra cluster requires -# authentication -# -# password Password to use if Cassandra cluster requires -# authentication -# -# max_requests_outstanding -# Limits the maximum number of concurrent database -# writes. Default is 10 million. For slower clusters, -# large numbers of concurrent writes can overload the -# cluster. Setting this option can help eliminate -# write timeouts and other write errors due to the -# cluster being overloaded. -# io_threads -# Set the number of IO threads used by the -# Cassandra driver. Defaults to 4. -# -# Notes: -# The 'node_db' entry configures the primary, persistent storage. -# -# The 'import_db' is used with the '--import' command line option to -# migrate the specified database into the current database given -# in the [node_db] section. -# -# [import_db] Settings for performing a one-time import (optional) -# [database_path] Path to the book-keeping databases. -# -# The server creates and maintains 4 to 5 bookkeeping SQLite databases in -# the 'database_path' location. If you omit this configuration setting, -# the server creates a directory called "db" located in the same place as -# your rippled.cfg file. -# Partial pathnames are relative to the location of the rippled executable. -# -# [shard_db] Settings for the Shard Database (optional) -# -# Format (without spaces): -# One or more lines of case-insensitive key / value pairs: -# '=' -# ... -# -# Example: -# path=db/shards/nudb -# -# Required keys: -# path Location to store the database -# -# Optional keys: -# max_historical_shards -# The maximum number of historical shards -# to store. -# -# [historical_shard_paths] Additional storage paths for the Shard Database (optional) -# -# Format (without spaces): -# One or more lines, each expressing a full path for storing historical shards: -# /mnt/disk1 -# /mnt/disk2 -# ... -# -# [sqlite] Tuning settings for the SQLite databases (optional) -# -# Format (without spaces): -# One or more lines of case-insensitive key / value pairs: -# '=' -# ... -# -# Example 1: -# safety_level=low -# -# Example 2: -# journal_mode=off -# synchronous=off -# -# WARNING: These settings can have significant effects on data integrity, -# particularly in systemic failure scenarios. It is strongly recommended -# that they be left at their defaults unless the server is having -# performance issues during normal operation or during automatic purging -# (online_delete) operations. A warning will be logged on startup if -# 'ledger_history' is configured to store more than 10,000,000 ledgers and -# any of these settings are less safe than the default. This is due to the -# inordinate amount of time and bandwidth it will take to safely rebuild a -# corrupted database of that size from other peers. -# -# Optional keys: -# -# safety_level Valid values: high, low -# The default is "high", which tunes the SQLite -# databases in the most reliable mode, and is -# equivalent to: -# journal_mode=wal -# synchronous=normal -# temp_store=file -# "low" is equivalent to: -# journal_mode=memory -# synchronous=off -# temp_store=memory -# These "low" settings trade speed and reduced I/O -# for a higher risk of data loss. See the -# individual settings below for more information. -# This setting may not be combined with any of the -# other tuning settings: "journal_mode", -# "synchronous", or "temp_store". -# -# journal_mode Valid values: delete, truncate, persist, memory, wal, off -# The default is "wal", which uses a write-ahead -# log to implement database transactions. -# Alternately, "memory" saves disk I/O, but if -# rippled crashes during a transaction, the -# database is likely to be corrupted. -# See https://www.sqlite.org/pragma.html#pragma_journal_mode -# for more details about the available options. -# This setting may not be combined with the -# "safety_level" setting. -# -# synchronous Valid values: off, normal, full, extra -# The default is "normal", which works well with -# the "wal" journal mode. Alternatively, "off" -# allows rippled to continue as soon as data is -# passed to the OS, which can significantly -# increase speed, but risks data corruption if -# the host computer crashes before writing that -# data to disk. -# See https://www.sqlite.org/pragma.html#pragma_synchronous -# for more details about the available options. -# This setting may not be combined with the -# "safety_level" setting. -# -# temp_store Valid values: default, file, memory -# The default is "file", which will use files -# for temporary database tables and indices. -# Alternatively, "memory" may save I/O, but -# rippled does not currently use many, if any, -# of these temporary objects. -# See https://www.sqlite.org/pragma.html#pragma_temp_store -# for more details about the available options. -# This setting may not be combined with the -# "safety_level" setting. -# -# [ledger_tx_tables] (optional) -# -# conninfo Info for connecting to Postgres. Format is -# postgres://[username]:[password]@[ip]/[database]. -# The database and user must already exist. If this -# section is missing and rippled is running in -# Reporting Mode, rippled will connect as the -# user running rippled to a database with the -# same name. On Linux and Mac OS X, the connection -# will take place using the server's UNIX domain -# socket. On Windows, through the localhost IP -# address. Default is empty. -# -# use_tx_tables Valid values: 1, 0 -# The default is 1 (true). Determines whether to use -# the SQLite transaction database. If set to 0, -# rippled will not write to the transaction database, -# and will reject tx, account_tx and tx_history RPCs. -# In Reporting Mode, this setting is ignored. -# -# max_connections Valid values: any positive integer up to 64 bit -# storage length. This configures the maximum -# number of concurrent connections to postgres. -# Default is the maximum possible value to -# fit in a 64 bit integer. -# -# timeout Number of seconds after which idle postgres -# connections are discconnected. If set to 0, -# connections never timeout. Default is 600. -# -# -# remember_ip Value values: 1, 0 -# Default is 1 (true). Whether to cache host and -# port connection settings. -# -# -#------------------------------------------------------------------------------- -# -# 7. Diagnostics -# -#--------------- -# -# These settings are designed to help server administrators diagnose -# problems, and obtain detailed information about the activities being -# performed by the rippled process. -# -# -# -# [debug_logfile] -# -# Specifies where a debug logfile is kept. By default, no debug log is kept. -# Unless absolute, the path is relative the directory containing this file. -# -# Example: debug.log -# -# -# -# [insight] -# -# Configuration parameters for the Beast. Insight stats collection module. -# -# Insight is a module that collects information from the areas of rippled -# that have instrumentation. The configuration parameters control where the -# collection metrics are sent. The parameters are expressed as key = value -# pairs with no white space. The main parameter is the choice of server: -# -# "server" -# -# Choice of server to send metrics to. Currently the only choice is -# "statsd" which sends UDP packets to a StatsD daemon, which must be -# running while rippled is running. More information on StatsD is -# available here: -# https://github.com/b/statsd_spec -# -# When server=statsd, these additional keys are used: -# -# "address" The UDP address and port of the listening StatsD server, -# in the format, n.n.n.n:port. -# -# "prefix" A string prepended to each collected metric. This is used -# to distinguish between different running instances of rippled. -# -# If this section is missing, or the server type is unspecified or unknown, -# statistics are not collected or reported. -# -# Example: -# -# [insight] -# server=statsd -# address=192.168.0.95:4201 -# prefix=my_validator -# -# [perf] -# -# Configuration of performance logging. If enabled, write Json-formatted -# performance-oriented data periodically to a distinct log file. -# -# "perf_log" A string specifying the pathname of the performance log -# file. A relative pathname will log relative to the -# configuration directory. Required to enable -# performance logging. -# -# "log_interval" Integer value for number of seconds between writing -# to performance log. Default 1. -# -# Example: -# [perf] -# perf_log=/var/log/rippled/perf.log -# log_interval=2 -# -#------------------------------------------------------------------------------- -# -# 8. Voting -# -#---------- -# -# The vote settings configure settings for the entire Ripple network. -# While a single instance of rippled cannot unilaterally enforce network-wide -# settings, these choices become part of the instance's vote during the -# consensus process for each voting ledger. -# -# [voting] -# -# A set of key/value pair parameters used during voting ledgers. -# -# reference_fee = -# -# The cost of the reference transaction fee, specified in drops. -# The reference transaction is the simplest form of transaction. -# It represents an XRP payment between two parties. -# -# If this parameter is unspecified, rippled will use an internal -# default. Don't change this without understanding the consequences. -# -# Example: -# reference_fee = 10 # 10 drops -# -# account_reserve = -# -# The account reserve requirement is specified in drops. The portion of an -# account's XRP balance that is at or below the reserve may only be -# spent on transaction fees, and not transferred out of the account. -# -# If this parameter is unspecified, rippled will use an internal -# default. Don't change this without understanding the consequences. -# -# Example: -# account_reserve = 10000000 # 10 XRP -# -# owner_reserve = -# -# The owner reserve is the amount of XRP reserved in the account for -# each ledger item owned by the account. Ledger items an account may -# own include trust lines, open orders, and tickets. -# -# If this parameter is unspecified, rippled will use an internal -# default. Don't change this without understanding the consequences. -# -# Example: -# owner_reserve = 2000000 # 2 XRP -# -#------------------------------------------------------------------------------- -# -# 9. Misc Settings -# -#----------------- -# -# [node_size] -# -# Tunes the servers based on the expected load and available memory. Legal -# sizes are "tiny", "small", "medium", "large", and "huge". We recommend -# you start at the default and raise the setting if you have extra memory. -# -# The code attempts to automatically determine the appropriate size for -# this parameter based on the amount of RAM and the number of execution -# cores available to the server. The current decision matrix is: -# -# | | Cores | -# |---------|------------------------| -# | RAM | 1 | 2 or 3 | ≥ 4 | -# |---------|------|--------|--------| -# | < ~8GB | tiny | tiny | tiny | -# | < ~12GB | tiny | small | small | -# | < ~16GB | tiny | small | medium | -# | < ~24GB | tiny | small | large | -# | < ~32GB | tiny | small | huge | -# -# [signing_support] -# -# Specifies whether the server will accept "sign" and "sign_for" commands -# from remote users. Even if the commands are sent over a secure protocol -# like secure websocket, this should generally be discouraged, because it -# requires sending the secret to use for signing to the server. In order -# to sign transactions, users should prefer to use a standalone signing -# tool instead. -# -# This flag has no effect on the "sign" and "sign_for" command line options -# that rippled makes available. -# -# The default value of this field is "false" -# -# Example: -# -# [signing_support] -# true -# -# [crawl] -# -# List of options to control what data is reported through the /crawl endpoint -# See https://xrpl.org/peer-crawler.html -# -# -# -# Enable or disable access to /crawl requests. Default is '1' which -# enables access. -# -# overlay = -# -# Report information about peers this server is connected to, similar -# to the "peers" RPC API. Default is '1' which means to report peer -# overlay info. -# -# server = -# -# Report information about the local server, similar to the "server_state" -# RPC API. Default is '1' which means to report local server info. -# -# counts = -# -# Report information about the local server health counters, similar to -# the "get_counts" RPC API. Default is '0' which means not to report -# server counts. -# -# unl = -# -# Report information about the local server's validator lists, similar to -# the "validators" and "validator_list_sites" RPC APIs. Default is '1' -# which means to report server validator lists. -# -# Examples: -# -# [crawl] -# 0 -# -# [crawl] -# overlay = 1 -# server = 1 -# counts = 0 -# unl = 1 -# -# [vl] -# -# Options to control what data is reported through the /vl endpoint -# See [...] -# -# enable = -# -# Enable or disable access to /vl requests. Default is '1' which -# enables access. -# -# [beta_rpc_api] -# -# 0 or 1. -# -# 0: Disable the beta API version for JSON-RPC and WebSocket [default] -# 1: Enable the beta API version for testing. The beta API version -# contains breaking changes that require a new API version number. -# They are not ready for public consumption. -# -#------------------------------------------------------------------------------- -# -# 10. Example Settings -# -#-------------------- -# -# Administrators can use these values as a starting point for configuring -# their instance of rippled, but each value should be checked to make sure -# it meets the business requirements for the organization. -# -# Server -# -# These example configuration settings create these ports: -# -# "peer" -# -# Peer protocol open to everyone. This is required to accept -# incoming rippled connections. This does not affect automatic -# or manual outgoing Peer protocol connections. -# -# "rpc" -# -# Administrative RPC commands over HTTPS, when originating from -# the same machine (via the loopback adapter at 127.0.0.1). -# -# "wss_admin" -# -# Admin level API commands over Secure Websockets, when originating -# from the same machine (via the loopback adapter at 127.0.0.1). -# -# This port is commented out but can be enabled by removing -# the '#' from each corresponding line including the entry under [server] -# -# "wss_public" -# -# Guest level API commands over Secure Websockets, open to everyone. -# -# For HTTPS and Secure Websockets ports, if no certificate and key file -# are specified then a self-signed certificate will be generated on startup. -# If you have a certificate and key file, uncomment the corresponding lines -# and ensure the paths to the files are correct. -# -# NOTE -# -# To accept connections on well known ports such as 80 (HTTP) or -# 443 (HTTPS), most operating systems will require rippled to -# run with administrator privileges, or else rippled will not start. - -[server] -port_rpc_admin_local -port_peer -port_ws_admin_local -#port_ws_public -#ssl_key = /etc/ssl/private/server.key -#ssl_cert = /etc/ssl/certs/server.crt - -[port_rpc_admin_local] -port = 5005 -ip = 127.0.0.1 -admin = 127.0.0.1 -protocol = http - -[port_peer] -port = 51235 -ip = 0.0.0.0 -# alternatively, to accept connections on IPv4 + IPv6, use: -#ip = :: -protocol = peer - -[port_ws_admin_local] -port = 6006 -ip = 127.0.0.1 -admin = 127.0.0.1 -protocol = ws - -[port_grpc] -port = 50051 -ip = 127.0.0.1 -secure_gateway = 127.0.0.1 - -#[port_ws_public] -#port = 6005 -#ip = 127.0.0.1 -#protocol = wss - -#------------------------------------------------------------------------------- - -# This is primary persistent datastore for rippled. This includes transaction -# metadata, account states, and ledger headers. Helpful information can be -# found at https://xrpl.org/capacity-planning.html#node-db-type -# type=NuDB is recommended for non-validators with fast SSDs. Validators or -# slow / spinning disks should use RocksDB. Caution: Spinning disks are -# not recommended. They do not perform well enough to consistently remain -# synced to the network. -# online_delete=512 is recommended to delete old ledgers while maintaining at -# least 512. -# advisory_delete=0 allows the online delete process to run automatically -# when the node has approximately two times the "online_delete" value of -# ledgers. No external administrative command is required to initiate -# deletion. -[node_db] -type=NuDB -path=/var/lib/rippled/db/nudb -online_delete=512 -advisory_delete=0 - -# This is the persistent datastore for shards. It is important for the health -# of the ripple network that rippled operators shard as much as practical. -# NuDB requires SSD storage. Helpful information can be found at -# https://xrpl.org/history-sharding.html -#[shard_db] -#path=/var/lib/rippled/db/shards/nudb -#max_historical_shards=50 -# -# This optional section can be configured with a list -# of paths to use for storing historical shards. Each -# path must correspond to a unique filesystem. -#[historical_shard_paths] -#/path/1 -#/path/2 - -[database_path] -/var/lib/rippled/db - - -# To use Postgres, uncomment this section and fill in the appropriate connection -# info. Postgres can only be used in Reporting Mode. -# To disable writing to the transaction database, uncomment this section, and -# set use_tx_tables=0 -# [ledger_tx_tables] -# conninfo = postgres://[username]:[password]@[ip]/[database] -# use_tx_tables=1 - - -# This needs to be an absolute directory reference, not a relative one. -# Modify this value as required. -[debug_logfile] -/var/log/rippled/debug.log - -# To use the XRP test network -# (see https://xrpl.org/connect-your-rippled-to-the-xrp-test-net.html), -# use the following [ips] section: -# [ips] -# r.altnet.rippletest.net 51235 - -# File containing trusted validator keys or validator list publishers. -# Unless an absolute path is specified, it will be considered relative to the -# folder in which the rippled.cfg file is located. -[validators_file] -validators.txt - -# Turn down default logging to save disk space in the long run. -# Valid values here are trace, debug, info, warning, error, and fatal -[rpc_startup] -{ "command": "log_level", "severity": "warning" } - -# If ssl_verify is 1, certificates will be validated. -# To allow the use of self-signed certificates for development or internal use, -# set to ssl_verify to 0. -[ssl_verify] -1 - - -# To run in Reporting Mode, uncomment this section and fill in the appropriate -# connection info for one or more ETL sources. -# [reporting] -# etl_source -# -# -# [etl_source] -# source_grpc_port=50051 -# source_ws_port=6005 -# source_ip=127.0.0.1 diff --git a/cfg/validators-example.txt b/cfg/validators-example.txt deleted file mode 100644 index 8f7c04729e0..00000000000 --- a/cfg/validators-example.txt +++ /dev/null @@ -1,72 +0,0 @@ -# -# Default validators.txt -# -# This file is located in the same folder as your rippled.cfg file -# and defines which validators your server trusts not to collude. -# -# This file is UTF-8 with DOS, UNIX, or Mac style line endings. -# Blank lines and lines starting with a '#' are ignored. -# -# -# -# [validators] -# -# List of the validation public keys of nodes to always accept as validators. -# -# Manually listing validator keys is not recommended for production networks. -# See validator_list_sites and validator_list_keys below. -# -# Examples: -# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5 -# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt -# -# [validator_list_sites] -# -# List of URIs serving lists of recommended validators. -# -# Examples: -# https://vl.ripple.com -# https://vl.xrplf.org -# http://127.0.0.1:8000 -# file:///etc/opt/ripple/vl.txt -# -# [validator_list_keys] -# -# List of keys belonging to trusted validator list publishers. -# Validator lists fetched from configured sites will only be considered -# if the list is accompanied by a valid signature from a trusted -# publisher key. -# Validator list keys should be hex-encoded. -# -# Examples: -# ED2677ABFFD1B33AC6FBC3062B71F1E8397C1505E1C42C64D11AD1B28FF73F4734 -# ED307A760EE34F2D0CAA103377B1969117C38B8AA0AA1E2A24DAC1F32FC97087ED -# - -# The default validator list publishers that the rippled instance -# trusts. -# -# WARNING: Changing these values can cause your rippled instance to see a -# validated ledger that contradicts other rippled instances' -# validated ledgers (aka a ledger fork) if your validator list(s) -# do not sufficiently overlap with the list(s) used by others. -# See: https://arxiv.org/pdf/1802.07242.pdf - -[validator_list_sites] -https://vl.ripple.com -https://vl.xrplf.org - -[validator_list_keys] -#vl.ripple.com -ED2677ABFFD1B33AC6FBC3062B71F1E8397C1505E1C42C64D11AD1B28FF73F4734 -# vl.xrplf.org -ED45D1840EE724BE327ABE9146503D5848EFD5F38B6D5FEDE71E80ACCE5E6E738B - -# To use the test network (see https://xrpl.org/connect-your-rippled-to-the-xrp-test-net.html), -# use the following configuration instead: -# -# [validator_list_sites] -# https://vl.altnet.rippletest.net -# -# [validator_list_keys] -# ED264807102805220DA0F312E71FC2C69E1552C9C5790F6C25E3729DEB573D5860 diff --git a/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp b/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp index 61aa7e0629a..88b327d357c 100644 --- a/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp +++ b/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp @@ -27,6 +27,7 @@ namespace ripple { + NotTEC NFTokenAcceptOffer::preflight(PreflightContext const& ctx) { diff --git a/src/ripple/app/tx/impl/NFTokenModify.cpp b/src/ripple/app/tx/impl/NFTokenModify.cpp new file mode 100644 index 00000000000..4852dd243ac --- /dev/null +++ b/src/ripple/app/tx/impl/NFTokenModify.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include + +NotTEC +NFTokenModify::preflight(PreflightContext const& ctx) +{ + if (!ctx.rules.enabled(featureNonFungibleTokensV1)) + return temDISABLED; + + if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + return ret; + + auto const nftID = ctx.tx[sfNFTokenID]; + auto const account = ctx.tx[sfAccount]; + + if (!account || !nftID) + return temMALFORMED; + + if (auto uri = ctx.tx[sfURI]) + { + if (uri->length() == 0 || uri->length() > maxTokenURILength) + return temMALFORMED; + } + + return preflight2(ctx); +} + +TER +NFTokenModify::preclaim(PreclaimContext const& ctx) +{ + auto const account = ctx.tx[sfAccount]; + + auto const owner = [&ctx]() { + if (ctx.tx.isFieldPresent(sfOwner)) + return ctx.tx.getAccountID(sfOwner); + + return ctx.tx[sfAccount]; + }(); + + if (!nft::findToken(ctx.view, owner, ctx.tx[sfNFTokenID])) + return tecNO_ENTRY; + + // Check if the NFT is mutable + if (!(nft::getFlags(ctx.tx[sfNFTokenID]) & nft::flagMutable)) + return tecNO_PERMISSION; + + // Verify permissions for the issuer + if (auto const issuer = nft::getIssuer(ctx.tx[sfNFTokenID]); + issuer != account) + { + if (auto const sle = ctx.view.read(keylet::account(issuer)); sle) + { + if (auto const minter = (*sle)[~sfNFTokenMinter]; + minter != account) + return tecNO_PERMISSION; + } + } + + return tesSUCCESS; +} + +TER +NFTokenModify::doApply() +{ + auto const nftokenID = ctx_.tx[sfNFTokenID]; + auto const account = ctx_.tx[sfAccount]; + + // Find the token and its page + auto tokenAndPage = nft::findTokenAndPage(view(), account, nftokenID); + if (!tokenAndPage) + return tecINTERNAL; + + // Replace the URI if present in the transaction + if (ctx_.tx.isFieldPresent(sfURI)) { + auto newURI = ctx_.tx[sfURI]; + (*tokenAndPage->token)[sfURI] = newURI; + } + + // Apply the changes to the token + if (auto const ret = nft::updateToken(view(), account, std::move(tokenAndPage->token), std::move(tokenAndPage->page)); !isTesSuccess(ret)) + return ret; + + return tesSUCCESS; +} diff --git a/src/ripple/app/tx/impl/NFTokenModify.h b/src/ripple/app/tx/impl/NFTokenModify.h new file mode 100644 index 00000000000..668bbe8d807 --- /dev/null +++ b/src/ripple/app/tx/impl/NFTokenModify.h @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2021 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_NFTOKENMODIFY_H_INCLUDED +#define RIPPLE_TX_NFTOKENMODIFY_H_INCLUDED + +#include + +namespace ripple { + +class NFTokenModify : public Transactor +{ +public: + static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; + + explicit NFTokenModify(ApplyContext& ctx) : Transactor(ctx) + { + } + + static NotTEC + preflight(PreflightContext const& ctx); + + static TER + preclaim(PreclaimContext const& ctx); + + TER + doApply() override; +}; + +} // namespace ripple + +#endif diff --git a/src/ripple/app/tx/impl/details/NFTokenUtils.cpp b/src/ripple/app/tx/impl/details/NFTokenUtils.cpp index 09ff8f13caa..0150b68884f 100644 --- a/src/ripple/app/tx/impl/details/NFTokenUtils.cpp +++ b/src/ripple/app/tx/impl/details/NFTokenUtils.cpp @@ -238,6 +238,22 @@ compareTokens(uint256 const& a, uint256 const& b) return a < b; } + +TER +updateToken(ApplyView& view, AccountID const& owner, STObject&& nft, std::shared_ptr&& page) +{ + // Remove the old token from the owner's directory + if (auto const ret = nft::removeToken(view, owner, nft.getFieldH256(sfNFTokenID), std::move(page)); !isTesSuccess(ret)) + return ret; + + // Insert the updated token into the owner's directory + if (auto const ret = nft::insertToken(view, owner, std::move(nft)); !isTesSuccess(ret)) + return ret; + + return tesSUCCESS; +} + + /** Insert the token in the owner's token directory. */ TER insertToken(ApplyView& view, AccountID owner, STObject&& nft) diff --git a/src/ripple/protocol/TxFlags.h b/src/ripple/protocol/TxFlags.h index ba2b97562db..267f05428e6 100644 --- a/src/ripple/protocol/TxFlags.h +++ b/src/ripple/protocol/TxFlags.h @@ -129,6 +129,7 @@ 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 tfMutable = 0x00000016; // Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between // accounts allowed a TrustLine to be added to the issuer of that token @@ -147,7 +148,7 @@ constexpr std::uint32_t const tfNFTokenMintOldMask = ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable); constexpr std::uint32_t const tfNFTokenMintMask = - ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable); + ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable | tfMutable); // NFTokenCreateOffer flags: constexpr std::uint32_t const tfSellNFToken = 0x00000001; From d85167878f3a89f397e76ef8581b380ccae6cf27 Mon Sep 17 00:00:00 2001 From: xVet Date: Mon, 27 Nov 2023 21:53:03 +0100 Subject: [PATCH 02/26] dNFTs initial --- Builds/CMake/RippledCore.cmake | 1 + src/ripple/app/tx/impl/NFTokenModify.cpp | 14 +++++++++++--- src/ripple/app/tx/impl/NFTokenModify.h | 19 +------------------ src/ripple/app/tx/impl/details/NFTokenUtils.h | 3 +++ src/ripple/protocol/nft.h | 1 + 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index 269c107ca9e..e2523a2c584 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -529,6 +529,7 @@ target_sources (rippled PRIVATE src/ripple/app/tx/impl/NFTokenCancelOffer.cpp src/ripple/app/tx/impl/NFTokenCreateOffer.cpp src/ripple/app/tx/impl/NFTokenMint.cpp + src/ripple/app/tx/impl/NFTokenModify.cpp src/ripple/app/tx/impl/OfferStream.cpp src/ripple/app/tx/impl/PayChan.cpp src/ripple/app/tx/impl/Payment.cpp diff --git a/src/ripple/app/tx/impl/NFTokenModify.cpp b/src/ripple/app/tx/impl/NFTokenModify.cpp index 4852dd243ac..b56ce37a23e 100644 --- a/src/ripple/app/tx/impl/NFTokenModify.cpp +++ b/src/ripple/app/tx/impl/NFTokenModify.cpp @@ -1,3 +1,5 @@ + +#include #include #include #include @@ -5,6 +7,8 @@ #include #include +namespace ripple { + NotTEC NFTokenModify::preflight(PreflightContext const& ctx) { @@ -20,9 +24,11 @@ NFTokenModify::preflight(PreflightContext const& ctx) if (!account || !nftID) return temMALFORMED; - if (auto uri = ctx.tx[sfURI]) + if (ctx.tx.isFieldPresent(sfURI)) { - if (uri->length() == 0 || uri->length() > maxTokenURILength) + auto uri = ctx.tx[sfURI]; + + if (uri.length() == 0 || uri.length() > maxTokenURILength) return temMALFORMED; } @@ -69,6 +75,7 @@ NFTokenModify::doApply() auto const nftokenID = ctx_.tx[sfNFTokenID]; auto const account = ctx_.tx[sfAccount]; + // Find the token and its page auto tokenAndPage = nft::findTokenAndPage(view(), account, nftokenID); if (!tokenAndPage) @@ -77,7 +84,7 @@ NFTokenModify::doApply() // Replace the URI if present in the transaction if (ctx_.tx.isFieldPresent(sfURI)) { auto newURI = ctx_.tx[sfURI]; - (*tokenAndPage->token)[sfURI] = newURI; + tokenAndPage->token[sfURI] = newURI; } // Apply the changes to the token @@ -86,3 +93,4 @@ NFTokenModify::doApply() return tesSUCCESS; } +} \ No newline at end of file diff --git a/src/ripple/app/tx/impl/NFTokenModify.h b/src/ripple/app/tx/impl/NFTokenModify.h index 668bbe8d807..07e5548ef61 100644 --- a/src/ripple/app/tx/impl/NFTokenModify.h +++ b/src/ripple/app/tx/impl/NFTokenModify.h @@ -1,21 +1,4 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 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_NFTOKENMODIFY_H_INCLUDED #define RIPPLE_TX_NFTOKENMODIFY_H_INCLUDED diff --git a/src/ripple/app/tx/impl/details/NFTokenUtils.h b/src/ripple/app/tx/impl/details/NFTokenUtils.h index 5242bf38ff3..924ff4c6bf7 100644 --- a/src/ripple/app/tx/impl/details/NFTokenUtils.h +++ b/src/ripple/app/tx/impl/details/NFTokenUtils.h @@ -97,6 +97,9 @@ deleteTokenOffer(ApplyView& view, std::shared_ptr const& offer); bool compareTokens(uint256 const& a, uint256 const& b); +TER +updateToken(ApplyView& view, AccountID const& owner, STObject&& nft, std::shared_ptr&& page); + } // namespace nft } // namespace ripple diff --git a/src/ripple/protocol/nft.h b/src/ripple/protocol/nft.h index 2df8e0b89ce..764f240e25e 100644 --- a/src/ripple/protocol/nft.h +++ b/src/ripple/protocol/nft.h @@ -54,6 +54,7 @@ constexpr std::uint16_t const flagBurnable = 0x0001; constexpr std::uint16_t const flagOnlyXRP = 0x0002; constexpr std::uint16_t const flagCreateTrustLines = 0x0004; constexpr std::uint16_t const flagTransferable = 0x0008; +constexpr std::uint16_t const flagMutable = 0x0016; inline std::uint16_t getFlags(uint256 const& id) From e30addced912d56450e1692abaac100beef34d69 Mon Sep 17 00:00:00 2001 From: xVet Date: Tue, 28 Nov 2023 02:14:51 +0100 Subject: [PATCH 03/26] added dnft amendment and placed guards --- cfg/rippled-example.cfg | 1742 ++++++++++++++++++++++ cfg/validators-example.txt | 72 + src/ripple/app/tx/impl/NFTokenMint.cpp | 20 +- src/ripple/app/tx/impl/NFTokenModify.cpp | 2 +- src/ripple/protocol/Feature.h | 1 + src/ripple/protocol/TxFlags.h | 22 +- src/ripple/protocol/impl/Feature.cpp | 1 + src/ripple/protocol/nft.h | 2 +- 8 files changed, 1827 insertions(+), 35 deletions(-) create mode 100644 cfg/rippled-example.cfg create mode 100644 cfg/validators-example.txt diff --git a/cfg/rippled-example.cfg b/cfg/rippled-example.cfg new file mode 100644 index 00000000000..a3bcf0056be --- /dev/null +++ b/cfg/rippled-example.cfg @@ -0,0 +1,1742 @@ +#------------------------------------------------------------------------------- +# +# +#------------------------------------------------------------------------------- +# +# Contents +# +# 1. Server +# +# 2. Peer Protocol +# +# 3. Ripple Protocol +# +# 4. HTTPS Client +# +# 5. Reporting Mode +# +# 6. Database +# +# 7. Diagnostics +# +# 8. Voting +# +# 9. Misc Settings +# +# 10. Example Settings +# +#------------------------------------------------------------------------------- +# +# Purpose +# +# This file documents and provides examples of all rippled server process +# configuration options. When the rippled server instance is launched, it +# looks for a file with the following name: +# +# rippled.cfg +# +# For more information on where the rippled server instance searches for the +# file, visit: +# +# https://xrpl.org/commandline-usage.html#generic-options +# +# This file should be named rippled.cfg. This file is UTF-8 with DOS, UNIX, +# or Mac style end of lines. Blank lines and lines beginning with '#' are +# ignored. Undefined sections are reserved. No escapes are currently defined. +# +# Notation +# +# In this document a simple BNF notation is used. Angle brackets denote +# required elements, square brackets denote optional elements, and single +# quotes indicate string literals. A vertical bar separating 1 or more +# elements is a logical "or"; any one of the elements may be chosen. +# Parentheses are notational only, and used to group elements; they are not +# part of the syntax unless they appear in quotes. White space may always +# appear between elements, it has no effect on values. +# +# A required identifier +# '=' The equals sign character +# | Logical "or" +# ( ) Used for grouping +# +# +# An identifier is a string of upper or lower case letters, digits, or +# underscores subject to the requirement that the first character of an +# identifier must be a letter. Identifiers are not case sensitive (but +# values may be). +# +# Some configuration sections contain key/value pairs. A line containing +# a key/value pair has this syntax: +# +# '=' +# +# Depending on the section and key, different value types are possible: +# +# A signed integer +# An unsigned integer +# A boolean. 1 = true/yes/on, 0 = false/no/off. +# +# Consult the documentation on the key in question to determine the possible +# value types. +# +# +# +#------------------------------------------------------------------------------- +# +# 1. Server +# +#---------- +# +# +# +# rippled offers various server protocols to clients making inbound +# connections. The listening ports rippled uses are "universal" ports +# which may be configured to handshake in one or more of the available +# supported protocols. These universal ports simplify administration: +# A single open port can be used for multiple protocols. +# +# NOTE At least one server port must be defined in order +# to accept incoming network connections. +# +# +# [server] +# +# A list of port names and key/value pairs. A port name must start with a +# letter and contain only letters and numbers. The name is not case-sensitive. +# For each name in this list, rippled will look for a configuration file +# section with the same name and use it to create a listening port. The +# name is informational only; the choice of name does not affect the function +# of the listening port. +# +# Key/value pairs specified in this section are optional, and apply to all +# listening ports unless the port overrides the value in its section. They +# may be considered default values. +# +# Suggestion: +# +# To avoid a conflict with port names and future configuration sections, +# we recommend prepending "port_" to the port name. This prefix is not +# required, but suggested. +# +# This example defines two ports with different port numbers and settings: +# +# [server] +# port_public +# port_private +# port = 80 +# +# [port_public] +# ip = 0.0.0.0 +# port = 443 +# protocol = peer,https +# +# [port_private] +# ip = 127.0.0.1 +# protocol = http +# +# When rippled is used as a command line client (for example, issuing a +# server stop command), the first port advertising the http or https +# protocol will be used to make the connection. +# +# +# +# [] +# +# A series of key/value pairs that define the settings for the port with +# the corresponding name. These keys are possible: +# +# ip = +# +# Required. Determines the IP address of the network interface to bind +# to. To bind to all available IPv4 interfaces, use 0.0.0.0 +# To binding to all IPv4 and IPv6 interfaces, use :: +# +# NOTE if the ip value is ::, then any incoming IPv4 connections will +# be made as mapped IPv4 addresses. +# +# port = +# +# Required. Sets the port number to use for this port. +# +# protocol = [ http, https, peer ] +# +# Required. A comma-separated list of protocols to support: +# +# http JSON-RPC over HTTP +# https JSON-RPC over HTTPS +# ws Websockets +# wss Secure Websockets +# peer Peer Protocol +# +# Restrictions: +# +# Only one port may be configured to support the peer protocol. +# A port cannot have websocket and non websocket protocols at the +# same time. It is possible have both Websockets and Secure Websockets +# together in one port. +# +# NOTE If no ports support the peer protocol, rippled cannot +# receive incoming peer connections or become a superpeer. +# +# limit = +# +# Optional. An integer value that will limit the number of connected +# clients that the port will accept. Once the limit is reached, new +# connections will be refused until other clients disconnect. +# Omit or set to 0 to allow unlimited numbers of clients. +# +# user = +# password = +# +# When set, these credentials will be required on HTTP/S requests. +# The credentials must be provided using HTTP's Basic Authentication +# headers. If either or both fields are empty, then no credentials are +# required. IP address restrictions, if any, will be checked in addition +# to the credentials specified here. +# +# When acting in the client role, rippled will supply these credentials +# using HTTP's Basic Authentication headers when making outbound HTTP/S +# requests. +# +# admin = [ IP, IP, IP, ... ] +# +# A comma-separated list of IP addresses or subnets. Subnets +# should be represented in "slash" notation, such as: +# 10.0.0.0/8 +# 172.16.0.0/12 +# 192.168.0.0/16 +# Those examples are ipv4, but ipv6 is also supported. +# When configuring subnets, the address must match the +# underlying network address. Otherwise, the desired IP range is +# ambiguous. For example, 10.1.2.3/24 has a network address of +# 10.1.2.0. Therefore, that subnet should be configured as +# 10.1.2.0/24. +# +# When set, grants administrative command access to the specified +# addresses. These commands may be issued over http, https, ws, or wss +# if configured on the port. If not provided, the default is to not allow +# administrative commands. +# +# NOTE A common configuration value for the admin field is "localhost". +# If you are listening on all IPv4/IPv6 addresses by specifing +# ip = :: then you can use admin = ::ffff:127.0.0.1,::1 to allow +# administrative access from both IPv4 and IPv6 localhost +# connections. +# +# *SECURITY WARNING* +# 0.0.0.0 or :: may be used to allow access from any IP address. It must +# be the only address specified and cannot be combined with other IPs. +# Use of this address can compromise server security, please consider its +# use carefully. +# +# admin_user = +# admin_password = +# +# When set, clients must provide these credentials in the submitted +# JSON for any administrative command requests submitted to the HTTP/S, +# WS, or WSS protocol interfaces. If administrative commands are +# disabled for a port, these credentials have no effect. +# +# When acting in the client role, rippled will supply these credentials +# in the submitted JSON for any administrative command requests when +# invoking JSON-RPC commands on remote servers. +# +# secure_gateway = [ IP, IP, IP, ... ] +# +# A comma-separated list of IP addresses or subnets. See the +# details for the "admin" option above. +# +# When set, allows the specified addresses to pass HTTP headers +# containing username and remote IP address for each session. If a +# non-empty username is passed in this way, then resource controls +# such as often resulting in "tooBusy" errors will be lifted. However, +# administrative RPC commands such as "stop" will not be allowed. +# The HTTP headers that secure_gateway hosts can set are X-User and +# X-Forwarded-For. Only the X-User header affects resource controls. +# However, both header values are logged to help identify user activity. +# If no X-User header is passed, or if its value is empty, then +# resource controls will default to those for non-administrative users. +# +# The secure_gateway IP addresses are intended to represent +# proxies. Since rippled trusts these hosts, they must be +# responsible for properly authenticating the remote user. +# +# If some IP addresses are included for both "admin" and +# "secure_gateway" connections, then they will be treated as +# "admin" addresses. +# +# ssl_key = +# ssl_cert = +# ssl_chain = +# +# Use the specified files when configuring SSL on the port. +# +# NOTE If no files are specified and secure protocols are selected, +# rippled will generate an internal self-signed certificate. +# +# The files have these meanings: +# +# ssl_key +# +# Specifies the filename holding the SSL key in PEM format. +# +# ssl_cert +# +# Specifies the path to the SSL certificate file in PEM format. +# This is not needed if the chain includes it. Use ssl_chain if +# your certificate includes one or more intermediates. +# +# ssl_chain +# +# If you need a certificate chain, specify the path to the +# certificate chain here. The chain may include the end certificate. +# This must be used if the certificate includes intermediates. +# +# ssl_ciphers = +# +# Control the ciphers which the server will support over SSL on the port, +# specified using the OpenSSL "cipher list format". +# +# NOTE If unspecified, rippled will automatically configure a modern +# cipher suite. This default suite should be widely supported. +# +# You should not modify this string unless you have a specific +# reason and cryptographic expertise. Incorrect modification may +# keep rippled from connecting to other instances of rippled or +# prevent RPC and WebSocket clients from connecting. +# +# send_queue_limit = [1..65535] +# +# A Websocket will disconnect when its send queue exceeds this limit. +# The default is 100. A larger value may help with erratic disconnects but +# may adversely affect server performance. +# +# WebSocket permessage-deflate extension options +# +# These settings configure the optional permessage-deflate extension +# options and may appear on any port configuration entry. They are meaningful +# only to ports which have enabled a WebSocket protocol. +# +# permessage_deflate = +# +# Determines if permessage_deflate extension negotiations are enabled. +# When enabled, clients may request the extension and the server will +# offer the enabled extension in response. +# +# client_max_window_bits = [9..15] +# server_max_window_bits = [9..15] +# client_no_context_takeover = +# server_no_context_takeover = +# +# These optional settings control options related to the permessage-deflate +# extension negotiation. For precise definitions of these fields please see +# the RFC 7692, "Compression Extensions for WebSocket": +# https://tools.ietf.org/html/rfc7692 +# +# compress_level = [0..9] +# +# When set, determines the amount of compression attempted, where 0 is +# the least amount and 9 is the most amount. Higher levels require more +# CPU resources. Levels 1 through 3 use a fast compression algorithm, +# while levels 4 through 9 use a more compact algorithm which uses more +# CPU resources. If unspecified, a default of 3 is used. +# +# memory_level = [1..9] +# +# When set, determines the relative amount of memory used to hold +# intermediate compression data. Higher numbers can give better compression +# ratios at the cost of higher memory and CPU resources. +# +# [rpc_startup] +# +# Specify a list of RPC commands to run at startup. +# +# Examples: +# { "command" : "server_info" } +# { "command" : "log_level", "partition" : "ripplecalc", "severity" : "trace" } +# +# +# +# [websocket_ping_frequency] +# +# +# +# The amount of time to wait in seconds, before sending a websocket 'ping' +# message. Ping messages are used to determine if the remote end of the +# connection is no longer available. +# +# +# [server_domain] +# +# domain name +# +# The domain under which a TOML file applicable to this server can be +# found. A server may lie about its domain so the TOML should contain +# a reference to this server by pubkey in the [nodes] array. +# +# +#------------------------------------------------------------------------------- +# +# 2. Peer Protocol +# +#----------------- +# +# These settings control security and access attributes of the Peer to Peer +# server section of the rippled process. Peer Protocol implements the +# Ripple Payment protocol. It is over peer connections that transactions +# and validations are passed from to machine to machine, to determine the +# contents of validated ledgers. +# +# +# +# [compression] +# +# true or false +# +# true - enables compression +# false - disables compression [default]. +# +# The rippled server can save bandwidth by compressing its peer-to-peer communications, +# at a cost of greater CPU usage. If you enable link compression, +# the server automatically compresses communications with peer servers +# that also have link compression enabled. +# https://xrpl.org/enable-link-compression.html +# +# +# +# [ips] +# +# List of hostnames or ips where the Ripple protocol is served. A default +# starter list is included in the code and used if no other hostnames are +# available. +# +# One address or domain name per line is allowed. A port may must be +# specified after adding a space to the address. The ordering of entries +# does not generally matter. +# +# The default list of entries is: +# - r.ripple.com 51235 +# - zaphod.alloy.ee 51235 +# - sahyadri.isrdc.in 51235 +# +# Examples: +# +# [ips] +# 192.168.0.1 +# 192.168.0.1 2459 +# r.ripple.com 51235 +# +# +# [ips_fixed] +# +# List of IP addresses or hostnames to which rippled should always attempt to +# maintain peer connections with. This is useful for manually forming private +# networks, for example to configure a validation server that connects to the +# Ripple network through a public-facing server, or for building a set +# of cluster peers. +# +# One address or domain names per line is allowed. A port must be specified +# after adding a space to the address. +# +# +# +# [peer_private] +# +# 0 or 1. +# +# 0: Request peers to broadcast your address. Normal outbound peer connections [default] +# 1: Request peers not broadcast your address. Only connect to configured peers. +# +# +# +# [peers_max] +# +# The largest number of desired peer connections (incoming or outgoing). +# Cluster and fixed peers do not count towards this total. There are +# implementation-defined lower limits imposed on this value for security +# purposes. +# +# +# +# [node_seed] +# +# This is used for clustering. To force a particular node seed or key, the +# key can be set here. The format is the same as the validation_seed field. +# To obtain a validation seed, use the validation_create command. +# +# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE +# shfArahZT9Q9ckTf3s1psJ7C7qzVN +# +# +# +# [cluster_nodes] +# +# To extend full trust to other nodes, place their node public keys here. +# Generally, you should only do this for nodes under common administration. +# Node public keys start with an 'n'. To give a node a name for identification +# place a space after the public key and then the name. +# +# +# +# [max_transactions] +# +# Configure the maximum number of transactions to have in the job queue +# +# Must be a number between 1000 and 100000, defaults to 10000 +# +# +# [overlay] +# +# Controls settings related to the peer to peer overlay. +# +# A set of key/value pair parameters to configure the overlay. +# +# public_ip = +# +# If the server has a known, fixed public IPv4 address, +# specify that IP address here in dotted decimal notation. +# Peers will use this information to reject attempt to proxy +# connections to or from this server. +# +# ip_limit = +# +# The maximum number of incoming peer connections allowed by a single +# IP that isn't classified as "private" in RFC1918. The implementation +# imposes some hard and soft upper limits on this value to prevent a +# single host from consuming all inbound slots. If the value is not +# present the server will autoconfigure an appropriate limit. +# +# max_unknown_time = +# +# The maximum amount of time, in seconds, that an outbound connection +# is allowed to stay in the "unknown" tracking state. This option can +# take any value between 300 and 1800 seconds, inclusive. If the option +# is not present the server will autoconfigure an appropriate limit. +# +# The current default (which is subject to change) is 600 seconds. +# +# max_diverged_time = +# +# The maximum amount of time, in seconds, that an outbound connection +# is allowed to stay in the "diverged" tracking state. The option can +# take any value between 60 and 900 seconds, inclusive. If the option +# is not present the server will autoconfigure an appropriate limit. +# +# The current default (which is subject to change) is 300 seconds. +# +# +# [transaction_queue] EXPERIMENTAL +# +# This section is EXPERIMENTAL, and should not be +# present for production configuration settings. +# +# A set of key/value pair parameters to tune the performance of the +# transaction queue. +# +# ledgers_in_queue = +# +# The queue will be limited to this of average ledgers' +# worth of transactions. If the queue fills up, the transactions +# with the lowest fee levels will be dropped from the queue any +# time a transaction with a higher fee level is added. +# Default: 20. +# +# minimum_queue_size = +# +# The queue will always be able to hold at least this of +# transactions, regardless of recent ledger sizes or the value of +# ledgers_in_queue. Default: 2000. +# +# retry_sequence_percent = +# +# If a client replaces a transaction in the queue (same sequence +# number as a transaction already in the queue), the new +# transaction's fee must be more than percent higher +# than the original transaction's fee, or meet the current open +# ledger fee to be considered. Default: 25. +# +# minimum_escalation_multiplier = +# +# At ledger close time, the median fee level of the transactions +# in that ledger is used as a multiplier in escalation +# calculations of the next ledger. This minimum value ensures that +# the escalation is significant. Default: 500. +# +# minimum_txn_in_ledger = +# +# Minimum number of transactions that must be allowed into the +# ledger at the minimum required fee before the required fee +# escalates. Default: 5. +# +# minimum_txn_in_ledger_standalone = +# +# Like minimum_txn_in_ledger when rippled is running in standalone +# mode. Default: 1000. +# +# target_txn_in_ledger = +# +# Number of transactions allowed into the ledger at the minimum +# required fee that the queue will "work toward" as long as +# consensus stays healthy. The limit will grow quickly until it +# reaches or exceeds this number. After that the limit may still +# change, but will stay above the target. If consensus is not +# healthy, the limit will be clamped to this value or lower. +# Default: 50. +# +# maximum_txn_in_ledger = +# +# (Optional) Maximum number of transactions that will be allowed +# into the ledger at the minimum required fee before the required +# fee escalates. Default: no maximum. +# +# normal_consensus_increase_percent = +# +# (Optional) When the ledger has more transactions than "expected", +# and performance is humming along nicely, the expected ledger size +# is updated to the previous ledger size plus this percentage. +# Default: 20 +# +# slow_consensus_decrease_percent = +# +# (Optional) When consensus takes longer than appropriate, the +# expected ledger size is updated to the minimum of the previous +# ledger size or the "expected" ledger size minus this percentage. +# Default: 50 +# +# maximum_txn_per_account = +# +# Maximum number of transactions that one account can have in the +# queue at any given time. Default: 10. +# +# minimum_last_ledger_buffer = +# +# If a transaction has a LastLedgerSequence, it must be at least +# this much larger than the current open ledger sequence number. +# Default: 2. +# +# zero_basefee_transaction_feelevel = +# +# So we don't deal with infinite fee levels, treat any transaction +# with a 0 base fee (ie. SetRegularKey password recovery) as +# having this fee level. +# Default: 256000. +# +# +#------------------------------------------------------------------------------- +# +# 3. Protocol +# +#------------------- +# +# These settings affect the behavior of the server instance with respect +# to protocol level activities such as validating and closing ledgers +# adjusting fees in response to server overloads. +# +# +# +# +# [relay_proposals] +# +# Controls the relay and processing behavior for proposals received by this +# server that are issued by validators that are not on the server's UNL. +# +# Legal values are: +# "all" - Relay and process all incoming proposals +# "trusted" - Relay only trusted proposals, but locally process all +# "drop_untrusted" - Relay only trusted proposals, do not process untrusted +# +# The default is "trusted". +# +# +# [relay_validations] +# +# Controls the relay and processing behavior for validations received by this +# server that are issued by validators that are not on the server's UNL. +# +# Legal values are: +# "all" - Relay and process all incoming validations +# "trusted" - Relay only trusted validations, but locally process all +# "drop_untrusted" - Relay only trusted validations, do not process untrusted +# +# The default is "all". +# +# +# +# +# +# [ledger_history] +# +# The number of past ledgers to acquire on server startup and the minimum to +# maintain while running. +# +# To serve clients, servers need historical ledger data. Servers that don't +# need to serve clients can set this to "none". Servers that want complete +# history can set this to "full". +# +# This must be less than or equal to online_delete (if online_delete is used) +# +# The default is: 256 +# +# +# +# [fetch_depth] +# +# The number of past ledgers to serve to other peers that request historical +# ledger data (or "full" for no limit). +# +# Servers that require low latency and high local performance may wish to +# restrict the historical ledgers they are willing to serve. Setting this +# below 32 can harm network stability as servers require easy access to +# recent history to stay in sync. Values below 128 are not recommended. +# +# The default is: full +# +# +# +# [validation_seed] +# +# To perform validation, this section should contain either a validation seed +# or key. The validation seed is used to generate the validation +# public/private key pair. To obtain a validation seed, use the +# validation_create command. +# +# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE +# shfArahZT9Q9ckTf3s1psJ7C7qzVN +# +# +# +# [validator_token] +# +# This is an alternative to [validation_seed] that allows rippled to perform +# validation without having to store the validator keys on the network +# connected server. The field should contain a single token in the form of a +# base64-encoded blob. +# An external tool is available for generating validator keys and tokens. +# +# +# +# [validator_key_revocation] +# +# If a validator's secret key has been compromised, a revocation must be +# generated and added to this field. The revocation notifies peers that it is +# no longer safe to trust the revoked key. The field should contain a single +# revocation in the form of a base64-encoded blob. +# An external tool is available for generating and revoking validator keys. +# +# +# +# [validators_file] +# +# Path or name of a file that determines the nodes to always accept as validators. +# +# The contents of the file should include a [validators] and/or +# [validator_list_sites] and [validator_list_keys] entries. +# [validators] should be followed by a list of validation public keys of +# nodes, one per line. +# [validator_list_sites] should be followed by a list of URIs each serving a +# list of recommended validators. +# [validator_list_keys] should be followed by a list of keys belonging to +# trusted validator list publishers. Validator lists fetched from configured +# sites will only be considered if the list is accompanied by a valid +# signature from a trusted publisher key. +# +# Specify the file by its name or path. +# Unless an absolute path is specified, it will be considered relative to +# the folder in which the rippled.cfg file is located. +# +# Examples: +# /home/ripple/validators.txt +# C:/home/ripple/validators.txt +# +# Example content: +# [validators] +# n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 +# n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj +# n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C +# n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS +# n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA +# +# +# +# [path_search] +# When searching for paths, the default search aggressiveness. This can take +# exponentially more resources as the size is increased. +# +# The recommended value to support advanced pathfinding is: 7 +# +# The default is: 2 +# +# [path_search_fast] +# [path_search_max] +# When searching for paths, the minimum and maximum search aggressiveness. +# +# If you do not need pathfinding, you can set path_search_max to zero to +# disable it and avoid some expensive bookkeeping. +# +# To support advanced pathfinding the recommended value for +# 'path_search_fast' is 2, and for 'path_search_max' is 10. +# +# The default for 'path_search_fast' is 2. The default for 'path_search_max' is 3. +# +# [path_search_old] +# +# For clients that use the legacy path finding interfaces, the search +# aggressiveness to use. +# +# The recommended value to support advanced pathfinding is: 7. +# +# The default is: 2 +# +# +# +# [fee_default] +# +# Sets the base cost of a transaction in drops. Used when the server has +# no other source of fee information, such as signing transactions offline. +# +# +# +# [workers] +# +# Configures the number of threads for processing work submitted by peers +# and clients. If not specified, then the value is automatically set to the +# number of processor threads plus 2 for networked nodes. Nodes running in +# stand alone mode default to 1 worker. +# +# [io_workers] +# +# Configures the number of threads for processing raw inbound and outbound IO. +# +# [prefetch_workers] +# +# Configures the number of threads for performing nodestore prefetching. +# +# +# +# [network_id] +# +# Specify the network which this server is configured to connect to and +# track. If set, the server will not establish connections with servers +# that are explicitly configured to track another network. +# +# Network identifiers are usually unsigned integers in the range 0 to +# 4294967295 inclusive. The server also maps the following well-known +# names to the corresponding numerical identifier: +# +# main -> 0 +# testnet -> 1 +# devnet -> 2 +# +# If this value is not specified the server is not explicitly configured +# to track a particular network. +# +# +# [ledger_replay] +# +# 0 or 1. +# +# 0: Disable the ledger replay feature [default] +# 1: Enable the ledger replay feature. With this feature enabled, when +# acquiring a ledger from the network, a rippled node only downloads +# the ledger header and the transactions instead of the whole ledger. +# And the ledger is built by applying the transactions to the parent +# ledger. +# +#------------------------------------------------------------------------------- +# +# 4. HTTPS Client +# +#---------------- +# +# The rippled server instance uses HTTPS GET requests in a variety of +# circumstances, including but not limited to contacting trusted domains to +# fetch information such as mapping an email address to a Ripple Payment +# Network address. +# +# [ssl_verify] +# +# 0 or 1. +# +# 0. HTTPS client connections will not verify certificates. +# 1. Certificates will be checked for HTTPS client connections. +# +# If not specified, this parameter defaults to 1. +# +# +# +# [ssl_verify_file] +# +# +# +# A file system path leading to the certificate verification file for +# HTTPS client requests. +# +# +# +# [ssl_verify_dir] +# +# +# +# +# A file system path leading to a file or directory containing the root +# certificates that the server will accept for verifying HTTP servers. +# Used only for outbound HTTPS client connections. +# +#------------------------------------------------------------------------------- +# +# 5. Reporting Mode +# +#------------ +# +# rippled has an optional operating mode called Reporting Mode. In Reporting +# Mode, rippled does not connect to the peer to peer network. Instead, rippled +# will continuously extract data from one or more rippled servers that are +# connected to the peer to peer network (referred to as an ETL source). +# Reporting mode servers will forward RPC requests that require access to the +# peer to peer network (submit, fee, etc) to an ETL source. +# +# [reporting] Settings for Reporting Mode. If and only if this section is +# present, rippled will start in reporting mode. This section +# contains a list of ETL source names, and key-value pairs. The +# ETL source names each correspond to a configuration file +# section; the names must match exactly. The key-value pairs are +# optional. +# +# +# [] +# +# A series of key/value pairs that specify an ETL source. +# +# source_ip = +# +# Required. IP address of the ETL source. Can also be a DNS record. +# +# source_ws_port = +# +# Required. Port on which ETL source is accepting unencrypted websocket +# connections. +# +# source_grpc_port = +# +# Required for ETL. Port on which ETL source is accepting gRPC requests. +# If this option is ommitted, this ETL source cannot actually be used for +# ETL; the Reporting Mode server can still forward RPCs to this ETL +# source, but cannot extract data from this ETL source. +# +# +# Key-value pairs (all optional): +# +# read_only Valid values: 0, 1. Default is 0. If set to 1, the server +# will start in strict read-only mode, and will not perform +# ETL. The server will still handle RPC requests, and will +# still forward RPC requests that require access to the p2p +# network. +# +# start_sequence +# Sequence of first ledger to extract if the database is empty. +# ETL extracts ledgers in order. If this setting is absent and +# the database is empty, ETL will start with the next ledger +# validated by the network. If this setting is present and the +# database is not empty, an exception is thrown. +# +# num_markers Degree of parallelism used during the initial ledger +# download. Only used if the database is empty. Valid values +# are 1-256. A higher degree of parallelism results in a +# faster download, but puts more load on the ETL source. +# Default is 2. +# +# Example: +# +# [reporting] +# etl_source1 +# etl_source2 +# read_only=0 +# start_sequence=32570 +# num_markers=8 +# +# [etl_source1] +# source_ip=1.2.3.4 +# source_ws_port=6005 +# source_grpc_port=50051 +# +# [etl_source2] +# source_ip=5.6.7.8 +# source_ws_port=6005 +# source_grpc_port=50051 +# +# Minimal Example: +# +# [reporting] +# etl_source1 +# +# [etl_source1] +# source_ip=1.2.3.4 +# source_ws_port=6005 +# source_grpc_port=50051 +# +# +# Notes: +# +# Reporting Mode requires Postgres (instead of SQLite). The Postgres +# connection info is specified under the [ledger_tx_tables] config section; +# see the Database section for further documentation. +# +# Each ETL source specified must have gRPC enabled (by adding a [port_grpc] +# section to the config). It is recommended to add a secure_gateway entry to +# the gRPC section, in order to bypass the server's rate limiting. +# This section needs to be added to the config of the ETL source, not +# the config of the reporting node. In the example below, the +# reporting server is running at 127.0.0.1. Multiple IPs can be +# specified in secure_gateway via a comma separated list. +# +# [port_grpc] +# ip = 0.0.0.0 +# port = 50051 +# secure_gateway = 127.0.0.1 +# +# +#------------------------------------------------------------------------------- +# +# 6. Database +# +#------------ +# +# rippled creates 4 SQLite database to hold bookkeeping information +# about transactions, local credentials, and various other things. +# It also creates the NodeDB, which holds all the objects that +# make up the current and historical ledgers. In Reporting Mode, rippled +# uses a Postgres database instead of SQLite. +# +# The simplest way to work with Postgres is to install it locally. +# When it is running, execute the initdb.sh script in the current +# directory as: sudo -u postgres ./initdb.sh +# This will create the rippled user and an empty database of the same name. +# +# The size of the NodeDB grows in proportion to the amount of new data and the +# amount of historical data (a configurable setting) so the performance of the +# underlying storage media where the NodeDB is placed can significantly affect +# the performance of the server. +# +# Partial pathnames will be considered relative to the location of +# the rippled.cfg file. +# +# [node_db] Settings for the Node Database (required) +# +# Format (without spaces): +# One or more lines of case-insensitive key / value pairs: +# '=' +# ... +# +# Example: +# type=nudb +# path=db/nudb +# +# The "type" field must be present and controls the choice of backend: +# +# type = NuDB +# +# NuDB is a high-performance database written by Ripple Labs and optimized +# for rippled and solid-state drives. +# +# NuDB maintains its high speed regardless of the amount of history +# stored. Online delete may be selected, but is not required. NuDB is +# available on all platforms that rippled runs on. +# +# type = RocksDB +# +# RocksDB is an open-source, general-purpose key/value store - see +# http://rocksdb.org/ for more details. +# +# RocksDB is an alternative backend for systems that don't use solid-state +# drives. Because RocksDB's performance degrades as it stores more data, +# keeping full history is not advised, and using online delete is +# recommended. +# +# type = Cassandra +# +# Apache Cassandra is an open-source, distributed key-value store - see +# https://cassandra.apache.org/ for more details. +# +# Cassandra is an alternative backend to be used only with Reporting Mode. +# See the Reporting Mode section for more details about Reporting Mode. +# +# Required keys for NuDB and RocksDB: +# +# path Location to store the database +# +# Required keys for Cassandra: +# +# contact_points IP of a node in the Cassandra cluster +# +# port CQL Native Transport Port +# +# secure_connect_bundle +# Absolute path to a secure connect bundle. When using +# a secure connect bundle, contact_points and port are +# not required. +# +# keyspace Name of Cassandra keyspace to use +# +# table_name Name of table in above keyspace to use +# +# Optional keys +# +# cache_size Size of cache for database records. Default is 16384. +# Setting this value to 0 will use the default value. +# +# cache_age Length of time in minutes to keep database records +# cached. Default is 5 minutes. Setting this value to +# 0 will use the default value. +# +# Note: if neither cache_size nor cache_age is +# specified, the cache for database records will not +# be created. If only one of cache_size or cache_age +# is specified, the cache will be created using the +# default value for the unspecified parameter. +# +# Note: the cache will not be created if online_delete +# is specified, or if shards are used. +# +# fast_load Boolean. If set, load the last persisted ledger +# from disk upon process start before syncing to +# the network. This is likely to improve performance +# if sufficient IOPS capacity is available. +# Default 0. +# +# Optional keys for NuDB or RocksDB: +# +# earliest_seq The default is 32570 to match the XRP ledger +# network's earliest allowed sequence. Alternate +# networks may set this value. Minimum value of 1. +# If a [shard_db] section is defined, and this +# value is present either [node_db] or [shard_db], +# it must be defined with the same value in both +# sections. +# +# online_delete Minimum value of 256. Enable automatic purging +# of older ledger information. Maintain at least this +# number of ledger records online. Must be greater +# than or equal to ledger_history. +# +# These keys modify the behavior of online_delete, and thus are only +# relevant if online_delete is defined and non-zero: +# +# advisory_delete 0 for disabled, 1 for enabled. If set, the +# administrative RPC call "can_delete" is required +# to enable online deletion of ledger records. +# Online deletion does not run automatically if +# non-zero and the last deletion was on a ledger +# greater than the current "can_delete" setting. +# Default is 0. +# +# delete_batch When automatically purging, SQLite database +# records are deleted in batches. This value +# controls the maximum size of each batch. Larger +# batches keep the databases locked for more time, +# which may cause other functions to fall behind, +# and thus cause the node to lose sync. +# Default is 100. +# +# back_off_milliseconds +# Number of milliseconds to wait between +# online_delete batches to allow other functions +# to catch up. +# Default is 100. +# +# age_threshold_seconds +# The online delete process will only run if the +# latest validated ledger is younger than this +# number of seconds. +# Default is 60. +# +# recovery_wait_seconds +# The online delete process checks periodically +# that rippled is still in sync with the network, +# and that the validated ledger is less than +# 'age_threshold_seconds' old. If not, then continue +# sleeping for this number of seconds and +# checking until healthy. +# Default is 5. +# +# Optional keys for Cassandra: +# +# username Username to use if Cassandra cluster requires +# authentication +# +# password Password to use if Cassandra cluster requires +# authentication +# +# max_requests_outstanding +# Limits the maximum number of concurrent database +# writes. Default is 10 million. For slower clusters, +# large numbers of concurrent writes can overload the +# cluster. Setting this option can help eliminate +# write timeouts and other write errors due to the +# cluster being overloaded. +# io_threads +# Set the number of IO threads used by the +# Cassandra driver. Defaults to 4. +# +# Notes: +# The 'node_db' entry configures the primary, persistent storage. +# +# The 'import_db' is used with the '--import' command line option to +# migrate the specified database into the current database given +# in the [node_db] section. +# +# [import_db] Settings for performing a one-time import (optional) +# [database_path] Path to the book-keeping databases. +# +# The server creates and maintains 4 to 5 bookkeeping SQLite databases in +# the 'database_path' location. If you omit this configuration setting, +# the server creates a directory called "db" located in the same place as +# your rippled.cfg file. +# Partial pathnames are relative to the location of the rippled executable. +# +# [shard_db] Settings for the Shard Database (optional) +# +# Format (without spaces): +# One or more lines of case-insensitive key / value pairs: +# '=' +# ... +# +# Example: +# path=db/shards/nudb +# +# Required keys: +# path Location to store the database +# +# Optional keys: +# max_historical_shards +# The maximum number of historical shards +# to store. +# +# [historical_shard_paths] Additional storage paths for the Shard Database (optional) +# +# Format (without spaces): +# One or more lines, each expressing a full path for storing historical shards: +# /mnt/disk1 +# /mnt/disk2 +# ... +# +# [sqlite] Tuning settings for the SQLite databases (optional) +# +# Format (without spaces): +# One or more lines of case-insensitive key / value pairs: +# '=' +# ... +# +# Example 1: +# safety_level=low +# +# Example 2: +# journal_mode=off +# synchronous=off +# +# WARNING: These settings can have significant effects on data integrity, +# particularly in systemic failure scenarios. It is strongly recommended +# that they be left at their defaults unless the server is having +# performance issues during normal operation or during automatic purging +# (online_delete) operations. A warning will be logged on startup if +# 'ledger_history' is configured to store more than 10,000,000 ledgers and +# any of these settings are less safe than the default. This is due to the +# inordinate amount of time and bandwidth it will take to safely rebuild a +# corrupted database of that size from other peers. +# +# Optional keys: +# +# safety_level Valid values: high, low +# The default is "high", which tunes the SQLite +# databases in the most reliable mode, and is +# equivalent to: +# journal_mode=wal +# synchronous=normal +# temp_store=file +# "low" is equivalent to: +# journal_mode=memory +# synchronous=off +# temp_store=memory +# These "low" settings trade speed and reduced I/O +# for a higher risk of data loss. See the +# individual settings below for more information. +# This setting may not be combined with any of the +# other tuning settings: "journal_mode", +# "synchronous", or "temp_store". +# +# journal_mode Valid values: delete, truncate, persist, memory, wal, off +# The default is "wal", which uses a write-ahead +# log to implement database transactions. +# Alternately, "memory" saves disk I/O, but if +# rippled crashes during a transaction, the +# database is likely to be corrupted. +# See https://www.sqlite.org/pragma.html#pragma_journal_mode +# for more details about the available options. +# This setting may not be combined with the +# "safety_level" setting. +# +# synchronous Valid values: off, normal, full, extra +# The default is "normal", which works well with +# the "wal" journal mode. Alternatively, "off" +# allows rippled to continue as soon as data is +# passed to the OS, which can significantly +# increase speed, but risks data corruption if +# the host computer crashes before writing that +# data to disk. +# See https://www.sqlite.org/pragma.html#pragma_synchronous +# for more details about the available options. +# This setting may not be combined with the +# "safety_level" setting. +# +# temp_store Valid values: default, file, memory +# The default is "file", which will use files +# for temporary database tables and indices. +# Alternatively, "memory" may save I/O, but +# rippled does not currently use many, if any, +# of these temporary objects. +# See https://www.sqlite.org/pragma.html#pragma_temp_store +# for more details about the available options. +# This setting may not be combined with the +# "safety_level" setting. +# +# [ledger_tx_tables] (optional) +# +# conninfo Info for connecting to Postgres. Format is +# postgres://[username]:[password]@[ip]/[database]. +# The database and user must already exist. If this +# section is missing and rippled is running in +# Reporting Mode, rippled will connect as the +# user running rippled to a database with the +# same name. On Linux and Mac OS X, the connection +# will take place using the server's UNIX domain +# socket. On Windows, through the localhost IP +# address. Default is empty. +# +# use_tx_tables Valid values: 1, 0 +# The default is 1 (true). Determines whether to use +# the SQLite transaction database. If set to 0, +# rippled will not write to the transaction database, +# and will reject tx, account_tx and tx_history RPCs. +# In Reporting Mode, this setting is ignored. +# +# max_connections Valid values: any positive integer up to 64 bit +# storage length. This configures the maximum +# number of concurrent connections to postgres. +# Default is the maximum possible value to +# fit in a 64 bit integer. +# +# timeout Number of seconds after which idle postgres +# connections are discconnected. If set to 0, +# connections never timeout. Default is 600. +# +# +# remember_ip Value values: 1, 0 +# Default is 1 (true). Whether to cache host and +# port connection settings. +# +# +#------------------------------------------------------------------------------- +# +# 7. Diagnostics +# +#--------------- +# +# These settings are designed to help server administrators diagnose +# problems, and obtain detailed information about the activities being +# performed by the rippled process. +# +# +# +# [debug_logfile] +# +# Specifies where a debug logfile is kept. By default, no debug log is kept. +# Unless absolute, the path is relative the directory containing this file. +# +# Example: debug.log +# +# +# +# [insight] +# +# Configuration parameters for the Beast. Insight stats collection module. +# +# Insight is a module that collects information from the areas of rippled +# that have instrumentation. The configuration parameters control where the +# collection metrics are sent. The parameters are expressed as key = value +# pairs with no white space. The main parameter is the choice of server: +# +# "server" +# +# Choice of server to send metrics to. Currently the only choice is +# "statsd" which sends UDP packets to a StatsD daemon, which must be +# running while rippled is running. More information on StatsD is +# available here: +# https://github.com/b/statsd_spec +# +# When server=statsd, these additional keys are used: +# +# "address" The UDP address and port of the listening StatsD server, +# in the format, n.n.n.n:port. +# +# "prefix" A string prepended to each collected metric. This is used +# to distinguish between different running instances of rippled. +# +# If this section is missing, or the server type is unspecified or unknown, +# statistics are not collected or reported. +# +# Example: +# +# [insight] +# server=statsd +# address=192.168.0.95:4201 +# prefix=my_validator +# +# [perf] +# +# Configuration of performance logging. If enabled, write Json-formatted +# performance-oriented data periodically to a distinct log file. +# +# "perf_log" A string specifying the pathname of the performance log +# file. A relative pathname will log relative to the +# configuration directory. Required to enable +# performance logging. +# +# "log_interval" Integer value for number of seconds between writing +# to performance log. Default 1. +# +# Example: +# [perf] +# perf_log=/var/log/rippled/perf.log +# log_interval=2 +# +#------------------------------------------------------------------------------- +# +# 8. Voting +# +#---------- +# +# The vote settings configure settings for the entire Ripple network. +# While a single instance of rippled cannot unilaterally enforce network-wide +# settings, these choices become part of the instance's vote during the +# consensus process for each voting ledger. +# +# [voting] +# +# A set of key/value pair parameters used during voting ledgers. +# +# reference_fee = +# +# The cost of the reference transaction fee, specified in drops. +# The reference transaction is the simplest form of transaction. +# It represents an XRP payment between two parties. +# +# If this parameter is unspecified, rippled will use an internal +# default. Don't change this without understanding the consequences. +# +# Example: +# reference_fee = 10 # 10 drops +# +# account_reserve = +# +# The account reserve requirement is specified in drops. The portion of an +# account's XRP balance that is at or below the reserve may only be +# spent on transaction fees, and not transferred out of the account. +# +# If this parameter is unspecified, rippled will use an internal +# default. Don't change this without understanding the consequences. +# +# Example: +# account_reserve = 10000000 # 10 XRP +# +# owner_reserve = +# +# The owner reserve is the amount of XRP reserved in the account for +# each ledger item owned by the account. Ledger items an account may +# own include trust lines, open orders, and tickets. +# +# If this parameter is unspecified, rippled will use an internal +# default. Don't change this without understanding the consequences. +# +# Example: +# owner_reserve = 2000000 # 2 XRP +# +#------------------------------------------------------------------------------- +# +# 9. Misc Settings +# +#----------------- +# +# [node_size] +# +# Tunes the servers based on the expected load and available memory. Legal +# sizes are "tiny", "small", "medium", "large", and "huge". We recommend +# you start at the default and raise the setting if you have extra memory. +# +# The code attempts to automatically determine the appropriate size for +# this parameter based on the amount of RAM and the number of execution +# cores available to the server. The current decision matrix is: +# +# | | Cores | +# |---------|------------------------| +# | RAM | 1 | 2 or 3 | ≥ 4 | +# |---------|------|--------|--------| +# | < ~8GB | tiny | tiny | tiny | +# | < ~12GB | tiny | small | small | +# | < ~16GB | tiny | small | medium | +# | < ~24GB | tiny | small | large | +# | < ~32GB | tiny | small | huge | +# +# [signing_support] +# +# Specifies whether the server will accept "sign" and "sign_for" commands +# from remote users. Even if the commands are sent over a secure protocol +# like secure websocket, this should generally be discouraged, because it +# requires sending the secret to use for signing to the server. In order +# to sign transactions, users should prefer to use a standalone signing +# tool instead. +# +# This flag has no effect on the "sign" and "sign_for" command line options +# that rippled makes available. +# +# The default value of this field is "false" +# +# Example: +# +# [signing_support] +# true +# +# [crawl] +# +# List of options to control what data is reported through the /crawl endpoint +# See https://xrpl.org/peer-crawler.html +# +# +# +# Enable or disable access to /crawl requests. Default is '1' which +# enables access. +# +# overlay = +# +# Report information about peers this server is connected to, similar +# to the "peers" RPC API. Default is '1' which means to report peer +# overlay info. +# +# server = +# +# Report information about the local server, similar to the "server_state" +# RPC API. Default is '1' which means to report local server info. +# +# counts = +# +# Report information about the local server health counters, similar to +# the "get_counts" RPC API. Default is '0' which means not to report +# server counts. +# +# unl = +# +# Report information about the local server's validator lists, similar to +# the "validators" and "validator_list_sites" RPC APIs. Default is '1' +# which means to report server validator lists. +# +# Examples: +# +# [crawl] +# 0 +# +# [crawl] +# overlay = 1 +# server = 1 +# counts = 0 +# unl = 1 +# +# [vl] +# +# Options to control what data is reported through the /vl endpoint +# See [...] +# +# enable = +# +# Enable or disable access to /vl requests. Default is '1' which +# enables access. +# +# [beta_rpc_api] +# +# 0 or 1. +# +# 0: Disable the beta API version for JSON-RPC and WebSocket [default] +# 1: Enable the beta API version for testing. The beta API version +# contains breaking changes that require a new API version number. +# They are not ready for public consumption. +# +#------------------------------------------------------------------------------- +# +# 10. Example Settings +# +#-------------------- +# +# Administrators can use these values as a starting point for configuring +# their instance of rippled, but each value should be checked to make sure +# it meets the business requirements for the organization. +# +# Server +# +# These example configuration settings create these ports: +# +# "peer" +# +# Peer protocol open to everyone. This is required to accept +# incoming rippled connections. This does not affect automatic +# or manual outgoing Peer protocol connections. +# +# "rpc" +# +# Administrative RPC commands over HTTPS, when originating from +# the same machine (via the loopback adapter at 127.0.0.1). +# +# "wss_admin" +# +# Admin level API commands over Secure Websockets, when originating +# from the same machine (via the loopback adapter at 127.0.0.1). +# +# This port is commented out but can be enabled by removing +# the '#' from each corresponding line including the entry under [server] +# +# "wss_public" +# +# Guest level API commands over Secure Websockets, open to everyone. +# +# For HTTPS and Secure Websockets ports, if no certificate and key file +# are specified then a self-signed certificate will be generated on startup. +# If you have a certificate and key file, uncomment the corresponding lines +# and ensure the paths to the files are correct. +# +# NOTE +# +# To accept connections on well known ports such as 80 (HTTP) or +# 443 (HTTPS), most operating systems will require rippled to +# run with administrator privileges, or else rippled will not start. + +[server] +port_rpc_admin_local +port_peer +port_ws_admin_local +#port_ws_public +#ssl_key = /etc/ssl/private/server.key +#ssl_cert = /etc/ssl/certs/server.crt + +[port_rpc_admin_local] +port = 5005 +ip = 127.0.0.1 +admin = 127.0.0.1 +protocol = http + +[port_peer] +port = 51235 +ip = 0.0.0.0 +# alternatively, to accept connections on IPv4 + IPv6, use: +#ip = :: +protocol = peer + +[port_ws_admin_local] +port = 6006 +ip = 127.0.0.1 +admin = 127.0.0.1 +protocol = ws + +[port_grpc] +port = 50051 +ip = 127.0.0.1 +secure_gateway = 127.0.0.1 + +#[port_ws_public] +#port = 6005 +#ip = 127.0.0.1 +#protocol = wss + +#------------------------------------------------------------------------------- + +# This is primary persistent datastore for rippled. This includes transaction +# metadata, account states, and ledger headers. Helpful information can be +# found at https://xrpl.org/capacity-planning.html#node-db-type +# type=NuDB is recommended for non-validators with fast SSDs. Validators or +# slow / spinning disks should use RocksDB. Caution: Spinning disks are +# not recommended. They do not perform well enough to consistently remain +# synced to the network. +# online_delete=512 is recommended to delete old ledgers while maintaining at +# least 512. +# advisory_delete=0 allows the online delete process to run automatically +# when the node has approximately two times the "online_delete" value of +# ledgers. No external administrative command is required to initiate +# deletion. +[node_db] +type=NuDB +path=/var/lib/rippled/db/nudb +online_delete=512 +advisory_delete=0 + +# This is the persistent datastore for shards. It is important for the health +# of the ripple network that rippled operators shard as much as practical. +# NuDB requires SSD storage. Helpful information can be found at +# https://xrpl.org/history-sharding.html +#[shard_db] +#path=/var/lib/rippled/db/shards/nudb +#max_historical_shards=50 +# +# This optional section can be configured with a list +# of paths to use for storing historical shards. Each +# path must correspond to a unique filesystem. +#[historical_shard_paths] +#/path/1 +#/path/2 + +[database_path] +/var/lib/rippled/db + + +# To use Postgres, uncomment this section and fill in the appropriate connection +# info. Postgres can only be used in Reporting Mode. +# To disable writing to the transaction database, uncomment this section, and +# set use_tx_tables=0 +# [ledger_tx_tables] +# conninfo = postgres://[username]:[password]@[ip]/[database] +# use_tx_tables=1 + + +# This needs to be an absolute directory reference, not a relative one. +# Modify this value as required. +[debug_logfile] +/var/log/rippled/debug.log + +# To use the XRP test network +# (see https://xrpl.org/connect-your-rippled-to-the-xrp-test-net.html), +# use the following [ips] section: +# [ips] +# r.altnet.rippletest.net 51235 + +# File containing trusted validator keys or validator list publishers. +# Unless an absolute path is specified, it will be considered relative to the +# folder in which the rippled.cfg file is located. +[validators_file] +validators.txt + +# Turn down default logging to save disk space in the long run. +# Valid values here are trace, debug, info, warning, error, and fatal +[rpc_startup] +{ "command": "log_level", "severity": "warning" } + +# If ssl_verify is 1, certificates will be validated. +# To allow the use of self-signed certificates for development or internal use, +# set to ssl_verify to 0. +[ssl_verify] +1 + + +# To run in Reporting Mode, uncomment this section and fill in the appropriate +# connection info for one or more ETL sources. +# [reporting] +# etl_source +# +# +# [etl_source] +# source_grpc_port=50051 +# source_ws_port=6005 +# source_ip=127.0.0.1 diff --git a/cfg/validators-example.txt b/cfg/validators-example.txt new file mode 100644 index 00000000000..8f7c04729e0 --- /dev/null +++ b/cfg/validators-example.txt @@ -0,0 +1,72 @@ +# +# Default validators.txt +# +# This file is located in the same folder as your rippled.cfg file +# and defines which validators your server trusts not to collude. +# +# This file is UTF-8 with DOS, UNIX, or Mac style line endings. +# Blank lines and lines starting with a '#' are ignored. +# +# +# +# [validators] +# +# List of the validation public keys of nodes to always accept as validators. +# +# Manually listing validator keys is not recommended for production networks. +# See validator_list_sites and validator_list_keys below. +# +# Examples: +# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5 +# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt +# +# [validator_list_sites] +# +# List of URIs serving lists of recommended validators. +# +# Examples: +# https://vl.ripple.com +# https://vl.xrplf.org +# http://127.0.0.1:8000 +# file:///etc/opt/ripple/vl.txt +# +# [validator_list_keys] +# +# List of keys belonging to trusted validator list publishers. +# Validator lists fetched from configured sites will only be considered +# if the list is accompanied by a valid signature from a trusted +# publisher key. +# Validator list keys should be hex-encoded. +# +# Examples: +# ED2677ABFFD1B33AC6FBC3062B71F1E8397C1505E1C42C64D11AD1B28FF73F4734 +# ED307A760EE34F2D0CAA103377B1969117C38B8AA0AA1E2A24DAC1F32FC97087ED +# + +# The default validator list publishers that the rippled instance +# trusts. +# +# WARNING: Changing these values can cause your rippled instance to see a +# validated ledger that contradicts other rippled instances' +# validated ledgers (aka a ledger fork) if your validator list(s) +# do not sufficiently overlap with the list(s) used by others. +# See: https://arxiv.org/pdf/1802.07242.pdf + +[validator_list_sites] +https://vl.ripple.com +https://vl.xrplf.org + +[validator_list_keys] +#vl.ripple.com +ED2677ABFFD1B33AC6FBC3062B71F1E8397C1505E1C42C64D11AD1B28FF73F4734 +# vl.xrplf.org +ED45D1840EE724BE327ABE9146503D5848EFD5F38B6D5FEDE71E80ACCE5E6E738B + +# To use the test network (see https://xrpl.org/connect-your-rippled-to-the-xrp-test-net.html), +# use the following configuration instead: +# +# [validator_list_sites] +# https://vl.altnet.rippletest.net +# +# [validator_list_keys] +# ED264807102805220DA0F312E71FC2C69E1552C9C5790F6C25E3729DEB573D5860 diff --git a/src/ripple/app/tx/impl/NFTokenMint.cpp b/src/ripple/app/tx/impl/NFTokenMint.cpp index c26fb1fb12a..ba228536b2a 100644 --- a/src/ripple/app/tx/impl/NFTokenMint.cpp +++ b/src/ripple/app/tx/impl/NFTokenMint.cpp @@ -40,22 +40,12 @@ NFTokenMint::preflight(PreflightContext const& ctx) if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; - // Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between - // accounts allowed a TrustLine to be added to the issuer of that token - // without explicit permission from that issuer. This was enabled by - // minting the NFToken with the tfTrustLine flag set. - // - // That capability could be used to attack the NFToken issuer. It - // would be possible for two accounts to trade the NFToken back and forth - // building up any number of TrustLines on the issuer, increasing the - // issuer's reserve without bound. - // - // The fixRemoveNFTokenAutoTrustLine amendment disables minting with the - // tfTrustLine flag as a way to prevent the attack. But until the - // amendment passes we still need to keep the old behavior available. + // if featureDNFT enabled then new flag allowing mutable URI available + std::uint32_t const NFTokenMintMask = - ctx.rules.enabled(fixRemoveNFTokenAutoTrustLine) ? tfNFTokenMintMask - : tfNFTokenMintOldMask; + ctx.rules.enabled(featureDNFT) ? tfNFTokenMintMask + : tfNFTokenMintOldMask; + if (ctx.tx.getFlags() & NFTokenMintMask) return temINVALID_FLAG; diff --git a/src/ripple/app/tx/impl/NFTokenModify.cpp b/src/ripple/app/tx/impl/NFTokenModify.cpp index b56ce37a23e..c45765cfddf 100644 --- a/src/ripple/app/tx/impl/NFTokenModify.cpp +++ b/src/ripple/app/tx/impl/NFTokenModify.cpp @@ -12,7 +12,7 @@ namespace ripple { NotTEC NFTokenModify::preflight(PreflightContext const& ctx) { - if (!ctx.rules.enabled(featureNonFungibleTokensV1)) + if (!ctx.rules.enabled(featureDNFT)) return temDISABLED; if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index 3bdfcb15c59..bd06b011182 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -353,6 +353,7 @@ extern uint256 const fixDisallowIncomingV1; extern uint256 const featureDID; extern uint256 const fixFillOrKill; + } // namespace ripple #endif diff --git a/src/ripple/protocol/TxFlags.h b/src/ripple/protocol/TxFlags.h index 267f05428e6..7189a70b22f 100644 --- a/src/ripple/protocol/TxFlags.h +++ b/src/ripple/protocol/TxFlags.h @@ -127,26 +127,12 @@ 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 tfMutable = 0x00000016; - -// Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between -// accounts allowed a TrustLine to be added to the issuer of that token -// without explicit permission from that issuer. This was enabled by -// minting the NFToken with the tfTrustLine flag set. -// -// That capability could be used to attack the NFToken issuer. It -// would be possible for two accounts to trade the NFToken back and forth -// building up any number of TrustLines on the issuer, increasing the -// issuer's reserve without bound. -// -// The fixRemoveNFTokenAutoTrustLine amendment disables minting with the -// tfTrustLine flag as a way to prevent the attack. But until the -// amendment passes we still need to keep the old behavior available. -constexpr std::uint32_t const tfNFTokenMintOldMask = - ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable); +constexpr std::uint32_t const tfMutable = 0x00000016; +constexpr std::uint32_t const tfNFTokenMintOldMask = + ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable); +// if featureDNFT enabled then new flag allowing mutable URI available constexpr std::uint32_t const tfNFTokenMintMask = ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable | tfMutable); diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index 25033d4336e..7a232ac52eb 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -459,6 +459,7 @@ REGISTER_FEATURE(XChainBridge, Supported::yes, VoteBehavior::De REGISTER_FIX (fixDisallowIncomingV1, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FEATURE(DID, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX(fixFillOrKill, Supported::yes, VoteBehavior::DefaultNo); +REGISTER_FEATURE(DNFT, Supported::yes, VoteBehavior::DefaultNo); // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/src/ripple/protocol/nft.h b/src/ripple/protocol/nft.h index 764f240e25e..9a236c3122b 100644 --- a/src/ripple/protocol/nft.h +++ b/src/ripple/protocol/nft.h @@ -54,7 +54,7 @@ constexpr std::uint16_t const flagBurnable = 0x0001; constexpr std::uint16_t const flagOnlyXRP = 0x0002; constexpr std::uint16_t const flagCreateTrustLines = 0x0004; constexpr std::uint16_t const flagTransferable = 0x0008; -constexpr std::uint16_t const flagMutable = 0x0016; +constexpr std::uint16_t const flagMutable = 0x0010; inline std::uint16_t getFlags(uint256 const& id) From 624e11ea2af152725ad0a72e1228d03d8493e9bb Mon Sep 17 00:00:00 2001 From: xVet Date: Tue, 28 Nov 2023 02:35:41 +0100 Subject: [PATCH 04/26] added featureDNFT in Feature.h --- src/ripple/protocol/Feature.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index bd06b011182..4eaead6de47 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -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 = 65; +static constexpr std::size_t numFeatures = 66; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -352,6 +352,7 @@ extern uint256 const featureXChainBridge; extern uint256 const fixDisallowIncomingV1; extern uint256 const featureDID; extern uint256 const fixFillOrKill; +extern uint256 const featureDNFT; } // namespace ripple From f6418aaec4330ea35bdfce167399044e197038c1 Mon Sep 17 00:00:00 2001 From: tequ Date: Fri, 16 Feb 2024 17:55:03 +0900 Subject: [PATCH 05/26] dNFTs --- src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp | 1 - src/ripple/app/tx/impl/NFTokenMint.cpp | 23 +- src/ripple/app/tx/impl/NFTokenModify.cpp | 55 ++--- src/ripple/app/tx/impl/NFTokenModify.h | 19 +- src/ripple/app/tx/impl/applySteps.cpp | 3 + src/ripple/protocol/TxFlags.h | 30 ++- src/ripple/protocol/TxFormats.h | 3 + src/ripple/protocol/impl/TxFormats.cpp | 9 + src/ripple/protocol/jss.h | 1 + src/test/app/NFToken_test.cpp | 231 +++++++++++++++++- src/test/jtx/impl/token.cpp | 10 + src/test/jtx/token.h | 4 + 12 files changed, 340 insertions(+), 49 deletions(-) diff --git a/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp b/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp index 1ed6a4cd90f..02471c1d482 100644 --- a/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp +++ b/src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp @@ -27,7 +27,6 @@ namespace ripple { - NotTEC NFTokenAcceptOffer::preflight(PreflightContext const& ctx) { diff --git a/src/ripple/app/tx/impl/NFTokenMint.cpp b/src/ripple/app/tx/impl/NFTokenMint.cpp index ba228536b2a..7eb82cafb53 100644 --- a/src/ripple/app/tx/impl/NFTokenMint.cpp +++ b/src/ripple/app/tx/impl/NFTokenMint.cpp @@ -40,11 +40,26 @@ NFTokenMint::preflight(PreflightContext const& ctx) if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; - // if featureDNFT enabled then new flag allowing mutable URI available - + // Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between + // accounts allowed a TrustLine to be added to the issuer of that token + // without explicit permission from that issuer. This was enabled by + // minting the NFToken with the tfTrustLine flag set. + // + // That capability could be used to attack the NFToken issuer. It + // would be possible for two accounts to trade the NFToken back and forth + // building up any number of TrustLines on the issuer, increasing the + // issuer's reserve without bound. + // + // The fixRemoveNFTokenAutoTrustLine amendment disables minting with the + // tfTrustLine flag as a way to prevent the attack. But until the + // amendment passes we still need to keep the old behavior available. std::uint32_t const NFTokenMintMask = - ctx.rules.enabled(featureDNFT) ? tfNFTokenMintMask - : tfNFTokenMintOldMask; + ctx.rules.enabled(fixRemoveNFTokenAutoTrustLine) + // if featureDNFT enabled then new flag allowing mutable URI + // available + ? ctx.rules.enabled(featureDNFT) ? tfNFTokenMintMaskWithMutable + : tfNFTokenMintMask + : tfNFTokenMintOldMask; if (ctx.tx.getFlags() & NFTokenMintMask) return temINVALID_FLAG; diff --git a/src/ripple/app/tx/impl/NFTokenModify.cpp b/src/ripple/app/tx/impl/NFTokenModify.cpp index c45765cfddf..2c0a53c860f 100644 --- a/src/ripple/app/tx/impl/NFTokenModify.cpp +++ b/src/ripple/app/tx/impl/NFTokenModify.cpp @@ -12,23 +12,19 @@ namespace ripple { NotTEC NFTokenModify::preflight(PreflightContext const& ctx) { - if (!ctx.rules.enabled(featureDNFT)) + if (!ctx.rules.enabled(featureNonFungibleTokensV1_1) || + !ctx.rules.enabled(featureDNFT)) return temDISABLED; if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; - auto const nftID = ctx.tx[sfNFTokenID]; - auto const account = ctx.tx[sfAccount]; - - if (!account || !nftID) - return temMALFORMED; + if (auto owner = ctx.tx[~sfOwner]; owner == ctx.tx[sfAccount]) + return temMALFORMED; - if (ctx.tx.isFieldPresent(sfURI)) + if (auto uri = ctx.tx[~sfURI]) { - auto uri = ctx.tx[sfURI]; - - if (uri.length() == 0 || uri.length() > maxTokenURILength) + if (uri->length() == 0 || uri->length() > maxTokenURILength) return temMALFORMED; } @@ -38,14 +34,9 @@ NFTokenModify::preflight(PreflightContext const& ctx) TER NFTokenModify::preclaim(PreclaimContext const& ctx) { - auto const account = ctx.tx[sfAccount]; - - auto const owner = [&ctx]() { - if (ctx.tx.isFieldPresent(sfOwner)) - return ctx.tx.getAccountID(sfOwner); - - return ctx.tx[sfAccount]; - }(); + auto const account = ctx.tx[sfAccount]; + auto const owner = + ctx.tx[ctx.tx.isFieldPresent(sfOwner) ? sfOwner : sfAccount]; if (!nft::findToken(ctx.view, owner, ctx.tx[sfNFTokenID])) return tecNO_ENTRY; @@ -60,8 +51,7 @@ NFTokenModify::preclaim(PreclaimContext const& ctx) { if (auto const sle = ctx.view.read(keylet::account(issuer)); sle) { - if (auto const minter = (*sle)[~sfNFTokenMinter]; - minter != account) + if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account) return tecNO_PERMISSION; } } @@ -73,24 +63,29 @@ TER NFTokenModify::doApply() { auto const nftokenID = ctx_.tx[sfNFTokenID]; - auto const account = ctx_.tx[sfAccount]; - + auto const owner = + ctx_.tx[ctx_.tx.isFieldPresent(sfOwner) ? sfOwner : sfAccount]; // Find the token and its page - auto tokenAndPage = nft::findTokenAndPage(view(), account, nftokenID); + auto tokenAndPage = nft::findTokenAndPage(view(), owner, nftokenID); if (!tokenAndPage) return tecINTERNAL; // Replace the URI if present in the transaction - if (ctx_.tx.isFieldPresent(sfURI)) { - auto newURI = ctx_.tx[sfURI]; - tokenAndPage->token[sfURI] = newURI; - } + if (auto const newURI = ctx_.tx[~sfURI]) + tokenAndPage->token.setFieldVL(sfURI, *newURI); + else + tokenAndPage->token.makeFieldAbsent(sfURI); // Apply the changes to the token - if (auto const ret = nft::updateToken(view(), account, std::move(tokenAndPage->token), std::move(tokenAndPage->page)); !isTesSuccess(ret)) + if (auto const ret = nft::updateToken( + view(), + owner, + std::move(tokenAndPage->token), + std::move(tokenAndPage->page)); + !isTesSuccess(ret)) return ret; - return tesSUCCESS; + return tesSUCCESS; } -} \ No newline at end of file +} // namespace ripple diff --git a/src/ripple/app/tx/impl/NFTokenModify.h b/src/ripple/app/tx/impl/NFTokenModify.h index 07e5548ef61..3766f5569fa 100644 --- a/src/ripple/app/tx/impl/NFTokenModify.h +++ b/src/ripple/app/tx/impl/NFTokenModify.h @@ -1,4 +1,21 @@ - +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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_NFTOKENMODIFY_H_INCLUDED #define RIPPLE_TX_NFTOKENMODIFY_H_INCLUDED diff --git a/src/ripple/app/tx/impl/applySteps.cpp b/src/ripple/app/tx/impl/applySteps.cpp index 10e2b0c4524..7359b1ef10f 100644 --- a/src/ripple/app/tx/impl/applySteps.cpp +++ b/src/ripple/app/tx/impl/applySteps.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -125,6 +126,8 @@ with_txn_type(TxType txnType, F&& f) return f.template operator()(); case ttNFTOKEN_ACCEPT_OFFER: return f.template operator()(); + case ttNFTOKEN_MODIFY: + return f.template operator()(); case ttCLAWBACK: return f.template operator()(); case ttAMM_CREATE: diff --git a/src/ripple/protocol/TxFlags.h b/src/ripple/protocol/TxFlags.h index 7189a70b22f..8f938816910 100644 --- a/src/ripple/protocol/TxFlags.h +++ b/src/ripple/protocol/TxFlags.h @@ -127,13 +127,31 @@ 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 tfMutable = 0x00000016; - -constexpr std::uint32_t const tfNFTokenMintOldMask = - ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable); -// if featureDNFT enabled then new flag allowing mutable URI available -constexpr std::uint32_t const tfNFTokenMintMask = +constexpr std::uint32_t const tfMutable = 0x00000010; + +// Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between +// accounts allowed a TrustLine to be added to the issuer of that token +// without explicit permission from that issuer. This was enabled by +// minting the NFToken with the tfTrustLine flag set. +// +// That capability could be used to attack the NFToken issuer. It +// would be possible for two accounts to trade the NFToken back and forth +// building up any number of TrustLines on the issuer, increasing the +// issuer's reserve without bound. +// +// The fixRemoveNFTokenAutoTrustLine amendment disables minting with the +// tfTrustLine flag as a way to prevent the attack. But until the +// amendment passes we still need to keep the old behavior available. + constexpr std::uint32_t const tfNFTokenMintOldMask = + ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable); + + constexpr std::uint32_t const tfNFTokenMintMask = + ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable); + +// if featureDNFT enabled then new flag allowing mutable URI available. +constexpr std::uint32_t const tfNFTokenMintMaskWithMutable = ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable | tfMutable); // NFTokenCreateOffer flags: diff --git a/src/ripple/protocol/TxFormats.h b/src/ripple/protocol/TxFormats.h index b12547b0a67..eeb4b7004e4 100644 --- a/src/ripple/protocol/TxFormats.h +++ b/src/ripple/protocol/TxFormats.h @@ -190,6 +190,9 @@ enum TxType : std::uint16_t /** This transaction type deletes a DID */ ttDID_DELETE = 50, + /** This transaction type modify a NFToken */ + ttNFTOKEN_MODIFY = 51, + /** This system-generated transaction type is used to update the status of the various amendments. diff --git a/src/ripple/protocol/impl/TxFormats.cpp b/src/ripple/protocol/impl/TxFormats.cpp index 7be8ca741e2..5f67c01fe66 100644 --- a/src/ripple/protocol/impl/TxFormats.cpp +++ b/src/ripple/protocol/impl/TxFormats.cpp @@ -371,6 +371,15 @@ TxFormats::TxFormats() }, commonFields); + add(jss::NFTokenModify, + ttNFTOKEN_MODIFY, + { + {sfNFTokenID, soeREQUIRED}, + {sfOwner, soeOPTIONAL}, + {sfURI, soeOPTIONAL}, + }, + commonFields); + add(jss::Clawback, ttCLAWBACK, { diff --git a/src/ripple/protocol/jss.h b/src/ripple/protocol/jss.h index fd1c94c67d2..744fcc8394a 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -100,6 +100,7 @@ JSS(NFTokenOffer); // ledger type. JSS(NFTokenAcceptOffer); // transaction type. JSS(NFTokenCancelOffer); // transaction type. JSS(NFTokenCreateOffer); // transaction type. +JSS(NFTokenModify); // transaction type. JSS(NFTokenPage); // ledger type. JSS(LPTokenOut); // in: AMM Liquidity Provider deposit tokens JSS(LPTokenIn); // in: AMM Liquidity Provider withdraw tokens diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index 8740b521132..c6fb9838563 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -7112,6 +7112,211 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite } } + void + testNFTokenModify(FeatureBitset features) + { + testcase("Test modify"); + + using namespace test::jtx; + + Account const minter{"minter"}; + Account const alice("alice"); + Account const bob("bob"); + + auto modifyEnabled = features[featureDNFT]; + + { + // Mint with tfMutable + Env env{*this, features}; + env.fund(XRP(10000), minter); + env.close(); + + auto const expectedTer = + modifyEnabled ? TER{tesSUCCESS} : TER{temINVALID_FLAG}; + env(token::mint(minter, 0u), txflags(tfMutable), ter(expectedTer)); + env.close(); + } + { + Env env{*this, features}; + env.fund(XRP(10000), minter); + env.close(); + + // Modify a nftoken + uint256 const nftId{token::getNextID(env, minter, 0u, tfMutable)}; + env(token::mint(minter, 0u), txflags(tfMutable)); + env.close(); + if (modifyEnabled) + { + BEAST_EXPECT(ownerCount(env, minter) == 1); + env(token::modify(minter, nftId)); + BEAST_EXPECT(ownerCount(env, minter) == 1); + } + else + { + env(token::modify(minter, nftId), ter(temDISABLED)); + env.close(); + } + } + if (!modifyEnabled) + return; + + { + Env env{*this, features}; + env.fund(XRP(10000), minter); + env.close(); + + uint256 const nftId{token::getNextID(env, minter, 0u, tfMutable)}; + env(token::mint(minter, 0u), txflags(tfMutable)); + env.close(); + + // Invalid Owner + env(token::modify(minter, nftId), + token::owner(minter), + ter(temMALFORMED)); + env.close(); + + // Invalid URI length = 0 + env(token::modify(minter, nftId), + token::uri(""), + ter(temMALFORMED)); + env.close(); + + // Invalid URI length > 256 + env(token::modify(minter, nftId), + token::uri(std::string(maxTokenURILength + 1, 'q')), + ter(temMALFORMED)); + env.close(); + } + { + Env env{*this, features}; + env.fund(XRP(10000), minter, alice); + env.close(); + + uint256 const nftId_not_exists{ + token::getNextID(env, minter, 0u, tfMutable)}; + env.close(); + + // NFToken not exists + env(token::modify(minter, nftId_not_exists), ter(tecNO_ENTRY)); + env.close(); + + uint256 const nftId_not_modifiable{ + token::getNextID(env, minter, 0u)}; + env(token::mint(minter, 0u)); + env.close(); + + // Invalid NFToken flagn + env(token::modify(minter, nftId_not_modifiable), + ter(tecNO_PERMISSION)); + env.close(); + + // Invalid NFTokenMinter + env(token::modify(alice, nftId_not_modifiable), + token::owner(minter), + ter(tecNO_PERMISSION)); + env.close(); + } + { + Env env{*this, features}; + env.fund(XRP(10000), minter, alice, bob); + env.close(); + + auto accountNFTs = [&](Env& env, Account const& acct) { + Json::Value params; + params[jss::account] = acct.human(); + params[jss::type] = "state"; + auto response = + env.rpc("json", "account_nfts", to_string(params)); + return response[jss::result][jss::account_nfts]; + }; + + uint256 const nftId{token::getNextID(env, minter, 0u, tfMutable)}; + env.close(); + + env(token::mint(minter, 0u), txflags(tfMutable), token::uri("uri")); + env.close(); + { + auto nfts = accountNFTs(env, minter); + if (!BEAST_EXPECT(nfts.isArray())) + return; + BEAST_EXPECT(nfts.size() == 1); + BEAST_EXPECT( + nfts[0u][sfURI.jsonName] == strHex(std::string("uri"))); + } + + // set URI Field + env(token::modify(minter, nftId), token::uri("new_uri")); + env.close(); + { + auto nfts = accountNFTs(env, minter); + if (!BEAST_EXPECT(nfts.isArray())) + return; + BEAST_EXPECT(nfts.size() == 1); + BEAST_EXPECT( + nfts[0u][sfURI.jsonName] == strHex(std::string("new_uri"))); + } + // unset URI Field + env(token::modify(minter, nftId)); + env.close(); + { + auto nfts = accountNFTs(env, minter); + if (!BEAST_EXPECT(nfts.isArray())) + return; + BEAST_EXPECT(nfts.size() == 1); + BEAST_EXPECT(!nfts[0u].isMember(sfURI.jsonName)); + } + // set URI Field + env(token::modify(minter, nftId), token::uri("uri")); + env.close(); + { + auto nfts = accountNFTs(env, minter); + if (!BEAST_EXPECT(nfts.isArray())) + return; + BEAST_EXPECT(nfts.size() == 1); + BEAST_EXPECT( + nfts[0u][sfURI.jsonName] == strHex(std::string("uri"))); + } + + // Account != Owner + uint256 const offerID = + keylet::nftoffer(minter, env.seq(minter)).key; + env(token::createOffer(minter, nftId, XRP(0)), + txflags(tfSellNFToken)); + env.close(); + env(token::acceptSellOffer(alice, offerID)); + env.close(); + + BEAST_EXPECT(ownerCount(env, minter) == 0); + BEAST_EXPECT(ownerCount(env, alice) == 1); + env(token::modify(minter, nftId), + token::owner(alice), + token::uri("new_uri")); + env.close(); + BEAST_EXPECT(ownerCount(env, minter) == 0); + BEAST_EXPECT(ownerCount(env, alice) == 1); + + env(token::modify(minter, nftId), token::owner(alice)); + env.close(); + + env(token::modify(minter, nftId), + token::owner(alice), + token::uri("uri")); + env.close(); + + // Modify by Issuer + env(token::setMinter(minter, bob)); + env.close(); + env(token::modify(bob, nftId), + token::owner(alice), + token::uri("new_uri")); + env(token::modify(bob, nftId), token::owner(alice)); + env(token::modify(bob, nftId), + token::owner(alice), + token::uri("uri")); + env.close(); + } + } + void testWithFeats(FeatureBitset features) { @@ -7146,6 +7351,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite testFixNFTokenRemint(features); testTxJsonMetaFields(features); testFixNFTokenBuyerReserve(features); + testNFTokenModify(features); } public: @@ -7156,15 +7362,16 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite static FeatureBitset const all{supported_amendments()}; static FeatureBitset const fixNFTDir{fixNFTokenDirV1}; - static std::array const feats{ + static std::array const feats{ all - fixNFTDir - fixNonFungibleTokensV1_2 - fixNFTokenRemint - - fixNFTokenReserve, + fixNFTokenReserve - featureDNFT, all - disallowIncoming - fixNonFungibleTokensV1_2 - - fixNFTokenRemint - fixNFTokenReserve, + fixNFTokenRemint - fixNFTokenReserve - featureDNFT, all - fixNonFungibleTokensV1_2 - fixNFTokenRemint - - fixNFTokenReserve, - all - fixNFTokenRemint - fixNFTokenReserve, - all - fixNFTokenReserve, + fixNFTokenReserve - featureDNFT, + all - fixNFTokenRemint - fixNFTokenReserve - featureDNFT, + all - fixNFTokenReserve - featureDNFT, + all - featureDNFT, all}; if (BEAST_EXPECT(instance < feats.size())) @@ -7217,12 +7424,21 @@ class NFTokenWOTokenReserve_test : public NFTokenBaseUtil_test } }; +class NFTokenWOModify_test : public NFTokenBaseUtil_test +{ + void + run() override + { + NFTokenBaseUtil_test::run(5); + } +}; + class NFTokenAllFeatures_test : public NFTokenBaseUtil_test { void run() override { - NFTokenBaseUtil_test::run(5, true); + NFTokenBaseUtil_test::run(6, true); } }; @@ -7231,6 +7447,7 @@ BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDisallowIncoming, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOfixV1, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenRemint, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenReserve, tx, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOModify, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAllFeatures, tx, ripple, 2); } // namespace ripple diff --git a/src/test/jtx/impl/token.cpp b/src/test/jtx/impl/token.cpp index 6c5cae4147a..d3cfb358e27 100644 --- a/src/test/jtx/impl/token.cpp +++ b/src/test/jtx/impl/token.cpp @@ -226,6 +226,16 @@ clearMinter(jtx::Account const& account) return fclear(account, asfAuthorizedNFTokenMinter); } +Json::Value +modify(jtx::Account const& account, uint256 const& nftokenID) +{ + Json::Value jv; + jv[sfAccount.jsonName] = account.human(); + jv[sfNFTokenID.jsonName] = to_string(nftokenID); + jv[jss::TransactionType] = jss::NFTokenModify; + return jv; +} + } // namespace token } // namespace jtx } // namespace test diff --git a/src/test/jtx/token.h b/src/test/jtx/token.h index 150ddfab0ea..455e62fe973 100644 --- a/src/test/jtx/token.h +++ b/src/test/jtx/token.h @@ -222,6 +222,10 @@ setMinter(jtx::Account const& account, jtx::Account const& minter); Json::Value clearMinter(jtx::Account const& account); +/** Modify an NFToken. */ +Json::Value +modify(jtx::Account const& account, uint256 const& nftokenID); + } // namespace token } // namespace jtx From 44790abb05d9eee72827143442dfa83f7209e195 Mon Sep 17 00:00:00 2001 From: tequ Date: Fri, 16 Feb 2024 18:04:11 +0900 Subject: [PATCH 06/26] rename dNFT to DynamicNFT --- src/ripple/app/tx/impl/NFTokenMint.cpp | 6 +++--- src/ripple/app/tx/impl/NFTokenModify.cpp | 2 +- src/ripple/protocol/Feature.h | 2 +- src/ripple/protocol/TxFlags.h | 2 +- src/ripple/protocol/impl/Feature.cpp | 2 +- src/test/app/NFToken_test.cpp | 20 ++++++++++---------- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/ripple/app/tx/impl/NFTokenMint.cpp b/src/ripple/app/tx/impl/NFTokenMint.cpp index 7eb82cafb53..68f943b2bb9 100644 --- a/src/ripple/app/tx/impl/NFTokenMint.cpp +++ b/src/ripple/app/tx/impl/NFTokenMint.cpp @@ -55,10 +55,10 @@ NFTokenMint::preflight(PreflightContext const& ctx) // amendment passes we still need to keep the old behavior available. std::uint32_t const NFTokenMintMask = ctx.rules.enabled(fixRemoveNFTokenAutoTrustLine) - // if featureDNFT enabled then new flag allowing mutable URI + // if featureDynamicNFT enabled then new flag allowing mutable URI // available - ? ctx.rules.enabled(featureDNFT) ? tfNFTokenMintMaskWithMutable - : tfNFTokenMintMask + ? ctx.rules.enabled(featureDynamicNFT) ? tfNFTokenMintMaskWithMutable + : tfNFTokenMintMask : tfNFTokenMintOldMask; if (ctx.tx.getFlags() & NFTokenMintMask) diff --git a/src/ripple/app/tx/impl/NFTokenModify.cpp b/src/ripple/app/tx/impl/NFTokenModify.cpp index 2c0a53c860f..be8681b2abc 100644 --- a/src/ripple/app/tx/impl/NFTokenModify.cpp +++ b/src/ripple/app/tx/impl/NFTokenModify.cpp @@ -13,7 +13,7 @@ NotTEC NFTokenModify::preflight(PreflightContext const& ctx) { if (!ctx.rules.enabled(featureNonFungibleTokensV1_1) || - !ctx.rules.enabled(featureDNFT)) + !ctx.rules.enabled(featureDynamicNFT)) return temDISABLED; if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index f0a3d0ec1be..1e407ced010 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -354,7 +354,7 @@ extern uint256 const featureDID; extern uint256 const fixFillOrKill; extern uint256 const fixNFTokenReserve; extern uint256 const fixInnerObjTemplate; -extern uint256 const featureDNFT; +extern uint256 const featureDynamicNFT; } // namespace ripple diff --git a/src/ripple/protocol/TxFlags.h b/src/ripple/protocol/TxFlags.h index 8f938816910..cbe79ebb0b4 100644 --- a/src/ripple/protocol/TxFlags.h +++ b/src/ripple/protocol/TxFlags.h @@ -150,7 +150,7 @@ constexpr std::uint32_t const tfMutable = 0x00000010; constexpr std::uint32_t const tfNFTokenMintMask = ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable); -// if featureDNFT enabled then new flag allowing mutable URI available. +// if featureDynamicNFT enabled then new flag allowing mutable URI available. constexpr std::uint32_t const tfNFTokenMintMaskWithMutable = ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable | tfMutable); diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index 72a0342bd91..f5f2f6c7ff6 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -461,7 +461,7 @@ REGISTER_FEATURE(DID, Supported::yes, VoteBehavior::De REGISTER_FIX(fixFillOrKill, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX (fixNFTokenReserve, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FIX(fixInnerObjTemplate, Supported::yes, VoteBehavior::DefaultNo); -REGISTER_FEATURE(DNFT, Supported::yes, VoteBehavior::DefaultNo); +REGISTER_FEATURE(DynamicNFT, Supported::yes, VoteBehavior::DefaultNo); // The following amendments are obsolete, but must remain supported // because they could potentially get enabled. diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index c6fb9838563..49463d4ecb6 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -985,9 +985,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, buyer) == 1); // Provide neither offers to cancel nor a root index. - env(token::cancelOffer(buyer), ter(temMALFORMED)); - env.close(); - BEAST_EXPECT(ownerCount(env, buyer) == 1); + // env(token::cancelOffer(buyer), ter(temMALFORMED)); + // env.close(); + // BEAST_EXPECT(ownerCount(env, buyer) == 1); //---------------------------------------------------------------------- // preclaim @@ -7123,7 +7123,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite Account const alice("alice"); Account const bob("bob"); - auto modifyEnabled = features[featureDNFT]; + auto modifyEnabled = features[featureDynamicNFT]; { // Mint with tfMutable @@ -7364,14 +7364,14 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite static std::array const feats{ all - fixNFTDir - fixNonFungibleTokensV1_2 - fixNFTokenRemint - - fixNFTokenReserve - featureDNFT, + fixNFTokenReserve - featureDynamicNFT, all - disallowIncoming - fixNonFungibleTokensV1_2 - - fixNFTokenRemint - fixNFTokenReserve - featureDNFT, + fixNFTokenRemint - fixNFTokenReserve - featureDynamicNFT, all - fixNonFungibleTokensV1_2 - fixNFTokenRemint - - fixNFTokenReserve - featureDNFT, - all - fixNFTokenRemint - fixNFTokenReserve - featureDNFT, - all - fixNFTokenReserve - featureDNFT, - all - featureDNFT, + fixNFTokenReserve - featureDynamicNFT, + all - fixNFTokenRemint - fixNFTokenReserve - featureDynamicNFT, + all - fixNFTokenReserve - featureDynamicNFT, + all - featureDynamicNFT, all}; if (BEAST_EXPECT(instance < feats.size())) From ef6ba44599e645adee7652a4813a013f2cb00e86 Mon Sep 17 00:00:00 2001 From: tequ Date: Fri, 16 Feb 2024 19:40:13 +0900 Subject: [PATCH 07/26] clang-format --- src/ripple/app/tx/impl/details/NFTokenUtils.cpp | 17 +++++++++++------ src/ripple/app/tx/impl/details/NFTokenUtils.h | 8 ++++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/ripple/app/tx/impl/details/NFTokenUtils.cpp b/src/ripple/app/tx/impl/details/NFTokenUtils.cpp index 0150b68884f..988d16492e5 100644 --- a/src/ripple/app/tx/impl/details/NFTokenUtils.cpp +++ b/src/ripple/app/tx/impl/details/NFTokenUtils.cpp @@ -238,22 +238,27 @@ compareTokens(uint256 const& a, uint256 const& b) return a < b; } - -TER -updateToken(ApplyView& view, AccountID const& owner, STObject&& nft, std::shared_ptr&& page) +TER +updateToken( + ApplyView& view, + AccountID const& owner, + STObject&& nft, + std::shared_ptr&& page) { // Remove the old token from the owner's directory - if (auto const ret = nft::removeToken(view, owner, nft.getFieldH256(sfNFTokenID), std::move(page)); !isTesSuccess(ret)) + if (auto const ret = nft::removeToken( + view, owner, nft.getFieldH256(sfNFTokenID), std::move(page)); + !isTesSuccess(ret)) return ret; // Insert the updated token into the owner's directory - if (auto const ret = nft::insertToken(view, owner, std::move(nft)); !isTesSuccess(ret)) + if (auto const ret = nft::insertToken(view, owner, std::move(nft)); + !isTesSuccess(ret)) return ret; return tesSUCCESS; } - /** Insert the token in the owner's token directory. */ TER insertToken(ApplyView& view, AccountID owner, STObject&& nft) diff --git a/src/ripple/app/tx/impl/details/NFTokenUtils.h b/src/ripple/app/tx/impl/details/NFTokenUtils.h index 924ff4c6bf7..39f8fe2bf6d 100644 --- a/src/ripple/app/tx/impl/details/NFTokenUtils.h +++ b/src/ripple/app/tx/impl/details/NFTokenUtils.h @@ -97,8 +97,12 @@ deleteTokenOffer(ApplyView& view, std::shared_ptr const& offer); bool compareTokens(uint256 const& a, uint256 const& b); -TER -updateToken(ApplyView& view, AccountID const& owner, STObject&& nft, std::shared_ptr&& page); +TER +updateToken( + ApplyView& view, + AccountID const& owner, + STObject&& nft, + std::shared_ptr&& page); } // namespace nft From b9becc485720f093283bf69bde0ad628a4a7c425 Mon Sep 17 00:00:00 2001 From: tequ Date: Fri, 16 Feb 2024 21:27:52 +0900 Subject: [PATCH 08/26] fix flag test --- src/ripple/app/tx/impl/NFTokenMint.cpp | 3 ++- src/ripple/protocol/TxFlags.h | 2 ++ src/test/app/NFToken_test.cpp | 14 ++++++++------ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/ripple/app/tx/impl/NFTokenMint.cpp b/src/ripple/app/tx/impl/NFTokenMint.cpp index 68f943b2bb9..d75ce9a7a6b 100644 --- a/src/ripple/app/tx/impl/NFTokenMint.cpp +++ b/src/ripple/app/tx/impl/NFTokenMint.cpp @@ -59,7 +59,8 @@ NFTokenMint::preflight(PreflightContext const& ctx) // available ? ctx.rules.enabled(featureDynamicNFT) ? tfNFTokenMintMaskWithMutable : tfNFTokenMintMask - : tfNFTokenMintOldMask; + : ctx.rules.enabled(featureDynamicNFT) ? tfNFTokenMintOldMaskWithMutable + : tfNFTokenMintOldMask; if (ctx.tx.getFlags() & NFTokenMintMask) return temINVALID_FLAG; diff --git a/src/ripple/protocol/TxFlags.h b/src/ripple/protocol/TxFlags.h index cbe79ebb0b4..dca93105f90 100644 --- a/src/ripple/protocol/TxFlags.h +++ b/src/ripple/protocol/TxFlags.h @@ -151,6 +151,8 @@ constexpr std::uint32_t const tfMutable = 0x00000010; ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable); // if featureDynamicNFT enabled then new flag allowing mutable URI available. +constexpr std::uint32_t const tfNFTokenMintOldMaskWithMutable = + ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable | tfMutable); constexpr std::uint32_t const tfNFTokenMintMaskWithMutable = ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable | tfMutable); diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index 49463d4ecb6..c6579bd664e 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -985,9 +985,9 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite BEAST_EXPECT(ownerCount(env, buyer) == 1); // Provide neither offers to cancel nor a root index. - // env(token::cancelOffer(buyer), ter(temMALFORMED)); - // env.close(); - // BEAST_EXPECT(ownerCount(env, buyer) == 1); + env(token::cancelOffer(buyer), ter(temMALFORMED)); + env.close(); + BEAST_EXPECT(ownerCount(env, buyer) == 1); //---------------------------------------------------------------------- // preclaim @@ -7123,7 +7123,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite Account const alice("alice"); Account const bob("bob"); - auto modifyEnabled = features[featureDynamicNFT]; + bool modifyEnabled = features[featureDynamicNFT]; { // Mint with tfMutable @@ -7143,16 +7143,18 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite // Modify a nftoken uint256 const nftId{token::getNextID(env, minter, 0u, tfMutable)}; - env(token::mint(minter, 0u), txflags(tfMutable)); - env.close(); if (modifyEnabled) { + env(token::mint(minter, 0u), txflags(tfMutable)); + env.close(); BEAST_EXPECT(ownerCount(env, minter) == 1); env(token::modify(minter, nftId)); BEAST_EXPECT(ownerCount(env, minter) == 1); } else { + env(token::mint(minter, 0u)); + env.close(); env(token::modify(minter, nftId), ter(temDISABLED)); env.close(); } From 8fd988d1223cafc70c43e24dfae47a92d9447ade Mon Sep 17 00:00:00 2001 From: tequ Date: Sat, 17 Feb 2024 01:24:43 +0900 Subject: [PATCH 09/26] add standard license/disclaimer text --- src/ripple/app/tx/impl/NFTokenModify.cpp | 18 ++++++++++++++++++ src/ripple/protocol/TxFlags.h | 8 ++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/ripple/app/tx/impl/NFTokenModify.cpp b/src/ripple/app/tx/impl/NFTokenModify.cpp index be8681b2abc..8bc09da2b8e 100644 --- a/src/ripple/app/tx/impl/NFTokenModify.cpp +++ b/src/ripple/app/tx/impl/NFTokenModify.cpp @@ -1,3 +1,21 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 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 #include diff --git a/src/ripple/protocol/TxFlags.h b/src/ripple/protocol/TxFlags.h index dca93105f90..aad53bf045f 100644 --- a/src/ripple/protocol/TxFlags.h +++ b/src/ripple/protocol/TxFlags.h @@ -144,11 +144,11 @@ constexpr std::uint32_t const tfMutable = 0x00000010; // The fixRemoveNFTokenAutoTrustLine amendment disables minting with the // tfTrustLine flag as a way to prevent the attack. But until the // amendment passes we still need to keep the old behavior available. - constexpr std::uint32_t const tfNFTokenMintOldMask = - ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable); +constexpr std::uint32_t const tfNFTokenMintOldMask = + ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable); - constexpr std::uint32_t const tfNFTokenMintMask = - ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable); +constexpr std::uint32_t const tfNFTokenMintMask = + ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable); // if featureDynamicNFT enabled then new flag allowing mutable URI available. constexpr std::uint32_t const tfNFTokenMintOldMaskWithMutable = From 750adda589611ee35f7492dbb4f081cb0a8b2935 Mon Sep 17 00:00:00 2001 From: tequ Date: Tue, 18 Jun 2024 11:57:40 +0900 Subject: [PATCH 10/26] chore --- src/ripple/protocol/Feature.h | 2 +- src/ripple/protocol/TxFormats.h | 7 +++---- src/test/app/NFToken_test.cpp | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index 5ace7189b6a..7aed4dd3188 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -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 = 74; +static constexpr std::size_t numFeatures = 76; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated diff --git a/src/ripple/protocol/TxFormats.h b/src/ripple/protocol/TxFormats.h index f4dda7effd3..d9447167de9 100644 --- a/src/ripple/protocol/TxFormats.h +++ b/src/ripple/protocol/TxFormats.h @@ -190,16 +190,15 @@ enum TxType : std::uint16_t /** This transaction type deletes a DID */ ttDID_DELETE = 50, - /** This transaction type modify a NFToken */ - ttNFTOKEN_MODIFY = 51, - - /** This transaction type creates an Oracle instance */ ttORACLE_SET = 51, /** This transaction type deletes an Oracle instance */ ttORACLE_DELETE = 52, + /** This transaction type modify a NFToken */ + ttNFTOKEN_MODIFY = 53, + /** This system-generated transaction type is used to update the status of the various amendments. For details, see: https://xrpl.org/amendments.html diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index c6579bd664e..b97b90df2c5 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -7207,7 +7207,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env(token::mint(minter, 0u)); env.close(); - // Invalid NFToken flagn + // Invalid NFToken flag env(token::modify(minter, nftId_not_modifiable), ter(tecNO_PERMISSION)); env.close(); From 4b3480c52a04605bb7b16807b6e42fbcc01ce03b Mon Sep 17 00:00:00 2001 From: tequ Date: Tue, 18 Jun 2024 12:25:53 +0900 Subject: [PATCH 11/26] fix tests --- src/test/app/NFToken_test.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index b97b90df2c5..3aa3836a201 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -7239,8 +7239,6 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); { auto nfts = accountNFTs(env, minter); - if (!BEAST_EXPECT(nfts.isArray())) - return; BEAST_EXPECT(nfts.size() == 1); BEAST_EXPECT( nfts[0u][sfURI.jsonName] == strHex(std::string("uri"))); @@ -7251,8 +7249,6 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); { auto nfts = accountNFTs(env, minter); - if (!BEAST_EXPECT(nfts.isArray())) - return; BEAST_EXPECT(nfts.size() == 1); BEAST_EXPECT( nfts[0u][sfURI.jsonName] == strHex(std::string("new_uri"))); @@ -7262,8 +7258,6 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); { auto nfts = accountNFTs(env, minter); - if (!BEAST_EXPECT(nfts.isArray())) - return; BEAST_EXPECT(nfts.size() == 1); BEAST_EXPECT(!nfts[0u].isMember(sfURI.jsonName)); } @@ -7272,8 +7266,6 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite env.close(); { auto nfts = accountNFTs(env, minter); - if (!BEAST_EXPECT(nfts.isArray())) - return; BEAST_EXPECT(nfts.size() == 1); BEAST_EXPECT( nfts[0u][sfURI.jsonName] == strHex(std::string("uri"))); From 579dc25fcb22476aa7d58a74244e4e05464d7ce8 Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Thu, 27 Jun 2024 15:07:49 -0700 Subject: [PATCH 12/26] [FOLD] An incremental approach to the tfNFTokenMintMask variants --- include/xrpl/protocol/TxFlags.h | 34 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/include/xrpl/protocol/TxFlags.h b/include/xrpl/protocol/TxFlags.h index aad53bf045f..4f96751256d 100644 --- a/include/xrpl/protocol/TxFlags.h +++ b/include/xrpl/protocol/TxFlags.h @@ -144,17 +144,18 @@ constexpr std::uint32_t const tfMutable = 0x00000010; // The fixRemoveNFTokenAutoTrustLine amendment disables minting with the // tfTrustLine flag as a way to prevent the attack. But until the // amendment passes we still need to keep the old behavior available. -constexpr std::uint32_t const tfNFTokenMintOldMask = - ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable); - constexpr std::uint32_t const tfNFTokenMintMask = ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable); +constexpr std::uint32_t const tfNFTokenMintOldMask = + ~( ~tfNFTokenMintMask | tfTrustLine); + // if featureDynamicNFT enabled then new flag allowing mutable URI available. constexpr std::uint32_t const tfNFTokenMintOldMaskWithMutable = - ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable | tfMutable); + ~( ~tfNFTokenMintOldMask | tfMutable); + constexpr std::uint32_t const tfNFTokenMintMaskWithMutable = - ~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable | tfMutable); + ~( ~tfNFTokenMintMask | tfMutable); // NFTokenCreateOffer flags: constexpr std::uint32_t const tfSellNFToken = 0x00000001; @@ -168,17 +169,17 @@ constexpr std::uint32_t const tfNFTokenCancelOfferMask = ~(tfUniversal); constexpr std::uint32_t const tfNFTokenAcceptOfferMask = ~tfUniversal; // Clawback flags: -constexpr std::uint32_t const tfClawbackMask = ~tfUniversal; +constexpr std::uint32_t const tfClawbackMask = ~tfUniversal; // AMM Flags: -constexpr std::uint32_t tfLPToken = 0x00010000; -constexpr std::uint32_t tfWithdrawAll = 0x00020000; -constexpr std::uint32_t tfOneAssetWithdrawAll = 0x00040000; -constexpr std::uint32_t tfSingleAsset = 0x00080000; -constexpr std::uint32_t tfTwoAsset = 0x00100000; -constexpr std::uint32_t tfOneAssetLPToken = 0x00200000; -constexpr std::uint32_t tfLimitLPToken = 0x00400000; -constexpr std::uint32_t tfTwoAssetIfEmpty = 0x00800000; +constexpr std::uint32_t tfLPToken = 0x00010000; +constexpr std::uint32_t tfWithdrawAll = 0x00020000; +constexpr std::uint32_t tfOneAssetWithdrawAll = 0x00040000; +constexpr std::uint32_t tfSingleAsset = 0x00080000; +constexpr std::uint32_t tfTwoAsset = 0x00100000; +constexpr std::uint32_t tfOneAssetLPToken = 0x00200000; +constexpr std::uint32_t tfLimitLPToken = 0x00400000; +constexpr std::uint32_t tfTwoAssetIfEmpty = 0x00800000; constexpr std::uint32_t tfWithdrawSubTx = tfLPToken | tfSingleAsset | tfTwoAsset | tfOneAssetLPToken | tfLimitLPToken | tfWithdrawAll | tfOneAssetWithdrawAll; @@ -189,8 +190,9 @@ constexpr std::uint32_t tfWithdrawMask = ~(tfUniversal | tfWithdrawSubTx); constexpr std::uint32_t tfDepositMask = ~(tfUniversal | tfDepositSubTx); // BridgeModify flags: -constexpr std::uint32_t tfClearAccountCreateAmount = 0x00010000; -constexpr std::uint32_t tfBridgeModifyMask = ~(tfUniversal | tfClearAccountCreateAmount); +constexpr std::uint32_t tfClearAccountCreateAmount = 0x00010000; +constexpr std::uint32_t tfBridgeModifyMask = + ~(tfUniversal | tfClearAccountCreateAmount); // clang-format on From cae9b6262871c0f5cf834a8b828a6273e155d930 Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Thu, 27 Jun 2024 16:37:20 -0700 Subject: [PATCH 13/26] [FOLD] Extend testNFTokenModify unit test --- src/test/app/NFToken_test.cpp | 224 ++++++++++++++++++++++------------ 1 file changed, 146 insertions(+), 78 deletions(-) diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index c70c765350b..e4bd1a7b85b 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -7751,43 +7751,43 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite using namespace test::jtx; - Account const minter{"minter"}; + Account const issuer{"issuer"}; Account const alice("alice"); Account const bob("bob"); - bool modifyEnabled = features[featureDynamicNFT]; + bool const modifyEnabled = features[featureDynamicNFT]; { // Mint with tfMutable Env env{*this, features}; - env.fund(XRP(10000), minter); + env.fund(XRP(10000), issuer); env.close(); auto const expectedTer = modifyEnabled ? TER{tesSUCCESS} : TER{temINVALID_FLAG}; - env(token::mint(minter, 0u), txflags(tfMutable), ter(expectedTer)); + env(token::mint(issuer, 0u), txflags(tfMutable), ter(expectedTer)); env.close(); } { Env env{*this, features}; - env.fund(XRP(10000), minter); + env.fund(XRP(10000), issuer); env.close(); // Modify a nftoken - uint256 const nftId{token::getNextID(env, minter, 0u, tfMutable)}; + uint256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)}; if (modifyEnabled) { - env(token::mint(minter, 0u), txflags(tfMutable)); + env(token::mint(issuer, 0u), txflags(tfMutable)); env.close(); - BEAST_EXPECT(ownerCount(env, minter) == 1); - env(token::modify(minter, nftId)); - BEAST_EXPECT(ownerCount(env, minter) == 1); + BEAST_EXPECT(ownerCount(env, issuer) == 1); + env(token::modify(issuer, nftId)); + BEAST_EXPECT(ownerCount(env, issuer) == 1); } else { - env(token::mint(minter, 0u)); + env(token::mint(issuer, 0u)); env.close(); - env(token::modify(minter, nftId), ter(temDISABLED)); + env(token::modify(issuer, nftId), ter(temDISABLED)); env.close(); } } @@ -7796,66 +7796,90 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite { Env env{*this, features}; - env.fund(XRP(10000), minter); + env.fund(XRP(10000), issuer); env.close(); - uint256 const nftId{token::getNextID(env, minter, 0u, tfMutable)}; - env(token::mint(minter, 0u), txflags(tfMutable)); + uint256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)}; + env(token::mint(issuer, 0u), txflags(tfMutable)); + env.close(); + + // Set a negative fee. Exercises invalid preflight1. + env(token::modify(issuer, nftId), + fee(STAmount(10ull, true)), + ter(temBAD_FEE)); env.close(); // Invalid Owner - env(token::modify(minter, nftId), - token::owner(minter), + env(token::modify(issuer, nftId), + token::owner(issuer), ter(temMALFORMED)); env.close(); // Invalid URI length = 0 - env(token::modify(minter, nftId), + env(token::modify(issuer, nftId), token::uri(""), ter(temMALFORMED)); env.close(); // Invalid URI length > 256 - env(token::modify(minter, nftId), + env(token::modify(issuer, nftId), token::uri(std::string(maxTokenURILength + 1, 'q')), ter(temMALFORMED)); env.close(); } { Env env{*this, features}; - env.fund(XRP(10000), minter, alice); + env.fund(XRP(10000), issuer, alice, bob); env.close(); - uint256 const nftId_not_exists{ - token::getNextID(env, minter, 0u, tfMutable)}; - env.close(); + { + // NFToken not exists + uint256 const nftIDNotExists{ + token::getNextID(env, issuer, 0u, tfMutable)}; + env.close(); - // NFToken not exists - env(token::modify(minter, nftId_not_exists), ter(tecNO_ENTRY)); - env.close(); + env(token::modify(issuer, nftIDNotExists), ter(tecNO_ENTRY)); + env.close(); + } + { + // Invalid NFToken flag + uint256 const nftIDNotModifiable{ + token::getNextID(env, issuer, 0u)}; + env(token::mint(issuer, 0u)); + env.close(); - uint256 const nftId_not_modifiable{ - token::getNextID(env, minter, 0u)}; - env(token::mint(minter, 0u)); - env.close(); + env(token::modify(issuer, nftIDNotModifiable), + ter(tecNO_PERMISSION)); + env.close(); + } + { + // Unauthorized account + uint256 const nftId{ + token::getNextID(env, issuer, 0u, tfMutable)}; + env(token::mint(issuer, 0u), txflags(tfMutable)); + env.close(); - // Invalid NFToken flag - env(token::modify(minter, nftId_not_modifiable), - ter(tecNO_PERMISSION)); - env.close(); + env(token::modify(bob, nftId), + token::owner(issuer), + ter(tecNO_PERMISSION)); + env.close(); - // Invalid NFTokenMinter - env(token::modify(alice, nftId_not_modifiable), - token::owner(minter), - ter(tecNO_PERMISSION)); - env.close(); + env(token::setMinter(issuer, alice)); + env.close(); + + env(token::modify(bob, nftId), + token::owner(issuer), + ter(tecNO_PERMISSION)); + env.close(); + } } { Env env{*this, features}; - env.fund(XRP(10000), minter, alice, bob); + env.fund(XRP(10000), issuer, alice, bob); env.close(); - auto accountNFTs = [&](Env& env, Account const& acct) { + // lambda that returns the JSON form of NFTokens held by acct + auto accountNFTs = [&env](Account const& acct) { Json::Value params; params[jss::account] = acct.human(); params[jss::type] = "state"; @@ -7864,82 +7888,126 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite return response[jss::result][jss::account_nfts]; }; - uint256 const nftId{token::getNextID(env, minter, 0u, tfMutable)}; + // lambda that checks for the expected URI value of an NFToken + auto checkURI = [&accountNFTs, this]( + Account const& acct, + char const* uri, + int line) { + auto const nfts = accountNFTs(acct); + if (nfts.size() == 1) + pass(); + else + { + std::ostringstream text; + text << "checkURI: unexpected NFT count on line " << line; + fail(text.str(), __FILE__, line); + return; + } + + if (uri == nullptr) + { + if (!nfts[0u].isMember(sfURI.jsonName)) + pass(); + else + { + std::ostringstream text; + text << "checkURI: unexpected URI present on line " + << line; + fail(text.str(), __FILE__, line); + } + return; + } + + if (nfts[0u][sfURI.jsonName] == strHex(std::string(uri))) + pass(); + else + { + std::ostringstream text; + text << "checkURI: unexpected URI contents on line " + << line; + fail(text.str(), __FILE__, line); + } + }; + + uint256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)}; env.close(); - env(token::mint(minter, 0u), txflags(tfMutable), token::uri("uri")); + env(token::mint(issuer, 0u), txflags(tfMutable), token::uri("uri")); env.close(); - { - auto nfts = accountNFTs(env, minter); - BEAST_EXPECT(nfts.size() == 1); - BEAST_EXPECT( - nfts[0u][sfURI.jsonName] == strHex(std::string("uri"))); - } + checkURI(issuer, "uri", __LINE__); // set URI Field - env(token::modify(minter, nftId), token::uri("new_uri")); + env(token::modify(issuer, nftId), token::uri("new_uri")); env.close(); - { - auto nfts = accountNFTs(env, minter); - BEAST_EXPECT(nfts.size() == 1); - BEAST_EXPECT( - nfts[0u][sfURI.jsonName] == strHex(std::string("new_uri"))); - } + checkURI(issuer, "new_uri", __LINE__); + // unset URI Field - env(token::modify(minter, nftId)); + env(token::modify(issuer, nftId)); env.close(); - { - auto nfts = accountNFTs(env, minter); - BEAST_EXPECT(nfts.size() == 1); - BEAST_EXPECT(!nfts[0u].isMember(sfURI.jsonName)); - } + checkURI(issuer, nullptr, __LINE__); + // set URI Field - env(token::modify(minter, nftId), token::uri("uri")); + env(token::modify(issuer, nftId), token::uri("uri")); env.close(); - { - auto nfts = accountNFTs(env, minter); - BEAST_EXPECT(nfts.size() == 1); - BEAST_EXPECT( - nfts[0u][sfURI.jsonName] == strHex(std::string("uri"))); - } + checkURI(issuer, "uri", __LINE__); // Account != Owner uint256 const offerID = - keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftId, XRP(0)), + keylet::nftoffer(issuer, env.seq(issuer)).key; + env(token::createOffer(issuer, nftId, XRP(0)), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(alice, offerID)); env.close(); + BEAST_EXPECT(ownerCount(env, issuer) == 0); + BEAST_EXPECT(ownerCount(env, alice) == 1); + checkURI(alice, "uri", __LINE__); - BEAST_EXPECT(ownerCount(env, minter) == 0); + // Modify by owner fails. + env(token::modify(alice, nftId), + token::uri("new_uri"), + ter(tecNO_PERMISSION)); + env.close(); + BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, alice) == 1); - env(token::modify(minter, nftId), + checkURI(alice, "uri", __LINE__); + + env(token::modify(issuer, nftId), token::owner(alice), token::uri("new_uri")); env.close(); - BEAST_EXPECT(ownerCount(env, minter) == 0); + BEAST_EXPECT(ownerCount(env, issuer) == 0); BEAST_EXPECT(ownerCount(env, alice) == 1); + checkURI(alice, "new_uri", __LINE__); - env(token::modify(minter, nftId), token::owner(alice)); + env(token::modify(issuer, nftId), token::owner(alice)); env.close(); + checkURI(alice, nullptr, __LINE__); - env(token::modify(minter, nftId), + env(token::modify(issuer, nftId), token::owner(alice), token::uri("uri")); env.close(); + checkURI(alice, "uri", __LINE__); - // Modify by Issuer - env(token::setMinter(minter, bob)); + // Modify by authorized minter + env(token::setMinter(issuer, bob)); env.close(); env(token::modify(bob, nftId), token::owner(alice), token::uri("new_uri")); + env.close(); + checkURI(alice, "new_uri", __LINE__); + env(token::modify(bob, nftId), token::owner(alice)); + env.close(); + checkURI(alice, nullptr, __LINE__); + env(token::modify(bob, nftId), token::owner(alice), token::uri("uri")); env.close(); + checkURI(alice, "uri", __LINE__); } } From 23ecb996c389dc26cd93ddeffbddd5548aea302e Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Thu, 27 Jun 2024 16:51:18 -0700 Subject: [PATCH 14/26] [FOLD] Avoid NFTPage coalescing and splitting when URI changes --- src/xrpld/app/tx/detail/NFTokenModify.cpp | 45 +++++++---------------- src/xrpld/app/tx/detail/NFTokenUtils.cpp | 40 +++++++++++++------- src/xrpld/app/tx/detail/NFTokenUtils.h | 14 +++---- 3 files changed, 46 insertions(+), 53 deletions(-) diff --git a/src/xrpld/app/tx/detail/NFTokenModify.cpp b/src/xrpld/app/tx/detail/NFTokenModify.cpp index 78ed0da0c9d..fe0247d0d63 100644 --- a/src/xrpld/app/tx/detail/NFTokenModify.cpp +++ b/src/xrpld/app/tx/detail/NFTokenModify.cpp @@ -34,7 +34,7 @@ NFTokenModify::preflight(PreflightContext const& ctx) !ctx.rules.enabled(featureDynamicNFT)) return temDISABLED; - if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) + if (NotTEC const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; if (auto owner = ctx.tx[~sfOwner]; owner == ctx.tx[sfAccount]) @@ -52,8 +52,8 @@ NFTokenModify::preflight(PreflightContext const& ctx) TER NFTokenModify::preclaim(PreclaimContext const& ctx) { - auto const account = ctx.tx[sfAccount]; - auto const owner = + AccountID const account = ctx.tx[sfAccount]; + AccountID const owner = ctx.tx[ctx.tx.isFieldPresent(sfOwner) ? sfOwner : sfAccount]; if (!nft::findToken(ctx.view, owner, ctx.tx[sfNFTokenID])) @@ -64,14 +64,14 @@ NFTokenModify::preclaim(PreclaimContext const& ctx) return tecNO_PERMISSION; // Verify permissions for the issuer - if (auto const issuer = nft::getIssuer(ctx.tx[sfNFTokenID]); + if (AccountID const issuer = nft::getIssuer(ctx.tx[sfNFTokenID]); issuer != account) { - if (auto const sle = ctx.view.read(keylet::account(issuer)); sle) - { - if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account) - return tecNO_PERMISSION; - } + if (auto const sle = ctx.view.read(keylet::account(issuer)); !sle) + return tecNO_PERMISSION; // Should not be possible + else if (auto const minter = (*sle)[~sfNFTokenMinter]; + minter != account) + return tecNO_PERMISSION; } return tesSUCCESS; @@ -80,30 +80,11 @@ NFTokenModify::preclaim(PreclaimContext const& ctx) TER NFTokenModify::doApply() { - auto const nftokenID = ctx_.tx[sfNFTokenID]; - auto const owner = + uint256 const nftokenID = ctx_.tx[sfNFTokenID]; + AccountID const owner = ctx_.tx[ctx_.tx.isFieldPresent(sfOwner) ? sfOwner : sfAccount]; - // Find the token and its page - auto tokenAndPage = nft::findTokenAndPage(view(), owner, nftokenID); - if (!tokenAndPage) - return tecINTERNAL; - - // Replace the URI if present in the transaction - if (auto const newURI = ctx_.tx[~sfURI]) - tokenAndPage->token.setFieldVL(sfURI, *newURI); - else - tokenAndPage->token.makeFieldAbsent(sfURI); - - // Apply the changes to the token - if (auto const ret = nft::updateToken( - view(), - owner, - std::move(tokenAndPage->token), - std::move(tokenAndPage->page)); - !isTesSuccess(ret)) - return ret; - - return tesSUCCESS; + return nft::changeTokenURI(view(), owner, nftokenID, ctx_.tx[~sfURI]); } + } // namespace ripple diff --git a/src/xrpld/app/tx/detail/NFTokenUtils.cpp b/src/xrpld/app/tx/detail/NFTokenUtils.cpp index 56bc571e290..4d14af669cc 100644 --- a/src/xrpld/app/tx/detail/NFTokenUtils.cpp +++ b/src/xrpld/app/tx/detail/NFTokenUtils.cpp @@ -34,7 +34,7 @@ namespace ripple { namespace nft { static std::shared_ptr -locatePage(ReadView const& view, AccountID owner, uint256 const& id) +locatePage(ReadView const& view, AccountID const& owner, uint256 const& id) { auto const first = keylet::nftpage(keylet::nftpage_min(owner), id); auto const last = keylet::nftpage_max(owner); @@ -48,7 +48,7 @@ locatePage(ReadView const& view, AccountID owner, uint256 const& id) } static std::shared_ptr -locatePage(ApplyView& view, AccountID owner, uint256 const& id) +locatePage(ApplyView& view, AccountID const& owner, uint256 const& id) { auto const first = keylet::nftpage(keylet::nftpage_min(owner), id); auto const last = keylet::nftpage_max(owner); @@ -239,23 +239,35 @@ compareTokens(uint256 const& a, uint256 const& b) } TER -updateToken( +changeTokenURI( ApplyView& view, AccountID const& owner, - STObject&& nft, - std::shared_ptr&& page) + uint256 const& nftokenID, + std::optional const& uri) { - // Remove the old token from the owner's directory - if (auto const ret = nft::removeToken( - view, owner, nft.getFieldH256(sfNFTokenID), std::move(page)); - !isTesSuccess(ret)) - return ret; + std::shared_ptr const page = locatePage(view, owner, nftokenID); + + // If the page couldn't be found, the given NFT isn't owned by this account + if (!page) + return tecNO_ENTRY; - // Insert the updated token into the owner's directory - if (auto const ret = nft::insertToken(view, owner, std::move(nft)); - !isTesSuccess(ret)) - return ret; + // Locate the NFT in the page + STArray& arr = page->peekFieldArray(sfNFTokens); + auto const nftIter = + std::find_if(arr.begin(), arr.end(), [&nftokenID](STObject const& obj) { + return (obj[sfNFTokenID] == nftokenID); + }); + + if (nftIter == arr.end()) + return tecNO_ENTRY; + + if (uri) + nftIter->setFieldVL(sfURI, *uri); + else if (nftIter->isFieldPresent(sfURI)) + nftIter->makeFieldAbsent(sfURI); + + view.update(page); return tesSUCCESS; } diff --git a/src/xrpld/app/tx/detail/NFTokenUtils.h b/src/xrpld/app/tx/detail/NFTokenUtils.h index 8eb06494661..2b063386605 100644 --- a/src/xrpld/app/tx/detail/NFTokenUtils.h +++ b/src/xrpld/app/tx/detail/NFTokenUtils.h @@ -98,6 +98,13 @@ deleteTokenOffer(ApplyView& view, std::shared_ptr const& offer); bool compareTokens(uint256 const& a, uint256 const& b); +TER +changeTokenURI( + ApplyView& view, + AccountID const& owner, + uint256 const& nftokenID, + std::optional const& uri); + /** Preflight checks shared by NFTokenCreateOffer and NFTokenMint */ NotTEC tokenOfferCreatePreflight( @@ -138,13 +145,6 @@ tokenOfferCreateApply( beast::Journal j, std::uint32_t txFlags = lsfSellNFToken); -TER -updateToken( - ApplyView& view, - AccountID const& owner, - STObject&& nft, - std::shared_ptr&& page); - } // namespace nft } // namespace ripple From 2eb7559019648f278fbc914b5d35ab854db27ff1 Mon Sep 17 00:00:00 2001 From: tequ Date: Sat, 29 Jun 2024 14:20:22 +0900 Subject: [PATCH 15/26] fix sorting testcase --- src/test/app/NFToken_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index e4bd1a7b85b..1ea43849911 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -8157,8 +8157,8 @@ BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDisallowIncoming, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOfixV1, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenRemint, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenReserve, tx, ripple, 2); -BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOModify, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOMintOffer, tx, ripple, 2); +BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOModify, tx, ripple, 2); BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAllFeatures, tx, ripple, 2); } // namespace ripple From 90aeef946e529b1cc9cb9cd57c695e605da93877 Mon Sep 17 00:00:00 2001 From: tequ Date: Fri, 12 Jul 2024 12:34:06 +0900 Subject: [PATCH 16/26] fix testcase name --- src/test/app/NFToken_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index 1ea43849911..dc987587fff 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -7747,7 +7747,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite void testNFTokenModify(FeatureBitset features) { - testcase("Test modify"); + testcase("Test NFTokenModify") using namespace test::jtx; From 4eea716ec0bb43476b27c544a5d826cb369438e4 Mon Sep 17 00:00:00 2001 From: tequ Date: Fri, 12 Jul 2024 12:40:07 +0900 Subject: [PATCH 17/26] chore: fix typo --- src/test/app/NFToken_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index dc987587fff..fe0564aba02 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -7747,7 +7747,7 @@ class NFTokenBaseUtil_test : public beast::unit_test::suite void testNFTokenModify(FeatureBitset features) { - testcase("Test NFTokenModify") + testcase("Test NFTokenModify"); using namespace test::jtx; From fc81bccfd7e5e50c517dd82cdc9adfa147721c5d Mon Sep 17 00:00:00 2001 From: tequ Date: Mon, 23 Sep 2024 18:19:01 +0900 Subject: [PATCH 18/26] clang-format --- src/libxrpl/protocol/Feature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libxrpl/protocol/Feature.cpp b/src/libxrpl/protocol/Feature.cpp index cd51600ded8..c658393d1cd 100644 --- a/src/libxrpl/protocol/Feature.cpp +++ b/src/libxrpl/protocol/Feature.cpp @@ -100,7 +100,7 @@ class FeatureCollections }; // Intermediate types to help with readability - template + template using feature_hashed_unique = boost::multi_index::hashed_unique< boost::multi_index::tag, boost::multi_index::member>; From 16541e22ae58f1cb604bf84b38c3a986ee777b18 Mon Sep 17 00:00:00 2001 From: tequ Date: Fri, 1 Nov 2024 16:22:49 +0900 Subject: [PATCH 19/26] fix bad merge --- include/xrpl/protocol/jss.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/xrpl/protocol/jss.h b/include/xrpl/protocol/jss.h index 21a12463bf9..bafdde4fbcc 100644 --- a/include/xrpl/protocol/jss.h +++ b/include/xrpl/protocol/jss.h @@ -82,10 +82,6 @@ JSS(MPToken); // ledger type. JSS(MPTokenIssuance); // ledger type. JSS(NetworkID); // field. JSS(NFTokenOffer); // ledger type. -JSS(NFTokenAcceptOffer); // transaction type. -JSS(NFTokenCancelOffer); // transaction type. -JSS(NFTokenCreateOffer); // transaction type. -JSS(NFTokenModify); // transaction type. JSS(NFTokenPage); // ledger type. JSS(LPTokenOut); // in: AMM Liquidity Provider deposit tokens JSS(LPTokenIn); // in: AMM Liquidity Provider withdraw tokens From a76809a3fd3402f97d87fc3f3944108aedd81a6d Mon Sep 17 00:00:00 2001 From: tequ Date: Fri, 1 Nov 2024 16:25:08 +0900 Subject: [PATCH 20/26] clang-format --- src/libxrpl/protocol/Feature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libxrpl/protocol/Feature.cpp b/src/libxrpl/protocol/Feature.cpp index a9366a6807d..3f6e760577a 100644 --- a/src/libxrpl/protocol/Feature.cpp +++ b/src/libxrpl/protocol/Feature.cpp @@ -100,7 +100,7 @@ class FeatureCollections }; // Intermediate types to help with readability - template + template using feature_hashed_unique = boost::multi_index::hashed_unique< boost::multi_index::tag, boost::multi_index::member>; From 29e7d4df07b873b50ce7dcfb872528c0fbcc2293 Mon Sep 17 00:00:00 2001 From: tequ Date: Thu, 7 Nov 2024 09:59:55 +0900 Subject: [PATCH 21/26] fix merge --- include/xrpl/protocol/detail/features.macro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xrpl/protocol/detail/features.macro b/include/xrpl/protocol/detail/features.macro index e3059529cb6..c4be17eeed7 100644 --- a/include/xrpl/protocol/detail/features.macro +++ b/include/xrpl/protocol/detail/features.macro @@ -29,12 +29,12 @@ // If you add an amendment here, then do not forget to increment `numFeatures` // in include/xrpl/protocol/Feature.h. +XRPL_FEATURE(DynamicNFT, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(Credentials, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(AMMClawback, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (AMMv1_2, Supported::yes, VoteBehavior::DefaultNo) // InvariantsV1_1 will be changes to Supported::yes when all the // invariants expected to be included under it are complete. -XRPL_FEATURE(DynamicNFT, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(MPTokensV1, Supported::yes, VoteBehavior::DefaultNo) XRPL_FEATURE(InvariantsV1_1, Supported::no, VoteBehavior::DefaultNo) XRPL_FIX (NFTokenPageLinks, Supported::yes, VoteBehavior::DefaultNo) From 71545340e0324d889dc5888594f479f7a0394288 Mon Sep 17 00:00:00 2001 From: tequ Date: Sun, 15 Dec 2024 17:35:38 +0900 Subject: [PATCH 22/26] Update src/xrpld/app/tx/detail/NFTokenModify.cpp Co-authored-by: Mayukha Vadari --- src/xrpld/app/tx/detail/NFTokenModify.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrpld/app/tx/detail/NFTokenModify.cpp b/src/xrpld/app/tx/detail/NFTokenModify.cpp index fe0247d0d63..3cce401e674 100644 --- a/src/xrpld/app/tx/detail/NFTokenModify.cpp +++ b/src/xrpld/app/tx/detail/NFTokenModify.cpp @@ -69,7 +69,7 @@ NFTokenModify::preclaim(PreclaimContext const& ctx) { if (auto const sle = ctx.view.read(keylet::account(issuer)); !sle) return tecNO_PERMISSION; // Should not be possible - else if (auto const minter = (*sle)[~sfNFTokenMinter]; + if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account) return tecNO_PERMISSION; } From 13156dddb4f5889664c7398bdcd4308a1ba651b0 Mon Sep 17 00:00:00 2001 From: tequ Date: Sun, 15 Dec 2024 17:41:11 +0900 Subject: [PATCH 23/26] Fix error handling that shoudn't be possible --- src/xrpld/app/tx/detail/NFTokenModify.cpp | 2 +- src/xrpld/app/tx/detail/NFTokenUtils.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xrpld/app/tx/detail/NFTokenModify.cpp b/src/xrpld/app/tx/detail/NFTokenModify.cpp index 3cce401e674..23a82f7f414 100644 --- a/src/xrpld/app/tx/detail/NFTokenModify.cpp +++ b/src/xrpld/app/tx/detail/NFTokenModify.cpp @@ -68,7 +68,7 @@ NFTokenModify::preclaim(PreclaimContext const& ctx) issuer != account) { if (auto const sle = ctx.view.read(keylet::account(issuer)); !sle) - return tecNO_PERMISSION; // Should not be possible + return tecINTERNAL; // LCOV_EXCL_LINE if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account) return tecNO_PERMISSION; diff --git a/src/xrpld/app/tx/detail/NFTokenUtils.cpp b/src/xrpld/app/tx/detail/NFTokenUtils.cpp index 6425e85f3ba..26f0d4111a2 100644 --- a/src/xrpld/app/tx/detail/NFTokenUtils.cpp +++ b/src/xrpld/app/tx/detail/NFTokenUtils.cpp @@ -252,7 +252,7 @@ changeTokenURI( // If the page couldn't be found, the given NFT isn't owned by this account if (!page) - return tecNO_ENTRY; + return tecINTERNAL; // LCOV_EXCL_LINE // Locate the NFT in the page STArray& arr = page->peekFieldArray(sfNFTokens); @@ -263,7 +263,7 @@ changeTokenURI( }); if (nftIter == arr.end()) - return tecNO_ENTRY; + return tecINTERNAL; // LCOV_EXCL_LINE if (uri) nftIter->setFieldVL(sfURI, *uri); From f6f8084e7782f0cc8d668cd22065b9849466279c Mon Sep 17 00:00:00 2001 From: tequ Date: Sun, 15 Dec 2024 17:43:29 +0900 Subject: [PATCH 24/26] clang-format --- src/xrpld/app/tx/detail/NFTokenModify.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/xrpld/app/tx/detail/NFTokenModify.cpp b/src/xrpld/app/tx/detail/NFTokenModify.cpp index 23a82f7f414..dc8b1330ae3 100644 --- a/src/xrpld/app/tx/detail/NFTokenModify.cpp +++ b/src/xrpld/app/tx/detail/NFTokenModify.cpp @@ -69,8 +69,7 @@ NFTokenModify::preclaim(PreclaimContext const& ctx) { if (auto const sle = ctx.view.read(keylet::account(issuer)); !sle) return tecINTERNAL; // LCOV_EXCL_LINE - if (auto const minter = (*sle)[~sfNFTokenMinter]; - minter != account) + if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account) return tecNO_PERMISSION; } From 7390b1db0f0233590c75f0aa647564d8f4ec8d82 Mon Sep 17 00:00:00 2001 From: tequ Date: Sun, 22 Dec 2024 15:32:51 +0900 Subject: [PATCH 25/26] fix build error --- src/xrpld/app/tx/detail/NFTokenModify.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xrpld/app/tx/detail/NFTokenModify.cpp b/src/xrpld/app/tx/detail/NFTokenModify.cpp index dc8b1330ae3..74ca1baef4f 100644 --- a/src/xrpld/app/tx/detail/NFTokenModify.cpp +++ b/src/xrpld/app/tx/detail/NFTokenModify.cpp @@ -67,7 +67,8 @@ NFTokenModify::preclaim(PreclaimContext const& ctx) if (AccountID const issuer = nft::getIssuer(ctx.tx[sfNFTokenID]); issuer != account) { - if (auto const sle = ctx.view.read(keylet::account(issuer)); !sle) + auto const sle = ctx.view.read(keylet::account(issuer)); + if (!sle) return tecINTERNAL; // LCOV_EXCL_LINE if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account) return tecNO_PERMISSION; From f7311ba1db36bfacc0e5e6201b5e2e27caea932a Mon Sep 17 00:00:00 2001 From: tequ Date: Mon, 23 Dec 2024 18:55:25 +0900 Subject: [PATCH 26/26] fix tt tag --- include/xrpl/protocol/detail/transactions.macro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xrpl/protocol/detail/transactions.macro b/include/xrpl/protocol/detail/transactions.macro index 8e4496d13c0..99e741036aa 100644 --- a/include/xrpl/protocol/detail/transactions.macro +++ b/include/xrpl/protocol/detail/transactions.macro @@ -448,7 +448,7 @@ TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete, ({ })) /** This transaction type modify a NFToken */ -TRANSACTION(ttNFTokenModify, 61, NFTokenModify, ({ +TRANSACTION(ttNFTOKEN_MODIFY, 61, NFTokenModify, ({ {sfNFTokenID, soeREQUIRED}, {sfOwner, soeOPTIONAL}, {sfURI, soeOPTIONAL},