rippled
Loading...
Searching...
No Matches
xchain_bridge.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2022 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/jtx/Env.h>
21#include <test/jtx/attester.h>
22#include <test/jtx/xchain_bridge.h>
23
24#include <xrpl/json/json_value.h>
25#include <xrpl/protocol/Issue.h>
26#include <xrpl/protocol/SField.h>
27#include <xrpl/protocol/STBase.h>
28#include <xrpl/protocol/STInteger.h>
29#include <xrpl/protocol/STObject.h>
30#include <xrpl/protocol/TxFlags.h>
31#include <xrpl/protocol/XChainAttestations.h>
32#include <xrpl/protocol/jss.h>
33
34namespace ripple {
35namespace test {
36namespace jtx {
37
38// use this for creating a bridge for a transaction
41 Account const& lockingChainDoor,
42 Issue const& lockingChainIssue,
43 Account const& issuingChainDoor,
44 Issue const& issuingChainIssue)
45{
46 Json::Value jv;
47 jv[sfLockingChainDoor.getJsonName()] = lockingChainDoor.human();
48 jv[sfLockingChainIssue.getJsonName()] = to_json(lockingChainIssue);
49 jv[sfIssuingChainDoor.getJsonName()] = issuingChainDoor.human();
50 jv[sfIssuingChainIssue.getJsonName()] = to_json(issuingChainIssue);
51 return jv;
52}
53
54// use this for creating a bridge for a rpc query
57 Account const& lockingChainDoor,
58 Issue const& lockingChainIssue,
59 Account const& issuingChainDoor,
60 Issue const& issuingChainIssue)
61{
62 Json::Value jv;
63 jv[sfLockingChainDoor.getJsonName()] = lockingChainDoor.human();
64 jv[sfLockingChainIssue.getJsonName()] = to_json(lockingChainIssue);
65 jv[sfIssuingChainDoor.getJsonName()] = issuingChainDoor.human();
66 jv[sfIssuingChainIssue.getJsonName()] = to_json(issuingChainIssue);
67 return jv;
68}
69
72 Account const& acc,
73 Json::Value const& bridge,
74 STAmount const& reward,
75 std::optional<STAmount> const& minAccountCreate)
76{
77 Json::Value jv;
78
79 jv[jss::Account] = acc.human();
80 jv[sfXChainBridge.getJsonName()] = bridge;
81 jv[sfSignatureReward.getJsonName()] = reward.getJson(JsonOptions::none);
82 if (minAccountCreate)
83 jv[sfMinAccountCreateAmount.getJsonName()] =
84 minAccountCreate->getJson(JsonOptions::none);
85
86 jv[jss::TransactionType] = jss::XChainCreateBridge;
87 jv[jss::Flags] = tfUniversal;
88 return jv;
89}
90
93 Account const& acc,
94 Json::Value const& bridge,
95 std::optional<STAmount> const& reward,
96 std::optional<STAmount> const& minAccountCreate)
97{
98 Json::Value jv;
99
100 jv[jss::Account] = acc.human();
101 jv[sfXChainBridge.getJsonName()] = bridge;
102 if (reward)
103 jv[sfSignatureReward.getJsonName()] =
104 reward->getJson(JsonOptions::none);
105 if (minAccountCreate)
106 jv[sfMinAccountCreateAmount.getJsonName()] =
107 minAccountCreate->getJson(JsonOptions::none);
108
109 jv[jss::TransactionType] = jss::XChainModifyBridge;
110 jv[jss::Flags] = tfUniversal;
111 return jv;
112}
113
116 Account const& acc,
117 Json::Value const& bridge,
118 STAmount const& reward,
119 Account const& otherChainSource)
120{
121 Json::Value jv;
122
123 jv[jss::Account] = acc.human();
124 jv[sfXChainBridge.getJsonName()] = bridge;
125 jv[sfSignatureReward.getJsonName()] = reward.getJson(JsonOptions::none);
126 jv[sfOtherChainSource.getJsonName()] = otherChainSource.human();
127
128 jv[jss::TransactionType] = jss::XChainCreateClaimID;
129 jv[jss::Flags] = tfUniversal;
130 return jv;
131}
132
135 Account const& acc,
136 Json::Value const& bridge,
137 std::uint32_t claimID,
138 AnyAmount const& amt,
139 std::optional<Account> const& dst)
140{
141 Json::Value jv;
142
143 jv[jss::Account] = acc.human();
144 jv[sfXChainBridge.getJsonName()] = bridge;
145 jv[sfXChainClaimID.getJsonName()] = claimID;
146 jv[jss::Amount] = amt.value.getJson(JsonOptions::none);
147 if (dst)
148 jv[sfOtherChainDestination.getJsonName()] = dst->human();
149
150 jv[jss::TransactionType] = jss::XChainCommit;
151 jv[jss::Flags] = tfUniversal;
152 return jv;
153}
154
157 Account const& acc,
158 Json::Value const& bridge,
159 std::uint32_t claimID,
160 AnyAmount const& amt,
161 Account const& dst)
162{
163 Json::Value jv;
164
165 jv[sfAccount.getJsonName()] = acc.human();
166 jv[sfXChainBridge.getJsonName()] = bridge;
167 jv[sfXChainClaimID.getJsonName()] = claimID;
168 jv[sfDestination.getJsonName()] = dst.human();
169 jv[sfAmount.getJsonName()] = amt.value.getJson(JsonOptions::none);
170
171 jv[jss::TransactionType] = jss::XChainClaim;
172 jv[jss::Flags] = tfUniversal;
173 return jv;
174}
175
178 Account const& acc,
179 Json::Value const& bridge,
180 Account const& dst,
181 AnyAmount const& amt,
182 AnyAmount const& reward)
183{
184 Json::Value jv;
185
186 jv[sfAccount.getJsonName()] = acc.human();
187 jv[sfXChainBridge.getJsonName()] = bridge;
188 jv[sfDestination.getJsonName()] = dst.human();
189 jv[sfAmount.getJsonName()] = amt.value.getJson(JsonOptions::none);
190 jv[sfSignatureReward.getJsonName()] =
192
193 jv[jss::TransactionType] = jss::XChainAccountCreateCommit;
194 jv[jss::Flags] = tfUniversal;
195 return jv;
196}
197
200 jtx::Account const& submittingAccount,
201 Json::Value const& jvBridge,
202 jtx::Account const& sendingAccount,
203 jtx::AnyAmount const& sendingAmount,
204 jtx::Account const& rewardAccount,
205 bool wasLockingChainSend,
206 std::uint64_t claimID,
208 jtx::signer const& signer)
209{
210 STXChainBridge const stBridge(jvBridge);
211
212 auto const& pk = signer.account.pk();
213 auto const& sk = signer.account.sk();
214 auto const sig = sign_claim_attestation(
215 pk,
216 sk,
217 stBridge,
218 sendingAccount,
219 sendingAmount.value,
220 rewardAccount,
221 wasLockingChainSend,
222 claimID,
223 dst);
224
225 Json::Value result;
226
227 result[sfAccount.getJsonName()] = submittingAccount.human();
228 result[sfXChainBridge.getJsonName()] = jvBridge;
229
230 result[sfAttestationSignerAccount.getJsonName()] = signer.account.human();
231 result[sfPublicKey.getJsonName()] = strHex(pk.slice());
232 result[sfSignature.getJsonName()] = strHex(sig);
233 result[sfOtherChainSource.getJsonName()] = toBase58(sendingAccount);
234 result[sfAmount.getJsonName()] =
235 sendingAmount.value.getJson(JsonOptions::none);
236 result[sfAttestationRewardAccount.getJsonName()] = toBase58(rewardAccount);
237 result[sfWasLockingChainSend.getJsonName()] = wasLockingChainSend ? 1 : 0;
238
239 result[sfXChainClaimID.getJsonName()] =
240 STUInt64{claimID}.getJson(JsonOptions::none);
241 if (dst)
242 result[sfDestination.getJsonName()] = toBase58(*dst);
243
244 result[jss::TransactionType] = jss::XChainAddClaimAttestation;
245 result[jss::Flags] = tfUniversal;
246
247 return result;
248}
249
252 jtx::Account const& submittingAccount,
253 Json::Value const& jvBridge,
254 jtx::Account const& sendingAccount,
255 jtx::AnyAmount const& sendingAmount,
256 jtx::AnyAmount const& rewardAmount,
257 jtx::Account const& rewardAccount,
258 bool wasLockingChainSend,
259 std::uint64_t createCount,
260 jtx::Account const& dst,
261 jtx::signer const& signer)
262{
263 STXChainBridge const stBridge(jvBridge);
264
265 auto const& pk = signer.account.pk();
266 auto const& sk = signer.account.sk();
268 pk,
269 sk,
270 stBridge,
271 sendingAccount,
272 sendingAmount.value,
273 rewardAmount.value,
274 rewardAccount,
275 wasLockingChainSend,
276 createCount,
277 dst);
278
279 Json::Value result;
280
281 result[sfAccount.getJsonName()] = submittingAccount.human();
282 result[sfXChainBridge.getJsonName()] = jvBridge;
283
284 result[sfAttestationSignerAccount.getJsonName()] = signer.account.human();
285 result[sfPublicKey.getJsonName()] = strHex(pk.slice());
286 result[sfSignature.getJsonName()] = strHex(sig);
287 result[sfOtherChainSource.getJsonName()] = toBase58(sendingAccount);
288 result[sfAmount.getJsonName()] =
289 sendingAmount.value.getJson(JsonOptions::none);
290 result[sfAttestationRewardAccount.getJsonName()] = toBase58(rewardAccount);
291 result[sfWasLockingChainSend.getJsonName()] = wasLockingChainSend ? 1 : 0;
292
293 result[sfXChainAccountCreateCount.getJsonName()] =
294 STUInt64{createCount}.getJson(JsonOptions::none);
295 result[sfDestination.getJsonName()] = toBase58(dst);
296 result[sfSignatureReward.getJsonName()] =
297 rewardAmount.value.getJson(JsonOptions::none);
298
299 result[jss::TransactionType] = jss::XChainAddAccountCreateAttestation;
300 result[jss::Flags] = tfUniversal;
301
302 return result;
303}
304
307 jtx::Account const& submittingAccount,
308 Json::Value const& jvBridge,
309 jtx::Account const& sendingAccount,
310 jtx::AnyAmount const& sendingAmount,
311 std::vector<jtx::Account> const& rewardAccounts,
312 bool wasLockingChainSend,
313 std::uint64_t claimID,
316 std::size_t const numAtts,
317 std::size_t const fromIdx)
318{
319 assert(fromIdx + numAtts <= rewardAccounts.size());
320 assert(fromIdx + numAtts <= signers.size());
321 JValueVec vec;
322 vec.reserve(numAtts);
323 for (auto i = fromIdx; i < fromIdx + numAtts; ++i)
325 submittingAccount,
326 jvBridge,
327 sendingAccount,
328 sendingAmount,
329 rewardAccounts[i],
330 wasLockingChainSend,
331 claimID,
332 dst,
333 signers[i]));
334 return vec;
335}
336
339 jtx::Account const& submittingAccount,
340 Json::Value const& jvBridge,
341 jtx::Account const& sendingAccount,
342 jtx::AnyAmount const& sendingAmount,
343 jtx::AnyAmount const& rewardAmount,
344 std::vector<jtx::Account> const& rewardAccounts,
345 bool wasLockingChainSend,
346 std::uint64_t createCount,
347 jtx::Account const& dst,
349 std::size_t const numAtts,
350 std::size_t const fromIdx)
351{
352 assert(fromIdx + numAtts <= rewardAccounts.size());
353 assert(fromIdx + numAtts <= signers.size());
354 JValueVec vec;
355 vec.reserve(numAtts);
356 for (auto i = fromIdx; i < fromIdx + numAtts; ++i)
358 submittingAccount,
359 jvBridge,
360 sendingAccount,
361 sendingAmount,
362 rewardAmount,
363 rewardAccounts[i],
364 wasLockingChainSend,
365 createCount,
366 dst,
367 signers[i]));
368 return vec;
369}
370
372 : mcDoor("mcDoor")
373 , mcAlice("mcAlice")
374 , mcBob("mcBob")
375 , mcCarol("mcCarol")
376 , mcGw("mcGw")
377 , scDoor("scDoor")
378 , scAlice("scAlice")
379 , scBob("scBob")
380 , scCarol("scCarol")
381 , scGw("scGw")
382 , scAttester("scAttester")
383 , scReward("scReward")
384 , mcuDoor("mcuDoor")
385 , mcuAlice("mcuAlice")
386 , mcuBob("mcuBob")
387 , mcuCarol("mcuCarol")
388 , mcuGw("mcuGw")
389 , scuDoor("scuDoor")
390 , scuAlice("scuAlice")
391 , scuBob("scuBob")
392 , scuCarol("scuCarol")
393 , scuGw("scuGw")
394 , mcUSD(mcGw["USD"])
395 , scUSD(scGw["USD"])
396 , jvXRPBridgeRPC(
397 bridge_rpc(mcDoor, xrpIssue(), Account::master, xrpIssue()))
398 , jvb(bridge(mcDoor, xrpIssue(), Account::master, xrpIssue()))
399 , jvub(bridge(mcuDoor, xrpIssue(), Account::master, xrpIssue()))
400 , features(supported_amendments() | FeatureBitset{featureXChainBridge})
401 , signers([] {
402 constexpr int numSigners = UT_XCHAIN_DEFAULT_NUM_SIGNERS;
403 std::vector<signer> result;
404 result.reserve(numSigners);
405 for (int i = 0; i < numSigners; ++i)
406 {
407 using namespace std::literals;
408 auto const a = Account(
409 "signer_"s + std::to_string(i),
411 result.emplace_back(a);
412 }
413 return result;
414 }())
415 , alt_signers([] {
416 constexpr int numSigners = UT_XCHAIN_DEFAULT_NUM_SIGNERS;
417 std::vector<signer> result;
418 result.reserve(numSigners);
419 for (int i = 0; i < numSigners; ++i)
420 {
421 using namespace std::literals;
422 auto const a = Account(
423 "alt_signer_"s + std::to_string(i),
425 result.emplace_back(a);
426 }
427 return result;
428 }())
429 , payee([&] {
431 r.reserve(signers.size());
432 for (int i = 0, e = signers.size(); i != e; ++i)
433 {
434 r.push_back(scReward);
435 }
436 return r;
437 }())
438 , payees([&] {
440 r.reserve(signers.size());
441 for (int i = 0, e = signers.size(); i != e; ++i)
442 {
443 using namespace std::literals;
444 auto const a = Account("reward_"s + std::to_string(i));
445 r.push_back(a);
446 }
447 return r;
448 }())
450 , reward(XRP(1))
451 , split_reward_quorum(
452 divide(reward, STAmount(UT_XCHAIN_DEFAULT_QUORUM), reward.issue()))
453 , split_reward_everyone(divide(
454 reward,
456 reward.issue()))
457 , tiny_reward(drops(37))
458 , tiny_reward_split((divide(
459 tiny_reward,
460 STAmount(UT_XCHAIN_DEFAULT_QUORUM),
461 tiny_reward.issue())))
462 , tiny_reward_remainder(
463 tiny_reward -
464 multiply(
465 tiny_reward_split,
466 STAmount(UT_XCHAIN_DEFAULT_QUORUM),
467 tiny_reward.issue()))
468 , one_xrp(XRP(1))
469 , xrp_dust(divide(one_xrp, STAmount(10000), one_xrp.issue()))
470{
471}
472
473void
475{
476 STAmount xrp_funds{XRP(10000)};
477 mcEnv.fund(xrp_funds, mcDoor, mcAlice, mcBob, mcCarol, mcGw);
478
479 // Signer's list must match the attestation signers
480 mcEnv(jtx::signers(mcDoor, signers.size(), signers));
481
482 // create XRP bridges in both direction
483 auto const reward = XRP(1);
484 STAmount const minCreate = XRP(20);
485
486 mcEnv(bridge_create(mcDoor, jvb, reward, minCreate));
487 mcEnv.close();
488}
489
490void
492{
493 STAmount xrp_funds{XRP(10000)};
494 scEnv.fund(
496
497 // Signer's list must match the attestation signers
499
500 // create XRP bridges in both direction
501 auto const reward = XRP(1);
502 STAmount const minCreate = XRP(20);
503
504 scEnv(bridge_create(Account::master, jvb, reward, minCreate));
505 scEnv.close();
506}
507
508void
510{
513}
514} // namespace jtx
515} // namespace test
516} // namespace ripple
Represents a JSON value.
Definition: json_value.h:150
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:719
A currency issued by an account.
Definition: Issue.h:36
Json::Value getJson(JsonOptions=JsonOptions::none) const override
Definition: STAmount.cpp:639
Immutable cryptographic account descriptor.
Definition: Account.h:39
PublicKey const & pk() const
Return the public key.
Definition: Account.h:90
static Account const master
The master account.
Definition: Account.h:48
SecretKey const & sk() const
Return the secret key.
Definition: Account.h:97
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:114
A transaction testing environment.
Definition: Env.h:121
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:117
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:233
Set the regular signature on a JTx.
Definition: sig.h:35
T emplace_back(T... args)
constexpr std::size_t UT_XCHAIN_DEFAULT_QUORUM
Definition: xchain_bridge.h:38
Json::Value create_account_attestation(jtx::Account const &submittingAccount, Json::Value const &jvBridge, jtx::Account const &sendingAccount, jtx::AnyAmount const &sendingAmount, jtx::AnyAmount const &rewardAmount, jtx::Account const &rewardAccount, bool wasLockingChainSend, std::uint64_t createCount, jtx::Account const &dst, jtx::signer const &signer)
JValueVec claim_attestations(jtx::Account const &submittingAccount, Json::Value const &jvBridge, jtx::Account const &sendingAccount, jtx::AnyAmount const &sendingAmount, std::vector< jtx::Account > const &rewardAccounts, bool wasLockingChainSend, std::uint64_t claimID, std::optional< jtx::Account > const &dst, std::vector< jtx::signer > const &signers, std::size_t const numAtts, std::size_t const fromIdx)
Json::Value bridge_create(Account const &acc, Json::Value const &bridge, STAmount const &reward, std::optional< STAmount > const &minAccountCreate)
Json::Value claim_attestation(jtx::Account const &submittingAccount, Json::Value const &jvBridge, jtx::Account const &sendingAccount, jtx::AnyAmount const &sendingAmount, jtx::Account const &rewardAccount, bool wasLockingChainSend, std::uint64_t claimID, std::optional< jtx::Account > const &dst, jtx::signer const &signer)
Json::Value bridge(Account const &lockingChainDoor, Issue const &lockingChainIssue, Account const &issuingChainDoor, Issue const &issuingChainIssue)
Json::Value signers(Account const &account, std::uint32_t quorum, std::vector< signer > const &v)
Definition: multisign.cpp:34
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value sidechain_xchain_account_create(Account const &acc, Json::Value const &bridge, Account const &dst, AnyAmount const &amt, AnyAmount const &reward)
Json::Value xchain_claim(Account const &acc, Json::Value const &bridge, std::uint32_t claimID, AnyAmount const &amt, Account const &dst)
constexpr std::size_t UT_XCHAIN_DEFAULT_NUM_SIGNERS
Definition: xchain_bridge.h:37
JValueVec create_account_attestations(jtx::Account const &submittingAccount, Json::Value const &jvBridge, jtx::Account const &sendingAccount, jtx::AnyAmount const &sendingAmount, jtx::AnyAmount const &rewardAmount, std::vector< jtx::Account > const &rewardAccounts, bool wasLockingChainSend, std::uint64_t createCount, jtx::Account const &dst, std::vector< jtx::signer > const &signers, std::size_t const numAtts, std::size_t const fromIdx)
Json::Value xchain_create_claim_id(Account const &acc, Json::Value const &bridge, STAmount const &reward, Account const &otherChainSource)
Json::Value bridge_modify(Account const &acc, Json::Value const &bridge, std::optional< STAmount > const &reward, std::optional< STAmount > const &minAccountCreate)
Buffer sign_claim_attestation(PublicKey const &pk, SecretKey const &sk, STXChainBridge const &bridge, AccountID const &sendingAccount, STAmount const &sendingAmount, AccountID const &rewardAccount, bool wasLockingChainSend, std::uint64_t claimID, std::optional< AccountID > const &dst)
Definition: attester.cpp:32
Json::Value xchain_commit(Account const &acc, Json::Value const &bridge, std::uint32_t claimID, AnyAmount const &amt, std::optional< Account > const &dst)
Buffer sign_create_account_attestation(PublicKey const &pk, SecretKey const &sk, STXChainBridge const &bridge, AccountID const &sendingAccount, STAmount const &sendingAmount, STAmount const &rewardAmount, AccountID const &rewardAccount, bool wasLockingChainSend, std::uint64_t createCount, AccountID const &dst)
Definition: attester.cpp:55
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:105
FeatureBitset supported_amendments()
Definition: Env.h:74
Json::Value bridge_rpc(Account const &lockingChainDoor, Issue const &lockingChainIssue, Account const &issuingChainDoor, Issue const &issuingChainIssue)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:118
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:114
STAmount divide(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:93
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:53
Json::Value to_json(Asset const &asset)
Definition: Asset.h:123
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
constexpr std::uint32_t tfUniversal
Definition: TxFlags.h:61
T reserve(T... args)
Amount specifier with an option for any issuer.
std::vector< signer > const signers
void createBridgeObjects(Env &mcEnv, Env &scEnv)
A signer in a SignerList.
Definition: multisign.h:38
T to_string(T... args)