//------------------------------------------------------------------------------ /* This file is part of rippled: https://github.com/ripple/rippled Copyright (c) 2022 Ripple Labs Inc. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ripple { namespace Attestations { AttestationBase::AttestationBase( AccountID attestationSignerAccount_, PublicKey const& publicKey_, Buffer signature_, AccountID const& sendingAccount_, STAmount const& sendingAmount_, AccountID const& rewardAccount_, bool wasLockingChainSend_) : attestationSignerAccount{attestationSignerAccount_} , publicKey{publicKey_} , signature{std::move(signature_)} , sendingAccount{sendingAccount_} , sendingAmount{sendingAmount_} , rewardAccount{rewardAccount_} , wasLockingChainSend{wasLockingChainSend_} { } bool AttestationBase::equalHelper( AttestationBase const& lhs, AttestationBase const& rhs) { return std::tie( lhs.attestationSignerAccount, lhs.publicKey, lhs.signature, lhs.sendingAccount, lhs.sendingAmount, lhs.rewardAccount, lhs.wasLockingChainSend) == std::tie( rhs.attestationSignerAccount, rhs.publicKey, rhs.signature, rhs.sendingAccount, rhs.sendingAmount, rhs.rewardAccount, rhs.wasLockingChainSend); } bool AttestationBase::sameEventHelper( AttestationBase const& lhs, AttestationBase const& rhs) { return std::tie( lhs.sendingAccount, lhs.sendingAmount, lhs.wasLockingChainSend) == std::tie( rhs.sendingAccount, rhs.sendingAmount, rhs.wasLockingChainSend); } bool AttestationBase::verify(STXChainBridge const& bridge) const { std::vector msg = message(bridge); return ripple::verify(publicKey, makeSlice(msg), signature); } AttestationBase::AttestationBase(STObject const& o) : attestationSignerAccount{o[sfAttestationSignerAccount]} , publicKey{o[sfPublicKey]} , signature{o[sfSignature]} , sendingAccount{o[sfAccount]} , sendingAmount{o[sfAmount]} , rewardAccount{o[sfAttestationRewardAccount]} , wasLockingChainSend{bool(o[sfWasLockingChainSend])} { } AttestationBase::AttestationBase(Json::Value const& v) : attestationSignerAccount{Json::getOrThrow( v, sfAttestationSignerAccount)} , publicKey{Json::getOrThrow(v, sfPublicKey)} , signature{Json::getOrThrow(v, sfSignature)} , sendingAccount{Json::getOrThrow(v, sfAccount)} , sendingAmount{Json::getOrThrow(v, sfAmount)} , rewardAccount{Json::getOrThrow(v, sfAttestationRewardAccount)} , wasLockingChainSend{Json::getOrThrow(v, sfWasLockingChainSend)} { } void AttestationBase::addHelper(STObject& o) const { o[sfAttestationSignerAccount] = attestationSignerAccount; o[sfPublicKey] = publicKey; o[sfSignature] = signature; o[sfAmount] = sendingAmount; o[sfAccount] = sendingAccount; o[sfAttestationRewardAccount] = rewardAccount; o[sfWasLockingChainSend] = wasLockingChainSend; } AttestationClaim::AttestationClaim( AccountID attestationSignerAccount_, PublicKey const& publicKey_, Buffer signature_, AccountID const& sendingAccount_, STAmount const& sendingAmount_, AccountID const& rewardAccount_, bool wasLockingChainSend_, std::uint64_t claimID_, std::optional const& dst_) : AttestationBase( attestationSignerAccount_, publicKey_, std::move(signature_), sendingAccount_, sendingAmount_, rewardAccount_, wasLockingChainSend_) , claimID{claimID_} , dst{dst_} { } AttestationClaim::AttestationClaim( STXChainBridge const& bridge, AccountID attestationSignerAccount_, PublicKey const& publicKey_, SecretKey const& secretKey_, AccountID const& sendingAccount_, STAmount const& sendingAmount_, AccountID const& rewardAccount_, bool wasLockingChainSend_, std::uint64_t claimID_, std::optional const& dst_) : AttestationClaim{ attestationSignerAccount_, publicKey_, Buffer{}, sendingAccount_, sendingAmount_, rewardAccount_, wasLockingChainSend_, claimID_, dst_} { auto const toSign = message(bridge); signature = sign(publicKey_, secretKey_, makeSlice(toSign)); } AttestationClaim::AttestationClaim(STObject const& o) : AttestationBase(o), claimID{o[sfXChainClaimID]}, dst{o[~sfDestination]} { } AttestationClaim::AttestationClaim(Json::Value const& v) : AttestationBase{v} , claimID{Json::getOrThrow(v, sfXChainClaimID)} { if (v.isMember(sfDestination.getJsonName())) dst = Json::getOrThrow(v, sfDestination); } STObject AttestationClaim::toSTObject() const { STObject o{sfXChainClaimAttestationCollectionElement}; addHelper(o); o[sfXChainClaimID] = claimID; if (dst) o[sfDestination] = *dst; return o; } std::vector AttestationClaim::message( STXChainBridge const& bridge, AccountID const& sendingAccount, STAmount const& sendingAmount, AccountID const& rewardAccount, bool wasLockingChainSend, std::uint64_t claimID, std::optional const& dst) { STObject o{sfGeneric}; // Serialize in SField order to make python serializers easier to write o[sfXChainClaimID] = claimID; o[sfAmount] = sendingAmount; if (dst) o[sfDestination] = *dst; o[sfOtherChainSource] = sendingAccount; o[sfAttestationRewardAccount] = rewardAccount; o[sfWasLockingChainSend] = wasLockingChainSend ? 1 : 0; o[sfXChainBridge] = bridge; Serializer s; o.add(s); return std::move(s.modData()); } std::vector AttestationClaim::message(STXChainBridge const& bridge) const { return AttestationClaim::message( bridge, sendingAccount, sendingAmount, rewardAccount, wasLockingChainSend, claimID, dst); } bool AttestationClaim::validAmounts() const { return isLegalNet(sendingAmount); } bool AttestationClaim::sameEvent(AttestationClaim const& rhs) const { return AttestationClaim::sameEventHelper(*this, rhs) && tie(claimID, dst) == tie(rhs.claimID, rhs.dst); } bool operator==(AttestationClaim const& lhs, AttestationClaim const& rhs) { return AttestationClaim::equalHelper(lhs, rhs) && tie(lhs.claimID, lhs.dst) == tie(rhs.claimID, rhs.dst); } AttestationCreateAccount::AttestationCreateAccount(STObject const& o) : AttestationBase(o) , createCount{o[sfXChainAccountCreateCount]} , toCreate{o[sfDestination]} , rewardAmount{o[sfSignatureReward]} { } AttestationCreateAccount::AttestationCreateAccount(Json::Value const& v) : AttestationBase{v} , createCount{Json::getOrThrow( v, sfXChainAccountCreateCount)} , toCreate{Json::getOrThrow(v, sfDestination)} , rewardAmount{Json::getOrThrow(v, sfSignatureReward)} { } AttestationCreateAccount::AttestationCreateAccount( AccountID attestationSignerAccount_, PublicKey const& publicKey_, Buffer signature_, AccountID const& sendingAccount_, STAmount const& sendingAmount_, STAmount const& rewardAmount_, AccountID const& rewardAccount_, bool wasLockingChainSend_, std::uint64_t createCount_, AccountID const& toCreate_) : AttestationBase( attestationSignerAccount_, publicKey_, std::move(signature_), sendingAccount_, sendingAmount_, rewardAccount_, wasLockingChainSend_) , createCount{createCount_} , toCreate{toCreate_} , rewardAmount{rewardAmount_} { } AttestationCreateAccount::AttestationCreateAccount( STXChainBridge const& bridge, AccountID attestationSignerAccount_, PublicKey const& publicKey_, SecretKey const& secretKey_, AccountID const& sendingAccount_, STAmount const& sendingAmount_, STAmount const& rewardAmount_, AccountID const& rewardAccount_, bool wasLockingChainSend_, std::uint64_t createCount_, AccountID const& toCreate_) : AttestationCreateAccount{ attestationSignerAccount_, publicKey_, Buffer{}, sendingAccount_, sendingAmount_, rewardAmount_, rewardAccount_, wasLockingChainSend_, createCount_, toCreate_} { auto const toSign = message(bridge); signature = sign(publicKey_, secretKey_, makeSlice(toSign)); } STObject AttestationCreateAccount::toSTObject() const { STObject o{sfXChainCreateAccountAttestationCollectionElement}; addHelper(o); o[sfXChainAccountCreateCount] = createCount; o[sfDestination] = toCreate; o[sfSignatureReward] = rewardAmount; return o; } std::vector AttestationCreateAccount::message( STXChainBridge const& bridge, AccountID const& sendingAccount, STAmount const& sendingAmount, STAmount const& rewardAmount, AccountID const& rewardAccount, bool wasLockingChainSend, std::uint64_t createCount, AccountID const& dst) { STObject o{sfGeneric}; // Serialize in SField order to make python serializers easier to write o[sfXChainAccountCreateCount] = createCount; o[sfAmount] = sendingAmount; o[sfSignatureReward] = rewardAmount; o[sfDestination] = dst; o[sfOtherChainSource] = sendingAccount; o[sfAttestationRewardAccount] = rewardAccount; o[sfWasLockingChainSend] = wasLockingChainSend ? 1 : 0; o[sfXChainBridge] = bridge; Serializer s; o.add(s); return std::move(s.modData()); } std::vector AttestationCreateAccount::message(STXChainBridge const& bridge) const { return AttestationCreateAccount::message( bridge, sendingAccount, sendingAmount, rewardAmount, rewardAccount, wasLockingChainSend, createCount, toCreate); } bool AttestationCreateAccount::validAmounts() const { return isLegalNet(rewardAmount) && isLegalNet(sendingAmount); } bool AttestationCreateAccount::sameEvent(AttestationCreateAccount const& rhs) const { return AttestationCreateAccount::sameEventHelper(*this, rhs) && std::tie(createCount, toCreate, rewardAmount) == std::tie(rhs.createCount, rhs.toCreate, rhs.rewardAmount); } bool operator==( AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs) { return AttestationCreateAccount::equalHelper(lhs, rhs) && std::tie(lhs.createCount, lhs.toCreate, lhs.rewardAmount) == std::tie(rhs.createCount, rhs.toCreate, rhs.rewardAmount); } } // namespace Attestations SField const& XChainClaimAttestation::ArrayFieldName{sfXChainClaimAttestations}; SField const& XChainCreateAccountAttestation::ArrayFieldName{ sfXChainCreateAccountAttestations}; XChainClaimAttestation::XChainClaimAttestation( AccountID const& keyAccount_, PublicKey const& publicKey_, STAmount const& amount_, AccountID const& rewardAccount_, bool wasLockingChainSend_, std::optional const& dst_) : keyAccount(keyAccount_) , publicKey(publicKey_) , amount(sfAmount, amount_) , rewardAccount(rewardAccount_) , wasLockingChainSend(wasLockingChainSend_) , dst(dst_) { } XChainClaimAttestation::XChainClaimAttestation( STAccount const& keyAccount_, PublicKey const& publicKey_, STAmount const& amount_, STAccount const& rewardAccount_, bool wasLockingChainSend_, std::optional const& dst_) : XChainClaimAttestation{ keyAccount_.value(), publicKey_, amount_, rewardAccount_.value(), wasLockingChainSend_, dst_ ? std::optional{dst_->value()} : std::nullopt} { } XChainClaimAttestation::XChainClaimAttestation(STObject const& o) : XChainClaimAttestation{ o[sfAttestationSignerAccount], PublicKey{o[sfPublicKey]}, o[sfAmount], o[sfAttestationRewardAccount], o[sfWasLockingChainSend] != 0, o[~sfDestination]} {}; XChainClaimAttestation::XChainClaimAttestation(Json::Value const& v) : XChainClaimAttestation{ Json::getOrThrow(v, sfAttestationSignerAccount), Json::getOrThrow(v, sfPublicKey), Json::getOrThrow(v, sfAmount), Json::getOrThrow(v, sfAttestationRewardAccount), Json::getOrThrow(v, sfWasLockingChainSend), std::nullopt} { if (v.isMember(sfDestination.getJsonName())) dst = Json::getOrThrow(v, sfDestination); }; XChainClaimAttestation::XChainClaimAttestation( XChainClaimAttestation::TSignedAttestation const& claimAtt) : XChainClaimAttestation{ claimAtt.attestationSignerAccount, claimAtt.publicKey, claimAtt.sendingAmount, claimAtt.rewardAccount, claimAtt.wasLockingChainSend, claimAtt.dst} { } STObject XChainClaimAttestation::toSTObject() const { STObject o{sfXChainClaimProofSig}; o[sfAttestationSignerAccount] = STAccount{sfAttestationSignerAccount, keyAccount}; o[sfPublicKey] = publicKey; o[sfAmount] = STAmount{sfAmount, amount}; o[sfAttestationRewardAccount] = STAccount{sfAttestationRewardAccount, rewardAccount}; o[sfWasLockingChainSend] = wasLockingChainSend; if (dst) o[sfDestination] = STAccount{sfDestination, *dst}; return o; } bool operator==(XChainClaimAttestation const& lhs, XChainClaimAttestation const& rhs) { return std::tie( lhs.keyAccount, lhs.publicKey, lhs.amount, lhs.rewardAccount, lhs.wasLockingChainSend, lhs.dst) == std::tie( rhs.keyAccount, rhs.publicKey, rhs.amount, rhs.rewardAccount, rhs.wasLockingChainSend, rhs.dst); } XChainClaimAttestation::MatchFields::MatchFields( XChainClaimAttestation::TSignedAttestation const& att) : amount{att.sendingAmount} , wasLockingChainSend{att.wasLockingChainSend} , dst{att.dst} { } AttestationMatch XChainClaimAttestation::match( XChainClaimAttestation::MatchFields const& rhs) const { if (std::tie(amount, wasLockingChainSend) != std::tie(rhs.amount, rhs.wasLockingChainSend)) return AttestationMatch::nonDstMismatch; if (dst != rhs.dst) return AttestationMatch::matchExceptDst; return AttestationMatch::match; } //------------------------------------------------------------------------------ XChainCreateAccountAttestation::XChainCreateAccountAttestation( AccountID const& keyAccount_, PublicKey const& publicKey_, STAmount const& amount_, STAmount const& rewardAmount_, AccountID const& rewardAccount_, bool wasLockingChainSend_, AccountID const& dst_) : keyAccount(keyAccount_) , publicKey(publicKey_) , amount(sfAmount, amount_) , rewardAmount(sfSignatureReward, rewardAmount_) , rewardAccount(rewardAccount_) , wasLockingChainSend(wasLockingChainSend_) , dst(dst_) { } XChainCreateAccountAttestation::XChainCreateAccountAttestation( STObject const& o) : XChainCreateAccountAttestation{ o[sfAttestationSignerAccount], PublicKey{o[sfPublicKey]}, o[sfAmount], o[sfSignatureReward], o[sfAttestationRewardAccount], o[sfWasLockingChainSend] != 0, o[sfDestination]} {}; XChainCreateAccountAttestation ::XChainCreateAccountAttestation( Json::Value const& v) : XChainCreateAccountAttestation{ Json::getOrThrow(v, sfAttestationSignerAccount), Json::getOrThrow(v, sfPublicKey), Json::getOrThrow(v, sfAmount), Json::getOrThrow(v, sfSignatureReward), Json::getOrThrow(v, sfAttestationRewardAccount), Json::getOrThrow(v, sfWasLockingChainSend), Json::getOrThrow(v, sfDestination)} { } XChainCreateAccountAttestation::XChainCreateAccountAttestation( XChainCreateAccountAttestation::TSignedAttestation const& createAtt) : XChainCreateAccountAttestation{ createAtt.attestationSignerAccount, createAtt.publicKey, createAtt.sendingAmount, createAtt.rewardAmount, createAtt.rewardAccount, createAtt.wasLockingChainSend, createAtt.toCreate} { } STObject XChainCreateAccountAttestation::toSTObject() const { STObject o{sfXChainCreateAccountProofSig}; o[sfAttestationSignerAccount] = STAccount{sfAttestationSignerAccount, keyAccount}; o[sfPublicKey] = publicKey; o[sfAmount] = STAmount{sfAmount, amount}; o[sfSignatureReward] = STAmount{sfSignatureReward, rewardAmount}; o[sfAttestationRewardAccount] = STAccount{sfAttestationRewardAccount, rewardAccount}; o[sfWasLockingChainSend] = wasLockingChainSend; o[sfDestination] = STAccount{sfDestination, dst}; return o; } XChainCreateAccountAttestation::MatchFields::MatchFields( XChainCreateAccountAttestation::TSignedAttestation const& att) : amount{att.sendingAmount} , rewardAmount(att.rewardAmount) , wasLockingChainSend{att.wasLockingChainSend} , dst{att.toCreate} { } AttestationMatch XChainCreateAccountAttestation::match( XChainCreateAccountAttestation::MatchFields const& rhs) const { if (std::tie(amount, rewardAmount, wasLockingChainSend) != std::tie(rhs.amount, rhs.rewardAmount, rhs.wasLockingChainSend)) return AttestationMatch::nonDstMismatch; if (dst != rhs.dst) return AttestationMatch::matchExceptDst; return AttestationMatch::match; } bool operator==( XChainCreateAccountAttestation const& lhs, XChainCreateAccountAttestation const& rhs) { return std::tie( lhs.keyAccount, lhs.publicKey, lhs.amount, lhs.rewardAmount, lhs.rewardAccount, lhs.wasLockingChainSend, lhs.dst) == std::tie( rhs.keyAccount, rhs.publicKey, rhs.amount, rhs.rewardAmount, rhs.rewardAccount, rhs.wasLockingChainSend, rhs.dst); } //------------------------------------------------------------------------------ // template XChainAttestationsBase::XChainAttestationsBase( XChainAttestationsBase::AttCollection&& atts) : attestations_{std::move(atts)} { } template typename XChainAttestationsBase::AttCollection::const_iterator XChainAttestationsBase::begin() const { return attestations_.begin(); } template typename XChainAttestationsBase::AttCollection::const_iterator XChainAttestationsBase::end() const { return attestations_.end(); } template typename XChainAttestationsBase::AttCollection::iterator XChainAttestationsBase::begin() { return attestations_.begin(); } template typename XChainAttestationsBase::AttCollection::iterator XChainAttestationsBase::end() { return attestations_.end(); } template XChainAttestationsBase::XChainAttestationsBase( Json::Value const& v) { if (!v.isObject()) { Throw( "XChainAttestationsBase can only be specified with an 'object' " "Json value"); } attestations_ = [&] { auto const jAtts = v[jss::attestations]; if (jAtts.size() > maxAttestations) Throw( "XChainAttestationsBase exceeded max number of attestations"); std::vector r; r.reserve(jAtts.size()); for (auto const& a : jAtts) r.emplace_back(a); return r; }(); } template XChainAttestationsBase::XChainAttestationsBase(STArray const& arr) { if (arr.size() > maxAttestations) Throw( "XChainAttestationsBase exceeded max number of attestations"); attestations_.reserve(arr.size()); for (auto const& o : arr) attestations_.emplace_back(o); } template STArray XChainAttestationsBase::toSTArray() const { STArray r{TAttestation::ArrayFieldName, attestations_.size()}; for (auto const& e : attestations_) r.emplace_back(e.toSTObject()); return r; } template class XChainAttestationsBase; template class XChainAttestationsBase; } // namespace ripple