#include #include #include #include #include #include #include #include #include // IWYU pragma: keep #include #include #include #include #include #include #include #include #include namespace xrpl { STBase* STValidation::copy(std::size_t n, void* buf) const { return emplace(n, buf, *this); } STBase* STValidation::move(std::size_t n, void* buf) { return emplace(n, buf, std::move(*this)); } SOTemplate const& STValidation::validationFormat() { // We can't have this be a magic static at namespace scope because // it relies on the SField's below being initialized, and we can't // guarantee the initialization order. // clang-format off static SOTemplate const kFormat{ {sfFlags, SoeRequired}, {sfLedgerHash, SoeRequired}, {sfLedgerSequence, SoeRequired}, {sfCloseTime, SoeOptional}, {sfLoadFee, SoeOptional}, {sfAmendments, SoeOptional}, {sfBaseFee, SoeOptional}, {sfReserveBase, SoeOptional}, {sfReserveIncrement, SoeOptional}, {sfSigningTime, SoeRequired}, {sfSigningPubKey, SoeRequired}, {sfSignature, SoeRequired}, {sfConsensusHash, SoeOptional}, {sfCookie, SoeDefault}, {sfValidatedHash, SoeOptional}, {sfServerVersion, SoeOptional}, // featureXRPFees {sfBaseFeeDrops, SoeOptional}, {sfReserveBaseDrops, SoeOptional}, {sfReserveIncrementDrops, SoeOptional}, // featureSmartEscrow {sfGasLimit, SoeOptional}, {sfBytecodeSizeLimit, SoeOptional}, {sfGasPrice, SoeOptional}, }; // clang-format on return kFormat; }; uint256 STValidation::getSigningHash() const { return STObject::getSigningHash(HashPrefix::Validation); } uint256 STValidation::getLedgerHash() const { return getFieldH256(sfLedgerHash); } uint256 STValidation::getConsensusHash() const { return getFieldH256(sfConsensusHash); } NetClock::time_point STValidation::getSignTime() const { return NetClock::time_point{NetClock::duration{getFieldU32(sfSigningTime)}}; } NetClock::time_point STValidation::getSeenTime() const noexcept { return seenTime_; } bool STValidation::isValid() const noexcept { if (!valid_) { XRPL_ASSERT( publicKeyType(getSignerPublic()) == KeyType::Secp256k1, "xrpl::STValidation::isValid : valid key type"); // Log that the signature was never checked, so an operator does not // read this as a bad key. The log is guarded because it can throw too. auto reportUncheckable = [this](char const* reason) noexcept { try { JLOG(debugLog().error()) << "Cannot check the signature of the validation for ledger " << getLedgerHash() << ": " << reason; } catch (...) // NOLINT(bugprone-empty-catch) { // Nothing can be reported when reporting is what failed. } }; // The signing hash re-serializes the fields, which can fail. This // function is noexcept, so report the validation as invalid instead of // throwing. valid_ stays unset, so a later call checks again. try { valid_ = verifyDigest( getSignerPublic(), getSigningHash(), makeSlice(getFieldVL(sfSignature)), (getFlags() & kVfFullyCanonicalSig) != 0u); } catch (std::exception const& e) { reportUncheckable(e.what()); return false; } catch (...) { reportUncheckable("unknown exception"); return false; } } return valid_.value(); } bool STValidation::isFull() const noexcept { return (getFlags() & kVfFullValidation) != 0; } Blob STValidation::getSignature() const { return getFieldVL(sfSignature); } Blob STValidation::getSerialized() const { Serializer s; add(s); return s.peekData(); } } // namespace xrpl