#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl { 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 xrpl::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 = STObject::makeInnerObject(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 = STObject::makeInnerObject(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 = STObject::makeInnerObject(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 = STObject::makeInnerObject(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 xrpl