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#include <xrpl/json/json_value.h>
24#include <xrpl/protocol/Issue.h>
25#include <xrpl/protocol/SField.h>
26#include <xrpl/protocol/STBase.h>
27#include <xrpl/protocol/STInteger.h>
28#include <xrpl/protocol/STObject.h>
29#include <xrpl/protocol/TxFlags.h>
30#include <xrpl/protocol/XChainAttestations.h>
31#include <xrpl/protocol/jss.h>
32
33namespace ripple {
34namespace test {
35namespace jtx {
36
37// use this for creating a bridge for a transaction
40 Account const& lockingChainDoor,
41 Issue const& lockingChainIssue,
42 Account const& issuingChainDoor,
43 Issue const& issuingChainIssue)
44{
45 Json::Value jv;
46 jv[sfLockingChainDoor.getJsonName()] = lockingChainDoor.human();
47 jv[sfLockingChainIssue.getJsonName()] = to_json(lockingChainIssue);
48 jv[sfIssuingChainDoor.getJsonName()] = issuingChainDoor.human();
49 jv[sfIssuingChainIssue.getJsonName()] = to_json(issuingChainIssue);
50 return jv;
51}
52
53// use this for creating a bridge for a rpc query
56 Account const& lockingChainDoor,
57 Issue const& lockingChainIssue,
58 Account const& issuingChainDoor,
59 Issue const& issuingChainIssue)
60{
61 Json::Value jv;
62 jv[sfLockingChainDoor.getJsonName()] = lockingChainDoor.human();
63 jv[sfLockingChainIssue.getJsonName()] = to_json(lockingChainIssue);
64 jv[sfIssuingChainDoor.getJsonName()] = issuingChainDoor.human();
65 jv[sfIssuingChainIssue.getJsonName()] = to_json(issuingChainIssue);
66 return jv;
67}
68
71 Account const& acc,
72 Json::Value const& bridge,
73 STAmount const& reward,
74 std::optional<STAmount> const& minAccountCreate)
75{
76 Json::Value jv;
77
78 jv[jss::Account] = acc.human();
79 jv[sfXChainBridge.getJsonName()] = bridge;
80 jv[sfSignatureReward.getJsonName()] = reward.getJson(JsonOptions::none);
81 if (minAccountCreate)
82 jv[sfMinAccountCreateAmount.getJsonName()] =
83 minAccountCreate->getJson(JsonOptions::none);
84
85 jv[jss::TransactionType] = jss::XChainCreateBridge;
86 jv[jss::Flags] = tfUniversal;
87 return jv;
88}
89
92 Account const& acc,
93 Json::Value const& bridge,
94 std::optional<STAmount> const& reward,
95 std::optional<STAmount> const& minAccountCreate)
96{
97 Json::Value jv;
98
99 jv[jss::Account] = acc.human();
100 jv[sfXChainBridge.getJsonName()] = bridge;
101 if (reward)
102 jv[sfSignatureReward.getJsonName()] =
103 reward->getJson(JsonOptions::none);
104 if (minAccountCreate)
105 jv[sfMinAccountCreateAmount.getJsonName()] =
106 minAccountCreate->getJson(JsonOptions::none);
107
108 jv[jss::TransactionType] = jss::XChainModifyBridge;
109 jv[jss::Flags] = tfUniversal;
110 return jv;
111}
112
115 Account const& acc,
116 Json::Value const& bridge,
117 STAmount const& reward,
118 Account const& otherChainSource)
119{
120 Json::Value jv;
121
122 jv[jss::Account] = acc.human();
123 jv[sfXChainBridge.getJsonName()] = bridge;
124 jv[sfSignatureReward.getJsonName()] = reward.getJson(JsonOptions::none);
125 jv[sfOtherChainSource.getJsonName()] = otherChainSource.human();
126
127 jv[jss::TransactionType] = jss::XChainCreateClaimID;
128 jv[jss::Flags] = tfUniversal;
129 return jv;
130}
131
134 Account const& acc,
135 Json::Value const& bridge,
136 std::uint32_t claimID,
137 AnyAmount const& amt,
138 std::optional<Account> const& dst)
139{
140 Json::Value jv;
141
142 jv[jss::Account] = acc.human();
143 jv[sfXChainBridge.getJsonName()] = bridge;
144 jv[sfXChainClaimID.getJsonName()] = claimID;
145 jv[jss::Amount] = amt.value.getJson(JsonOptions::none);
146 if (dst)
147 jv[sfOtherChainDestination.getJsonName()] = dst->human();
148
149 jv[jss::TransactionType] = jss::XChainCommit;
150 jv[jss::Flags] = tfUniversal;
151 return jv;
152}
153
156 Account const& acc,
157 Json::Value const& bridge,
158 std::uint32_t claimID,
159 AnyAmount const& amt,
160 Account const& dst)
161{
162 Json::Value jv;
163
164 jv[sfAccount.getJsonName()] = acc.human();
165 jv[sfXChainBridge.getJsonName()] = bridge;
166 jv[sfXChainClaimID.getJsonName()] = claimID;
167 jv[sfDestination.getJsonName()] = dst.human();
168 jv[sfAmount.getJsonName()] = amt.value.getJson(JsonOptions::none);
169
170 jv[jss::TransactionType] = jss::XChainClaim;
171 jv[jss::Flags] = tfUniversal;
172 return jv;
173}
174
177 Account const& acc,
178 Json::Value const& bridge,
179 Account const& dst,
180 AnyAmount const& amt,
181 AnyAmount const& reward)
182{
183 Json::Value jv;
184
185 jv[sfAccount.getJsonName()] = acc.human();
186 jv[sfXChainBridge.getJsonName()] = bridge;
187 jv[sfDestination.getJsonName()] = dst.human();
188 jv[sfAmount.getJsonName()] = amt.value.getJson(JsonOptions::none);
189 jv[sfSignatureReward.getJsonName()] =
191
192 jv[jss::TransactionType] = jss::XChainAccountCreateCommit;
193 jv[jss::Flags] = tfUniversal;
194 return jv;
195}
196
199 jtx::Account const& submittingAccount,
200 Json::Value const& jvBridge,
201 jtx::Account const& sendingAccount,
202 jtx::AnyAmount const& sendingAmount,
203 jtx::Account const& rewardAccount,
204 bool wasLockingChainSend,
205 std::uint64_t claimID,
207 jtx::signer const& signer)
208{
209 STXChainBridge const stBridge(jvBridge);
210
211 auto const& pk = signer.account.pk();
212 auto const& sk = signer.account.sk();
213 auto const sig = sign_claim_attestation(
214 pk,
215 sk,
216 stBridge,
217 sendingAccount,
218 sendingAmount.value,
219 rewardAccount,
220 wasLockingChainSend,
221 claimID,
222 dst);
223
224 Json::Value result;
225
226 result[sfAccount.getJsonName()] = submittingAccount.human();
227 result[sfXChainBridge.getJsonName()] = jvBridge;
228
229 result[sfAttestationSignerAccount.getJsonName()] = signer.account.human();
230 result[sfPublicKey.getJsonName()] = strHex(pk.slice());
231 result[sfSignature.getJsonName()] = strHex(sig);
232 result[sfOtherChainSource.getJsonName()] = toBase58(sendingAccount);
233 result[sfAmount.getJsonName()] =
234 sendingAmount.value.getJson(JsonOptions::none);
235 result[sfAttestationRewardAccount.getJsonName()] = toBase58(rewardAccount);
236 result[sfWasLockingChainSend.getJsonName()] = wasLockingChainSend ? 1 : 0;
237
238 result[sfXChainClaimID.getJsonName()] =
239 STUInt64{claimID}.getJson(JsonOptions::none);
240 if (dst)
241 result[sfDestination.getJsonName()] = toBase58(*dst);
242
243 result[jss::TransactionType] = jss::XChainAddClaimAttestation;
244 result[jss::Flags] = tfUniversal;
245
246 return result;
247}
248
251 jtx::Account const& submittingAccount,
252 Json::Value const& jvBridge,
253 jtx::Account const& sendingAccount,
254 jtx::AnyAmount const& sendingAmount,
255 jtx::AnyAmount const& rewardAmount,
256 jtx::Account const& rewardAccount,
257 bool wasLockingChainSend,
258 std::uint64_t createCount,
259 jtx::Account const& dst,
260 jtx::signer const& signer)
261{
262 STXChainBridge const stBridge(jvBridge);
263
264 auto const& pk = signer.account.pk();
265 auto const& sk = signer.account.sk();
267 pk,
268 sk,
269 stBridge,
270 sendingAccount,
271 sendingAmount.value,
272 rewardAmount.value,
273 rewardAccount,
274 wasLockingChainSend,
275 createCount,
276 dst);
277
278 Json::Value result;
279
280 result[sfAccount.getJsonName()] = submittingAccount.human();
281 result[sfXChainBridge.getJsonName()] = jvBridge;
282
283 result[sfAttestationSignerAccount.getJsonName()] = signer.account.human();
284 result[sfPublicKey.getJsonName()] = strHex(pk.slice());
285 result[sfSignature.getJsonName()] = strHex(sig);
286 result[sfOtherChainSource.getJsonName()] = toBase58(sendingAccount);
287 result[sfAmount.getJsonName()] =
288 sendingAmount.value.getJson(JsonOptions::none);
289 result[sfAttestationRewardAccount.getJsonName()] = toBase58(rewardAccount);
290 result[sfWasLockingChainSend.getJsonName()] = wasLockingChainSend ? 1 : 0;
291
292 result[sfXChainAccountCreateCount.getJsonName()] =
293 STUInt64{createCount}.getJson(JsonOptions::none);
294 result[sfDestination.getJsonName()] = toBase58(dst);
295 result[sfSignatureReward.getJsonName()] =
296 rewardAmount.value.getJson(JsonOptions::none);
297
298 result[jss::TransactionType] = jss::XChainAddAccountCreateAttestation;
299 result[jss::Flags] = tfUniversal;
300
301 return result;
302}
303
306 jtx::Account const& submittingAccount,
307 Json::Value const& jvBridge,
308 jtx::Account const& sendingAccount,
309 jtx::AnyAmount const& sendingAmount,
310 std::vector<jtx::Account> const& rewardAccounts,
311 bool wasLockingChainSend,
312 std::uint64_t claimID,
315 std::size_t const numAtts,
316 std::size_t const fromIdx)
317{
318 assert(fromIdx + numAtts <= rewardAccounts.size());
319 assert(fromIdx + numAtts <= signers.size());
320 JValueVec vec;
321 vec.reserve(numAtts);
322 for (auto i = fromIdx; i < fromIdx + numAtts; ++i)
324 submittingAccount,
325 jvBridge,
326 sendingAccount,
327 sendingAmount,
328 rewardAccounts[i],
329 wasLockingChainSend,
330 claimID,
331 dst,
332 signers[i]));
333 return vec;
334}
335
338 jtx::Account const& submittingAccount,
339 Json::Value const& jvBridge,
340 jtx::Account const& sendingAccount,
341 jtx::AnyAmount const& sendingAmount,
342 jtx::AnyAmount const& rewardAmount,
343 std::vector<jtx::Account> const& rewardAccounts,
344 bool wasLockingChainSend,
345 std::uint64_t createCount,
346 jtx::Account const& dst,
348 std::size_t const numAtts,
349 std::size_t const fromIdx)
350{
351 assert(fromIdx + numAtts <= rewardAccounts.size());
352 assert(fromIdx + numAtts <= signers.size());
353 JValueVec vec;
354 vec.reserve(numAtts);
355 for (auto i = fromIdx; i < fromIdx + numAtts; ++i)
357 submittingAccount,
358 jvBridge,
359 sendingAccount,
360 sendingAmount,
361 rewardAmount,
362 rewardAccounts[i],
363 wasLockingChainSend,
364 createCount,
365 dst,
366 signers[i]));
367 return vec;
368}
369
371 : mcDoor("mcDoor")
372 , mcAlice("mcAlice")
373 , mcBob("mcBob")
374 , mcCarol("mcCarol")
375 , mcGw("mcGw")
376 , scDoor("scDoor")
377 , scAlice("scAlice")
378 , scBob("scBob")
379 , scCarol("scCarol")
380 , scGw("scGw")
381 , scAttester("scAttester")
382 , scReward("scReward")
383 , mcuDoor("mcuDoor")
384 , mcuAlice("mcuAlice")
385 , mcuBob("mcuBob")
386 , mcuCarol("mcuCarol")
387 , mcuGw("mcuGw")
388 , scuDoor("scuDoor")
389 , scuAlice("scuAlice")
390 , scuBob("scuBob")
391 , scuCarol("scuCarol")
392 , scuGw("scuGw")
393 , mcUSD(mcGw["USD"])
394 , scUSD(scGw["USD"])
395 , jvXRPBridgeRPC(
396 bridge_rpc(mcDoor, xrpIssue(), Account::master, xrpIssue()))
397 , jvb(bridge(mcDoor, xrpIssue(), Account::master, xrpIssue()))
398 , jvub(bridge(mcuDoor, xrpIssue(), Account::master, xrpIssue()))
399 , features(supported_amendments() | FeatureBitset{featureXChainBridge})
400 , signers([] {
401 constexpr int numSigners = UT_XCHAIN_DEFAULT_NUM_SIGNERS;
402 std::vector<signer> result;
403 result.reserve(numSigners);
404 for (int i = 0; i < numSigners; ++i)
405 {
406 using namespace std::literals;
407 auto const a = Account(
408 "signer_"s + std::to_string(i),
410 result.emplace_back(a);
411 }
412 return result;
413 }())
414 , alt_signers([] {
415 constexpr int numSigners = UT_XCHAIN_DEFAULT_NUM_SIGNERS;
416 std::vector<signer> result;
417 result.reserve(numSigners);
418 for (int i = 0; i < numSigners; ++i)
419 {
420 using namespace std::literals;
421 auto const a = Account(
422 "alt_signer_"s + std::to_string(i),
424 result.emplace_back(a);
425 }
426 return result;
427 }())
428 , payee([&] {
430 r.reserve(signers.size());
431 for (int i = 0, e = signers.size(); i != e; ++i)
432 {
433 r.push_back(scReward);
434 }
435 return r;
436 }())
437 , payees([&] {
439 r.reserve(signers.size());
440 for (int i = 0, e = signers.size(); i != e; ++i)
441 {
442 using namespace std::literals;
443 auto const a = Account("reward_"s + std::to_string(i));
444 r.push_back(a);
445 }
446 return r;
447 }())
449 , reward(XRP(1))
450 , split_reward_quorum(
451 divide(reward, STAmount(UT_XCHAIN_DEFAULT_QUORUM), reward.issue()))
452 , split_reward_everyone(divide(
453 reward,
455 reward.issue()))
456 , tiny_reward(drops(37))
457 , tiny_reward_split((divide(
458 tiny_reward,
459 STAmount(UT_XCHAIN_DEFAULT_QUORUM),
460 tiny_reward.issue())))
461 , tiny_reward_remainder(
462 tiny_reward -
463 multiply(
464 tiny_reward_split,
465 STAmount(UT_XCHAIN_DEFAULT_QUORUM),
466 tiny_reward.issue()))
467 , one_xrp(XRP(1))
468 , xrp_dust(divide(one_xrp, STAmount(10000), one_xrp.issue()))
469{
470}
471
472void
474{
475 STAmount xrp_funds{XRP(10000)};
476 mcEnv.fund(xrp_funds, mcDoor, mcAlice, mcBob, mcCarol, mcGw);
477
478 // Signer's list must match the attestation signers
479 mcEnv(jtx::signers(mcDoor, signers.size(), signers));
480
481 // create XRP bridges in both direction
482 auto const reward = XRP(1);
483 STAmount const minCreate = XRP(20);
484
485 mcEnv(bridge_create(mcDoor, jvb, reward, minCreate));
486 mcEnv.close();
487}
488
489void
491{
492 STAmount xrp_funds{XRP(10000)};
493 scEnv.fund(
495
496 // Signer's list must match the attestation signers
498
499 // create XRP bridges in both direction
500 auto const reward = XRP(1);
501 STAmount const minCreate = XRP(20);
502
503 scEnv(bridge_create(Account::master, jvb, reward, minCreate));
504 scEnv.close();
505}
506
507void
509{
512}
513} // namespace jtx
514} // namespace test
515} // namespace ripple
Represents a JSON value.
Definition: json_value.h:148
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:712
A currency issued by an account.
Definition: Issue.h:36
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:636
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:118
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:115
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:231
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:37
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:33
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:36
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:31
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:54
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:104
FeatureBitset supported_amendments()
Definition: Env.h:71
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.cpp:82
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)