mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
gRPC support for account_tx and tx
- Add support for all transaction types and ledger object types to gRPC implementation of tx and account_tx. - Create common handlers for tx and account_tx. - Remove mutex and abort() from gRPC server. JobQueue is stopped before gRPC server, with all coroutines executed to completion, so no need for synchronization.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -82,25 +82,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/** Set InvoiceID on a JTx. */
|
||||
class invoice_id
|
||||
{
|
||||
private:
|
||||
uint256 const id_;
|
||||
|
||||
public:
|
||||
explicit invoice_id (uint256 const& id)
|
||||
: id_{id}
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jt) const
|
||||
{
|
||||
jt[sfInvoiceID.jsonName] = to_string (id_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace jtx
|
||||
} // namespace test
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <ripple/json/to_string.h>
|
||||
#include <test/jtx/Account.h>
|
||||
#include <test/jtx/account_txn_id.h>
|
||||
#include <test/jtx/acctdelete.h>
|
||||
#include <test/jtx/amount.h>
|
||||
#include <test/jtx/balance.h>
|
||||
@@ -34,8 +35,10 @@
|
||||
#include <test/jtx/Env_ss.h>
|
||||
#include <test/jtx/fee.h>
|
||||
#include <test/jtx/flags.h>
|
||||
#include <test/jtx/invoice_id.h>
|
||||
#include <test/jtx/jtx_json.h>
|
||||
#include <test/jtx/JTx.h>
|
||||
#include <test/jtx/last_ledger_sequence.h>
|
||||
#include <test/jtx/memo.h>
|
||||
#include <test/jtx/multisign.h>
|
||||
#include <test/jtx/noop.h>
|
||||
|
||||
42
src/test/jtx/account_txn_id.h
Normal file
42
src/test/jtx/account_txn_id.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TEST_JTX_ACCOUNT_TXN_ID_H_INCLUDED
|
||||
#define RIPPLE_TEST_JTX_ACCOUNT_TXN_ID_H_INCLUDED
|
||||
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace jtx {
|
||||
|
||||
struct account_txn_id
|
||||
{
|
||||
private:
|
||||
uint256 hash_;
|
||||
public:
|
||||
explicit account_txn_id(uint256 const& hash) : hash_(hash) {}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jt) const;
|
||||
};
|
||||
} // jtx
|
||||
} // test
|
||||
} // ripple
|
||||
#endif
|
||||
35
src/test/jtx/impl/account_txn_id.cpp
Normal file
35
src/test/jtx/impl/account_txn_id.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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 <test/jtx/account_txn_id.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace jtx {
|
||||
|
||||
void
|
||||
account_txn_id::operator()(Env&, JTx& jt) const
|
||||
{
|
||||
if (!hash_.isZero())
|
||||
jt["AccountTxnID"] = strHex(hash_);
|
||||
}
|
||||
|
||||
} // jtx
|
||||
} // test
|
||||
} // ripple
|
||||
36
src/test/jtx/impl/invoice_id.cpp
Normal file
36
src/test/jtx/impl/invoice_id.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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 <test/jtx/invoice_id.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace jtx {
|
||||
|
||||
void
|
||||
invoice_id::operator()(Env&, JTx& jt) const
|
||||
{
|
||||
if (!hash_.isZero())
|
||||
jt["InvoiceID"] = strHex(hash_);
|
||||
}
|
||||
|
||||
} // jtx
|
||||
} // test
|
||||
} // ripple
|
||||
37
src/test/jtx/impl/last_ledger_sequence.cpp
Normal file
37
src/test/jtx/impl/last_ledger_sequence.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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 <test/jtx/last_ledger_sequence.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace jtx {
|
||||
|
||||
|
||||
void
|
||||
last_ledger_seq::operator()(Env&, JTx& jt) const
|
||||
{
|
||||
jt["LastLedgerSequence"] = num_;
|
||||
}
|
||||
|
||||
} // jtx
|
||||
} // test
|
||||
} // ripple
|
||||
|
||||
42
src/test/jtx/invoice_id.h
Normal file
42
src/test/jtx/invoice_id.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TEST_JTX_INVOICE_ID_H_INCLUDED
|
||||
#define RIPPLE_TEST_JTX_INVOICE_ID_H_INCLUDED
|
||||
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace jtx {
|
||||
|
||||
struct invoice_id
|
||||
{
|
||||
private:
|
||||
uint256 hash_;
|
||||
public:
|
||||
explicit invoice_id(uint256 const& hash) : hash_(hash) {}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jt) const;
|
||||
};
|
||||
} // jtx
|
||||
} // test
|
||||
} // ripple
|
||||
#endif
|
||||
44
src/test/jtx/last_ledger_sequence.h
Normal file
44
src/test/jtx/last_ledger_sequence.h
Normal file
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TEST_JTX_LAST_LEDGER_SEQUENCE_H_INCLUDED
|
||||
#define RIPPLE_TEST_JTX_LAST_LEDGER_SEQUENCE_H_INCLUDED
|
||||
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace jtx {
|
||||
|
||||
struct last_ledger_seq
|
||||
{
|
||||
private:
|
||||
std::uint32_t num_;
|
||||
public:
|
||||
explicit last_ledger_seq(std::uint32_t num) : num_(num) {}
|
||||
|
||||
void
|
||||
operator()(Env&, JTx& jt) const;
|
||||
};
|
||||
|
||||
} // jtx
|
||||
} // test
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
@@ -324,8 +324,8 @@ public:
|
||||
class GetAccountInfoClient : public GRPCTestClientBase
|
||||
{
|
||||
public:
|
||||
rpc::v1::GetAccountInfoRequest request;
|
||||
rpc::v1::GetAccountInfoResponse reply;
|
||||
org::xrpl::rpc::v1::GetAccountInfoRequest request;
|
||||
org::xrpl::rpc::v1::GetAccountInfoResponse reply;
|
||||
|
||||
explicit GetAccountInfoClient(std::string const& port)
|
||||
: GRPCTestClientBase(port)
|
||||
@@ -358,11 +358,10 @@ public:
|
||||
client.GetAccountInfo();
|
||||
if (!BEAST_EXPECT(client.status.ok()))
|
||||
{
|
||||
std::cout << client.reply.DebugString() << std::endl;
|
||||
return;
|
||||
}
|
||||
BEAST_EXPECT(
|
||||
client.reply.account_data().account().address() ==
|
||||
client.reply.account_data().account().value().address() ==
|
||||
alice.human());
|
||||
}
|
||||
{
|
||||
@@ -374,13 +373,13 @@ public:
|
||||
if (!BEAST_EXPECT(client.status.ok()))
|
||||
return;
|
||||
BEAST_EXPECT(
|
||||
client.reply.account_data().balance().drops() ==
|
||||
client.reply.account_data().balance().value().xrp_amount().drops() ==
|
||||
1000 * 1000 * 1000);
|
||||
BEAST_EXPECT(
|
||||
client.reply.account_data().account().address() ==
|
||||
client.reply.account_data().account().value().address() ==
|
||||
alice.human());
|
||||
BEAST_EXPECT(
|
||||
client.reply.account_data().sequence() == env.seq(alice));
|
||||
client.reply.account_data().sequence().value() == env.seq(alice));
|
||||
BEAST_EXPECT(client.reply.queue_data().txn_count() == 0);
|
||||
}
|
||||
}
|
||||
@@ -473,7 +472,7 @@ public:
|
||||
{
|
||||
return;
|
||||
}
|
||||
BEAST_EXPECT(client.reply.account_data().owner_count() == 1);
|
||||
BEAST_EXPECT(client.reply.account_data().owner_count().value() == 1);
|
||||
BEAST_EXPECT(client.reply.signer_list().signer_entries_size() == 1);
|
||||
}
|
||||
|
||||
@@ -518,16 +517,16 @@ public:
|
||||
{
|
||||
return;
|
||||
}
|
||||
BEAST_EXPECT(client.reply.account_data().owner_count() == 1);
|
||||
BEAST_EXPECT(client.reply.account_data().owner_count().value() == 1);
|
||||
auto& signerList = client.reply.signer_list();
|
||||
BEAST_EXPECT(signerList.signer_quorum() == 4);
|
||||
BEAST_EXPECT(signerList.signer_quorum().value() == 4);
|
||||
BEAST_EXPECT(signerList.signer_entries_size() == 8);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
BEAST_EXPECT(signerList.signer_entries(i).signer_weight() == 1);
|
||||
BEAST_EXPECT(signerList.signer_entries(i).signer_weight().value() == 1);
|
||||
BEAST_EXPECT(
|
||||
accounts.erase(
|
||||
signerList.signer_entries(i).account().address()) == 1);
|
||||
signerList.signer_entries(i).account().value().address()) == 1);
|
||||
}
|
||||
BEAST_EXPECT(accounts.size() == 0);
|
||||
}
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/rpc/GRPCHandlers.h>
|
||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||
#include <test/rpc/GRPCTestClientBase.h>
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/jtx/envconfig.h>
|
||||
|
||||
#include <ripple/rpc/GRPCHandlers.h>
|
||||
#include <test/rpc/GRPCTestClientBase.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
@@ -39,8 +39,8 @@ class Fee_test : public beast::unit_test::suite
|
||||
class GrpcFeeClient : public GRPCTestClientBase
|
||||
{
|
||||
public:
|
||||
rpc::v1::GetFeeRequest request;
|
||||
rpc::v1::GetFeeResponse reply;
|
||||
org::xrpl::rpc::v1::GetFeeRequest request;
|
||||
org::xrpl::rpc::v1::GetFeeResponse reply;
|
||||
|
||||
explicit GrpcFeeClient(std::string const& grpcPort)
|
||||
: GRPCTestClientBase(grpcPort)
|
||||
@@ -54,12 +54,12 @@ class Fee_test : public beast::unit_test::suite
|
||||
}
|
||||
};
|
||||
|
||||
std::pair<bool, rpc::v1::GetFeeResponse>
|
||||
std::pair<bool, org::xrpl::rpc::v1::GetFeeResponse>
|
||||
grpcGetFee(std::string const& grpcPort)
|
||||
{
|
||||
GrpcFeeClient client(grpcPort);
|
||||
client.GetFee();
|
||||
return std::pair<bool, rpc::v1::GetFeeResponse>(
|
||||
return std::pair<bool, org::xrpl::rpc::v1::GetFeeResponse>(
|
||||
client.status.ok(), client.reply);
|
||||
}
|
||||
|
||||
@@ -104,29 +104,29 @@ class Fee_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(reply.max_queue_size() == *metrics.txQMaxSize);
|
||||
|
||||
// fee levels data
|
||||
rpc::v1::FeeLevels& levels = *reply.mutable_levels();
|
||||
org::xrpl::rpc::v1::FeeLevels& levels = *reply.mutable_levels();
|
||||
BEAST_EXPECT(levels.median_level() == metrics.medFeeLevel);
|
||||
BEAST_EXPECT(levels.minimum_level() == metrics.minProcessingFeeLevel);
|
||||
BEAST_EXPECT(levels.open_ledger_level() == metrics.openLedgerFeeLevel);
|
||||
BEAST_EXPECT(levels.reference_level() == metrics.referenceFeeLevel);
|
||||
|
||||
// fee data
|
||||
rpc::v1::Fee& drops = *reply.mutable_drops();
|
||||
org::xrpl::rpc::v1::Fee& fee = *reply.mutable_fee();
|
||||
auto const baseFee = view->fees().base;
|
||||
BEAST_EXPECT(
|
||||
drops.base_fee().drops() ==
|
||||
fee.base_fee().drops() ==
|
||||
toDrops(metrics.referenceFeeLevel, baseFee).second);
|
||||
BEAST_EXPECT(
|
||||
drops.minimum_fee().drops() ==
|
||||
fee.minimum_fee().drops() ==
|
||||
toDrops(metrics.minProcessingFeeLevel, baseFee).second);
|
||||
BEAST_EXPECT(
|
||||
drops.median_fee().drops() ==
|
||||
fee.median_fee().drops() ==
|
||||
toDrops(metrics.medFeeLevel, baseFee).second);
|
||||
auto openLedgerFee =
|
||||
toDrops(metrics.openLedgerFeeLevel - FeeLevel64{1}, baseFee)
|
||||
.second +
|
||||
1;
|
||||
BEAST_EXPECT(drops.open_ledger_fee().drops() == openLedgerFee.drops());
|
||||
BEAST_EXPECT(fee.open_ledger_fee().drops() == openLedgerFee.drops());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef RIPPLED_GRPCTESTCLIENTBASE_H
|
||||
#define RIPPLED_GRPCTESTCLIENTBASE_H
|
||||
|
||||
#include <rpc/v1/xrp_ledger.grpc.pb.h>
|
||||
#include <org/xrpl/rpc/v1/xrp_ledger.grpc.pb.h>
|
||||
#include <test/jtx/envconfig.h>
|
||||
|
||||
namespace ripple {
|
||||
@@ -29,7 +29,7 @@ namespace test {
|
||||
struct GRPCTestClientBase
|
||||
{
|
||||
explicit GRPCTestClientBase(std::string const& port)
|
||||
: stub_(rpc::v1::XRPLedgerAPIService::NewStub(grpc::CreateChannel(
|
||||
: stub_(org::xrpl::rpc::v1::XRPLedgerAPIService::NewStub(grpc::CreateChannel(
|
||||
beast::IP::Endpoint(
|
||||
boost::asio::ip::make_address(getEnvLocalhostAddr()),
|
||||
std::stoi(port))
|
||||
@@ -40,7 +40,7 @@ struct GRPCTestClientBase
|
||||
|
||||
grpc::Status status;
|
||||
grpc::ClientContext context;
|
||||
std::unique_ptr<rpc::v1::XRPLedgerAPIService::Stub> stub_;
|
||||
std::unique_ptr<org::xrpl::rpc::v1::XRPLedgerAPIService::Stub> stub_;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
@@ -36,8 +36,8 @@ public:
|
||||
class SubmitClient : public GRPCTestClientBase
|
||||
{
|
||||
public:
|
||||
rpc::v1::SubmitTransactionRequest request;
|
||||
rpc::v1::SubmitTransactionResponse reply;
|
||||
org::xrpl::rpc::v1::SubmitTransactionRequest request;
|
||||
org::xrpl::rpc::v1::SubmitTransactionResponse reply;
|
||||
|
||||
explicit SubmitClient(std::string const& port)
|
||||
: GRPCTestClientBase(port)
|
||||
|
||||
@@ -29,9 +29,12 @@
|
||||
#include <test/jtx/envconfig.h>
|
||||
|
||||
#include <ripple/rpc/GRPCHandlers.h>
|
||||
#include <ripple/rpc/impl/GRPCHelpers.h>
|
||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||
#include <test/rpc/GRPCTestClientBase.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
@@ -46,16 +49,23 @@ class Tx_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
cmpAmount(const rpc::v1::CurrencyAmount& proto_amount, STAmount amount)
|
||||
cmpAmount(
|
||||
const org::xrpl::rpc::v1::CurrencyAmount& proto_amount,
|
||||
STAmount amount)
|
||||
{
|
||||
if (amount.native())
|
||||
{
|
||||
if (!BEAST_EXPECT(proto_amount.has_xrp_amount()))
|
||||
return;
|
||||
BEAST_EXPECT(
|
||||
proto_amount.xrp_amount().drops() == amount.xrp().drops());
|
||||
}
|
||||
else
|
||||
{
|
||||
rpc::v1::IssuedCurrencyAmount issuedCurrency =
|
||||
if (!BEAST_EXPECT(proto_amount.has_issued_currency_amount()))
|
||||
return;
|
||||
|
||||
org::xrpl::rpc::v1::IssuedCurrencyAmount issuedCurrency =
|
||||
proto_amount.issued_currency_amount();
|
||||
Issue const& issue = amount.issue();
|
||||
Currency currency = issue.currency;
|
||||
@@ -70,60 +80,183 @@ class Tx_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
cmpTx(const rpc::v1::Transaction& proto, std::shared_ptr<STTx const> txnSt)
|
||||
cmpPaymentTx(
|
||||
const org::xrpl::rpc::v1::Transaction& proto,
|
||||
std::shared_ptr<STTx const> txnSt)
|
||||
{
|
||||
if (!BEAST_EXPECT(proto.has_payment()))
|
||||
return;
|
||||
|
||||
if (!BEAST_EXPECT(
|
||||
safe_cast<TxType>(txnSt->getFieldU16(sfTransactionType)) ==
|
||||
TxType::ttPAYMENT))
|
||||
return;
|
||||
|
||||
AccountID account = txnSt->getAccountID(sfAccount);
|
||||
BEAST_EXPECT(proto.account().address() == toBase58(account));
|
||||
|
||||
if (!BEAST_EXPECT(proto.has_account()))
|
||||
return;
|
||||
BEAST_EXPECT(proto.account().value().address() == toBase58(account));
|
||||
|
||||
STAmount amount = txnSt->getFieldAmount(sfAmount);
|
||||
cmpAmount(proto.payment().amount(), amount);
|
||||
if (!BEAST_EXPECT(proto.payment().has_amount()))
|
||||
return;
|
||||
cmpAmount(proto.payment().amount().value(), amount);
|
||||
|
||||
AccountID accountDest = txnSt->getAccountID(sfDestination);
|
||||
if (!BEAST_EXPECT(proto.payment().has_destination()))
|
||||
return;
|
||||
BEAST_EXPECT(
|
||||
proto.payment().destination().address() == toBase58(accountDest));
|
||||
proto.payment().destination().value().address() ==
|
||||
toBase58(accountDest));
|
||||
|
||||
STAmount fee = txnSt->getFieldAmount(sfFee);
|
||||
if (!BEAST_EXPECT(proto.has_fee()))
|
||||
return;
|
||||
BEAST_EXPECT(proto.fee().drops() == fee.xrp().drops());
|
||||
|
||||
BEAST_EXPECT(proto.sequence() == txnSt->getFieldU32(sfSequence));
|
||||
if (!BEAST_EXPECT(proto.has_sequence()))
|
||||
return;
|
||||
BEAST_EXPECT(
|
||||
proto.sequence().value() == txnSt->getFieldU32(sfSequence));
|
||||
|
||||
if (!BEAST_EXPECT(proto.has_signing_public_key()))
|
||||
return;
|
||||
|
||||
Blob signingPubKey = txnSt->getFieldVL(sfSigningPubKey);
|
||||
BEAST_EXPECT(proto.signing_public_key() == toByteString(signingPubKey));
|
||||
|
||||
BEAST_EXPECT(proto.flags() == txnSt->getFieldU32(sfFlags));
|
||||
|
||||
BEAST_EXPECT(
|
||||
proto.last_ledger_sequence() ==
|
||||
txnSt->getFieldU32(sfLastLedgerSequence));
|
||||
proto.signing_public_key().value() == toByteString(signingPubKey));
|
||||
|
||||
Blob blob = txnSt->getFieldVL(sfTxnSignature);
|
||||
BEAST_EXPECT(proto.signature() == toByteString(blob));
|
||||
if (txnSt->isFieldPresent(sfFlags))
|
||||
{
|
||||
if (!BEAST_EXPECT(proto.has_flags()))
|
||||
return;
|
||||
BEAST_EXPECT(proto.flags().value() == txnSt->getFieldU32(sfFlags));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!proto.has_flags());
|
||||
}
|
||||
|
||||
if (txnSt->isFieldPresent(sfLastLedgerSequence))
|
||||
{
|
||||
if (!BEAST_EXPECT(proto.has_last_ledger_sequence()))
|
||||
return;
|
||||
|
||||
BEAST_EXPECT(
|
||||
proto.last_ledger_sequence().value() ==
|
||||
txnSt->getFieldU32(sfLastLedgerSequence));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!proto.has_last_ledger_sequence());
|
||||
}
|
||||
|
||||
if (txnSt->isFieldPresent(sfTxnSignature))
|
||||
{
|
||||
if (!BEAST_EXPECT(proto.has_transaction_signature()))
|
||||
return;
|
||||
|
||||
Blob blob = txnSt->getFieldVL(sfTxnSignature);
|
||||
BEAST_EXPECT(
|
||||
proto.transaction_signature().value() == toByteString(blob));
|
||||
}
|
||||
|
||||
if (txnSt->isFieldPresent(sfSendMax))
|
||||
{
|
||||
if (!BEAST_EXPECT(proto.payment().has_send_max()))
|
||||
return;
|
||||
STAmount const& send_max = txnSt->getFieldAmount(sfSendMax);
|
||||
cmpAmount(proto.payment().send_max(), send_max);
|
||||
cmpAmount(proto.payment().send_max().value(), send_max);
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!proto.payment().has_send_max());
|
||||
}
|
||||
|
||||
if (txnSt->isFieldPresent(sfAccountTxnID))
|
||||
{
|
||||
if (!BEAST_EXPECT(proto.has_account_transaction_id()))
|
||||
return;
|
||||
auto field = txnSt->getFieldH256(sfAccountTxnID);
|
||||
BEAST_EXPECT(proto.account_transaction_id() == toByteString(field));
|
||||
BEAST_EXPECT(
|
||||
proto.account_transaction_id().value() == toByteString(field));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!proto.has_account_transaction_id());
|
||||
}
|
||||
|
||||
if (txnSt->isFieldPresent(sfSourceTag))
|
||||
{
|
||||
if (!BEAST_EXPECT(proto.has_source_tag()))
|
||||
return;
|
||||
BEAST_EXPECT(
|
||||
proto.source_tag().value() == txnSt->getFieldU32(sfSourceTag));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!proto.has_source_tag());
|
||||
}
|
||||
|
||||
if (txnSt->isFieldPresent(sfDestinationTag))
|
||||
{
|
||||
if (!BEAST_EXPECT(proto.payment().has_destination_tag()))
|
||||
return;
|
||||
|
||||
BEAST_EXPECT(
|
||||
proto.payment().destination_tag().value() ==
|
||||
txnSt->getFieldU32(sfDestinationTag));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!proto.payment().has_destination_tag());
|
||||
}
|
||||
|
||||
if (txnSt->isFieldPresent(sfInvoiceID))
|
||||
{
|
||||
if (!BEAST_EXPECT(proto.payment().has_invoice_id()))
|
||||
return;
|
||||
|
||||
auto field = txnSt->getFieldH256(sfInvoiceID);
|
||||
BEAST_EXPECT(
|
||||
proto.payment().invoice_id().value() == toByteString(field));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!proto.payment().has_invoice_id());
|
||||
}
|
||||
|
||||
if (txnSt->isFieldPresent(sfDeliverMin))
|
||||
{
|
||||
if (!BEAST_EXPECT(proto.payment().has_deliver_min()))
|
||||
return;
|
||||
STAmount const& deliverMin = txnSt->getFieldAmount(sfDeliverMin);
|
||||
cmpAmount(proto.payment().deliver_min().value(), deliverMin);
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!proto.payment().has_deliver_min());
|
||||
}
|
||||
|
||||
// populate path data
|
||||
STPathSet const& pathset = txnSt->getFieldPathSet(sfPaths);
|
||||
if (!BEAST_EXPECT(pathset.size() == proto.payment().paths_size()))
|
||||
return;
|
||||
|
||||
int ind = 0;
|
||||
for (auto it = pathset.begin(); it < pathset.end(); ++it)
|
||||
{
|
||||
STPath const& path = *it;
|
||||
|
||||
const rpc::v1::Path& protoPath = proto.payment().paths(ind++);
|
||||
const org::xrpl::rpc::v1::Payment_Path& protoPath =
|
||||
proto.payment().paths(ind++);
|
||||
if (!BEAST_EXPECT(protoPath.elements_size() == path.size()))
|
||||
continue;
|
||||
|
||||
int ind2 = 0;
|
||||
for (auto it2 = path.begin(); it2 != path.end(); ++it2)
|
||||
{
|
||||
const rpc::v1::PathElement& protoElement =
|
||||
const org::xrpl::rpc::v1::Payment_PathElement& protoElement =
|
||||
protoPath.elements(ind2++);
|
||||
STPathElement const& elt = *it2;
|
||||
|
||||
@@ -132,47 +265,224 @@ class Tx_test : public beast::unit_test::suite
|
||||
if (elt.hasCurrency())
|
||||
{
|
||||
Currency const& currency = elt.getCurrency();
|
||||
BEAST_EXPECT(
|
||||
protoElement.currency().name() ==
|
||||
to_string(currency));
|
||||
if (BEAST_EXPECT(protoElement.has_currency()))
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
protoElement.currency().name() ==
|
||||
to_string(currency));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!protoElement.has_currency());
|
||||
}
|
||||
if (elt.hasIssuer())
|
||||
{
|
||||
AccountID const& issuer = elt.getIssuerID();
|
||||
BEAST_EXPECT(
|
||||
protoElement.issuer().address() ==
|
||||
toBase58(issuer));
|
||||
if (BEAST_EXPECT(protoElement.has_issuer()))
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
protoElement.issuer().address() ==
|
||||
toBase58(issuer));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!protoElement.has_issuer());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AccountID const& path_account = elt.getAccountID();
|
||||
BEAST_EXPECT(
|
||||
protoElement.account().address() ==
|
||||
toBase58(path_account));
|
||||
if (BEAST_EXPECT(protoElement.has_account()))
|
||||
{
|
||||
AccountID const& path_account = elt.getAccountID();
|
||||
BEAST_EXPECT(
|
||||
protoElement.account().address() ==
|
||||
toBase58(path_account));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!protoElement.has_account());
|
||||
}
|
||||
|
||||
BEAST_EXPECT(!protoElement.has_issuer());
|
||||
BEAST_EXPECT(!protoElement.has_currency());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (txnSt->isFieldPresent(sfMemos))
|
||||
{
|
||||
auto arr = txnSt->getFieldArray(sfMemos);
|
||||
if (BEAST_EXPECT(proto.memos_size() == arr.size()))
|
||||
{
|
||||
for (size_t i = 0; i < arr.size(); ++i)
|
||||
{
|
||||
auto protoMemo = proto.memos(i);
|
||||
auto stMemo = arr[i];
|
||||
|
||||
if (stMemo.isFieldPresent(sfMemoData))
|
||||
{
|
||||
if (BEAST_EXPECT(protoMemo.has_memo_data()))
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
protoMemo.memo_data().value() ==
|
||||
toByteString(stMemo.getFieldVL(sfMemoData)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!protoMemo.has_memo_data());
|
||||
}
|
||||
|
||||
if (stMemo.isFieldPresent(sfMemoType))
|
||||
{
|
||||
if (BEAST_EXPECT(protoMemo.has_memo_type()))
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
protoMemo.memo_type().value() ==
|
||||
toByteString(stMemo.getFieldVL(sfMemoType)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!protoMemo.has_memo_type());
|
||||
}
|
||||
|
||||
if (stMemo.isFieldPresent(sfMemoFormat))
|
||||
{
|
||||
if (BEAST_EXPECT(protoMemo.has_memo_format()))
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
protoMemo.memo_format().value() ==
|
||||
toByteString(stMemo.getFieldVL(sfMemoFormat)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!protoMemo.has_memo_format());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(proto.memos_size() == 0);
|
||||
}
|
||||
|
||||
if (txnSt->isFieldPresent(sfSigners))
|
||||
{
|
||||
auto arr = txnSt->getFieldArray(sfSigners);
|
||||
if (BEAST_EXPECT(proto.signers_size() == arr.size()))
|
||||
{
|
||||
for (size_t i = 0; i < arr.size(); ++i)
|
||||
{
|
||||
auto protoSigner = proto.signers(i);
|
||||
auto stSigner = arr[i];
|
||||
|
||||
if (stSigner.isFieldPresent(sfAccount))
|
||||
{
|
||||
if (BEAST_EXPECT(protoSigner.has_account()))
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
protoSigner.account().value().address() ==
|
||||
toBase58(stSigner.getAccountID(sfAccount)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!protoSigner.has_account());
|
||||
}
|
||||
|
||||
if (stSigner.isFieldPresent(sfTxnSignature))
|
||||
{
|
||||
if (BEAST_EXPECT(
|
||||
protoSigner.has_transaction_signature()))
|
||||
{
|
||||
Blob blob = stSigner.getFieldVL(sfTxnSignature);
|
||||
BEAST_EXPECT(
|
||||
protoSigner.transaction_signature().value() ==
|
||||
toByteString(blob));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!protoSigner.has_transaction_signature());
|
||||
}
|
||||
|
||||
if (stSigner.isFieldPresent(sfSigningPubKey))
|
||||
{
|
||||
if (BEAST_EXPECT(protoSigner.has_signing_public_key()))
|
||||
{
|
||||
Blob signingPubKey =
|
||||
stSigner.getFieldVL(sfSigningPubKey);
|
||||
BEAST_EXPECT(
|
||||
protoSigner.signing_public_key().value() ==
|
||||
toByteString(signingPubKey));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!protoSigner.has_signing_public_key());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(proto.signers_size() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cmpMeta(const rpc::v1::Meta& proto, std::shared_ptr<TxMeta> txMeta)
|
||||
cmpMeta(
|
||||
const org::xrpl::rpc::v1::Meta& proto,
|
||||
std::shared_ptr<TxMeta> txMeta)
|
||||
{
|
||||
BEAST_EXPECT(proto.transaction_index() == txMeta->getIndex());
|
||||
BEAST_EXPECT(
|
||||
proto.transaction_result().result() ==
|
||||
transToken(txMeta->getResultTER()));
|
||||
|
||||
rpc::v1::TransactionResult r;
|
||||
org::xrpl::rpc::v1::TransactionResult r;
|
||||
|
||||
RPC::populateTransactionResultType(r, txMeta->getResultTER());
|
||||
RPC::convert(r, txMeta->getResultTER());
|
||||
|
||||
BEAST_EXPECT(
|
||||
proto.transaction_result().result_type() == r.result_type());
|
||||
}
|
||||
|
||||
if (txMeta->hasDeliveredAmount())
|
||||
void
|
||||
cmpDeliveredAmount(
|
||||
const org::xrpl::rpc::v1::Meta& meta,
|
||||
const org::xrpl::rpc::v1::Transaction& txn,
|
||||
const std::shared_ptr<TxMeta> expMeta,
|
||||
const std::shared_ptr<STTx const> expTxn,
|
||||
bool checkAmount = true)
|
||||
{
|
||||
if (expMeta->hasDeliveredAmount())
|
||||
{
|
||||
cmpAmount(proto.delivered_amount(), txMeta->getDeliveredAmount());
|
||||
if (!BEAST_EXPECT(meta.has_delivered_amount()))
|
||||
return;
|
||||
cmpAmount(
|
||||
meta.delivered_amount().value(), expMeta->getDeliveredAmount());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (expTxn->isFieldPresent(sfAmount))
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
if (checkAmount)
|
||||
{
|
||||
cmpAmount(
|
||||
meta.delivered_amount().value(),
|
||||
expTxn->getFieldAmount(sfAmount));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!meta.has_delivered_amount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,8 +490,8 @@ class Tx_test : public beast::unit_test::suite
|
||||
class GrpcTxClient : public GRPCTestClientBase
|
||||
{
|
||||
public:
|
||||
rpc::v1::GetTxRequest request;
|
||||
rpc::v1::GetTxResponse reply;
|
||||
org::xrpl::rpc::v1::GetTransactionRequest request;
|
||||
org::xrpl::rpc::v1::GetTransactionResponse reply;
|
||||
|
||||
explicit GrpcTxClient(std::string const& port)
|
||||
: GRPCTestClientBase(port)
|
||||
@@ -191,7 +501,7 @@ class Tx_test : public beast::unit_test::suite
|
||||
void
|
||||
Tx()
|
||||
{
|
||||
status = stub_->GetTx(&context, request, &reply);
|
||||
status = stub_->GetTransaction(&context, request, &reply);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -205,33 +515,137 @@ class Tx_test : public beast::unit_test::suite
|
||||
std::string grpcPort = *(*config)["port_grpc"].get<std::string>("port");
|
||||
Env env(*this, std::move(config));
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
// Set time to this value (or greater) to get delivered_amount in meta
|
||||
env.timeKeeper().set(NetClock::time_point{446000001s});
|
||||
|
||||
auto grpcTx = [&grpcPort](auto hash, auto binary) {
|
||||
GrpcTxClient client(grpcPort);
|
||||
client.request.set_hash(&hash, sizeof(hash));
|
||||
client.request.set_binary(binary);
|
||||
client.Tx();
|
||||
return std::pair<bool, rpc::v1::GetTxResponse>(
|
||||
return std::pair<bool, org::xrpl::rpc::v1::GetTransactionResponse>(
|
||||
client.status.ok(), client.reply);
|
||||
};
|
||||
|
||||
Account A1{"A1"};
|
||||
Account A2{"A2"};
|
||||
Account A3{"A3"};
|
||||
env.fund(XRP(10000), A1);
|
||||
env.fund(XRP(10000), A2);
|
||||
env.close();
|
||||
env.trust(A2["USD"](1000), A1);
|
||||
env.close();
|
||||
env(fset(A2, 5)); // set asfAccountTxnID flag
|
||||
|
||||
// SignerListSet
|
||||
env(signers(A2, 1, {{"bogie", 1}, {"demon", 1}, {A1, 1}, {A3, 1}}),
|
||||
sig(A2));
|
||||
env.close();
|
||||
std::vector<std::shared_ptr<STTx const>> txns;
|
||||
auto const startLegSeq = env.current()->info().seq;
|
||||
|
||||
uint256 prevHash;
|
||||
for (int i = 0; i < 14; ++i)
|
||||
{
|
||||
auto const baseFee = env.current()->fees().base;
|
||||
auto txfee = fee(i + (2 * baseFee));
|
||||
auto lls = last_ledger_seq(i + startLegSeq + 20);
|
||||
auto dsttag = dtag(i * 456);
|
||||
auto srctag = stag(i * 321);
|
||||
auto sm = sendmax(A2["USD"](1000));
|
||||
auto dm = delivermin(A2["USD"](50));
|
||||
auto txf = txflags(131072); // partial payment flag
|
||||
auto txnid = account_txn_id(prevHash);
|
||||
auto inv = invoice_id(prevHash);
|
||||
auto mem1 = memo("foo", "bar", "baz");
|
||||
auto mem2 = memo("dragons", "elves", "goblins");
|
||||
|
||||
if (i & 1)
|
||||
env(pay(A2, A1, A2["USD"](100)));
|
||||
{
|
||||
if (i & 2)
|
||||
{
|
||||
env(pay(A2, A1, A2["USD"](100)),
|
||||
txfee,
|
||||
srctag,
|
||||
dsttag,
|
||||
lls,
|
||||
sm,
|
||||
dm,
|
||||
txf,
|
||||
txnid,
|
||||
inv,
|
||||
mem1,
|
||||
mem2,
|
||||
sig(A2));
|
||||
}
|
||||
else
|
||||
{
|
||||
env(pay(A2, A1, A2["USD"](100)),
|
||||
txfee,
|
||||
srctag,
|
||||
dsttag,
|
||||
lls,
|
||||
sm,
|
||||
dm,
|
||||
txf,
|
||||
txnid,
|
||||
inv,
|
||||
mem1,
|
||||
mem2,
|
||||
msig(A3));
|
||||
}
|
||||
}
|
||||
else
|
||||
env(pay(A2, A1, A2["XRP"](200)));
|
||||
{
|
||||
if (i & 2)
|
||||
{
|
||||
env(pay(A2, A1, A2["XRP"](200)),
|
||||
txfee,
|
||||
srctag,
|
||||
dsttag,
|
||||
lls,
|
||||
txnid,
|
||||
inv,
|
||||
mem1,
|
||||
mem2,
|
||||
sig(A2));
|
||||
}
|
||||
else
|
||||
{
|
||||
env(pay(A2, A1, A2["XRP"](200)),
|
||||
txfee,
|
||||
srctag,
|
||||
dsttag,
|
||||
lls,
|
||||
txnid,
|
||||
inv,
|
||||
mem1,
|
||||
mem2,
|
||||
msig(A3));
|
||||
}
|
||||
}
|
||||
txns.emplace_back(env.tx());
|
||||
prevHash = txns.back()->getTransactionID();
|
||||
env.close();
|
||||
}
|
||||
|
||||
// Payment with Paths
|
||||
auto const gw = Account("gateway");
|
||||
auto const USD = gw["USD"];
|
||||
env.fund(XRP(10000), "alice", "bob", gw);
|
||||
env.trust(USD(600), "alice");
|
||||
env.trust(USD(700), "bob");
|
||||
env(pay(gw, "alice", USD(70)));
|
||||
txns.emplace_back(env.tx());
|
||||
env.close();
|
||||
env(pay(gw, "bob", USD(50)));
|
||||
txns.emplace_back(env.tx());
|
||||
env.close();
|
||||
env(pay("alice", "bob", Account("bob")["USD"](5)), path(gw));
|
||||
txns.emplace_back(env.tx());
|
||||
env.close();
|
||||
|
||||
auto const endLegSeq = env.closed()->info().seq;
|
||||
|
||||
// Find the existing transactions
|
||||
@@ -257,7 +671,7 @@ class Tx_test : public beast::unit_test::suite
|
||||
}
|
||||
else
|
||||
{
|
||||
cmpTx(result.second.transaction(), tx);
|
||||
cmpPaymentTx(result.second.transaction(), tx);
|
||||
}
|
||||
|
||||
if (ledger && !b)
|
||||
@@ -269,6 +683,11 @@ class Tx_test : public beast::unit_test::suite
|
||||
id, ledger->seq(), *rawMeta);
|
||||
|
||||
cmpMeta(result.second.meta(), txMeta);
|
||||
cmpDeliveredAmount(
|
||||
result.second.meta(),
|
||||
result.second.transaction(),
|
||||
txMeta,
|
||||
tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,6 +718,41 @@ class Tx_test : public beast::unit_test::suite
|
||||
|
||||
BEAST_EXPECT(result.first == false);
|
||||
}
|
||||
|
||||
// non final transaction
|
||||
env(pay(A2, A1, A2["XRP"](200)));
|
||||
auto res = grpcTx(env.tx()->getTransactionID(), false);
|
||||
BEAST_EXPECT(res.first);
|
||||
BEAST_EXPECT(res.second.has_transaction());
|
||||
if (!BEAST_EXPECT(res.second.has_meta()))
|
||||
return;
|
||||
if (!BEAST_EXPECT(res.second.meta().has_transaction_result()))
|
||||
return;
|
||||
|
||||
BEAST_EXPECT(
|
||||
res.second.meta().transaction_result().result() == "tesSUCCESS");
|
||||
BEAST_EXPECT(
|
||||
res.second.meta().transaction_result().result_type() ==
|
||||
org::xrpl::rpc::v1::TransactionResult::RESULT_TYPE_TES);
|
||||
BEAST_EXPECT(!res.second.validated());
|
||||
BEAST_EXPECT(!res.second.meta().has_delivered_amount());
|
||||
env.close();
|
||||
|
||||
res = grpcTx(env.tx()->getTransactionID(), false);
|
||||
BEAST_EXPECT(res.first);
|
||||
BEAST_EXPECT(res.second.has_transaction());
|
||||
if (!BEAST_EXPECT(res.second.has_meta()))
|
||||
return;
|
||||
if (!BEAST_EXPECT(res.second.meta().has_transaction_result()))
|
||||
return;
|
||||
|
||||
BEAST_EXPECT(
|
||||
res.second.meta().transaction_result().result() == "tesSUCCESS");
|
||||
BEAST_EXPECT(
|
||||
res.second.meta().transaction_result().result_type() ==
|
||||
org::xrpl::rpc::v1::TransactionResult::RESULT_TYPE_TES);
|
||||
BEAST_EXPECT(res.second.validated());
|
||||
BEAST_EXPECT(res.second.meta().has_delivered_amount());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user