diff --git a/include/xrpl/protocol/ConfidentialTransfer.h b/include/xrpl/protocol/ConfidentialTransfer.h index 35d31aa129..5b1bcbf606 100644 --- a/include/xrpl/protocol/ConfidentialTransfer.h +++ b/include/xrpl/protocol/ConfidentialTransfer.h @@ -29,12 +29,12 @@ namespace xrpl { */ struct ConfidentialRecipient { - /** @brief The recipient's ElGamal public key (size=xrpl::ecPubKeyLength). */ + /** @brief The recipient's ElGamal public key (size=xrpl::kEcPubKeyLength). */ Slice publicKey; /** * @brief The encrypted amount ciphertext - * (size=xrpl::ecGamalEncryptedTotalLength). + * (size=xrpl::kEcGamalEncryptedTotalLength). */ Slice encryptedAmount; }; @@ -148,10 +148,12 @@ getConvertBackContextHash( /** * @brief Parses an ElGamal ciphertext into two secp256k1 public key components. * - * Breaks a 66-byte encrypted amount (two 33-byte compressed EC points) into + * Breaks an encrypted amount (size=xrpl::kEcGamalEncryptedTotalLength, two + * compressed EC points of size=xrpl::kEcCiphertextComponentLength) into * a pair containing (C1, C2) for use in cryptographic operations. * - * @param buffer The 66-byte buffer containing the compressed ciphertext. + * @param buffer The buffer containing the compressed ciphertext + * (size=xrpl::kEcGamalEncryptedTotalLength). * @return The parsed pair (c1, c2) if successful, std::nullopt if the buffer is invalid. */ std::optional @@ -160,11 +162,13 @@ makeEcPair(Slice const& buffer); /** * @brief Serializes an EcPair into compressed form. * - * Converts an EcPair (C1, C2) back into a 66-byte buffer containing - * two 33-byte compressed EC points. + * Converts an EcPair (C1, C2) back into a buffer + * (size=xrpl::kEcGamalEncryptedTotalLength) containing two compressed EC + * points (size=xrpl::kEcCiphertextComponentLength each). * * @param pair The EcPair to serialize. - * @return The 66-byte buffer, or std::nullopt if serialization fails. + * @return The buffer (size=xrpl::kEcGamalEncryptedTotalLength), or std::nullopt + * if serialization fails. */ std::optional serializeEcPair(EcPair const& pair); @@ -184,7 +188,8 @@ isValidCiphertext(Slice const& buffer); * Can be used to validate both compressed public keys and Pedersen commitments. * Fails early if the prefix byte is not 0x02 or 0x03. * - * @param buffer The input buffer containing a compressed EC point (33 bytes). + * @param buffer The input buffer containing a compressed EC point + * (size=xrpl::kCompressedEcPointLength). * @return true if the point can be parsed successfully, false otherwise. */ bool @@ -196,8 +201,8 @@ isValidCompressedECPoint(Slice const& buffer); * Uses the additive homomorphic property of ElGamal encryption to compute * Enc(a + b) from Enc(a) and Enc(b) without decryption. * - * @param a The first ciphertext (66 bytes). - * @param b The second ciphertext (66 bytes). + * @param a The first ciphertext (size=xrpl::kEcGamalEncryptedTotalLength). + * @param b The second ciphertext (size=xrpl::kEcGamalEncryptedTotalLength). * @return The resulting ciphertext Enc(a + b), or std::nullopt on failure. */ std::optional @@ -209,8 +214,8 @@ homomorphicAdd(Slice const& a, Slice const& b); * Uses the additive homomorphic property of ElGamal encryption to compute * Enc(a - b) from Enc(a) and Enc(b) without decryption. * - * @param a The minuend ciphertext (66 bytes). - * @param b The subtrahend ciphertext (66 bytes). + * @param a The minuend ciphertext (size=xrpl::kEcGamalEncryptedTotalLength). + * @param b The subtrahend ciphertext (size=xrpl::kEcGamalEncryptedTotalLength). * @return The resulting ciphertext Enc(a - b), or std::nullopt on failure. */ std::optional @@ -223,9 +228,11 @@ homomorphicSubtract(Slice const& a, Slice const& b); * This is used when a public, deterministic scalar must perturb ciphertext * randomness while preserving ledger reproducibility. * - * @param ciphertext The ciphertext to re-randomize (66 bytes). + * @param ciphertext The ciphertext to re-randomize + * (size=xrpl::kEcGamalEncryptedTotalLength). * @param pubKeySlice The ElGamal public key matching the ciphertext recipient. - * @param randomness The scalar used as zero-encryption randomness (32 bytes). + * @param randomness The scalar used as zero-encryption randomness + * (size=xrpl::kEcScalarLength). * @return The re-randomized ciphertext, or std::nullopt on failure. */ std::optional @@ -238,10 +245,10 @@ rerandomizeCiphertext(Slice const& ciphertext, Slice const& pubKeySlice, Slice c * using the provided blinding factor r. * * @param amt The plaintext amount to encrypt. - * @param pubKeySlice The recipient's ElGamal public key (size=xrpl::ecPubKeyLength). + * @param pubKeySlice The recipient's ElGamal public key (size=xrpl::kEcPubKeyLength). * @param blindingFactor The randomness used as blinding factor r * (size=xrpl::ecBlindingFactorLength). - * @return The ciphertext (size=xrpl::ecGamalEncryptedTotalLength), or std::nullopt on failure. + * @return The ciphertext (size=xrpl::kEcGamalEncryptedTotalLength), or std::nullopt on failure. */ std::optional encryptAmount(uint64_t const amt, Slice const& pubKeySlice, Slice const& blindingFactor); @@ -252,10 +259,10 @@ encryptAmount(uint64_t const amt, Slice const& pubKeySlice, Slice const& blindin * Creates a deterministic encryption of zero that is unique to the account * and MPT issuance. Used to initialize confidential balance fields. * - * @param pubKeySlice The holder's ElGamal public key (size=xrpl::ecPubKeyLength). + * @param pubKeySlice The holder's ElGamal public key (size=xrpl::kEcPubKeyLength). * @param account The account ID of the token holder. * @param mptId The MPToken Issuance ID. - * @return The canonical zero ciphertext (size=xrpl::ecGamalEncryptedTotalLength), or std::nullopt + * @return The canonical zero ciphertext (size=xrpl::kEcGamalEncryptedTotalLength), or std::nullopt * on failure. */ std::optional @@ -267,7 +274,7 @@ encryptCanonicalZeroAmount(Slice const& pubKeySlice, AccountID const& account, M * Proves that the submitter knows the secret key corresponding to the * provided public key, without revealing the secret key itself. * - * @param pubKeySlice The ElGamal public key (size=xrpl::ecPubKeyLength). + * @param pubKeySlice The ElGamal public key (size=xrpl::kEcPubKeyLength). * @param proofSlice The Schnorr proof (size=xrpl::ecSchnorrProofLength). * @param contextHash The 256-bit context hash binding the proof. * @return tesSUCCESS if valid, or an error code otherwise. @@ -335,9 +342,9 @@ getConfidentialRecipientCount(bool hasAuditor) * * @param amount The revealed plaintext amount. * @param proof The zero-knowledge proof bytes (ecClawbackProofLength). - * @param pubKeySlice The issuer's ElGamal public key (ecPubKeyLength bytes). + * @param pubKeySlice The issuer's ElGamal public key (kEcPubKeyLength bytes). * @param ciphertext The issuer's encrypted balance on the holder's account - * (ecGamalEncryptedTotalLength bytes). + * (kEcGamalEncryptedTotalLength bytes). * @param contextHash The 256-bit context hash binding the proof. * @return tesSUCCESS if the proof is valid, or an error code otherwise. */ @@ -350,12 +357,14 @@ verifyClawbackProof( uint256 const& contextHash); /** - * @brief Generates a cryptographically secure 32-byte blinding factor. + * @brief Generates a cryptographically secure blinding factor + * (size=xrpl::kEcBlindingFactorLength). * * Produces random bytes suitable for use as an ElGamal blinding factor * or Pedersen commitment randomness. * - * @return A 32-byte buffer containing the random blinding factor. + * @return A buffer containing the random blinding factor + * (size=xrpl::kEcBlindingFactorLength). */ Buffer generateBlindingFactor(); diff --git a/include/xrpl/protocol/LedgerFormats.h b/include/xrpl/protocol/LedgerFormats.h index 72429e5988..e4f244e1c5 100644 --- a/include/xrpl/protocol/LedgerFormats.h +++ b/include/xrpl/protocol/LedgerFormats.h @@ -178,7 +178,7 @@ enum LedgerEntryType : std::uint16_t { LSF_FLAG(lsfMPTCanTrade, 0x00000010) \ LSF_FLAG(lsfMPTCanTransfer, 0x00000020) \ LSF_FLAG(lsfMPTCanClawback, 0x00000040) \ - LSF_FLAG(lsfMPTCanConfidentialAmount, 0x00000080)) \ + LSF_FLAG(lsfMPTCanHoldConfidentialBalance, 0x00000080)) \ \ LEDGER_OBJECT(MPTokenIssuanceMutable, \ LSF_FLAG(lsmfMPTCanEnableCanLock, 0x00000002) \ @@ -189,7 +189,7 @@ enum LedgerEntryType : std::uint16_t { LSF_FLAG(lsmfMPTCanEnableCanClawback, 0x00000040) \ LSF_FLAG(lsmfMPTCanMutateMetadata, 0x00010000) \ LSF_FLAG(lsmfMPTCanMutateTransferFee, 0x00020000) \ - LSF_FLAG(lsmfMPTCannotMutateCanConfidentialAmount, 0x00040000)) \ + LSF_FLAG(lsmfMPTCannotEnableCanHoldConfidentialBalance, 0x00040000)) \ \ LEDGER_OBJECT(MPToken, \ LSF_FLAG2(lsfMPTLocked, 0x00000001) \ diff --git a/include/xrpl/protocol/Protocol.h b/include/xrpl/protocol/Protocol.h index 80b1923094..7eac92e83c 100644 --- a/include/xrpl/protocol/Protocol.h +++ b/include/xrpl/protocol/Protocol.h @@ -4,6 +4,10 @@ #include #include +#include +#include + +#include #include namespace xrpl { @@ -307,46 +311,54 @@ constexpr std::size_t kPermissionMaxSize = 10; /** The maximum number of transactions that can be in a batch. */ constexpr std::size_t kMaxBatchTxCount = 8; -/** Length of one component of EC ElGamal ciphertext */ -constexpr std::size_t kEcGamalEncryptedLength = 33; - -/** EC ElGamal ciphertext length: two 33-byte components concatenated */ -constexpr std::size_t kEcGamalEncryptedTotalLength = kEcGamalEncryptedLength * 2; +/** Length of a secp256k1 scalar in bytes. */ +constexpr std::size_t kEcScalarLength = kMPT_SCALAR_SIZE; /** Length of EC point (compressed) */ constexpr std::size_t kCompressedEcPointLength = 33; +/** Length of one compressed EC point component in an EC ElGamal ciphertext. */ +constexpr std::size_t kEcCiphertextComponentLength = kMPT_ELGAMAL_CIPHER_SIZE; + +/** EC ElGamal ciphertext length: two compressed EC points concatenated. */ +constexpr std::size_t kEcGamalEncryptedTotalLength = kMPT_ELGAMAL_TOTAL_SIZE; + /** Length of EC public key (compressed) */ -constexpr std::size_t kEcPubKeyLength = kCompressedEcPointLength; +constexpr std::size_t kEcPubKeyLength = kMPT_PUBKEY_SIZE; /** Length of EC private key in bytes */ -constexpr std::size_t kEcPrivKeyLength = 32; +constexpr std::size_t kEcPrivKeyLength = kMPT_PRIVKEY_SIZE; /** Length of the EC blinding factor in bytes */ -constexpr std::size_t kEcBlindingFactorLength = 32; +constexpr std::size_t kEcBlindingFactorLength = kMPT_BLINDING_FACTOR_SIZE; /** Length of Schnorr ZKProof for public key registration (compact form) in bytes */ -constexpr std::size_t kEcSchnorrProofLength = 64; +constexpr std::size_t kEcSchnorrProofLength = kMPT_SCHNORR_PROOF_SIZE; /** Length of Pedersen Commitment (compressed) */ -constexpr std::size_t kEcPedersenCommitmentLength = kCompressedEcPointLength; +constexpr std::size_t kEcPedersenCommitmentLength = kMPT_PEDERSEN_COMMIT_SIZE; /** Length of single bulletproof (range proof for 1 commitment) in bytes */ -constexpr std::size_t kEcSingleBulletproofLength = 688; +constexpr std::size_t kEcSingleBulletproofLength = kMPT_SINGLE_BULLETPROOF_SIZE; /** Length of double bulletproof (range proof for 2 commitments) in bytes */ -constexpr std::size_t kEcDoubleBulletproofLength = 754; +constexpr std::size_t kEcDoubleBulletproofLength = kMPT_DOUBLE_BULLETPROOF_SIZE; -/** Length of the ZKProof for ConfidentialMPTSend. - * 192 bytes compact sigma proof + 754 bytes double bulletproof. */ -constexpr std::size_t kEcSendProofLength = 946; +/** Length of the compact sigma proof component for ConfidentialMPTSend. */ +constexpr std::size_t kEcSendSigmaProofLength = SECP256K1_COMPACT_STANDARD_PROOF_SIZE; -/** Length of the ZKProof for ConfidentialMPTConvertBack. - * 128 bytes compact sigma proof + 688 bytes single bulletproof. */ -constexpr std::size_t kEcConvertBackProofLength = 816; +/** 192 bytes compact sigma proof + 754 bytes double bulletproof. */ +constexpr std::size_t kEcSendProofLength = kEcSendSigmaProofLength + kEcDoubleBulletproofLength; + +/** Length of the compact sigma proof component for ConfidentialMPTConvertBack. */ +constexpr std::size_t kEcConvertBackSigmaProofLength = SECP256K1_COMPACT_CONVERTBACK_PROOF_SIZE; + +/** 128 bytes compact sigma proof + 688 bytes single bulletproof. */ +constexpr std::size_t kEcConvertBackProofLength = + kEcConvertBackSigmaProofLength + kEcSingleBulletproofLength; /** Length of the ZKProof for ConfidentialMPTClawback. */ -constexpr std::size_t kEcClawbackProofLength = 64; +constexpr std::size_t kEcClawbackProofLength = SECP256K1_COMPACT_CLAWBACK_PROOF_SIZE; /** Extra base fee multiplier charged to confidential MPT transactions. */ constexpr std::uint32_t kConfidentialFeeMultiplier = 9; diff --git a/include/xrpl/protocol/TxFlags.h b/include/xrpl/protocol/TxFlags.h index 8ce2d8f8b8..461afd24e7 100644 --- a/include/xrpl/protocol/TxFlags.h +++ b/include/xrpl/protocol/TxFlags.h @@ -141,7 +141,7 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal; TF_FLAG(tfMPTCanTrade, lsfMPTCanTrade) \ TF_FLAG(tfMPTCanTransfer, lsfMPTCanTransfer) \ TF_FLAG(tfMPTCanClawback, lsfMPTCanClawback) \ - TF_FLAG(tfMPTCanConfidentialAmount, lsfMPTCanConfidentialAmount), \ + TF_FLAG(tfMPTCanHoldConfidentialBalance, lsfMPTCanHoldConfidentialBalance), \ MASK_ADJ(0)) \ \ TRANSACTION(MPTokenAuthorize, \ @@ -350,12 +350,13 @@ inline constexpr FlagValue tmfMPTCanEnableCanTransfer = lsmfMPTCanEnableCanTrans inline constexpr FlagValue tmfMPTCanEnableCanClawback = lsmfMPTCanEnableCanClawback; inline constexpr FlagValue tmfMPTCanMutateMetadata = lsmfMPTCanMutateMetadata; inline constexpr FlagValue tmfMPTCanMutateTransferFee = lsmfMPTCanMutateTransferFee; -inline constexpr FlagValue tmfMPTCannotMutateCanConfidentialAmount = - lsmfMPTCannotMutateCanConfidentialAmount; -inline constexpr FlagValue tmfMPTokenIssuanceCreateMutableMask = ~( - tmfMPTCanEnableCanLock | tmfMPTCanEnableRequireAuth | tmfMPTCanEnableCanEscrow | - tmfMPTCanEnableCanTrade | tmfMPTCanEnableCanTransfer | tmfMPTCanEnableCanClawback | - tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee | tmfMPTCannotMutateCanConfidentialAmount); +inline constexpr FlagValue tmfMPTCannotEnableCanHoldConfidentialBalance = + lsmfMPTCannotEnableCanHoldConfidentialBalance; +inline constexpr FlagValue tmfMPTokenIssuanceCreateMutableMask = + ~(tmfMPTCanEnableCanLock | tmfMPTCanEnableRequireAuth | tmfMPTCanEnableCanEscrow | + tmfMPTCanEnableCanTrade | tmfMPTCanEnableCanTransfer | tmfMPTCanEnableCanClawback | + tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee | + tmfMPTCannotEnableCanHoldConfidentialBalance); // MPTokenIssuanceSet MutableFlags: // Enable mutable capability flags. These flags are one-way: once enabled, @@ -367,10 +368,10 @@ inline constexpr FlagValue tmfMPTSetCanEscrow = 0x00000004; inline constexpr FlagValue tmfMPTSetCanTrade = 0x00000008; inline constexpr FlagValue tmfMPTSetCanTransfer = 0x00000010; inline constexpr FlagValue tmfMPTSetCanClawback = 0x00000020; -inline constexpr FlagValue tmfMPTSetCanConfidentialAmount = 0x00000040; +inline constexpr FlagValue tmfMPTSetCanHoldConfidentialBalance = 0x00000040; inline constexpr FlagValue tmfMPTokenIssuanceSetMutableMask = ~(tmfMPTSetCanLock | tmfMPTSetRequireAuth | tmfMPTSetCanEscrow | tmfMPTSetCanTrade | - tmfMPTSetCanTransfer | tmfMPTSetCanClawback | tmfMPTSetCanConfidentialAmount); + tmfMPTSetCanTransfer | tmfMPTSetCanClawback | tmfMPTSetCanHoldConfidentialBalance); // 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. diff --git a/include/xrpl/tx/Transactor.h b/include/xrpl/tx/Transactor.h index 470571eb48..02fedfe970 100644 --- a/include/xrpl/tx/Transactor.h +++ b/include/xrpl/tx/Transactor.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -186,6 +187,10 @@ public: static XRPAmount calculateBaseFee(ReadView const& view, STTx const& tx); + // Returns the base fee plus extra base fee units, not scaled for load. + static XRPAmount + calculateBaseFee(ReadView const& view, STTx const& tx, std::uint32_t extraBaseFeeMultiplier); + /* Do NOT define an invokePreflight function in a derived class. Instead, define: diff --git a/include/xrpl/tx/invariants/MPTInvariant.h b/include/xrpl/tx/invariants/MPTInvariant.h index 92ce67c252..6585ac4f32 100644 --- a/include/xrpl/tx/invariants/MPTInvariant.h +++ b/include/xrpl/tx/invariants/MPTInvariant.h @@ -128,7 +128,7 @@ public: * Cannot delete if sfConfidentialBalanceInbox and sfConfidentialBalanceSpending exist * - Privacy flag consistency: * MPToken confidential balance fields can only be created or changed if - * lsfMPTCanConfidentialAmount is set on the issuance. + * lsfMPTCanHoldConfidentialBalance is set on the issuance. * - Encrypted field existence consistency: * If sfConfidentialBalanceSpending/sfConfidentialBalanceInbox exists, then * sfIssuerEncryptedBalance must also exist (and vice versa). diff --git a/src/libxrpl/protocol/ConfidentialTransfer.cpp b/src/libxrpl/protocol/ConfidentialTransfer.cpp index 15c0c1334f..0baff1e33a 100644 --- a/src/libxrpl/protocol/ConfidentialTransfer.cpp +++ b/src/libxrpl/protocol/ConfidentialTransfer.cpp @@ -44,6 +44,21 @@ toIssuanceId(uint192 const& issuance) return res; } +/** + * @brief Pack a ConfidentialRecipient (public key + ElGamal ciphertext) into the + * secp256k1-mpt participant struct. Callers MUST have already validated that + * r.publicKey.size() == kEcPubKeyLength and + * r.encryptedAmount.size() == kEcGamalEncryptedTotalLength; + */ +mpt_confidential_participant +toParticipant(ConfidentialRecipient const& r) +{ + mpt_confidential_participant p{}; + std::memcpy(p.pubkey, r.publicKey.data(), kEcPubKeyLength); + std::memcpy(p.ciphertext, r.encryptedAmount.data(), kEcGamalEncryptedTotalLength); + return p; +} + } // namespace uint256 @@ -107,15 +122,15 @@ getConvertBackContextHash( std::optional makeEcPair(Slice const& buffer) { - if (buffer.length() != 2 * kEcGamalEncryptedLength) + if (buffer.length() != 2 * kEcCiphertextComponentLength) return std::nullopt; // LCOV_EXCL_LINE auto parsePubKey = [](Slice const& slice, secp256k1_pubkey& out) { return secp256k1_ec_pubkey_parse(secp256k1Context(), &out, slice.data(), slice.length()); }; - Slice const s1{buffer.data(), kEcGamalEncryptedLength}; - Slice const s2{buffer.data() + kEcGamalEncryptedLength, kEcGamalEncryptedLength}; + Slice const s1{buffer.data(), kEcCiphertextComponentLength}; + Slice const s2{buffer.data() + kEcCiphertextComponentLength, kEcCiphertextComponentLength}; EcPair pair{}; if (parsePubKey(s1, pair.c1) != 1 || parsePubKey(s2, pair.c2) != 1) @@ -128,16 +143,16 @@ std::optional serializeEcPair(EcPair const& pair) { auto serializePubKey = [](secp256k1_pubkey const& pub, unsigned char* out) { - size_t outLen = kEcGamalEncryptedLength; // 33 bytes + size_t outLen = kEcCiphertextComponentLength; // 33 bytes auto const ret = secp256k1_ec_pubkey_serialize( secp256k1Context(), out, &outLen, &pub, SECP256K1_EC_COMPRESSED); - return ret == 1 && outLen == kEcGamalEncryptedLength; + return ret == 1 && outLen == kEcCiphertextComponentLength; }; Buffer buffer(kEcGamalEncryptedTotalLength); auto const ptr = buffer.data(); bool const res1 = serializePubKey(pair.c1, ptr); - bool const res2 = serializePubKey(pair.c2, ptr + kEcGamalEncryptedLength); + bool const res2 = serializePubKey(pair.c2, ptr + kEcCiphertextComponentLength); if (!res1 || !res2) return std::nullopt; @@ -288,16 +303,9 @@ verifyRevealedAmount( return tecINTERNAL; // LCOV_EXCL_LINE } - auto toParticipant = [](ConfidentialRecipient const& r) { - mpt_confidential_participant p; - std::memcpy(p.pubkey, r.publicKey.data(), kMPT_PUBKEY_SIZE); - std::memcpy(p.ciphertext, r.encryptedAmount.data(), kMPT_ELGAMAL_TOTAL_SIZE); - return p; - }; - auto const holderP = toParticipant(holder); auto const issuerP = toParticipant(issuer); - mpt_confidential_participant auditorP; + mpt_confidential_participant auditorP{}; mpt_confidential_participant const* auditorPtr = nullptr; if (auditor) { @@ -414,18 +422,11 @@ verifySendProof( return tecINTERNAL; // LCOV_EXCL_LINE } - auto makeParticipant = [](ConfidentialRecipient const& r) { - mpt_confidential_participant p; - std::memcpy(p.pubkey, r.publicKey.data(), kMPT_PUBKEY_SIZE); - std::memcpy(p.ciphertext, r.encryptedAmount.data(), kMPT_ELGAMAL_TOTAL_SIZE); - return p; - }; - std::vector participants; participants.reserve(recipientCount); - participants.push_back(makeParticipant(sender)); - participants.push_back(makeParticipant(destination)); - participants.push_back(makeParticipant(issuer)); + participants.push_back(toParticipant(sender)); + participants.push_back(toParticipant(destination)); + participants.push_back(toParticipant(issuer)); if (auditor) { if (auditor->publicKey.size() != kEcPubKeyLength || @@ -433,7 +434,7 @@ verifySendProof( { return tecINTERNAL; // LCOV_EXCL_LINE } - participants.push_back(makeParticipant(*auditor)); + participants.push_back(toParticipant(*auditor)); } if (participants.size() != recipientCount) return tecINTERNAL; // LCOV_EXCL_LINE diff --git a/src/libxrpl/tx/Transactor.cpp b/src/libxrpl/tx/Transactor.cpp index 2ff24d92b5..fe35750c91 100644 --- a/src/libxrpl/tx/Transactor.cpp +++ b/src/libxrpl/tx/Transactor.cpp @@ -356,6 +356,15 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx) return baseFee + (signerCount * baseFee); } +XRPAmount +Transactor::calculateBaseFee( + ReadView const& view, + STTx const& tx, + std::uint32_t extraBaseFeeMultiplier) +{ + return calculateBaseFee(view, tx) + view.fees().base * extraBaseFeeMultiplier; +} + // Returns the fee in fee units, not scaled for load. XRPAmount Transactor::calculateOwnerReserveFee(ReadView const& view, STTx const& tx) diff --git a/src/libxrpl/tx/invariants/MPTInvariant.cpp b/src/libxrpl/tx/invariants/MPTInvariant.cpp index c01e1c0e4b..87f1e148b1 100644 --- a/src/libxrpl/tx/invariants/MPTInvariant.cpp +++ b/src/libxrpl/tx/invariants/MPTInvariant.cpp @@ -31,7 +31,8 @@ namespace xrpl { -static constexpr auto kConfidentialMptTxTypes = std::to_array({ +namespace { +constexpr auto kConfidentialMptTxTypes = std::to_array({ ttCONFIDENTIAL_MPT_SEND, ttCONFIDENTIAL_MPT_CONVERT, ttCONFIDENTIAL_MPT_CONVERT_BACK, @@ -39,6 +40,29 @@ static constexpr auto kConfidentialMptTxTypes = std::to_array({ ttCONFIDENTIAL_MPT_CLAWBACK, }); +// Clamp to the cap (== INT64_MAX) before the signed conversion. Invariant +// tests can inject INT64_MAX + 1, which would result in undefined behavior +// under UBSan if converted directly. +std::int64_t +toSignedMPTAmount(std::uint64_t amount) +{ + return static_cast(std::min(amount, kMaxMpTokenAmount)); +} + +std::int64_t +addMPTAmountDelta(std::int64_t delta, std::uint64_t amount) +{ + return delta + toSignedMPTAmount(amount); +} + +std::int64_t +subtractMPTAmountDelta(std::int64_t delta, std::uint64_t amount) +{ + return delta - toSignedMPTAmount(amount); +} + +} // namespace + void ValidMPTIssuance::visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) { @@ -506,16 +530,12 @@ ValidConfidentialMPToken::visitEntry( return beast::kZero; }; - // Clamp to the cap (== INT64_MAX) before the signed conversion. We do INT64_MAX + 1 - // which the invariant tests inject, which would result in undefined behavior (under UBSan). - auto const toSignedAmount = [](std::uint64_t v) -> std::int64_t { - return static_cast(std::min(v, kMaxMpTokenAmount)); - }; - if (before && before->getType() == ltMPTOKEN) { uint192 const id = getMptID(before); - changes_[id].mptAmountDelta -= toSignedAmount(before->getFieldU64(sfMPTAmount)); + auto& change = changes_[id]; + change.mptAmountDelta = + subtractMPTAmountDelta(change.mptAmountDelta, before->getFieldU64(sfMPTAmount)); // Cannot delete MPToken with non-zero confidential state or non-zero public amount if (isDelete) @@ -533,7 +553,9 @@ ValidConfidentialMPToken::visitEntry( if (after && after->getType() == ltMPTOKEN) { uint192 const id = getMptID(after); - changes_[id].mptAmountDelta += toSignedAmount(after->getFieldU64(sfMPTAmount)); + auto& change = changes_[id]; + change.mptAmountDelta = + addMPTAmountDelta(change.mptAmountDelta, after->getFieldU64(sfMPTAmount)); // Encrypted field existence consistency bool const hasIssuerBalance = after->isFieldPresent(sfIssuerEncryptedBalance); @@ -568,12 +590,14 @@ ValidConfidentialMPToken::visitEntry( if (before && before->getType() == ltMPTOKEN_ISSUANCE) { uint192 const id = getMptID(before); + auto& change = changes_[id]; if (before->isFieldPresent(sfConfidentialOutstandingAmount)) { - changes_[id].coaDelta -= - toSignedAmount(before->getFieldU64(sfConfidentialOutstandingAmount)); + change.coaDelta = subtractMPTAmountDelta( + change.coaDelta, before->getFieldU64(sfConfidentialOutstandingAmount)); } - changes_[id].outstandingDelta -= toSignedAmount(before->getFieldU64(sfOutstandingAmount)); + change.outstandingDelta = subtractMPTAmountDelta( + change.outstandingDelta, before->getFieldU64(sfOutstandingAmount)); } if (after && after->getType() == ltMPTOKEN_ISSUANCE) @@ -586,9 +610,9 @@ ValidConfidentialMPToken::visitEntry( std::uint64_t const oa = after->getFieldU64(sfOutstandingAmount); if (hasCOA) - change.coaDelta += toSignedAmount(coa); + change.coaDelta = addMPTAmountDelta(change.coaDelta, coa); - change.outstandingDelta += toSignedAmount(oa); + change.outstandingDelta = addMPTAmountDelta(change.outstandingDelta, oa); change.issuance = after; // COA <= OutstandingAmount @@ -671,11 +695,11 @@ ValidConfidentialMPToken::finalize( // changing those fields requires the issuance privacy flag. if (checks.changesConfidentialFields) { - if (!issuance->isFlag(lsfMPTCanConfidentialAmount)) + if (!issuance->isFlag(lsfMPTCanHoldConfidentialBalance)) { JLOG(j.fatal()) << "Invariant failed: MPToken has encrypted " "fields but Issuance does not have " - "lsfMPTCanConfidentialAmount set"; + "lsfMPTCanHoldConfidentialBalance set"; return false; } } diff --git a/src/libxrpl/tx/transactors/token/ConfidentialMPTClawback.cpp b/src/libxrpl/tx/transactors/token/ConfidentialMPTClawback.cpp index 88f59bf2f2..ae568dbce7 100644 --- a/src/libxrpl/tx/transactors/token/ConfidentialMPTClawback.cpp +++ b/src/libxrpl/tx/transactors/token/ConfidentialMPTClawback.cpp @@ -50,10 +50,7 @@ ConfidentialMPTClawback::preflight(PreflightContext const& ctx) XRPAmount ConfidentialMPTClawback::calculateBaseFee(ReadView const& view, STTx const& tx) { - // Transactor::calculateBaseFee = baseFee + (signerCount * baseFee). - // We charge kConfidentialFeeMultiplier extra base fees so the total is - // 10 * baseFee + (signerCount * baseFee). - return Transactor::calculateBaseFee(view, tx) + view.fees().base * kConfidentialFeeMultiplier; + return Transactor::calculateBaseFee(view, tx, kConfidentialFeeMultiplier); } TER @@ -88,8 +85,8 @@ ConfidentialMPTClawback::preclaim(PreclaimContext const& ctx) return tecNO_PERMISSION; // Check if issuance allows confidential transfer - if (!sleIssuance->isFlag(lsfMPTCanConfidentialAmount)) - return tecNO_PERMISSION; // LCOV_EXCL_LINE + if (!sleIssuance->isFlag(lsfMPTCanHoldConfidentialBalance)) + return tecNO_PERMISSION; // Check holder's MPToken auto const sleHolderMPToken = ctx.view.read(keylet::mptoken(mptIssuanceID, holder)); @@ -98,11 +95,11 @@ ConfidentialMPTClawback::preclaim(PreclaimContext const& ctx) // Check if holder has confidential balances to claw back if (!sleHolderMPToken->isFieldPresent(sfIssuerEncryptedBalance)) - return tecNO_PERMISSION; // LCOV_EXCL_LINE + return tecNO_PERMISSION; // Check if Holder has ElGamal public Key if (!sleHolderMPToken->isFieldPresent(sfHolderEncryptionKey)) - return tecNO_PERMISSION; // LCOV_EXCL_LINE + return tecNO_PERMISSION; // Sanity check: claw amount can not exceed confidential outstanding amount // or total outstanding amount (prevents underflow in doApply) diff --git a/src/libxrpl/tx/transactors/token/ConfidentialMPTConvert.cpp b/src/libxrpl/tx/transactors/token/ConfidentialMPTConvert.cpp index 6370d82e00..4a87faa7f8 100644 --- a/src/libxrpl/tx/transactors/token/ConfidentialMPTConvert.cpp +++ b/src/libxrpl/tx/transactors/token/ConfidentialMPTConvert.cpp @@ -68,10 +68,7 @@ ConfidentialMPTConvert::preflight(PreflightContext const& ctx) XRPAmount ConfidentialMPTConvert::calculateBaseFee(ReadView const& view, STTx const& tx) { - // Transactor::calculateBaseFee = baseFee + (signerCount * baseFee). - // We charge kConfidentialFeeMultiplier extra base fees so the total is - // 10 * baseFee + (signerCount * baseFee). - return Transactor::calculateBaseFee(view, tx) + view.fees().base * kConfidentialFeeMultiplier; + return Transactor::calculateBaseFee(view, tx, kConfidentialFeeMultiplier); } TER @@ -86,7 +83,7 @@ ConfidentialMPTConvert::preclaim(PreclaimContext const& ctx) if (!sleIssuance) return tecOBJECT_NOT_FOUND; - if (!sleIssuance->isFlag(lsfMPTCanConfidentialAmount) || + if (!sleIssuance->isFlag(lsfMPTCanHoldConfidentialBalance) || !sleIssuance->isFieldPresent(sfIssuerEncryptionKey)) { return tecNO_PERMISSION; diff --git a/src/libxrpl/tx/transactors/token/ConfidentialMPTConvertBack.cpp b/src/libxrpl/tx/transactors/token/ConfidentialMPTConvertBack.cpp index 1754ec9c4e..b05474c851 100644 --- a/src/libxrpl/tx/transactors/token/ConfidentialMPTConvertBack.cpp +++ b/src/libxrpl/tx/transactors/token/ConfidentialMPTConvertBack.cpp @@ -52,10 +52,7 @@ ConfidentialMPTConvertBack::preflight(PreflightContext const& ctx) XRPAmount ConfidentialMPTConvertBack::calculateBaseFee(ReadView const& view, STTx const& tx) { - // Transactor::calculateBaseFee = baseFee + (signerCount * baseFee). - // We charge kConfidentialFeeMultiplier extra base fees so the total is - // 10 * baseFee + (signerCount * baseFee). - return Transactor::calculateBaseFee(view, tx) + view.fees().base * kConfidentialFeeMultiplier; + return Transactor::calculateBaseFee(view, tx, kConfidentialFeeMultiplier); } /** @@ -155,7 +152,7 @@ ConfidentialMPTConvertBack::preclaim(PreclaimContext const& ctx) if (!sleIssuance) return tecOBJECT_NOT_FOUND; - if (!sleIssuance->isFlag(lsfMPTCanConfidentialAmount) || + if (!sleIssuance->isFlag(lsfMPTCanHoldConfidentialBalance) || !sleIssuance->isFieldPresent(sfIssuerEncryptionKey)) return tecNO_PERMISSION; diff --git a/src/libxrpl/tx/transactors/token/ConfidentialMPTMergeInbox.cpp b/src/libxrpl/tx/transactors/token/ConfidentialMPTMergeInbox.cpp index 33c305dfb1..ab9529942b 100644 --- a/src/libxrpl/tx/transactors/token/ConfidentialMPTMergeInbox.cpp +++ b/src/libxrpl/tx/transactors/token/ConfidentialMPTMergeInbox.cpp @@ -36,10 +36,7 @@ ConfidentialMPTMergeInbox::preflight(PreflightContext const& ctx) XRPAmount ConfidentialMPTMergeInbox::calculateBaseFee(ReadView const& view, STTx const& tx) { - // Transactor::calculateBaseFee = baseFee + (signerCount * baseFee). - // We charge kConfidentialFeeMultiplier extra base fees so the total is - // 10 * baseFee + (signerCount * baseFee). - return Transactor::calculateBaseFee(view, tx) + view.fees().base * kConfidentialFeeMultiplier; + return Transactor::calculateBaseFee(view, tx, kConfidentialFeeMultiplier); } TER @@ -49,7 +46,7 @@ ConfidentialMPTMergeInbox::preclaim(PreclaimContext const& ctx) if (!sleIssuance) return tecOBJECT_NOT_FOUND; - if (!sleIssuance->isFlag(lsfMPTCanConfidentialAmount)) + if (!sleIssuance->isFlag(lsfMPTCanHoldConfidentialBalance)) return tecNO_PERMISSION; // already checked in preflight, but should also check that issuer on the diff --git a/src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp b/src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp index 0959293fee..bbe5745353 100644 --- a/src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp +++ b/src/libxrpl/tx/transactors/token/ConfidentialMPTSend.cpp @@ -93,13 +93,12 @@ ConfidentialMPTSend::preflight(PreflightContext const& ctx) XRPAmount ConfidentialMPTSend::calculateBaseFee(ReadView const& view, STTx const& tx) { - // Transactor::calculateBaseFee = baseFee + (signerCount * baseFee). - // We charge kConfidentialFeeMultiplier extra base fees so the total is - // 10 * baseFee + (signerCount * baseFee). - return Transactor::calculateBaseFee(view, tx) + view.fees().base * kConfidentialFeeMultiplier; + return Transactor::calculateBaseFee(view, tx, kConfidentialFeeMultiplier); } -TER +namespace detail { + +static TER verifySendProofs( PreclaimContext const& ctx, std::shared_ptr const& sleSenderMPToken, @@ -150,6 +149,8 @@ verifySendProofs( contextHash); } +} // namespace detail + TER ConfidentialMPTSend::preclaim(PreclaimContext const& ctx) { @@ -182,14 +183,14 @@ ConfidentialMPTSend::preclaim(PreclaimContext const& ctx) return tecNO_AUTH; // Check if issuance allows confidential transfer - if (!sleIssuance->isFlag(lsfMPTCanConfidentialAmount)) + if (!sleIssuance->isFlag(lsfMPTCanHoldConfidentialBalance)) return tecNO_PERMISSION; - // Sanity check: transfer rate must be 0 for confidential MPTs. - // This is unreachable since it is already enforced during MPTokenIssuanceCreate and - // MPTokenIssuanceSet. + // Sanity check: transfer fee must be 0 for confidential MPTs. This should + // be unreachable in valid ledger state because MPTokenIssuanceCreate and + // MPTokenIssuanceSet enforce it. if ((*sleIssuance)[~sfTransferFee].value_or(0) > 0) - return tecNO_PERMISSION; // LCOV_EXCL_LINE + return tecNO_PERMISSION; // Check if issuance has issuer ElGamal public key if (!sleIssuance->isFieldPresent(sfIssuerEncryptionKey)) @@ -268,7 +269,7 @@ ConfidentialMPTSend::preclaim(PreclaimContext const& ctx) if (!isTesSuccess(preauthErr)) return preauthErr; - return verifySendProofs(ctx, sleSenderMPToken, sleDestinationMPToken, sleIssuance); + return detail::verifySendProofs(ctx, sleSenderMPToken, sleDestinationMPToken, sleIssuance); } TER diff --git a/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp b/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp index 56cac8d3fe..0bd48277dd 100644 --- a/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp +++ b/src/libxrpl/tx/transactors/token/MPTokenIssuanceCreate.cpp @@ -37,13 +37,14 @@ MPTokenIssuanceCreate::checkExtraFeatures(PreflightContext const& ctx) if (ctx.tx.isFieldPresent(sfMutableFlags) && !ctx.rules.enabled(featureDynamicMPT)) return false; - if (ctx.tx.isFlag(tfMPTCanConfidentialAmount) && + if (ctx.tx.isFlag(tfMPTCanHoldConfidentialBalance) && !ctx.rules.enabled(featureConfidentialTransfer)) return false; - // can not set tmfMPTCannotMutateCanConfidentialAmount without featureConfidentialTransfer + // can not set tmfMPTCannotEnableCanHoldConfidentialBalance without featureConfidentialTransfer auto const mutableFlags = ctx.tx[~sfMutableFlags]; - return !mutableFlags || ((*mutableFlags & tmfMPTCannotMutateCanConfidentialAmount) == 0u) || + return !mutableFlags || + ((*mutableFlags & tmfMPTCannotEnableCanHoldConfidentialBalance) == 0u) || ctx.rules.enabled(featureConfidentialTransfer); } @@ -79,7 +80,7 @@ MPTokenIssuanceCreate::preflight(PreflightContext const& ctx) return temMALFORMED; // Confidential amounts are encrypted so transfer rate is disallowed. - if (fee > 0u && ctx.tx.isFlag(tfMPTCanConfidentialAmount)) + if (fee > 0u && ctx.tx.isFlag(tfMPTCanHoldConfidentialBalance)) return temBAD_TRANSFER_FEE; } diff --git a/src/libxrpl/tx/transactors/token/MPTokenIssuanceSet.cpp b/src/libxrpl/tx/transactors/token/MPTokenIssuanceSet.cpp index b17bfaeb67..1e1ffbc745 100644 --- a/src/libxrpl/tx/transactors/token/MPTokenIssuanceSet.cpp +++ b/src/libxrpl/tx/transactors/token/MPTokenIssuanceSet.cpp @@ -80,7 +80,7 @@ MPTokenIssuanceSet::preflight(PreflightContext const& ctx) auto const txFlags = ctx.tx.getFlags(); bool const enablePrivacy = - mutableFlags && (*mutableFlags & tmfMPTSetCanConfidentialAmount) != 0u; + mutableFlags && (*mutableFlags & tmfMPTSetCanHoldConfidentialBalance) != 0u; auto const hasDomain = ctx.tx.isFieldPresent(sfDomainID); auto const hasHolder = ctx.tx.isFieldPresent(sfHolder); @@ -218,7 +218,7 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx) auto const mutableFlags = ctx.tx[~sfMutableFlags]; // Whether the transaction is enabling confidential amounts. bool const enablesConfidentialAmount = - mutableFlags && (*mutableFlags & tmfMPTSetCanConfidentialAmount) != 0u; + mutableFlags && (*mutableFlags & tmfMPTSetCanHoldConfidentialBalance) != 0u; if (mutableFlags) { if (std::ranges::any_of(kMptMutabilityFlags, [mutableFlags, &isMutableFlag](auto const& f) { @@ -226,7 +226,8 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx) })) return tecNO_PERMISSION; - if (enablesConfidentialAmount && isMutableFlag(lsmfMPTCannotMutateCanConfidentialAmount)) + if (enablesConfidentialAmount && + isMutableFlag(lsmfMPTCannotEnableCanHoldConfidentialBalance)) return tecNO_PERMISSION; } @@ -244,7 +245,7 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx) // Cannot set a non-zero TransferFee on an issuance that has confidential // transfer enabled - if (fee > 0u && sleMptIssuance->isFlag(lsfMPTCanConfidentialAmount)) + if (fee > 0u && sleMptIssuance->isFlag(lsfMPTCanHoldConfidentialBalance)) return tecNO_PERMISSION; if (!isMutableFlag(lsmfMPTCanMutateTransferFee)) @@ -272,13 +273,13 @@ MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx) // Encryption keys can only be set if confidential amounts are already // enabled on the issuance OR if the transaction is enabling it if (ctx.tx.isFieldPresent(sfIssuerEncryptionKey) && - !sleMptIssuance->isFlag(lsfMPTCanConfidentialAmount) && !enablesConfidentialAmount) + !sleMptIssuance->isFlag(lsfMPTCanHoldConfidentialBalance) && !enablesConfidentialAmount) { return tecNO_PERMISSION; } if (ctx.tx.isFieldPresent(sfAuditorEncryptionKey) && - !sleMptIssuance->isFlag(lsfMPTCanConfidentialAmount) && !enablesConfidentialAmount) + !sleMptIssuance->isFlag(lsfMPTCanHoldConfidentialBalance) && !enablesConfidentialAmount) { return tecNO_PERMISSION; } @@ -336,8 +337,8 @@ MPTokenIssuanceSet::doApply() } } - if ((mutableFlags & tmfMPTSetCanConfidentialAmount) != 0u) - flagsOut |= lsfMPTCanConfidentialAmount; + if ((mutableFlags & tmfMPTSetCanHoldConfidentialBalance) != 0u) + flagsOut |= lsfMPTCanHoldConfidentialBalance; } if (flagsIn != flagsOut) diff --git a/src/test/app/ConfidentialTransferExtended_test.cpp b/src/test/app/ConfidentialTransferExtended_test.cpp index 5bd79d31e5..0aee7516c9 100644 --- a/src/test/app/ConfidentialTransferExtended_test.cpp +++ b/src/test/app/ConfidentialTransferExtended_test.cpp @@ -604,7 +604,7 @@ class ConfidentialTransferExtended_test : public ConfidentialTransferTestBase MPTTester mptAlice(env, alice, {.holders = {bob}}); mptAlice.create({ - .flags = kMptDexFlags | tfMPTCanClawback | tfMPTCanConfidentialAmount, + .flags = kMptDexFlags | tfMPTCanClawback | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.pay(alice, bob, 1'000); @@ -654,7 +654,7 @@ class ConfidentialTransferExtended_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -741,7 +741,7 @@ class ConfidentialTransferExtended_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.pay(alice, bob, 100); @@ -809,7 +809,7 @@ class ConfidentialTransferExtended_test : public ConfidentialTransferTestBase env, alice, {{.account = bob}, {.account = carol, .payAmount = 1000, .convertAmount = 50}}, - tfMPTCanTransfer | tfMPTCanConfidentialAmount}; + tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance}; auto& mptAlice = confEnv.mpt; // Set RequireDest on carol @@ -864,7 +864,7 @@ class ConfidentialTransferExtended_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, .holderCount = 0, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.pay(alice, bob, 100); @@ -1640,8 +1640,8 @@ class ConfidentialTransferExtended_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = - tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback | + tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -1755,7 +1755,7 @@ class ConfidentialTransferExtended_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.pay(alice, bob, 100); @@ -1817,7 +1817,7 @@ class ConfidentialTransferExtended_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -1885,7 +1885,7 @@ class ConfidentialTransferExtended_test : public ConfidentialTransferTestBase alice, {{.account = bob, .payAmount = 100, .convertAmount = 50}, {.account = carol, .payAmount = 100, .convertAmount = 100}}, - tfMPTCanTransfer | tfMPTCanClawback | tfMPTCanConfidentialAmount}; + tfMPTCanTransfer | tfMPTCanClawback | tfMPTCanHoldConfidentialBalance}; auto& mptAlice = confEnv.mpt; env.fund(XRP(10000), dave); env.close(); @@ -2295,7 +2295,7 @@ class ConfidentialTransferExtended_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount | tfMPTCanClawback, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance | tfMPTCanClawback, }); mptAlice.authorize({.account = bob}); mptAlice.pay(alice, bob, 200); @@ -2454,7 +2454,7 @@ class ConfidentialTransferExtended_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount | tfMPTCanClawback, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance | tfMPTCanClawback, }); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); diff --git a/src/test/app/ConfidentialTransfer_test.cpp b/src/test/app/ConfidentialTransfer_test.cpp index d3d86f3fd9..0f54e139ad 100644 --- a/src/test/app/ConfidentialTransfer_test.cpp +++ b/src/test/app/ConfidentialTransfer_test.cpp @@ -73,7 +73,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -118,7 +118,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -153,7 +153,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -216,7 +216,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -265,7 +265,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase MPTTester mptAlice(env, alice); mptAlice.create({ - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.generateKeyPair(alice); @@ -426,7 +426,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -475,7 +475,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -521,7 +521,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -590,7 +590,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.generateKeyPair(alice); @@ -616,7 +616,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.set({ .account = alice, - .mutableFlags = tmfMPTSetCanConfidentialAmount, + .mutableFlags = tmfMPTSetCanHoldConfidentialBalance, }); } @@ -637,14 +637,14 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.set({ .account = alice, - .mutableFlags = tmfMPTSetCanConfidentialAmount, + .mutableFlags = tmfMPTSetCanHoldConfidentialBalance, .issuerPubKey = mptAlice.getPubKey(alice), .auditorPubKey = mptAlice.getPubKey(auditor), }); - // Verify lsfMPTCanConfidentialAmount flag is set + // Verify lsfMPTCanHoldConfidentialBalance flag is set BEAST_EXPECT(mptAlice.checkFlags( - lsfMPTCanTransfer | lsfMPTCanLock | lsfMPTCanConfidentialAmount)); + lsfMPTCanTransfer | lsfMPTCanLock | lsfMPTCanHoldConfidentialBalance)); // Verify keys are persisted on the issuance auto const sle = env.le(keylet::mptIssuance(mptAlice.issuanceID())); @@ -695,7 +695,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -796,7 +796,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.generateKeyPair(alice); @@ -828,7 +828,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.generateKeyPair(alice); @@ -880,11 +880,11 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase Account const alice("alice"); MPTTester mptAlice(env, alice, {.holders = {}}); - // Create with tmfMPTCannotMutateCanConfidentialAmount + // Create with tmfMPTCannotEnableCanHoldConfidentialBalance mptAlice.create({ .ownerCount = 1, .flags = tfMPTCanTransfer | tfMPTCanLock, - .mutableFlags = tmfMPTCannotMutateCanConfidentialAmount, + .mutableFlags = tmfMPTCannotEnableCanHoldConfidentialBalance, }); mptAlice.generateKeyPair(alice); @@ -893,7 +893,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase // because the issuance cannot mutate canConfidentialAmount mptAlice.set({ .account = alice, - .mutableFlags = tmfMPTSetCanConfidentialAmount, + .mutableFlags = tmfMPTSetCanHoldConfidentialBalance, .issuerPubKey = mptAlice.getPubKey(alice), .err = tecNO_PERMISSION, }); @@ -908,7 +908,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.generateKeyPair(alice); @@ -939,7 +939,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase using namespace test::jtx; // MPTokenIssuanceCreate: cannot create with both TransferFee > 0 and - // tfMPTCanConfidentialAmount + // tfMPTCanHoldConfidentialBalance { Env env{*this, features}; Account const alice("alice"); @@ -947,14 +947,14 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .transferFee = 100, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, .err = temBAD_TRANSFER_FEE, }); - // transferFee being 0 is allowed, even with tfMPTCanConfidentialAmount + // transferFee being 0 is allowed, even with tfMPTCanHoldConfidentialBalance mptAlice.create({ .transferFee = 0, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, }); } @@ -973,7 +973,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.set({ .account = alice, - .mutableFlags = tmfMPTSetCanConfidentialAmount, + .mutableFlags = tmfMPTSetCanHoldConfidentialBalance, .transferFee = 100, .err = temBAD_TRANSFER_FEE, }); @@ -995,13 +995,13 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.set({ .account = alice, - .mutableFlags = tmfMPTSetCanConfidentialAmount, + .mutableFlags = tmfMPTSetCanHoldConfidentialBalance, .err = tecNO_PERMISSION, }); } // MPTokenIssuanceSet (preclaim): cannot set TransferFee > 0 on an - // issuance that already has lsfMPTCanConfidentialAmount + // issuance that already has lsfMPTCanHoldConfidentialBalance { Env env{*this, features}; Account const alice("alice"); @@ -1009,7 +1009,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, .mutableFlags = tmfMPTCanMutateTransferFee, }); @@ -1033,7 +1033,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase testcase("Convert preclaim"); using namespace test::jtx; - // tfMPTCanConfidentialAmount is not set on issuance + // tfMPTCanHoldConfidentialBalance is not set on issuance { Env env{*this, features}; Account const alice("alice"); @@ -1070,7 +1070,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1098,7 +1098,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1128,7 +1128,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.generateKeyPair(alice); @@ -1154,7 +1154,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1214,7 +1214,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1245,7 +1245,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1279,7 +1279,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1328,8 +1328,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = - tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth | + tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1383,7 +1383,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1422,8 +1422,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = - tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth | + tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1474,7 +1474,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1511,7 +1511,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1550,7 +1550,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase }); mptAlice.create({ - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1585,7 +1585,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1616,7 +1616,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1646,7 +1646,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1693,7 +1693,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.pay(alice, bob, 100); @@ -1726,7 +1726,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.pay(alice, bob, 100); @@ -1778,7 +1778,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1827,7 +1827,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1846,7 +1846,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase }); } - // tfMPTCanConfidentialAmount is not set on issuance + // tfMPTCanHoldConfidentialBalance is not set on issuance { Env env{*this, features}; Account const alice("alice"); @@ -1881,7 +1881,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.generateKeyPair(alice); @@ -1903,7 +1903,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1932,7 +1932,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -1985,8 +1985,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = - tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount | tfMPTRequireAuth, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance | + tfMPTRequireAuth, }); mptAlice.authorize({ @@ -2089,7 +2089,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}, {.account = carol, .payAmount = 50, .convertAmount = 20}}, - tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, auditor}; auto& mptAlice = confEnv.mpt; @@ -2162,7 +2162,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -2350,7 +2350,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -2425,8 +2425,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase // authorize bob, carol, dave (not eve) mptAlice.create({ - .flags = - tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth | + tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ .account = bob, @@ -2491,7 +2491,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); mptAlice.create({ - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ .account = bob, @@ -2750,7 +2750,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}, {.account = carol, .payAmount = 50, .convertAmount = 20}}, - tfMPTCanLock | tfMPTCanConfidentialAmount}; + tfMPTCanLock | tfMPTCanHoldConfidentialBalance}; auto& mptAlice = confEnv.mpt; // bob sends 10 to carol @@ -2762,6 +2762,40 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase }); } + // Confidential MPTs should not have a transfer fee. Force malformed + // ledger state to cover the defensive preclaim check. + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + Account const carol("carol"); + ConfidentialEnv confEnv{ + env, + alice, + {{.account = bob, .payAmount = 100, .convertAmount = 60}, + {.account = carol, .payAmount = 50, .convertAmount = 20}}}; + auto& mptAlice = confEnv.mpt; + + BEAST_EXPECT(env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal) { + auto const issuance = std::const_pointer_cast( + view.read(keylet::mptIssuance(mptAlice.issuanceID()))); + if (!issuance) + return false; + + issuance->setFieldU16(sfTransferFee, 1); + view.rawReplace(issuance); + return true; + })); + + mptAlice.send({ + .account = bob, + .dest = carol, + .amt = 10, + .proof = getTrivialSendProofHex(), + .err = tecNO_PERMISSION, + }); + } + // bad proof { Env env{*this, features}; @@ -2813,7 +2847,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -2984,7 +3018,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -3062,7 +3096,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -3099,7 +3133,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -3146,7 +3180,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -3180,7 +3214,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -3271,12 +3305,12 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase // to simulate a scenario where vault shares somehow have // confidential balances env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal) { - // Set lsfMPTCanConfidentialAmount on the share issuance + // Set lsfMPTCanHoldConfidentialBalance on the share issuance // so the invariant allows encrypted fields on the MPToken auto issuance = std::const_pointer_cast(view.read(keylet::mptIssuance(share))); if (!issuance) return false; - issuance->setFlag(lsfMPTCanConfidentialAmount); + issuance->setFlag(lsfMPTCanHoldConfidentialBalance); view.rawReplace(issuance); auto const k = keylet::mptoken(share, depositor.id()); @@ -3287,8 +3321,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase Buffer dummyCiphertext(kEcGamalEncryptedTotalLength); std::memset(dummyCiphertext.data(), 0, kEcGamalEncryptedTotalLength); dummyCiphertext.data()[0] = kEcCompressedPrefixEvenY; - dummyCiphertext.data()[kEcGamalEncryptedLength] = kEcCompressedPrefixEvenY; - dummyCiphertext.data()[kEcGamalEncryptedLength - 1] = 0x01; + dummyCiphertext.data()[kEcCiphertextComponentLength] = kEcCompressedPrefixEvenY; + dummyCiphertext.data()[kEcCiphertextComponentLength - 1] = 0x01; dummyCiphertext.data()[kEcGamalEncryptedTotalLength - 1] = 0x01; sle->setFieldVL(sfConfidentialBalanceSpending, dummyCiphertext); sle->setFieldVL(sfConfidentialBalanceInbox, dummyCiphertext); @@ -3363,7 +3397,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -3484,7 +3518,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 40}}, - tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, auditor}; auto& mptAlice = confEnv.mpt; @@ -3634,7 +3668,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -3654,7 +3688,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase }); } - // tfMPTCanConfidentialAmount is not set on issuance + // tfMPTCanHoldConfidentialBalance is not set on issuance { Env env{*this, features}; Account const alice("alice"); @@ -3690,7 +3724,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.generateKeyPair(alice); @@ -3714,7 +3748,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -3750,7 +3784,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -3801,8 +3835,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = - tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth | + tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -3933,7 +3967,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 50}}, - tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, auditor}; auto& mptAlice = confEnv.mpt; @@ -3970,8 +4004,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase MPTTester mptAlice(env, alice, {.holders = {bob, carol, dave}}); mptAlice.create({ - .flags = - tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback | + tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ .account = bob, @@ -4095,8 +4129,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase }); mptAlice.create({ - .flags = - tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback | + tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ .account = bob, @@ -4203,7 +4237,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}}, - tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback | tfMPTCanConfidentialAmount}; + tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback | + tfMPTCanHoldConfidentialBalance}; auto& mptAlice = confEnv.mpt; auto const privKey = mptAlice.getPrivKey(alice); @@ -4311,7 +4346,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -4396,7 +4431,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .flags = tfMPTCanTransfer | tfMPTCanClawback | tfMPTRequireAuth | - tfMPTCanConfidentialAmount, + tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ .account = bob, @@ -4469,7 +4504,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase MPTTester mptAlice(env, alice, {.holders = {bob}}); mptAlice.create({ - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ .account = bob, @@ -4492,7 +4527,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); mptAlice.create({ - .flags = tfMPTCanClawback | tfMPTCanConfidentialAmount, + .flags = tfMPTCanClawback | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ .account = bob, @@ -4514,7 +4549,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); mptAlice.create({ - .flags = tfMPTCanClawback | tfMPTCanConfidentialAmount, + .flags = tfMPTCanClawback | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ .account = bob, @@ -4539,7 +4574,87 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase // After setup, bob has confidential balance 60 in spending. std::uint32_t const setupFlags = tfMPTCanTransfer | tfMPTCanClawback | tfMPTRequireAuth | - tfMPTCanLock | tfMPTCanConfidentialAmount; + tfMPTCanLock | tfMPTCanHoldConfidentialBalance; + std::string const dummyClawbackProof(kEcClawbackProofLength * 2, '0'); + + auto removeMPTokenField = + [&](Env& env, MPTTester const& mpt, Account const& holder, SField const& field) { + BEAST_EXPECT(env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal) { + auto const sle = std::const_pointer_cast( + view.read(keylet::mptoken(mpt.issuanceID(), holder.id()))); + if (!sle) + return false; + + sle->makeFieldAbsent(field); + view.rawReplace(sle); + return true; + })); + }; + + // After global COA is drained to zero, a further confidential clawback + // fails because the amount exceeds the remaining confidential + // outstanding amount. + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + ConfidentialEnv confEnv{ + env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}}, setupFlags}; + auto& mptAlice = confEnv.mpt; + + mptAlice.confidentialClaw({ + .account = alice, + .holder = bob, + .amt = 60, + }); + + mptAlice.confidentialClaw({ + .account = alice, + .holder = bob, + .amt = 1, + .proof = dummyClawbackProof, + .err = tecINSUFFICIENT_FUNDS, + }); + } + + // Missing issuer encrypted balance should fail before proof + // verification. + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + ConfidentialEnv confEnv{ + env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}}, setupFlags}; + auto& mptAlice = confEnv.mpt; + + removeMPTokenField(env, mptAlice, bob, sfIssuerEncryptedBalance); + mptAlice.confidentialClaw({ + .account = alice, + .holder = bob, + .amt = 60, + .proof = dummyClawbackProof, + .err = tecNO_PERMISSION, + }); + } + + // Missing holder encryption key should fail before proof verification. + { + Env env{*this, features}; + Account const alice("alice"); + Account const bob("bob"); + ConfidentialEnv confEnv{ + env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}}, setupFlags}; + auto& mptAlice = confEnv.mpt; + + removeMPTokenField(env, mptAlice, bob, sfHolderEncryptionKey); + mptAlice.confidentialClaw({ + .account = alice, + .holder = bob, + .amt = 60, + .proof = dummyClawbackProof, + .err = tecNO_PERMISSION, + }); + } // lock should not block clawback. lock bob individually { @@ -4643,7 +4758,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); mptAlice.create({ - .flags = tfMPTCanTransfer | tfMPTCanClawback | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanClawback | tfMPTCanHoldConfidentialBalance, }); for (auto const& [acct, amt] : {std::pair{bob, 1000}, {carol, 2000}}) @@ -4896,7 +5011,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 50}}, - tfMPTCanTransfer | tfMPTCanConfidentialAmount}; + tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance}; env.fund(XRP(1'000), carol); ct.mpt.authorize({.account = carol}); @@ -4916,7 +5031,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); @@ -4952,7 +5067,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 50}}, - tfMPTCanTransfer | tfMPTCanClawback | tfMPTCanConfidentialAmount}; + tfMPTCanTransfer | tfMPTCanClawback | tfMPTCanHoldConfidentialBalance}; env.fund(XRP(1'000), carol); ct.mpt.authorize({.account = carol}); @@ -4968,10 +5083,10 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase void testMutatePrivacy(FeatureBitset features) { - testcase("mutate lsfMPTCanConfidentialAmount"); + testcase("mutate lsfMPTCanHoldConfidentialBalance"); using namespace test::jtx; - // can not create mpt issuance with tmfMPTCannotMutateCanConfidentialAmount + // can not create mpt issuance with tmfMPTCannotEnableCanHoldConfidentialBalance // when featureDynamicMPT is disabled { Env env{*this, features - featureDynamicMPT}; @@ -4981,12 +5096,12 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 0, - .mutableFlags = tmfMPTCannotMutateCanConfidentialAmount, + .mutableFlags = tmfMPTCannotEnableCanHoldConfidentialBalance, .err = temDISABLED, }); } - // can not create mpt issuance with tmfMPTCannotMutateCanConfidentialAmount when + // can not create mpt issuance with tmfMPTCannotEnableCanHoldConfidentialBalance when // featureConfidentialTransfer is disabled { Env env{*this, features - featureConfidentialTransfer}; @@ -4996,13 +5111,13 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 0, - .mutableFlags = tmfMPTCannotMutateCanConfidentialAmount, + .mutableFlags = tmfMPTCannotEnableCanHoldConfidentialBalance, .err = temDISABLED, }); } - // if lsmfMPTCannotMutateCanConfidentialAmount is set, can not set/clear - // lsfMPTCanConfidentialAmount + // if lsmfMPTCannotEnableCanHoldConfidentialBalance is set, can not set/clear + // lsfMPTCanHoldConfidentialBalance { Env env{*this, features}; Account const alice("alice"); @@ -5012,17 +5127,17 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, .flags = tfMPTCanTransfer, - .mutableFlags = tmfMPTCannotMutateCanConfidentialAmount, + .mutableFlags = tmfMPTCannotEnableCanHoldConfidentialBalance, }); mptAlice.set({ .account = alice, - .mutableFlags = tmfMPTSetCanConfidentialAmount, + .mutableFlags = tmfMPTSetCanHoldConfidentialBalance, .err = tecNO_PERMISSION, }); } - // Toggle lsfMPTCanConfidentialAmount + // Toggle lsfMPTCanHoldConfidentialBalance { Env env{*this, features}; Account const alice("alice"); @@ -5031,7 +5146,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, .mutableFlags = tmfMPTCanEnableCanLock, }); @@ -5080,18 +5195,18 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase } }; - // set lsfMPTCanConfidentialAmount, but no effect because lsfMPTCanConfidentialAmount - // was already set + // set lsfMPTCanHoldConfidentialBalance, but no effect because + // lsfMPTCanHoldConfidentialBalance was already set mptAlice.set({ .account = alice, - .mutableFlags = tmfMPTSetCanConfidentialAmount, + .mutableFlags = tmfMPTSetCanHoldConfidentialBalance, }); verifyToggle(tesSUCCESS, 10); - // set lsfMPTCanConfidentialAmount again + // set tmfMPTSetCanHoldConfidentialBalance again mptAlice.set({ .account = alice, - .mutableFlags = tmfMPTSetCanConfidentialAmount, + .mutableFlags = tmfMPTSetCanHoldConfidentialBalance, }); verifyToggle(tesSUCCESS, 30); } @@ -5104,11 +5219,11 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase Account const bob("bob"); MPTTester mptAlice(env, alice, {.holders = {bob}}); - // lsmfMPTCannotMutateCanConfidentialAmount is false by default, - // so that lsfMPTCanConfidentialAmount can be mutated + // lsmfMPTCannotEnableCanHoldConfidentialBalance is false by default, + // so that lsfMPTCanHoldConfidentialBalance can be mutated mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({ @@ -5123,11 +5238,11 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase // bob convert 50 to confidential mptAlice.convert({.account = bob, .amt = 50, .holderPubKey = mptAlice.getPubKey(bob)}); - // set lsfMPTCanConfidentialAmount should fail because of + // set lsfMPTCanHoldConfidentialBalance should fail because of // confidential outstanding balance mptAlice.set({ .account = alice, - .mutableFlags = tmfMPTSetCanConfidentialAmount, + .mutableFlags = tmfMPTSetCanHoldConfidentialBalance, .err = tecNO_PERMISSION, }); } @@ -6111,15 +6226,15 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase std::memset(badC1goodC2.data(), 0xFF, kEcGamalEncryptedTotalLength); badC1goodC2.data()[0] = kEcCompressedPrefixEvenY; std::memcpy( - badC1goodC2.data() + kEcGamalEncryptedLength, - tc.data() + kEcGamalEncryptedLength, - kEcGamalEncryptedLength); + badC1goodC2.data() + kEcCiphertextComponentLength, + tc.data() + kEcCiphertextComponentLength, + kEcCiphertextComponentLength); // C1 = valid trivial point, C2 = bad (0xFF...FF) Buffer goodC1badC2(kEcGamalEncryptedTotalLength); std::memset(goodC1badC2.data(), 0xFF, kEcGamalEncryptedTotalLength); - std::memcpy(goodC1badC2.data(), tc.data(), kEcGamalEncryptedLength); - goodC1badC2.data()[kEcGamalEncryptedLength] = kEcCompressedPrefixEvenY; + std::memcpy(goodC1badC2.data(), tc.data(), kEcCiphertextComponentLength); + goodC1badC2.data()[kEcCiphertextComponentLength] = kEcCompressedPrefixEvenY; // sender's encrypted amount — bad C1 mptAlice.send({ @@ -6215,8 +6330,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase Buffer wrongGroupCt(kEcGamalEncryptedTotalLength); wrongGroupCt.data()[0] = kEcCompressedPrefixEvenY; std::memcpy(wrongGroupCt.data() + 1, kP256GeneratorX, 32); - wrongGroupCt.data()[kEcGamalEncryptedLength] = kEcCompressedPrefixEvenY; - std::memcpy(wrongGroupCt.data() + kEcGamalEncryptedLength + 1, kP256GeneratorX, 32); + wrongGroupCt.data()[kEcCiphertextComponentLength] = kEcCompressedPrefixEvenY; + std::memcpy(wrongGroupCt.data() + kEcCiphertextComponentLength + 1, kP256GeneratorX, 32); // A 33-byte commitment using the same wrong-curve x-coordinate. Buffer wrongGroupCommitment(kEcPedersenCommitmentLength); @@ -6307,7 +6422,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.authorize({.account = carol}); @@ -6344,7 +6459,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase MPTTester mptAlice(env, alice, {.holders = {bob}}); mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); mptAlice.pay(alice, bob, 100); @@ -6440,7 +6555,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase alice, {{.account = bob, .payAmount = 100, .convertAmount = 50}, {.account = carol, .payAmount = 50, .convertAmount = 50}}, - tfMPTCanLock | tfMPTCanConfidentialAmount | tfMPTCanTransfer, + tfMPTCanLock | tfMPTCanHoldConfidentialBalance | tfMPTCanTransfer, auditor}; auto& mptAlice = confEnv.mpt; @@ -6538,7 +6653,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase [&](MPTTester& mpt, Account const& alice, Account const& bob, Account const& carol) { mpt.create({ .ownerCount = 1, - .flags = tfMPTCanLock | tfMPTCanConfidentialAmount | tfMPTCanTransfer | + .flags = tfMPTCanLock | tfMPTCanHoldConfidentialBalance | tfMPTCanTransfer | tfMPTCanClawback, }); mpt.authorize({.account = bob}); @@ -6559,7 +6674,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase setup(mptAlice, alice, bob, carol); auto const baseFee = env.current()->fees().base; - auto const expectedFee = baseFee * 10; + auto const expectedFee = baseFee * (kConfidentialFeeMultiplier + 1); // lambda function to submit confidential transaction and check fee charged to the // account @@ -6605,19 +6720,20 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase MPTTester mptAlice(env, alice, {.holders = {bob, carol}}); setup(mptAlice, alice, bob, carol); auto const baseFee = env.current()->fees().base; + auto const expectedFee = baseFee * (kConfidentialFeeMultiplier + 1); mptAlice.convert( {.account = bob, .amt = 1, .holderPubKey = mptAlice.getPubKey(bob), - .fee = baseFee * 10 - 1, + .fee = expectedFee - 1, .err = telINSUF_FEE_P}); mptAlice.mergeInbox({.account = bob, .fee = baseFee, .err = telINSUF_FEE_P}); mptAlice.send( {.account = bob, .dest = carol, .amt = 1, - .fee = baseFee * 9, + .fee = baseFee * kConfidentialFeeMultiplier, .err = telINSUF_FEE_P}); mptAlice.convertBack({.account = bob, .amt = 1, .fee = baseFee, .err = telINSUF_FEE_P}); mptAlice.confidentialClaw( @@ -6636,7 +6752,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase setup(mptAlice, alice, bob, carol); auto const baseFee = env.current()->fees().base; - auto const highFee = baseFee * 20; + auto const highFee = baseFee * (kConfidentialFeeMultiplier + 1) * 2; auto const bobBefore = env.balance(bob); mptAlice.convert( {.account = bob, @@ -7179,7 +7295,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase env, alice, {{.account = bob}, {.account = carol, .payAmount = 1000, .convertAmount = 50}}, - tfMPTCanLock | tfMPTCanConfidentialAmount | tfMPTCanTransfer | tfMPTCanClawback}; + tfMPTCanLock | tfMPTCanHoldConfidentialBalance | tfMPTCanTransfer | tfMPTCanClawback}; auto& mptAlice = confEnv.mpt; uint64_t const sendAmount = 10; @@ -7300,7 +7416,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase env, alice, {{.account = bob}, {.account = carol, .payAmount = 1000, .convertAmount = 50}}, - tfMPTCanTransfer | tfMPTCanConfidentialAmount}; + tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance}; auto& mptAlice = confEnv.mpt; uint64_t const sendAmount = 10; @@ -7398,7 +7514,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase env, alice, {{.account = bob}, {.account = carol, .payAmount = 1000, .convertAmount = 50}}, - tfMPTCanTransfer | tfMPTCanConfidentialAmount}; + tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance}; auto& mptAlice = confEnv.mpt; uint64_t const sendAmount = 10; @@ -7409,8 +7525,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase // swaps them: -P has the same x but opposite y. auto negateCiphertext = [](Buffer const& ct) -> Buffer { Buffer neg = ct; - neg.data()[0] ^= 0x01; // negate C1 - neg.data()[kEcGamalEncryptedLength] ^= 0x01; // negate C2 + neg.data()[0] ^= 0x01; // negate C1 + neg.data()[kEcCiphertextComponentLength] ^= 0x01; // negate C2 return neg; }; @@ -7503,7 +7619,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase alice, {{.account = bob, .payAmount = 1000, .convertAmount = 200}, {.account = carol, .payAmount = 1000, .convertAmount = 100}}, - tfMPTCanTransfer | tfMPTCanConfidentialAmount}; + tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance}; auto& mptAlice = confEnv.mpt; uint64_t const m1 = 10; @@ -7618,7 +7734,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase env, alice, {{.account = bob}, {.account = carol, .payAmount = 1000, .convertAmount = 50}}, - tfMPTCanTransfer | tfMPTCanConfidentialAmount}; + tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance}; auto& mptAlice = confEnv.mpt; uint64_t const sendAmount = 10; @@ -7628,8 +7744,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase // ciphertext (C1', C2). auto substituteC1 = [](Buffer const& target, Buffer const& source) -> Buffer { Buffer result = target; - // Copy C1 (first ecGamalEncryptedLength bytes) from source - std::memcpy(result.data(), source.data(), kEcGamalEncryptedLength); + // Copy C1 (the first ciphertext component) from source. + std::memcpy(result.data(), source.data(), kEcCiphertextComponentLength); return result; }; @@ -7707,7 +7823,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase env, alice, {{.account = bob}, {.account = carol, .payAmount = 1000, .convertAmount = 50}}, - tfMPTCanTransfer | tfMPTCanConfidentialAmount}; + tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance}; auto& mptAlice = confEnv.mpt; uint64_t const sendAmount = 10; @@ -7740,9 +7856,9 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase // C2 half: use a valid point so only C1 is the problem auto const& tc = getTrivialCiphertext(); std::memcpy( - zeroCiphertext.data() + kEcGamalEncryptedLength, - tc.data() + kEcGamalEncryptedLength, - kEcGamalEncryptedLength); + zeroCiphertext.data() + kEcCiphertextComponentLength, + tc.data() + kEcCiphertextComponentLength, + kEcCiphertextComponentLength); obj.setFieldVL(sfSenderEncryptedAmount, zeroCiphertext); // Re-serialize with the original (now-stale) signature @@ -7770,9 +7886,9 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase std::memset(zeroCiphertext.data(), 0, kEcGamalEncryptedTotalLength); auto const& tc = getTrivialCiphertext(); std::memcpy( - zeroCiphertext.data() + kEcGamalEncryptedLength, - tc.data() + kEcGamalEncryptedLength, - kEcGamalEncryptedLength); + zeroCiphertext.data() + kEcCiphertextComponentLength, + tc.data() + kEcCiphertextComponentLength, + kEcCiphertextComponentLength); mptAlice.send( {.account = bob, @@ -7825,7 +7941,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase mptAlice.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mptAlice.authorize({.account = bob}); @@ -7943,7 +8059,7 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase testSendPreclaim(features); testSendRangeProof(features); - // testSendZeroAmount(features); + testSendZeroAmount(features); testSendWithAuditor(features); // ConfidentialMPTClawback diff --git a/src/test/app/Invariants_test.cpp b/src/test/app/Invariants_test.cpp index eba392cf9a..46ec3de8f7 100644 --- a/src/test/app/Invariants_test.cpp +++ b/src/test/app/Invariants_test.cpp @@ -4978,7 +4978,7 @@ class Invariants_test : public beast::unit_test::Suite auto const precloseConfidential = [&mptID](Account const& a1, Account const& a2, Env& env) -> bool { MPTTester mpt(env, a1, {.holders = {a2}, .fund = false}); - mpt.create({.flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount}); + mpt.create({.flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance}); mptID = mpt.issuanceID(); mpt.authorize({.account = a2}); @@ -5033,7 +5033,7 @@ class Invariants_test : public beast::unit_test::Suite auto const precloseNoPrivacy = [&mptID]( Account const& a1, Account const& a2, Env& env) -> bool { MPTTester mpt(env, a1, {.holders = {a2}, .fund = false}); - // completely omitted the tfMPTCanConfidentialAmount flag here. + // completely omitted the tfMPTCanHoldConfidentialBalance flag here. mpt.create({.flags = tfMPTCanTransfer}); mptID = mpt.issuanceID(); mpt.authorize({.account = a2}); @@ -5042,7 +5042,8 @@ class Invariants_test : public beast::unit_test::Suite }; doInvariantCheck( - {"MPToken has encrypted fields but Issuance does not have lsfMPTCanConfidentialAmount " + {"MPToken has encrypted fields but Issuance does not have " + "lsfMPTCanHoldConfidentialBalance " "set"}, [&mptID](Account const& a1, Account const& a2, ApplyContext& ac) { auto sleToken = ac.view().peek(keylet::mptoken(mptID, a2.id())); @@ -5159,7 +5160,7 @@ class Invariants_test : public beast::unit_test::Suite auto const precloseOrphan = [&mptID]( Account const& a1, Account const& a2, Env& env) -> bool { MPTTester mpt(env, a1, {.holders = {a2}, .fund = false}); - mpt.create({.flags = tfMPTCanTransfer | tfMPTCanConfidentialAmount}); + mpt.create({.flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance}); mptID = mpt.issuanceID(); mpt.authorize({.account = a2}); diff --git a/src/test/jtx/ConfidentialTransfer.h b/src/test/jtx/ConfidentialTransfer.h index 37487bdd25..b758683da6 100644 --- a/src/test/jtx/ConfidentialTransfer.h +++ b/src/test/jtx/ConfidentialTransfer.h @@ -126,7 +126,7 @@ protected: std::memset(buf.data(), 0xFF, kEcGamalEncryptedTotalLength); buf.data()[0] = kEcCompressedPrefixEvenY; - buf.data()[kEcGamalEncryptedLength] = kEcCompressedPrefixEvenY; + buf.data()[kEcCiphertextComponentLength] = kEcCompressedPrefixEvenY; return buf; }(); @@ -144,9 +144,9 @@ protected: std::memset(buf.data(), 0, kEcGamalEncryptedTotalLength); buf.data()[0] = kEcCompressedPrefixEvenY; - buf.data()[kEcGamalEncryptedLength] = kEcCompressedPrefixEvenY; + buf.data()[kEcCiphertextComponentLength] = kEcCompressedPrefixEvenY; - buf.data()[kEcGamalEncryptedLength - 1] = 0x01; + buf.data()[kEcCiphertextComponentLength - 1] = 0x01; buf.data()[kEcGamalEncryptedTotalLength - 1] = 0x01; return buf; @@ -180,11 +180,11 @@ protected: Buffer buf(kEcSendProofLength); std::memset(buf.data(), 0, kEcSendProofLength); - for (std::size_t i = 0; i < kEcSendProofLength; i += kEcGamalEncryptedLength) + for (std::size_t i = 0; i < kEcSendProofLength; i += kEcCiphertextComponentLength) { buf.data()[i] = kEcCompressedPrefixEvenY; - if (i + kEcGamalEncryptedLength - 1 < kEcSendProofLength) - buf.data()[i + kEcGamalEncryptedLength - 1] = 0x01; + if (i + kEcCiphertextComponentLength - 1 < kEcSendProofLength) + buf.data()[i + kEcCiphertextComponentLength - 1] = 0x01; } return strHex(buf); @@ -359,7 +359,7 @@ protected: test::jtx::Env& env, test::jtx::Account const& issuer, std::vector const& holders, - std::uint32_t flags = tfMPTCanLock | tfMPTCanConfidentialAmount | tfMPTCanTransfer, + std::uint32_t flags = tfMPTCanLock | tfMPTCanHoldConfidentialBalance | tfMPTCanTransfer, std::optional auditor = std::nullopt) : mpt{env, issuer, {.holders = extractAccounts(holders), .auditor = auditor}} { @@ -427,7 +427,7 @@ protected: using namespace test::jtx; mpt.create({ .ownerCount = 1, - .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanConfidentialAmount, + .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance, }); mpt.authorize({.account = bob}); mpt.authorize({.account = carol}); diff --git a/src/test/jtx/impl/batch.cpp b/src/test/jtx/impl/batch.cpp index 7f1df1e9f0..66ca0c7d54 100644 --- a/src/test/jtx/impl/batch.cpp +++ b/src/test/jtx/impl/batch.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,7 @@ calcConfidentialBatchFee( uint32_t const& txns) { XRPAmount const feeDrops = env.current()->fees().base; - return ((numSigners + 2) * feeDrops) + feeDrops * 10 * txns; + return ((numSigners + 2) * feeDrops) + feeDrops * (kConfidentialFeeMultiplier + 1) * txns; } // Batch. diff --git a/src/test/jtx/impl/mpt.cpp b/src/test/jtx/impl/mpt.cpp index 8d3f527d15..ba62f3a6bc 100644 --- a/src/test/jtx/impl/mpt.cpp +++ b/src/test/jtx/impl/mpt.cpp @@ -521,8 +521,8 @@ MPTTester::set(MPTSet const& arg) } } - if (*arg.mutableFlags & tmfMPTSetCanConfidentialAmount) - flags |= lsfMPTCanConfidentialAmount; + if (*arg.mutableFlags & tmfMPTSetCanHoldConfidentialBalance) + flags |= tfMPTCanHoldConfidentialBalance; } } env_.require(MptFlags(*this, flags, holder)); @@ -879,8 +879,9 @@ MPTTester::getConfidentialSendProof( { return std::nullopt; } - std::memcpy(participants[i].pubkey, r.publicKey.data(), kMPT_PUBKEY_SIZE); - std::memcpy(participants[i].ciphertext, r.encryptedAmount.data(), kMPT_ELGAMAL_TOTAL_SIZE); + std::memcpy(participants[i].pubkey, r.publicKey.data(), kEcPubKeyLength); + std::memcpy( + participants[i].ciphertext, r.encryptedAmount.data(), kEcGamalEncryptedTotalLength); } size_t proofLen = kEcSendProofLength; @@ -1396,10 +1397,17 @@ MPTTester::send(MPTConfidentialSend const& arg) auto const prevSenderInbox = getDecryptedBalance(*arg.account, holderEncryptedInbox); auto const prevSenderSpending = getDecryptedBalance(*arg.account, holderEncryptedSpending); auto const prevSenderIssuer = getDecryptedBalance(*arg.account, issuerEncryptedBalance); + auto const prevSenderInboxEncrypted = getEncryptedBalance(*arg.account, holderEncryptedInbox); + auto const prevSenderSpendingEncrypted = + getEncryptedBalance(*arg.account, holderEncryptedSpending); + auto const prevSenderIssuerEncrypted = + getEncryptedBalance(*arg.account, issuerEncryptedBalance); if (!prevSenderInbox || !prevSenderSpending || !prevSenderIssuer) Throw("Failed to get Pre-send balance"); std::optional prevSenderAuditor; + auto const prevSenderAuditorEncrypted = + getEncryptedBalance(*arg.account, auditorEncryptedBalance); if (arg.auditorEncryptedAmt || auditor_) { prevSenderAuditor = getDecryptedBalance(*arg.account, auditorEncryptedBalance); @@ -1411,10 +1419,14 @@ MPTTester::send(MPTConfidentialSend const& arg) auto const prevDestInbox = getDecryptedBalance(*arg.dest, holderEncryptedInbox); auto const prevDestSpending = getDecryptedBalance(*arg.dest, holderEncryptedSpending); auto const prevDestIssuer = getDecryptedBalance(*arg.dest, issuerEncryptedBalance); + auto const prevDestInboxEncrypted = getEncryptedBalance(*arg.dest, holderEncryptedInbox); + auto const prevDestSpendingEncrypted = getEncryptedBalance(*arg.dest, holderEncryptedSpending); + auto const prevDestIssuerEncrypted = getEncryptedBalance(*arg.dest, issuerEncryptedBalance); if (!prevDestInbox || !prevDestSpending || !prevDestIssuer) Throw("Failed to get Pre-send balance"); std::optional prevDestAuditor; + auto const prevDestAuditorEncrypted = getEncryptedBalance(*arg.dest, auditorEncryptedBalance); if (arg.auditorEncryptedAmt || auditor_) { prevDestAuditor = getDecryptedBalance(*arg.dest, auditorEncryptedBalance); @@ -1512,16 +1524,13 @@ MPTTester::send(MPTConfidentialSend const& arg) } } - auto const prevEncryptedSenderSpending = - getEncryptedBalance(*arg.account, holderEncryptedSpending); - std::optional proof; // Skip proof generation if encrypted balance is missing (e.g., // feature disabled), when the sender and destination are the same // (malformed case causing pcm to be zero), or when spending balance // is 0 - if (arg.account != arg.dest && prevEncryptedSenderSpending && *prevSenderSpending > 0) + if (arg.account != arg.dest && prevSenderSpendingEncrypted && *prevSenderSpending > 0) { proof = getConfidentialSendProof( *arg.account, @@ -1538,7 +1547,7 @@ MPTTester::send(MPTConfidentialSend const& arg) { .pedersenCommitment = balanceCommitment, .amt = *prevSenderSpending, - .encryptedAmt = *prevEncryptedSenderSpending, + .encryptedAmt = *prevSenderSpendingEncrypted, .blindingFactor = balanceBlindingFactor, }); } diff --git a/src/test/jtx/impl/utility.cpp b/src/test/jtx/impl/utility.cpp index 63c9d94264..6d10acc22e 100644 --- a/src/test/jtx/impl/utility.cpp +++ b/src/test/jtx/impl/utility.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -60,14 +61,14 @@ fillFee(json::Value& jv, ReadView const& view) auto const base = view.fees().base; - // For confidential transactions, the fee higher because confidential + // For confidential transactions, the fee is higher because confidential // transaction processing is more expensive. auto const txType = jv[jss::TransactionType].asString(); if (txType == jss::ConfidentialMPTConvert || txType == jss::ConfidentialMPTConvertBack || txType == jss::ConfidentialMPTSend || txType == jss::ConfidentialMPTMergeInbox || txType == jss::ConfidentialMPTClawback) { - jv[jss::Fee] = to_string(base * 10); + jv[jss::Fee] = to_string(base * (kConfidentialFeeMultiplier + 1)); } else {