mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-03 08:55:52 +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:
@@ -3,6 +3,7 @@
|
|||||||
core functionality, useable by some client software perhaps
|
core functionality, useable by some client software perhaps
|
||||||
#]===================================================================]
|
#]===================================================================]
|
||||||
|
|
||||||
|
|
||||||
file (GLOB_RECURSE rb_headers
|
file (GLOB_RECURSE rb_headers
|
||||||
src/ripple/beast/*.h
|
src/ripple/beast/*.h
|
||||||
src/ripple/beast/*.hpp)
|
src/ripple/beast/*.hpp)
|
||||||
@@ -613,6 +614,7 @@ target_sources (rippled PRIVATE
|
|||||||
src/ripple/rpc/handlers/WalletPropose.cpp
|
src/ripple/rpc/handlers/WalletPropose.cpp
|
||||||
src/ripple/rpc/impl/DeliveredAmount.cpp
|
src/ripple/rpc/impl/DeliveredAmount.cpp
|
||||||
src/ripple/rpc/impl/Handler.cpp
|
src/ripple/rpc/impl/Handler.cpp
|
||||||
|
src/ripple/rpc/impl/GRPCHelpers.cpp
|
||||||
src/ripple/rpc/impl/LegacyPathFind.cpp
|
src/ripple/rpc/impl/LegacyPathFind.cpp
|
||||||
src/ripple/rpc/impl/RPCHandler.cpp
|
src/ripple/rpc/impl/RPCHandler.cpp
|
||||||
src/ripple/rpc/impl/RPCHelpers.cpp
|
src/ripple/rpc/impl/RPCHelpers.cpp
|
||||||
@@ -621,6 +623,7 @@ target_sources (rippled PRIVATE
|
|||||||
src/ripple/rpc/impl/ShardArchiveHandler.cpp
|
src/ripple/rpc/impl/ShardArchiveHandler.cpp
|
||||||
src/ripple/rpc/impl/Status.cpp
|
src/ripple/rpc/impl/Status.cpp
|
||||||
src/ripple/rpc/impl/TransactionSign.cpp
|
src/ripple/rpc/impl/TransactionSign.cpp
|
||||||
|
|
||||||
#[===============================[
|
#[===============================[
|
||||||
main sources:
|
main sources:
|
||||||
subdir: server
|
subdir: server
|
||||||
@@ -786,6 +789,7 @@ target_sources (rippled PRIVATE
|
|||||||
src/test/jtx/impl/ManualTimeKeeper.cpp
|
src/test/jtx/impl/ManualTimeKeeper.cpp
|
||||||
src/test/jtx/impl/WSClient.cpp
|
src/test/jtx/impl/WSClient.cpp
|
||||||
src/test/jtx/impl/acctdelete.cpp
|
src/test/jtx/impl/acctdelete.cpp
|
||||||
|
src/test/jtx/impl/account_txn_id.cpp
|
||||||
src/test/jtx/impl/amount.cpp
|
src/test/jtx/impl/amount.cpp
|
||||||
src/test/jtx/impl/balance.cpp
|
src/test/jtx/impl/balance.cpp
|
||||||
src/test/jtx/impl/check.cpp
|
src/test/jtx/impl/check.cpp
|
||||||
@@ -794,7 +798,9 @@ target_sources (rippled PRIVATE
|
|||||||
src/test/jtx/impl/envconfig.cpp
|
src/test/jtx/impl/envconfig.cpp
|
||||||
src/test/jtx/impl/fee.cpp
|
src/test/jtx/impl/fee.cpp
|
||||||
src/test/jtx/impl/flags.cpp
|
src/test/jtx/impl/flags.cpp
|
||||||
|
src/test/jtx/impl/invoice_id.cpp
|
||||||
src/test/jtx/impl/jtx_json.cpp
|
src/test/jtx/impl/jtx_json.cpp
|
||||||
|
src/test/jtx/impl/last_ledger_sequence.cpp
|
||||||
src/test/jtx/impl/memo.cpp
|
src/test/jtx/impl/memo.cpp
|
||||||
src/test/jtx/impl/multisign.cpp
|
src/test/jtx/impl/multisign.cpp
|
||||||
src/test/jtx/impl/offer.cpp
|
src/test/jtx/impl/offer.cpp
|
||||||
@@ -812,6 +818,7 @@ target_sources (rippled PRIVATE
|
|||||||
src/test/jtx/impl/trust.cpp
|
src/test/jtx/impl/trust.cpp
|
||||||
src/test/jtx/impl/txflags.cpp
|
src/test/jtx/impl/txflags.cpp
|
||||||
src/test/jtx/impl/utility.cpp
|
src/test/jtx/impl/utility.cpp
|
||||||
|
|
||||||
#[===============================[
|
#[===============================[
|
||||||
test sources:
|
test sources:
|
||||||
subdir: ledger
|
subdir: ledger
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ set (GRPC_GEN_DIR "${CMAKE_BINARY_DIR}/proto_gen_grpc")
|
|||||||
file (MAKE_DIRECTORY ${GRPC_GEN_DIR})
|
file (MAKE_DIRECTORY ${GRPC_GEN_DIR})
|
||||||
set (GRPC_PROTO_SRCS)
|
set (GRPC_PROTO_SRCS)
|
||||||
set (GRPC_PROTO_HDRS)
|
set (GRPC_PROTO_HDRS)
|
||||||
set (GRPC_PROTO_ROOT "${CMAKE_SOURCE_DIR}/src/ripple/proto/rpc")
|
set (GRPC_PROTO_ROOT "${CMAKE_SOURCE_DIR}/src/ripple/proto/org")
|
||||||
file(GLOB_RECURSE GRPC_DEFINITION_FILES LIST_DIRECTORIES false "${GRPC_PROTO_ROOT}/*.proto")
|
file(GLOB_RECURSE GRPC_DEFINITION_FILES LIST_DIRECTORIES false "${GRPC_PROTO_ROOT}/*.proto")
|
||||||
foreach(file ${GRPC_DEFINITION_FILES})
|
foreach(file ${GRPC_DEFINITION_FILES})
|
||||||
get_filename_component(_abs_file ${file} ABSOLUTE)
|
get_filename_component(_abs_file ${file} ABSOLUTE)
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ getEndpoint(std::string const& peer)
|
|||||||
|
|
||||||
template <class Request, class Response>
|
template <class Request, class Response>
|
||||||
GRPCServerImpl::CallData<Request, Response>::CallData(
|
GRPCServerImpl::CallData<Request, Response>::CallData(
|
||||||
rpc::v1::XRPLedgerAPIService::AsyncService& service,
|
org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService& service,
|
||||||
grpc::ServerCompletionQueue& cq,
|
grpc::ServerCompletionQueue& cq,
|
||||||
Application& app,
|
Application& app,
|
||||||
BindListener<Request, Response> bindListener,
|
BindListener<Request, Response> bindListener,
|
||||||
@@ -52,7 +52,6 @@ GRPCServerImpl::CallData<Request, Response>::CallData(
|
|||||||
, cq_(cq)
|
, cq_(cq)
|
||||||
, finished_(false)
|
, finished_(false)
|
||||||
, app_(app)
|
, app_(app)
|
||||||
, aborted_(false)
|
|
||||||
, responder_(&ctx_)
|
, responder_(&ctx_)
|
||||||
, bindListener_(std::move(bindListener))
|
, bindListener_(std::move(bindListener))
|
||||||
, handler_(std::move(handler))
|
, handler_(std::move(handler))
|
||||||
@@ -87,20 +86,31 @@ GRPCServerImpl::CallData<Request, Response>::process()
|
|||||||
|
|
||||||
std::shared_ptr<CallData<Request, Response>> thisShared =
|
std::shared_ptr<CallData<Request, Response>> thisShared =
|
||||||
this->shared_from_this();
|
this->shared_from_this();
|
||||||
app_.getJobQueue().postCoro(
|
|
||||||
|
// Need to set finished to true before processing the response,
|
||||||
|
// because as soon as the response is posted to the completion
|
||||||
|
// queue (via responder_.Finish(...) or responder_.FinishWithError(...)),
|
||||||
|
// the CallData object is returned as a tag in handleRpcs().
|
||||||
|
// handleRpcs() checks the finished variable, and if true, destroys
|
||||||
|
// the object. Setting finished to true before calling process
|
||||||
|
// ensures that finished is always true when this CallData object
|
||||||
|
// is returned as a tag in handleRpcs(), after sending the response
|
||||||
|
finished_ = true;
|
||||||
|
auto coro = app_.getJobQueue().postCoro(
|
||||||
JobType::jtRPC,
|
JobType::jtRPC,
|
||||||
"gRPC-Client",
|
"gRPC-Client",
|
||||||
[thisShared](std::shared_ptr<JobQueue::Coro> coro) {
|
[thisShared](std::shared_ptr<JobQueue::Coro> coro) {
|
||||||
std::lock_guard lock{thisShared->mut_};
|
|
||||||
|
|
||||||
// Do nothing if call has been aborted due to server shutdown
|
|
||||||
// or if handler was already executed
|
|
||||||
if (thisShared->aborted_ || thisShared->finished_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
thisShared->process(coro);
|
thisShared->process(coro);
|
||||||
thisShared->finished_ = true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// If coro is null, then the JobQueue has already been shutdown
|
||||||
|
if (!coro)
|
||||||
|
{
|
||||||
|
grpc::Status status{grpc::StatusCode::INTERNAL,
|
||||||
|
"Job Queue is already stopped"};
|
||||||
|
responder_.FinishWithError(status, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Request, class Response>
|
template <class Request, class Response>
|
||||||
@@ -141,7 +151,7 @@ GRPCServerImpl::CallData<Request, Response>::process(
|
|||||||
if (conditionMetRes != rpcSUCCESS)
|
if (conditionMetRes != rpcSUCCESS)
|
||||||
{
|
{
|
||||||
RPC::ErrorInfo errorInfo = RPC::get_error_info(conditionMetRes);
|
RPC::ErrorInfo errorInfo = RPC::get_error_info(conditionMetRes);
|
||||||
grpc::Status status{grpc::StatusCode::INTERNAL,
|
grpc::Status status{grpc::StatusCode::FAILED_PRECONDITION,
|
||||||
errorInfo.message.c_str()};
|
errorInfo.message.c_str()};
|
||||||
responder_.FinishWithError(status, this);
|
responder_.FinishWithError(status, this);
|
||||||
}
|
}
|
||||||
@@ -163,21 +173,9 @@ template <class Request, class Response>
|
|||||||
bool
|
bool
|
||||||
GRPCServerImpl::CallData<Request, Response>::isFinished()
|
GRPCServerImpl::CallData<Request, Response>::isFinished()
|
||||||
{
|
{
|
||||||
// Need to lock here because this object can be returned from cq_.Next(..)
|
|
||||||
// as soon as the response is sent, which could be before finished_ is set
|
|
||||||
// to true, causing the handler to be executed twice
|
|
||||||
std::lock_guard lock{mut_};
|
|
||||||
return finished_;
|
return finished_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Request, class Response>
|
|
||||||
void
|
|
||||||
GRPCServerImpl::CallData<Request, Response>::abort()
|
|
||||||
{
|
|
||||||
std::lock_guard lock{mut_};
|
|
||||||
aborted_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Request, class Response>
|
template <class Request, class Response>
|
||||||
Resource::Charge
|
Resource::Charge
|
||||||
GRPCServerImpl::CallData<Request, Response>::getLoadType()
|
GRPCServerImpl::CallData<Request, Response>::getLoadType()
|
||||||
@@ -202,7 +200,8 @@ GRPCServerImpl::CallData<Request, Response>::getUsage()
|
|||||||
return app_.getResourceManager().newInboundEndpoint(endpoint.get());
|
return app_.getResourceManager().newInboundEndpoint(endpoint.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
GRPCServerImpl::GRPCServerImpl(Application& app) : app_(app)
|
GRPCServerImpl::GRPCServerImpl(Application& app)
|
||||||
|
: app_(app), journal_(app_.journal("gRPC Server"))
|
||||||
{
|
{
|
||||||
// if present, get endpoint from config
|
// if present, get endpoint from config
|
||||||
if (app_.config().exists("port_grpc"))
|
if (app_.config().exists("port_grpc"))
|
||||||
@@ -233,9 +232,24 @@ GRPCServerImpl::GRPCServerImpl(Application& app) : app_(app)
|
|||||||
void
|
void
|
||||||
GRPCServerImpl::shutdown()
|
GRPCServerImpl::shutdown()
|
||||||
{
|
{
|
||||||
|
JLOG(journal_.debug()) << "Shutting down";
|
||||||
|
|
||||||
|
//The below call cancels all "listeners" (CallData objects that are waiting
|
||||||
|
//for a request, as opposed to processing a request), and blocks until all
|
||||||
|
//requests being processed are completed. CallData objects in the midst of
|
||||||
|
//processing requests need to actually send data back to the client, via
|
||||||
|
//responder_.Finish(...) or responder_.FinishWithError(...), for this call
|
||||||
|
//to unblock. Each cancelled listener is returned via cq_.Next(...) with ok
|
||||||
|
//set to false
|
||||||
server_->Shutdown();
|
server_->Shutdown();
|
||||||
// Always shutdown the completion queue after the server.
|
JLOG(journal_.debug()) << "Server has been shutdown";
|
||||||
|
|
||||||
|
// Always shutdown the completion queue after the server. This call allows
|
||||||
|
// cq_.Next() to return false, once all events posted to the completion
|
||||||
|
// queue have been processed. See handleRpcs() for more details.
|
||||||
cq_->Shutdown();
|
cq_->Shutdown();
|
||||||
|
JLOG(journal_.debug()) << "Completion Queue has been shutdown";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -265,21 +279,33 @@ GRPCServerImpl::handleRpcs()
|
|||||||
// memory address of a CallData instance.
|
// memory address of a CallData instance.
|
||||||
// The return value of Next should always be checked. This return value
|
// The return value of Next should always be checked. This return value
|
||||||
// tells us whether there is any kind of event or cq_ is shutting down.
|
// tells us whether there is any kind of event or cq_ is shutting down.
|
||||||
|
// When cq_.Next(...) returns false, all work has been completed and the
|
||||||
|
// loop can exit. When the server is shutdown, each CallData object that is
|
||||||
|
// listening for a request is forceably cancelled, and is returned by
|
||||||
|
// cq_->Next() with ok set to false. Then, each CallData object processing
|
||||||
|
// a request must complete (by sending data to the client), each of which
|
||||||
|
// will be returned from cq_->Next() with ok set to true. After all
|
||||||
|
// cancelled listeners and all CallData objects processing requests are
|
||||||
|
// returned via cq_->Next(), cq_->Next() will return false, causing the
|
||||||
|
// loop to exit.
|
||||||
while (cq_->Next(&tag, &ok))
|
while (cq_->Next(&tag, &ok))
|
||||||
{
|
{
|
||||||
auto ptr = static_cast<Processor*>(tag);
|
auto ptr = static_cast<Processor*>(tag);
|
||||||
// if ok is false, event was terminated as part of a shutdown sequence
|
JLOG(journal_.trace()) << "Processing CallData object."
|
||||||
// need to abort any further processing
|
<< " ptr = " << ptr
|
||||||
|
<< " ok = " << ok;
|
||||||
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
{
|
{
|
||||||
// abort first, then erase. Otherwise, erase can delete object
|
JLOG(journal_.debug()) << "Request listener cancelled. "
|
||||||
ptr->abort();
|
<< "Destroying object";
|
||||||
erase(ptr);
|
erase(ptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!ptr->isFinished())
|
if (!ptr->isFinished())
|
||||||
{
|
{
|
||||||
|
JLOG(journal_.debug()) << "Received new request. Processing";
|
||||||
// ptr is now processing a request, so create a new CallData
|
// ptr is now processing a request, so create a new CallData
|
||||||
// object to handle additional requests
|
// object to handle additional requests
|
||||||
auto cloned = ptr->clone();
|
auto cloned = ptr->clone();
|
||||||
@@ -289,10 +315,13 @@ GRPCServerImpl::handleRpcs()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
|
JLOG(journal_.debug()) << "Sent response. Destroying object";
|
||||||
erase(ptr);
|
erase(ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
JLOG(journal_.debug()) << "Completion Queue drained";
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a CallData instance for each RPC
|
// create a CallData instance for each RPC
|
||||||
@@ -306,58 +335,76 @@ GRPCServerImpl::setupListeners()
|
|||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
using cd = CallData<rpc::v1::GetFeeRequest, rpc::v1::GetFeeResponse>;
|
using cd = CallData<org::xrpl::rpc::v1::GetFeeRequest, org::xrpl::rpc::v1::GetFeeResponse>;
|
||||||
|
|
||||||
addToRequests(std::make_shared<cd>(
|
addToRequests(std::make_shared<cd>(
|
||||||
service_,
|
service_,
|
||||||
*cq_,
|
*cq_,
|
||||||
app_,
|
app_,
|
||||||
&rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetFee,
|
&org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetFee,
|
||||||
doFeeGrpc,
|
doFeeGrpc,
|
||||||
RPC::NEEDS_CURRENT_LEDGER,
|
RPC::NEEDS_CURRENT_LEDGER,
|
||||||
Resource::feeReferenceRPC));
|
Resource::feeReferenceRPC));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
using cd = CallData<
|
using cd = CallData<
|
||||||
rpc::v1::GetAccountInfoRequest,
|
org::xrpl::rpc::v1::GetAccountInfoRequest,
|
||||||
rpc::v1::GetAccountInfoResponse>;
|
org::xrpl::rpc::v1::GetAccountInfoResponse>;
|
||||||
|
|
||||||
addToRequests(std::make_shared<cd>(
|
addToRequests(std::make_shared<cd>(
|
||||||
service_,
|
service_,
|
||||||
*cq_,
|
*cq_,
|
||||||
app_,
|
app_,
|
||||||
&rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetAccountInfo,
|
&org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetAccountInfo,
|
||||||
doAccountInfoGrpc,
|
doAccountInfoGrpc,
|
||||||
RPC::NEEDS_CURRENT_LEDGER,
|
RPC::NO_CONDITION,
|
||||||
Resource::feeReferenceRPC));
|
Resource::feeReferenceRPC));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
using cd = CallData<rpc::v1::GetTxRequest, rpc::v1::GetTxResponse>;
|
using cd = CallData<
|
||||||
|
org::xrpl::rpc::v1::GetTransactionRequest,
|
||||||
|
org::xrpl::rpc::v1::GetTransactionResponse>;
|
||||||
|
|
||||||
addToRequests(std::make_shared<cd>(
|
addToRequests(std::make_shared<cd>(
|
||||||
service_,
|
service_,
|
||||||
*cq_,
|
*cq_,
|
||||||
app_,
|
app_,
|
||||||
&rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetTx,
|
&org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetTransaction,
|
||||||
doTxGrpc,
|
doTxGrpc,
|
||||||
RPC::NEEDS_CURRENT_LEDGER,
|
RPC::NEEDS_CURRENT_LEDGER,
|
||||||
Resource::feeReferenceRPC));
|
Resource::feeReferenceRPC));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
using cd = CallData<
|
using cd = CallData<
|
||||||
rpc::v1::SubmitTransactionRequest,
|
org::xrpl::rpc::v1::SubmitTransactionRequest,
|
||||||
rpc::v1::SubmitTransactionResponse>;
|
org::xrpl::rpc::v1::SubmitTransactionResponse>;
|
||||||
|
|
||||||
addToRequests(std::make_shared<cd>(
|
addToRequests(std::make_shared<cd>(
|
||||||
service_,
|
service_,
|
||||||
*cq_,
|
*cq_,
|
||||||
app_,
|
app_,
|
||||||
&rpc::v1::XRPLedgerAPIService::AsyncService::
|
&org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::
|
||||||
RequestSubmitTransaction,
|
RequestSubmitTransaction,
|
||||||
doSubmitGrpc,
|
doSubmitGrpc,
|
||||||
RPC::NEEDS_CURRENT_LEDGER,
|
RPC::NEEDS_CURRENT_LEDGER,
|
||||||
Resource::feeMediumBurdenRPC));
|
Resource::feeMediumBurdenRPC));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
using cd = CallData<
|
||||||
|
org::xrpl::rpc::v1::GetAccountTransactionHistoryRequest,
|
||||||
|
org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse>;
|
||||||
|
|
||||||
|
addToRequests(std::make_shared<cd>(
|
||||||
|
service_,
|
||||||
|
*cq_,
|
||||||
|
app_,
|
||||||
|
&org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::
|
||||||
|
RequestGetAccountTransactionHistory,
|
||||||
|
doAccountTxGrpc,
|
||||||
|
RPC::NO_CONDITION,
|
||||||
|
Resource::feeMediumBurdenRPC));
|
||||||
|
}
|
||||||
return requests;
|
return requests;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -368,6 +415,8 @@ GRPCServerImpl::start()
|
|||||||
if (serverAddress_.empty())
|
if (serverAddress_.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
JLOG(journal_.info()) << "Starting gRPC server at " << serverAddress_;
|
||||||
|
|
||||||
grpc::ServerBuilder builder;
|
grpc::ServerBuilder builder;
|
||||||
// Listen on the given address without any authentication mechanism.
|
// Listen on the given address without any authentication mechanism.
|
||||||
builder.AddListeningPort(serverAddress_, grpc::InsecureServerCredentials());
|
builder.AddListeningPort(serverAddress_, grpc::InsecureServerCredentials());
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||||
#include <ripple/rpc/impl/Tuning.h>
|
#include <ripple/rpc/impl/Tuning.h>
|
||||||
|
|
||||||
#include "rpc/v1/xrp_ledger.grpc.pb.h"
|
#include "org/xrpl/rpc/v1/xrp_ledger.grpc.pb.h"
|
||||||
#include <grpcpp/grpcpp.h>
|
#include <grpcpp/grpcpp.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -54,10 +54,6 @@ public:
|
|||||||
virtual void
|
virtual void
|
||||||
process() = 0;
|
process() = 0;
|
||||||
|
|
||||||
// abort processing this request. called when server shutsdown
|
|
||||||
virtual void
|
|
||||||
abort() = 0;
|
|
||||||
|
|
||||||
// create a new instance of this CallData object, with the same type
|
// create a new instance of this CallData object, with the same type
|
||||||
//(same template parameters) as original. This is called when a CallData
|
//(same template parameters) as original. This is called when a CallData
|
||||||
// object starts processing a request. Creating a new instance allows the
|
// object starts processing a request. Creating a new instance allows the
|
||||||
@@ -81,7 +77,7 @@ private:
|
|||||||
std::vector<std::shared_ptr<Processor>> requests_;
|
std::vector<std::shared_ptr<Processor>> requests_;
|
||||||
|
|
||||||
// The gRPC service defined by the .proto files
|
// The gRPC service defined by the .proto files
|
||||||
rpc::v1::XRPLedgerAPIService::AsyncService service_;
|
org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService service_;
|
||||||
|
|
||||||
std::unique_ptr<grpc::Server> server_;
|
std::unique_ptr<grpc::Server> server_;
|
||||||
|
|
||||||
@@ -89,12 +85,14 @@ private:
|
|||||||
|
|
||||||
std::string serverAddress_;
|
std::string serverAddress_;
|
||||||
|
|
||||||
|
beast::Journal journal_;
|
||||||
|
|
||||||
// typedef for function to bind a listener
|
// typedef for function to bind a listener
|
||||||
// This is always of the form:
|
// This is always of the form:
|
||||||
// rpc::v1::XRPLedgerAPIService::AsyncService::Request[RPC NAME]
|
// org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::Request[RPC NAME]
|
||||||
template <class Request, class Response>
|
template <class Request, class Response>
|
||||||
using BindListener = std::function<void(
|
using BindListener = std::function<void(
|
||||||
rpc::v1::XRPLedgerAPIService::AsyncService&,
|
org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService&,
|
||||||
grpc::ServerContext*,
|
grpc::ServerContext*,
|
||||||
Request*,
|
Request*,
|
||||||
grpc::ServerAsyncResponseWriter<Response>*,
|
grpc::ServerAsyncResponseWriter<Response>*,
|
||||||
@@ -142,7 +140,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
// The means of communication with the gRPC runtime for an asynchronous
|
// The means of communication with the gRPC runtime for an asynchronous
|
||||||
// server.
|
// server.
|
||||||
rpc::v1::XRPLedgerAPIService::AsyncService& service_;
|
org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService& service_;
|
||||||
|
|
||||||
// The producer-consumer queue for asynchronous server notifications.
|
// The producer-consumer queue for asynchronous server notifications.
|
||||||
grpc::ServerCompletionQueue& cq_;
|
grpc::ServerCompletionQueue& cq_;
|
||||||
@@ -153,16 +151,14 @@ private:
|
|||||||
grpc::ServerContext ctx_;
|
grpc::ServerContext ctx_;
|
||||||
|
|
||||||
// true if finished processing request
|
// true if finished processing request
|
||||||
bool finished_;
|
// Note, this variable does not need to be atomic, since it is
|
||||||
|
// currently only accessed from one thread. However, isFinished(),
|
||||||
|
// which returns the value of this variable, is public facing. In the
|
||||||
|
// interest of avoiding future concurrency bugs, we make it atomic.
|
||||||
|
std::atomic_bool finished_;
|
||||||
|
|
||||||
Application& app_;
|
Application& app_;
|
||||||
|
|
||||||
// mutex for signaling abort
|
|
||||||
std::mutex mut_;
|
|
||||||
|
|
||||||
// whether the call should be aborted, due to server shutdown
|
|
||||||
bool aborted_;
|
|
||||||
|
|
||||||
// What we get from the client.
|
// What we get from the client.
|
||||||
Request request_;
|
Request request_;
|
||||||
|
|
||||||
@@ -191,7 +187,7 @@ private:
|
|||||||
// asynchronous server) and the completion queue "cq" used for
|
// asynchronous server) and the completion queue "cq" used for
|
||||||
// asynchronous communication with the gRPC runtime.
|
// asynchronous communication with the gRPC runtime.
|
||||||
explicit CallData(
|
explicit CallData(
|
||||||
rpc::v1::XRPLedgerAPIService::AsyncService& service,
|
org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService& service,
|
||||||
grpc::ServerCompletionQueue& cq,
|
grpc::ServerCompletionQueue& cq,
|
||||||
Application& app,
|
Application& app,
|
||||||
BindListener<Request, Response> bindListener,
|
BindListener<Request, Response> bindListener,
|
||||||
@@ -210,9 +206,6 @@ private:
|
|||||||
virtual bool
|
virtual bool
|
||||||
isFinished() override;
|
isFinished() override;
|
||||||
|
|
||||||
virtual void
|
|
||||||
abort() override;
|
|
||||||
|
|
||||||
std::shared_ptr<Processor>
|
std::shared_ptr<Processor>
|
||||||
clone() override;
|
clone() override;
|
||||||
|
|
||||||
|
|||||||
@@ -434,15 +434,21 @@ public:
|
|||||||
bool binary, bool count, bool bUnlimited);
|
bool binary, bool count, bool bUnlimited);
|
||||||
|
|
||||||
// Client information retrieval functions.
|
// Client information retrieval functions.
|
||||||
|
using NetworkOPs::AccountTxMarker;
|
||||||
using NetworkOPs::AccountTxs;
|
using NetworkOPs::AccountTxs;
|
||||||
AccountTxs getAccountTxs (
|
AccountTxs getAccountTxs (
|
||||||
AccountID const& account,
|
AccountID const& account,
|
||||||
std::int32_t minLedger, std::int32_t maxLedger, bool descending,
|
std::int32_t minLedger, std::int32_t maxLedger, bool descending,
|
||||||
std::uint32_t offset, int limit, bool bUnlimited) override;
|
std::uint32_t offset, int limit, bool bUnlimited) override;
|
||||||
|
|
||||||
AccountTxs getTxsAccount (
|
AccountTxs
|
||||||
AccountID const& account, std::int32_t minLedger,
|
getTxsAccount(
|
||||||
std::int32_t maxLedger, bool forward, Json::Value& token, int limit,
|
AccountID const& account,
|
||||||
|
std::int32_t minLedger,
|
||||||
|
std::int32_t maxLedger,
|
||||||
|
bool forward,
|
||||||
|
std::optional<AccountTxMarker>& marker,
|
||||||
|
int limit,
|
||||||
bool bUnlimited) override;
|
bool bUnlimited) override;
|
||||||
|
|
||||||
using NetworkOPs::txnMetaLedgerType;
|
using NetworkOPs::txnMetaLedgerType;
|
||||||
@@ -454,11 +460,16 @@ public:
|
|||||||
std::int32_t maxLedger, bool descending, std::uint32_t offset,
|
std::int32_t maxLedger, bool descending, std::uint32_t offset,
|
||||||
int limit, bool bUnlimited) override;
|
int limit, bool bUnlimited) override;
|
||||||
|
|
||||||
|
|
||||||
MetaTxsList
|
MetaTxsList
|
||||||
getTxsAccountB (
|
getTxsAccountB(
|
||||||
AccountID const& account, std::int32_t minLedger,
|
AccountID const& account,
|
||||||
std::int32_t maxLedger, bool forward, Json::Value& token,
|
std::int32_t minLedger,
|
||||||
int limit, bool bUnlimited) override;
|
std::int32_t maxLedger,
|
||||||
|
bool forward,
|
||||||
|
std::optional<AccountTxMarker>& marker,
|
||||||
|
int limit,
|
||||||
|
bool bUnlimited) override;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Monitoring: publisher side.
|
// Monitoring: publisher side.
|
||||||
@@ -2193,7 +2204,7 @@ std::vector<NetworkOPsImp::txnMetaLedgerType> NetworkOPsImp::getAccountTxsB (
|
|||||||
rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or (0));
|
rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or (0));
|
||||||
|
|
||||||
ret.emplace_back (
|
ret.emplace_back (
|
||||||
strHex (rawTxn), strHex (txnMeta), seq);
|
std::move(rawTxn), std::move(txnMeta), seq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2201,59 +2212,80 @@ std::vector<NetworkOPsImp::txnMetaLedgerType> NetworkOPsImp::getAccountTxsB (
|
|||||||
}
|
}
|
||||||
|
|
||||||
NetworkOPsImp::AccountTxs
|
NetworkOPsImp::AccountTxs
|
||||||
NetworkOPsImp::getTxsAccount (
|
NetworkOPsImp::getTxsAccount(
|
||||||
AccountID const& account, std::int32_t minLedger,
|
AccountID const& account,
|
||||||
std::int32_t maxLedger, bool forward, Json::Value& token,
|
std::int32_t minLedger,
|
||||||
int limit, bool bUnlimited)
|
std::int32_t maxLedger,
|
||||||
|
bool forward,
|
||||||
|
std::optional<AccountTxMarker>& marker,
|
||||||
|
int limit,
|
||||||
|
bool bUnlimited)
|
||||||
{
|
{
|
||||||
static std::uint32_t const page_length (200);
|
static std::uint32_t const page_length(200);
|
||||||
|
|
||||||
Application& app = app_;
|
Application& app = app_;
|
||||||
NetworkOPsImp::AccountTxs ret;
|
NetworkOPsImp::AccountTxs ret;
|
||||||
|
|
||||||
auto bound = [&ret, &app](
|
auto bound = [&ret, &app](
|
||||||
std::uint32_t ledger_index,
|
std::uint32_t ledger_index,
|
||||||
std::string const& status,
|
std::string const& status,
|
||||||
Blob const& rawTxn,
|
Blob const& rawTxn,
|
||||||
Blob const& rawMeta)
|
Blob const& rawMeta) {
|
||||||
{
|
convertBlobsToTxResult(ret, ledger_index, status, rawTxn, rawMeta, app);
|
||||||
convertBlobsToTxResult (
|
|
||||||
ret, ledger_index, status, rawTxn, rawMeta, app);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
accountTxPage(app_.getTxnDB (), app_.accountIDCache(),
|
accountTxPage(
|
||||||
std::bind(saveLedgerAsync, std::ref(app_),
|
app_.getTxnDB(),
|
||||||
std::placeholders::_1), bound, account, minLedger,
|
app_.accountIDCache(),
|
||||||
maxLedger, forward, token, limit, bUnlimited,
|
std::bind(saveLedgerAsync, std::ref(app_), std::placeholders::_1),
|
||||||
page_length);
|
bound,
|
||||||
|
account,
|
||||||
|
minLedger,
|
||||||
|
maxLedger,
|
||||||
|
forward,
|
||||||
|
marker,
|
||||||
|
limit,
|
||||||
|
bUnlimited,
|
||||||
|
page_length);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkOPsImp::MetaTxsList
|
NetworkOPsImp::MetaTxsList
|
||||||
NetworkOPsImp::getTxsAccountB (
|
NetworkOPsImp::getTxsAccountB(
|
||||||
AccountID const& account, std::int32_t minLedger,
|
AccountID const& account,
|
||||||
std::int32_t maxLedger, bool forward, Json::Value& token,
|
std::int32_t minLedger,
|
||||||
int limit, bool bUnlimited)
|
std::int32_t maxLedger,
|
||||||
|
bool forward,
|
||||||
|
std::optional<AccountTxMarker>& marker,
|
||||||
|
int limit,
|
||||||
|
bool bUnlimited)
|
||||||
{
|
{
|
||||||
static const std::uint32_t page_length (500);
|
static const std::uint32_t page_length(500);
|
||||||
|
|
||||||
MetaTxsList ret;
|
MetaTxsList ret;
|
||||||
|
|
||||||
auto bound = [&ret](
|
auto bound = [&ret](
|
||||||
std::uint32_t ledgerIndex,
|
std::uint32_t ledgerIndex,
|
||||||
std::string const& status,
|
std::string const& status,
|
||||||
Blob const& rawTxn,
|
Blob const& rawTxn,
|
||||||
Blob const& rawMeta)
|
Blob const& rawMeta) {
|
||||||
{
|
ret.emplace_back(std::move(rawTxn), std::move(rawMeta), ledgerIndex);
|
||||||
ret.emplace_back (strHex(rawTxn), strHex (rawMeta), ledgerIndex);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
accountTxPage(app_.getTxnDB (), app_.accountIDCache(),
|
accountTxPage(
|
||||||
std::bind(saveLedgerAsync, std::ref(app_),
|
app_.getTxnDB(),
|
||||||
std::placeholders::_1), bound, account, minLedger,
|
app_.accountIDCache(),
|
||||||
maxLedger, forward, token, limit, bUnlimited,
|
std::bind(saveLedgerAsync, std::ref(app_), std::placeholders::_1),
|
||||||
page_length);
|
bound,
|
||||||
|
account,
|
||||||
|
minLedger,
|
||||||
|
maxLedger,
|
||||||
|
forward,
|
||||||
|
marker,
|
||||||
|
limit,
|
||||||
|
bUnlimited,
|
||||||
|
page_length);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -212,6 +212,12 @@ public:
|
|||||||
virtual void updateLocalTx (ReadView const& newValidLedger) = 0;
|
virtual void updateLocalTx (ReadView const& newValidLedger) = 0;
|
||||||
virtual std::size_t getLocalTxCount () = 0;
|
virtual std::size_t getLocalTxCount () = 0;
|
||||||
|
|
||||||
|
struct AccountTxMarker
|
||||||
|
{
|
||||||
|
uint32_t ledgerSeq = 0;
|
||||||
|
uint32_t txnSeq = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// client information retrieval functions
|
// client information retrieval functions
|
||||||
using AccountTx = std::pair<std::shared_ptr<Transaction>, TxMeta::pointer>;
|
using AccountTx = std::pair<std::shared_ptr<Transaction>, TxMeta::pointer>;
|
||||||
using AccountTxs = std::vector<AccountTx>;
|
using AccountTxs = std::vector<AccountTx>;
|
||||||
@@ -221,21 +227,32 @@ public:
|
|||||||
std::int32_t minLedger, std::int32_t maxLedger, bool descending,
|
std::int32_t minLedger, std::int32_t maxLedger, bool descending,
|
||||||
std::uint32_t offset, int limit, bool bUnlimited) = 0;
|
std::uint32_t offset, int limit, bool bUnlimited) = 0;
|
||||||
|
|
||||||
virtual AccountTxs getTxsAccount (
|
virtual AccountTxs
|
||||||
|
getTxsAccount(
|
||||||
AccountID const& account,
|
AccountID const& account,
|
||||||
std::int32_t minLedger, std::int32_t maxLedger, bool forward,
|
std::int32_t minLedger,
|
||||||
Json::Value& token, int limit, bool bUnlimited) = 0;
|
std::int32_t maxLedger,
|
||||||
|
bool forward,
|
||||||
|
std::optional<AccountTxMarker>& marker,
|
||||||
|
int limit,
|
||||||
|
bool bUnlimited) = 0;
|
||||||
|
|
||||||
using txnMetaLedgerType = std::tuple<std::string, std::string, std::uint32_t>;
|
using txnMetaLedgerType = std::tuple<Blob, Blob, std::uint32_t>;
|
||||||
using MetaTxsList = std::vector<txnMetaLedgerType>;
|
using MetaTxsList = std::vector<txnMetaLedgerType>;
|
||||||
|
|
||||||
virtual MetaTxsList getAccountTxsB (AccountID const& account,
|
virtual MetaTxsList getAccountTxsB (AccountID const& account,
|
||||||
std::int32_t minLedger, std::int32_t maxLedger, bool descending,
|
std::int32_t minLedger, std::int32_t maxLedger, bool descending,
|
||||||
std::uint32_t offset, int limit, bool bUnlimited) = 0;
|
std::uint32_t offset, int limit, bool bUnlimited) = 0;
|
||||||
|
|
||||||
virtual MetaTxsList getTxsAccountB (AccountID const& account,
|
virtual MetaTxsList
|
||||||
std::int32_t minLedger, std::int32_t maxLedger, bool forward,
|
getTxsAccountB(
|
||||||
Json::Value& token, int limit, bool bUnlimited) = 0;
|
AccountID const& account,
|
||||||
|
std::int32_t minLedger,
|
||||||
|
std::int32_t maxLedger,
|
||||||
|
bool forward,
|
||||||
|
std::optional<AccountTxMarker>& marker,
|
||||||
|
int limit,
|
||||||
|
bool bUnlimited) = 0;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -61,24 +61,25 @@ saveLedgerAsync (Application& app, std::uint32_t seq)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
accountTxPage (
|
accountTxPage(
|
||||||
DatabaseCon& connection,
|
DatabaseCon& connection,
|
||||||
AccountIDCache const& idCache,
|
AccountIDCache const& idCache,
|
||||||
std::function<void (std::uint32_t)> const& onUnsavedLedger,
|
std::function<void(std::uint32_t)> const& onUnsavedLedger,
|
||||||
std::function<void (std::uint32_t,
|
std::function<void(
|
||||||
std::string const&,
|
std::uint32_t,
|
||||||
Blob const&,
|
std::string const&,
|
||||||
Blob const&)> const& onTransaction,
|
Blob const&,
|
||||||
|
Blob const&)> const& onTransaction,
|
||||||
AccountID const& account,
|
AccountID const& account,
|
||||||
std::int32_t minLedger,
|
std::int32_t minLedger,
|
||||||
std::int32_t maxLedger,
|
std::int32_t maxLedger,
|
||||||
bool forward,
|
bool forward,
|
||||||
Json::Value& token,
|
std::optional<NetworkOPs::AccountTxMarker>& marker,
|
||||||
int limit,
|
int limit,
|
||||||
bool bAdmin,
|
bool bAdmin,
|
||||||
std::uint32_t page_length)
|
std::uint32_t page_length)
|
||||||
{
|
{
|
||||||
bool lookingForMarker = token.isObject();
|
bool lookingForMarker = marker.has_value();
|
||||||
|
|
||||||
std::uint32_t numberOfResults;
|
std::uint32_t numberOfResults;
|
||||||
|
|
||||||
@@ -97,24 +98,14 @@ accountTxPage (
|
|||||||
|
|
||||||
if (lookingForMarker)
|
if (lookingForMarker)
|
||||||
{
|
{
|
||||||
try
|
findLedger = marker->ledgerSeq;
|
||||||
{
|
findSeq = marker->txnSeq;
|
||||||
if (!token.isMember(jss::ledger) || !token.isMember(jss::seq))
|
|
||||||
return;
|
|
||||||
findLedger = token[jss::ledger].asInt();
|
|
||||||
findSeq = token[jss::seq].asInt();
|
|
||||||
}
|
|
||||||
catch (std::exception const&)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're using the token reference both for passing inputs and outputs, so
|
// marker is also an output parameter, so need to reset
|
||||||
// we need to clear it in between.
|
marker.reset();
|
||||||
token = Json::nullValue;
|
|
||||||
|
|
||||||
static std::string const prefix (
|
static std::string const prefix(
|
||||||
R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
|
R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
|
||||||
Status,RawTxn,TxnMeta
|
Status,RawTxn,TxnMeta
|
||||||
FROM AccountTransactions INNER JOIN Transactions
|
FROM AccountTransactions INNER JOIN Transactions
|
||||||
@@ -128,22 +119,20 @@ accountTxPage (
|
|||||||
|
|
||||||
if (forward && (findLedger == 0))
|
if (forward && (findLedger == 0))
|
||||||
{
|
{
|
||||||
sql = boost::str (boost::format(
|
sql = boost::str(
|
||||||
prefix +
|
boost::format(
|
||||||
(R"(AccountTransactions.LedgerSeq BETWEEN '%u' AND '%u'
|
prefix + (R"(AccountTransactions.LedgerSeq BETWEEN '%u' AND '%u'
|
||||||
ORDER BY AccountTransactions.LedgerSeq ASC,
|
ORDER BY AccountTransactions.LedgerSeq ASC,
|
||||||
AccountTransactions.TxnSeq ASC
|
AccountTransactions.TxnSeq ASC
|
||||||
LIMIT %u;)"))
|
LIMIT %u;)")) %
|
||||||
% idCache.toBase58(account)
|
idCache.toBase58(account) % minLedger % maxLedger % queryLimit);
|
||||||
% minLedger
|
|
||||||
% maxLedger
|
|
||||||
% queryLimit);
|
|
||||||
}
|
}
|
||||||
else if (forward && (findLedger != 0))
|
else if (forward && (findLedger != 0))
|
||||||
{
|
{
|
||||||
auto b58acct = idCache.toBase58(account);
|
auto b58acct = idCache.toBase58(account);
|
||||||
sql = boost::str (boost::format(
|
sql = boost::str(
|
||||||
(R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
|
boost::format((
|
||||||
|
R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
|
||||||
Status,RawTxn,TxnMeta
|
Status,RawTxn,TxnMeta
|
||||||
FROM AccountTransactions, Transactions WHERE
|
FROM AccountTransactions, Transactions WHERE
|
||||||
(AccountTransactions.TransID = Transactions.TransID AND
|
(AccountTransactions.TransID = Transactions.TransID AND
|
||||||
@@ -157,33 +146,26 @@ accountTxPage (
|
|||||||
ORDER BY AccountTransactions.LedgerSeq ASC,
|
ORDER BY AccountTransactions.LedgerSeq ASC,
|
||||||
AccountTransactions.TxnSeq ASC
|
AccountTransactions.TxnSeq ASC
|
||||||
LIMIT %u;
|
LIMIT %u;
|
||||||
)"))
|
)")) %
|
||||||
% b58acct
|
b58acct % (findLedger + 1) % maxLedger % b58acct % findLedger %
|
||||||
% (findLedger + 1)
|
findSeq % queryLimit);
|
||||||
% maxLedger
|
|
||||||
% b58acct
|
|
||||||
% findLedger
|
|
||||||
% findSeq
|
|
||||||
% queryLimit);
|
|
||||||
}
|
}
|
||||||
else if (!forward && (findLedger == 0))
|
else if (!forward && (findLedger == 0))
|
||||||
{
|
{
|
||||||
sql = boost::str (boost::format(
|
sql = boost::str(
|
||||||
prefix +
|
boost::format(
|
||||||
(R"(AccountTransactions.LedgerSeq BETWEEN '%u' AND '%u'
|
prefix + (R"(AccountTransactions.LedgerSeq BETWEEN '%u' AND '%u'
|
||||||
ORDER BY AccountTransactions.LedgerSeq DESC,
|
ORDER BY AccountTransactions.LedgerSeq DESC,
|
||||||
AccountTransactions.TxnSeq DESC
|
AccountTransactions.TxnSeq DESC
|
||||||
LIMIT %u;)"))
|
LIMIT %u;)")) %
|
||||||
% idCache.toBase58(account)
|
idCache.toBase58(account) % minLedger % maxLedger % queryLimit);
|
||||||
% minLedger
|
|
||||||
% maxLedger
|
|
||||||
% queryLimit);
|
|
||||||
}
|
}
|
||||||
else if (!forward && (findLedger != 0))
|
else if (!forward && (findLedger != 0))
|
||||||
{
|
{
|
||||||
auto b58acct = idCache.toBase58(account);
|
auto b58acct = idCache.toBase58(account);
|
||||||
sql = boost::str (boost::format(
|
sql = boost::str(
|
||||||
(R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
|
boost::format((
|
||||||
|
R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
|
||||||
Status,RawTxn,TxnMeta
|
Status,RawTxn,TxnMeta
|
||||||
FROM AccountTransactions, Transactions WHERE
|
FROM AccountTransactions, Transactions WHERE
|
||||||
(AccountTransactions.TransID = Transactions.TransID AND
|
(AccountTransactions.TransID = Transactions.TransID AND
|
||||||
@@ -197,24 +179,19 @@ accountTxPage (
|
|||||||
ORDER BY AccountTransactions.LedgerSeq DESC,
|
ORDER BY AccountTransactions.LedgerSeq DESC,
|
||||||
AccountTransactions.TxnSeq DESC
|
AccountTransactions.TxnSeq DESC
|
||||||
LIMIT %u;
|
LIMIT %u;
|
||||||
)"))
|
)")) %
|
||||||
% b58acct
|
b58acct % minLedger % (findLedger - 1) % b58acct % findLedger %
|
||||||
% minLedger
|
findSeq % queryLimit);
|
||||||
% (findLedger - 1)
|
|
||||||
% b58acct
|
|
||||||
% findLedger
|
|
||||||
% findSeq
|
|
||||||
% queryLimit);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert (false);
|
assert(false);
|
||||||
// sql is empty
|
// sql is empty
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto db (connection.checkoutDb());
|
auto db(connection.checkoutDb());
|
||||||
|
|
||||||
Blob rawData;
|
Blob rawData;
|
||||||
Blob rawMeta;
|
Blob rawMeta;
|
||||||
@@ -222,55 +199,59 @@ accountTxPage (
|
|||||||
boost::optional<std::uint64_t> ledgerSeq;
|
boost::optional<std::uint64_t> ledgerSeq;
|
||||||
boost::optional<std::uint32_t> txnSeq;
|
boost::optional<std::uint32_t> txnSeq;
|
||||||
boost::optional<std::string> status;
|
boost::optional<std::string> status;
|
||||||
soci::blob txnData (*db);
|
soci::blob txnData(*db);
|
||||||
soci::blob txnMeta (*db);
|
soci::blob txnMeta(*db);
|
||||||
soci::indicator dataPresent, metaPresent;
|
soci::indicator dataPresent, metaPresent;
|
||||||
|
|
||||||
soci::statement st = (db->prepare << sql,
|
soci::statement st =
|
||||||
soci::into (ledgerSeq),
|
(db->prepare << sql,
|
||||||
soci::into (txnSeq),
|
soci::into(ledgerSeq),
|
||||||
soci::into (status),
|
soci::into(txnSeq),
|
||||||
soci::into (txnData, dataPresent),
|
soci::into(status),
|
||||||
soci::into (txnMeta, metaPresent));
|
soci::into(txnData, dataPresent),
|
||||||
|
soci::into(txnMeta, metaPresent));
|
||||||
|
|
||||||
st.execute ();
|
st.execute();
|
||||||
|
|
||||||
while (st.fetch ())
|
while (st.fetch())
|
||||||
{
|
{
|
||||||
if (lookingForMarker)
|
if (lookingForMarker)
|
||||||
{
|
{
|
||||||
if (findLedger == ledgerSeq.value_or (0) &&
|
if (findLedger == ledgerSeq.value_or(0) &&
|
||||||
findSeq == txnSeq.value_or (0))
|
findSeq == txnSeq.value_or(0))
|
||||||
{
|
{
|
||||||
lookingForMarker = false;
|
lookingForMarker = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (numberOfResults == 0)
|
else if (numberOfResults == 0)
|
||||||
{
|
{
|
||||||
token = Json::objectValue;
|
marker = {
|
||||||
token[jss::ledger] = rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or (0));
|
rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
|
||||||
token[jss::seq] = txnSeq.value_or (0);
|
txnSeq.value_or(0)};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lookingForMarker)
|
if (!lookingForMarker)
|
||||||
{
|
{
|
||||||
if (dataPresent == soci::i_ok)
|
if (dataPresent == soci::i_ok)
|
||||||
convert (txnData, rawData);
|
convert(txnData, rawData);
|
||||||
else
|
else
|
||||||
rawData.clear ();
|
rawData.clear();
|
||||||
|
|
||||||
if (metaPresent == soci::i_ok)
|
if (metaPresent == soci::i_ok)
|
||||||
convert (txnMeta, rawMeta);
|
convert(txnMeta, rawMeta);
|
||||||
else
|
else
|
||||||
rawMeta.clear ();
|
rawMeta.clear();
|
||||||
|
|
||||||
// Work around a bug that could leave the metadata missing
|
// Work around a bug that could leave the metadata missing
|
||||||
if (rawMeta.size() == 0)
|
if (rawMeta.size() == 0)
|
||||||
onUnsavedLedger(ledgerSeq.value_or (0));
|
onUnsavedLedger(ledgerSeq.value_or(0));
|
||||||
|
|
||||||
onTransaction(rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or (0)),
|
onTransaction(
|
||||||
*status, rawData, rawMeta);
|
rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
|
||||||
|
*status,
|
||||||
|
rawData,
|
||||||
|
rawMeta);
|
||||||
--numberOfResults;
|
--numberOfResults;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,5 +259,4 @@ accountTxPage (
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,23 +44,23 @@ void
|
|||||||
saveLedgerAsync (Application& app, std::uint32_t seq);
|
saveLedgerAsync (Application& app, std::uint32_t seq);
|
||||||
|
|
||||||
void
|
void
|
||||||
accountTxPage (
|
accountTxPage(
|
||||||
DatabaseCon& database,
|
DatabaseCon& connection,
|
||||||
AccountIDCache const& idCache,
|
AccountIDCache const& idCache,
|
||||||
std::function<void (std::uint32_t)> const& onUnsavedLedger,
|
std::function<void(std::uint32_t)> const& onUnsavedLedger,
|
||||||
std::function<void (std::uint32_t,
|
std::function<void(
|
||||||
std::string const&,
|
std::uint32_t,
|
||||||
Blob const&,
|
std::string const&,
|
||||||
Blob const&)> const&,
|
Blob const&,
|
||||||
|
Blob const&)> const& onTransaction,
|
||||||
AccountID const& account,
|
AccountID const& account,
|
||||||
std::int32_t minLedger,
|
std::int32_t minLedger,
|
||||||
std::int32_t maxLedger,
|
std::int32_t maxLedger,
|
||||||
bool forward,
|
bool forward,
|
||||||
Json::Value& token,
|
std::optional<NetworkOPs::AccountTxMarker>& marker,
|
||||||
int limit,
|
int limit,
|
||||||
bool bAdmin,
|
bool bAdmin,
|
||||||
std::uint32_t pageLength);
|
std::uint32_t page_length);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
14
src/ripple/proto/org/xrpl/rpc/v1/account.proto
Normal file
14
src/ripple/proto/org/xrpl/rpc/v1/account.proto
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
// A representation of an account address
|
||||||
|
// Next field: 2
|
||||||
|
message AccountAddress
|
||||||
|
{
|
||||||
|
// base58 encoding of an account
|
||||||
|
string address = 1;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,29 +1,32 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package rpc.v1;
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
message CurrencyAmount {
|
import "org/xrpl/rpc/v1/account.proto";
|
||||||
oneof amount {
|
|
||||||
|
// Next field: 3
|
||||||
|
message CurrencyAmount
|
||||||
|
{
|
||||||
|
oneof amount
|
||||||
|
{
|
||||||
XRPDropsAmount xrp_amount = 1;
|
XRPDropsAmount xrp_amount = 1;
|
||||||
IssuedCurrencyAmount issued_currency_amount = 2;
|
IssuedCurrencyAmount issued_currency_amount = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A representation of an amount of XRP.
|
// A representation of an amount of XRP.
|
||||||
message XRPDropsAmount {
|
// Next field: 2
|
||||||
|
message XRPDropsAmount
|
||||||
uint64 drops = 1;
|
{
|
||||||
}
|
uint64 drops = 1 [jstype=JS_STRING];
|
||||||
|
|
||||||
// A representation of an account address
|
|
||||||
message AccountAddress {
|
|
||||||
|
|
||||||
//base58 encoding of an account
|
|
||||||
string address = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A representation of an amount of issued currency.
|
// A representation of an amount of issued currency.
|
||||||
message IssuedCurrencyAmount {
|
// Next field: 4
|
||||||
|
message IssuedCurrencyAmount
|
||||||
|
{
|
||||||
// The currency used to value the amount.
|
// The currency used to value the amount.
|
||||||
Currency currency = 1;
|
Currency currency = 1;
|
||||||
|
|
||||||
@@ -34,8 +37,9 @@ message IssuedCurrencyAmount {
|
|||||||
AccountAddress issuer = 3;
|
AccountAddress issuer = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Currency {
|
// Next field: 3
|
||||||
|
message Currency
|
||||||
|
{
|
||||||
// 3 character ASCII code
|
// 3 character ASCII code
|
||||||
string name = 1;
|
string name = 1;
|
||||||
|
|
||||||
476
src/ripple/proto/org/xrpl/rpc/v1/common.proto
Normal file
476
src/ripple/proto/org/xrpl/rpc/v1/common.proto
Normal file
@@ -0,0 +1,476 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import "org/xrpl/rpc/v1/amount.proto";
|
||||||
|
import "org/xrpl/rpc/v1/account.proto";
|
||||||
|
|
||||||
|
// These fields are used in many different messsage types. They can be present
|
||||||
|
// in one or more transactions, as well as metadata of one or more transactions.
|
||||||
|
// Each is defined as its own message type with a single field "value", to
|
||||||
|
// ensure the field is the correct type everywhere it's used
|
||||||
|
|
||||||
|
|
||||||
|
// *** Messages wrapping uint32 ***
|
||||||
|
|
||||||
|
message CancelAfter
|
||||||
|
{
|
||||||
|
// time in seconds since Ripple epoch
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ClearFlag
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CloseTime
|
||||||
|
{
|
||||||
|
// time in seconds since Ripple epoch
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Date
|
||||||
|
{
|
||||||
|
// time in seconds since Ripple epoch
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DestinationTag
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Expiration
|
||||||
|
{
|
||||||
|
// time in seconds since Ripple epoch
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message FinishAfter
|
||||||
|
{
|
||||||
|
// time in seconds since Ripple epoch
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Flags
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message HighQualityIn
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message HighQualityOut
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LastLedgerSequence
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LowQualityIn
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LowQualityOut
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OfferSequence
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message OwnerCount
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PreviousTransactionLedgerSequence
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message QualityIn
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message QualityOut
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ReferenceFeeUnits
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ReserveBase
|
||||||
|
{
|
||||||
|
// in drops
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ReserveIncrement
|
||||||
|
{
|
||||||
|
// in drops
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Sequence
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SetFlag
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SettleDelay
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SignerListID
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SignerQuorum
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SignerWeight
|
||||||
|
{
|
||||||
|
// is actually uint16
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SourceTag
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TickSize
|
||||||
|
{
|
||||||
|
// is actually uint8
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransferRate
|
||||||
|
{
|
||||||
|
uint32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** Messages wrapping uint64 ***
|
||||||
|
|
||||||
|
message BaseFee
|
||||||
|
{
|
||||||
|
// in drops
|
||||||
|
uint64 value = 1 [jstype=JS_STRING];
|
||||||
|
}
|
||||||
|
|
||||||
|
message BookNode
|
||||||
|
{
|
||||||
|
uint64 value = 1 [jstype=JS_STRING];
|
||||||
|
}
|
||||||
|
|
||||||
|
message DestinationNode
|
||||||
|
{
|
||||||
|
uint64 value = 1 [jstype=JS_STRING];
|
||||||
|
}
|
||||||
|
|
||||||
|
message HighNode
|
||||||
|
{
|
||||||
|
uint64 value = 1 [jstype=JS_STRING];
|
||||||
|
}
|
||||||
|
|
||||||
|
message IndexNext
|
||||||
|
{
|
||||||
|
uint64 value = 1 [jstype=JS_STRING];
|
||||||
|
}
|
||||||
|
|
||||||
|
message IndexPrevious
|
||||||
|
{
|
||||||
|
uint64 value = 1 [jstype=JS_STRING];
|
||||||
|
}
|
||||||
|
|
||||||
|
message LowNode
|
||||||
|
{
|
||||||
|
uint64 value = 1 [jstype=JS_STRING];
|
||||||
|
}
|
||||||
|
|
||||||
|
message OwnerNode
|
||||||
|
{
|
||||||
|
uint64 value = 1 [jstype=JS_STRING];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** Messages wrapping 16 bytes ***
|
||||||
|
|
||||||
|
message EmailHash
|
||||||
|
{
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** Messages wrapping 20 bytes ***
|
||||||
|
|
||||||
|
message TakerGetsIssuer
|
||||||
|
{
|
||||||
|
// 20 bytes
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TakerPaysIssuer
|
||||||
|
{
|
||||||
|
// 20 bytes
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** Messages wrapping 32 bytes ***
|
||||||
|
|
||||||
|
message AccountTransactionID
|
||||||
|
{
|
||||||
|
// 32 bytes
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BookDirectory
|
||||||
|
{
|
||||||
|
// 32 btes
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Channel
|
||||||
|
{
|
||||||
|
// 32 bytes
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CheckID
|
||||||
|
{
|
||||||
|
// 32 bytes
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Hash
|
||||||
|
{
|
||||||
|
// 32 bytes
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Index
|
||||||
|
{
|
||||||
|
// 32 bytes
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message InvoiceID
|
||||||
|
{
|
||||||
|
// 32 bytes
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PreviousTransactionID
|
||||||
|
{
|
||||||
|
// 32 bytes
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RootIndex
|
||||||
|
{
|
||||||
|
// 32 bytes
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** Messages wrapping variable length byte arrays ***
|
||||||
|
|
||||||
|
message Condition
|
||||||
|
{
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Fulfillment
|
||||||
|
{
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MemoData
|
||||||
|
{
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MemoFormat
|
||||||
|
{
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MemoType
|
||||||
|
{
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MessageKey
|
||||||
|
{
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PublicKey
|
||||||
|
{
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PaymentChannelSignature
|
||||||
|
{
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SigningPublicKey
|
||||||
|
{
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TransactionSignature
|
||||||
|
{
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** Messages wrapping a Currency value ***
|
||||||
|
|
||||||
|
message TakerGetsCurreny
|
||||||
|
{
|
||||||
|
Currency value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TakerPaysCurrency
|
||||||
|
{
|
||||||
|
Currency value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** Messages wrapping a CurrencyAmount ***
|
||||||
|
|
||||||
|
message Amount
|
||||||
|
{
|
||||||
|
// Note, CurrencyAmount is a oneof, that can represent an XRP drops amount
|
||||||
|
// or an Issued Currency amount. However, in some transaction types/ledger
|
||||||
|
// objects, this value can only be in drops. For instance, the Amount field
|
||||||
|
// of a Payment transaction can be specified in XRP drops or an Issued
|
||||||
|
// Currency amount, but the Amount field of a PaymentChannelClaim
|
||||||
|
// transaction can only be an XRP drops amount.
|
||||||
|
CurrencyAmount value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Balance
|
||||||
|
{
|
||||||
|
CurrencyAmount value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeliverMin
|
||||||
|
{
|
||||||
|
CurrencyAmount value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeliveredAmount
|
||||||
|
{
|
||||||
|
CurrencyAmount value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message HighLimit
|
||||||
|
{
|
||||||
|
CurrencyAmount value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LimitAmount
|
||||||
|
{
|
||||||
|
CurrencyAmount value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message LowLimit
|
||||||
|
{
|
||||||
|
CurrencyAmount value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SendMax
|
||||||
|
{
|
||||||
|
CurrencyAmount value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TakerGets
|
||||||
|
{
|
||||||
|
CurrencyAmount value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TakerPays
|
||||||
|
{
|
||||||
|
CurrencyAmount value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** Messages wrapping an AccountAddress ***
|
||||||
|
|
||||||
|
message Account
|
||||||
|
{
|
||||||
|
AccountAddress value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Authorize
|
||||||
|
{
|
||||||
|
AccountAddress value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Destination
|
||||||
|
{
|
||||||
|
AccountAddress value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Owner
|
||||||
|
{
|
||||||
|
AccountAddress value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RegularKey
|
||||||
|
{
|
||||||
|
AccountAddress value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Unauthorize
|
||||||
|
{
|
||||||
|
AccountAddress value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** Messages wrapping a string ***
|
||||||
|
|
||||||
|
message Domain
|
||||||
|
{
|
||||||
|
string value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// *** Aggregate type messages
|
||||||
|
|
||||||
|
// Next field: 3
|
||||||
|
message SignerEntry
|
||||||
|
{
|
||||||
|
Account account = 1;
|
||||||
|
|
||||||
|
SignerWeight signer_weight = 2;
|
||||||
|
}
|
||||||
@@ -1,12 +1,19 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package rpc.v1;
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
import "rpc/v1/ledger_objects.proto";
|
import "org/xrpl/rpc/v1/ledger_objects.proto";
|
||||||
import "rpc/v1/amount.proto";
|
import "org/xrpl/rpc/v1/amount.proto";
|
||||||
|
import "org/xrpl/rpc/v1/account.proto";
|
||||||
|
import "org/xrpl/rpc/v1/ledger.proto";
|
||||||
|
import "org/xrpl/rpc/v1/common.proto";
|
||||||
|
|
||||||
// A request to get info about an account.
|
// A request to get info about an account.
|
||||||
message GetAccountInfoRequest {
|
// Next field: 6
|
||||||
|
message GetAccountInfoRequest
|
||||||
|
{
|
||||||
// The address to get info about.
|
// The address to get info about.
|
||||||
AccountAddress account = 1;
|
AccountAddress account = 1;
|
||||||
|
|
||||||
@@ -19,25 +26,10 @@ message GetAccountInfoRequest {
|
|||||||
bool signer_lists = 5;
|
bool signer_lists = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LedgerSpecifier {
|
|
||||||
enum Shortcut {
|
|
||||||
SHORTCUT_UNSPECIFIED = 0;
|
|
||||||
SHORTCUT_VALIDATED = 1;
|
|
||||||
SHORTCUT_CLOSED = 2;
|
|
||||||
SHORTCUT_CURRENT = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
oneof ledger {
|
|
||||||
Shortcut shortcut = 1;
|
|
||||||
uint32 sequence = 2;
|
|
||||||
// 32 bytes
|
|
||||||
bytes hash = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Response to GetAccountInfo RPC
|
// Response to GetAccountInfo RPC
|
||||||
message GetAccountInfoResponse {
|
// Next field: 6
|
||||||
|
message GetAccountInfoResponse
|
||||||
|
{
|
||||||
AccountRoot account_data = 1;
|
AccountRoot account_data = 1;
|
||||||
|
|
||||||
SignerList signer_list = 2;
|
SignerList signer_list = 2;
|
||||||
@@ -50,8 +42,9 @@ message GetAccountInfoResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Aggregate data about queued transactions
|
// Aggregate data about queued transactions
|
||||||
message QueueData {
|
// Next field: 7
|
||||||
|
message QueueData
|
||||||
|
{
|
||||||
uint32 txn_count = 1;
|
uint32 txn_count = 1;
|
||||||
|
|
||||||
bool auth_change_queued = 2;
|
bool auth_change_queued = 2;
|
||||||
@@ -66,16 +59,18 @@ message QueueData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Data about a single queued transaction
|
// Data about a single queued transaction
|
||||||
message QueuedTransaction {
|
// Next field: 7
|
||||||
|
message QueuedTransaction
|
||||||
|
{
|
||||||
bool auth_change = 1;
|
bool auth_change = 1;
|
||||||
|
|
||||||
XRPDropsAmount fee = 2;
|
XRPDropsAmount fee = 2;
|
||||||
|
|
||||||
uint64 fee_level = 3;
|
uint64 fee_level = 3 [jstype=JS_STRING];
|
||||||
|
|
||||||
XRPDropsAmount max_spend_drops = 4;
|
XRPDropsAmount max_spend_drops = 4;
|
||||||
|
|
||||||
uint32 sequence = 5;
|
Sequence sequence = 5;
|
||||||
|
|
||||||
uint32 last_ledger_sequence = 6;
|
LastLedgerSequence last_ledger_sequence = 6;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
import "org/xrpl/rpc/v1/get_transaction.proto";
|
||||||
|
import "org/xrpl/rpc/v1/account.proto";
|
||||||
|
import "org/xrpl/rpc/v1/ledger.proto";
|
||||||
|
|
||||||
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
// Next field: 8
|
||||||
|
message GetAccountTransactionHistoryRequest
|
||||||
|
{
|
||||||
|
AccountAddress account = 1;
|
||||||
|
|
||||||
|
// What ledger to include results from. Specifying a not yet validated
|
||||||
|
// ledger results in an error. Not specifying a ledger uses the entire
|
||||||
|
// range of validated ledgers available to the server.
|
||||||
|
oneof ledger
|
||||||
|
{
|
||||||
|
LedgerSpecifier ledger_specifier = 2;
|
||||||
|
LedgerRange ledger_range = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return results as binary blobs. Defaults to false.
|
||||||
|
bool binary = 4;
|
||||||
|
|
||||||
|
// If set to true, returns values indexed by older ledger first.
|
||||||
|
// Default to false.
|
||||||
|
bool forward = 5;
|
||||||
|
|
||||||
|
// Limit the number of results. Server may choose a lower limit.
|
||||||
|
// If this value is 0, the limit is ignored and the number of results
|
||||||
|
// returned is determined by the server
|
||||||
|
uint32 limit = 6;
|
||||||
|
|
||||||
|
// Marker to resume where previous request left off
|
||||||
|
// Used for pagination
|
||||||
|
Marker marker = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Next field: 8
|
||||||
|
message GetAccountTransactionHistoryResponse
|
||||||
|
{
|
||||||
|
AccountAddress account = 1;
|
||||||
|
|
||||||
|
uint32 ledger_index_min = 2;
|
||||||
|
|
||||||
|
uint32 ledger_index_max = 3;
|
||||||
|
|
||||||
|
uint32 limit = 4;
|
||||||
|
|
||||||
|
Marker marker = 5;
|
||||||
|
|
||||||
|
repeated GetTransactionResponse transactions = 6;
|
||||||
|
|
||||||
|
bool validated = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 3
|
||||||
|
message Marker
|
||||||
|
{
|
||||||
|
uint32 ledger_index = 1;
|
||||||
|
|
||||||
|
uint32 account_sequence = 2;
|
||||||
|
}
|
||||||
|
|
||||||
57
src/ripple/proto/org/xrpl/rpc/v1/get_fee.proto
Normal file
57
src/ripple/proto/org/xrpl/rpc/v1/get_fee.proto
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import "org/xrpl/rpc/v1/amount.proto";
|
||||||
|
|
||||||
|
// A request for the current transaction fee on the ledger.
|
||||||
|
// Next field: 1
|
||||||
|
message GetFeeRequest
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response to a GetFee RPC
|
||||||
|
// Next field: 8
|
||||||
|
message GetFeeResponse
|
||||||
|
{
|
||||||
|
uint64 current_ledger_size = 1 [jstype=JS_STRING];
|
||||||
|
|
||||||
|
uint64 current_queue_size = 2 [jstype=JS_STRING];
|
||||||
|
|
||||||
|
Fee fee = 3;
|
||||||
|
|
||||||
|
uint64 expected_ledger_size = 4 [jstype=JS_STRING];
|
||||||
|
|
||||||
|
uint32 ledger_current_index = 5;
|
||||||
|
|
||||||
|
FeeLevels levels = 6;
|
||||||
|
|
||||||
|
uint64 max_queue_size = 7 [jstype=JS_STRING];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 5
|
||||||
|
message Fee
|
||||||
|
{
|
||||||
|
XRPDropsAmount base_fee = 1;
|
||||||
|
|
||||||
|
XRPDropsAmount median_fee = 2;
|
||||||
|
|
||||||
|
XRPDropsAmount minimum_fee = 3;
|
||||||
|
|
||||||
|
XRPDropsAmount open_ledger_fee = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 5
|
||||||
|
message FeeLevels
|
||||||
|
{
|
||||||
|
uint64 median_level = 1 [jstype=JS_STRING];
|
||||||
|
|
||||||
|
uint64 minimum_level = 2 [jstype=JS_STRING];
|
||||||
|
|
||||||
|
uint64 open_ledger_level = 3 [jstype=JS_STRING];
|
||||||
|
|
||||||
|
uint64 reference_level = 4 [jstype=JS_STRING];
|
||||||
|
}
|
||||||
56
src/ripple/proto/org/xrpl/rpc/v1/get_transaction.proto
Normal file
56
src/ripple/proto/org/xrpl/rpc/v1/get_transaction.proto
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import "org/xrpl/rpc/v1/meta.proto";
|
||||||
|
import "org/xrpl/rpc/v1/ledger.proto";
|
||||||
|
import "org/xrpl/rpc/v1/transaction.proto";
|
||||||
|
import "org/xrpl/rpc/v1/common.proto";
|
||||||
|
|
||||||
|
// Next field: 4
|
||||||
|
message GetTransactionRequest {
|
||||||
|
|
||||||
|
// hash of the transaction. 32 bytes
|
||||||
|
// ATTN: this is in binary, not hex. The JSON API accepts a hex string for
|
||||||
|
// a transaction hash, but here we need that hex string converted into its
|
||||||
|
// binary form. Each pair of hex characters should be converted into its
|
||||||
|
// corresponding byte. For example, the 4 character hex string "00FF"
|
||||||
|
// should be converted to a 2 byte array: [0, 255]
|
||||||
|
bytes hash = 1;
|
||||||
|
|
||||||
|
// if true, return data in binary format. defaults to false
|
||||||
|
bool binary = 2;
|
||||||
|
|
||||||
|
// search only specified range. optional
|
||||||
|
LedgerRange ledger_range = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 9
|
||||||
|
message GetTransactionResponse {
|
||||||
|
|
||||||
|
oneof serialized_transaction {
|
||||||
|
|
||||||
|
Transaction transaction = 1;
|
||||||
|
// Variable length
|
||||||
|
bytes transaction_binary = 2;
|
||||||
|
};
|
||||||
|
// Sequence number of ledger that contains this transaction
|
||||||
|
uint32 ledger_index = 3;
|
||||||
|
|
||||||
|
// 32 bytes
|
||||||
|
bytes hash = 4;
|
||||||
|
|
||||||
|
// whether the ledger has been validated
|
||||||
|
bool validated = 5;
|
||||||
|
|
||||||
|
// metadata about the transaction
|
||||||
|
oneof serialized_meta {
|
||||||
|
Meta meta = 6;
|
||||||
|
// Variable length
|
||||||
|
bytes meta_binary = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
Date date = 8;
|
||||||
|
}
|
||||||
37
src/ripple/proto/org/xrpl/rpc/v1/ledger.proto
Normal file
37
src/ripple/proto/org/xrpl/rpc/v1/ledger.proto
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
// Next field: 4
|
||||||
|
message LedgerSpecifier
|
||||||
|
{
|
||||||
|
// Next field: 4
|
||||||
|
enum Shortcut
|
||||||
|
{
|
||||||
|
SHORTCUT_UNSPECIFIED = 0;
|
||||||
|
SHORTCUT_VALIDATED = 1;
|
||||||
|
SHORTCUT_CLOSED = 2;
|
||||||
|
SHORTCUT_CURRENT = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
oneof ledger
|
||||||
|
{
|
||||||
|
Shortcut shortcut = 1;
|
||||||
|
uint32 sequence = 2;
|
||||||
|
// 32 bytes
|
||||||
|
bytes hash = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 3
|
||||||
|
message LedgerRange
|
||||||
|
{
|
||||||
|
uint32 ledger_index_min = 1;
|
||||||
|
|
||||||
|
// Note, if ledger_index_min is non-zero and ledger_index_max is 0, the
|
||||||
|
// software will use the max validated ledger in place of ledger_index_max
|
||||||
|
uint32 ledger_index_max = 2;
|
||||||
|
};
|
||||||
|
|
||||||
331
src/ripple/proto/org/xrpl/rpc/v1/ledger_objects.proto
Normal file
331
src/ripple/proto/org/xrpl/rpc/v1/ledger_objects.proto
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import "org/xrpl/rpc/v1/common.proto";
|
||||||
|
|
||||||
|
// Next field: 13
|
||||||
|
message LedgerObject
|
||||||
|
{
|
||||||
|
oneof object
|
||||||
|
{
|
||||||
|
AccountRoot account_root = 1;
|
||||||
|
Amendments amendments = 2;
|
||||||
|
Check check = 3;
|
||||||
|
DepositPreauthObject deposit_preauth = 4;
|
||||||
|
DirectoryNode directory_node = 5;
|
||||||
|
Escrow escrow = 6;
|
||||||
|
FeeSettings fee_settings = 7;
|
||||||
|
LedgerHashes ledger_hashes = 8;
|
||||||
|
Offer offer = 9;
|
||||||
|
PayChannel pay_channel = 10;
|
||||||
|
RippleState ripple_state = 11;
|
||||||
|
SignerList signer_list = 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 13
|
||||||
|
enum LedgerEntryType
|
||||||
|
{
|
||||||
|
LEDGER_ENTRY_TYPE_UNSPECIFIED = 0;
|
||||||
|
LEDGER_ENTRY_TYPE_ACCOUNT_ROOT = 1;
|
||||||
|
LEDGER_ENTRY_TYPE_AMENDMENTS = 2;
|
||||||
|
LEDGER_ENTRY_TYPE_CHECK = 3;
|
||||||
|
LEDGER_ENTRY_TYPE_DEPOSIT_PREAUTH = 4;
|
||||||
|
LEDGER_ENTRY_TYPE_DIRECTORY_NODE = 5;
|
||||||
|
LEDGER_ENTRY_TYPE_ESCROW = 6;
|
||||||
|
LEDGER_ENTRY_TYPE_FEE_SETTINGS = 7;
|
||||||
|
LEDGER_ENTRY_TYPE_LEDGER_HASHES = 8;
|
||||||
|
LEDGER_ENTRY_TYPE_OFFER = 9;
|
||||||
|
LEDGER_ENTRY_TYPE_PAY_CHANNEL = 10;
|
||||||
|
LEDGER_ENTRY_TYPE_RIPPLE_STATE = 11;
|
||||||
|
LEDGER_ENTRY_TYPE_SIGNER_LIST = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 15
|
||||||
|
message AccountRoot
|
||||||
|
{
|
||||||
|
Account account = 1;
|
||||||
|
|
||||||
|
Balance balance = 2;
|
||||||
|
|
||||||
|
Sequence sequence = 3;
|
||||||
|
|
||||||
|
Flags flags = 4;
|
||||||
|
|
||||||
|
OwnerCount owner_count = 5;
|
||||||
|
|
||||||
|
PreviousTransactionID previous_transaction_id = 6;
|
||||||
|
|
||||||
|
PreviousTransactionLedgerSequence previous_transaction_ledger_sequence = 7;
|
||||||
|
|
||||||
|
AccountTransactionID account_transaction_id = 8;
|
||||||
|
|
||||||
|
Domain domain = 9;
|
||||||
|
|
||||||
|
EmailHash email_hash = 10;
|
||||||
|
|
||||||
|
MessageKey message_key = 11;
|
||||||
|
|
||||||
|
RegularKey regular_key = 12;
|
||||||
|
|
||||||
|
TickSize tick_size = 13;
|
||||||
|
|
||||||
|
TransferRate transfer_rate = 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 4
|
||||||
|
message Amendments
|
||||||
|
{
|
||||||
|
// Next field: 2
|
||||||
|
message Amendment
|
||||||
|
{
|
||||||
|
// 32 bytes
|
||||||
|
bytes value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 3
|
||||||
|
message Majority
|
||||||
|
{
|
||||||
|
Amendment amendment = 1;
|
||||||
|
|
||||||
|
CloseTime close_time = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated Amendment amendments = 1;
|
||||||
|
|
||||||
|
repeated Majority majorities = 2;
|
||||||
|
|
||||||
|
Flags flags = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 14
|
||||||
|
message Check
|
||||||
|
{
|
||||||
|
Account account = 1;
|
||||||
|
|
||||||
|
Destination destination = 2;
|
||||||
|
|
||||||
|
Flags flags = 3;
|
||||||
|
|
||||||
|
OwnerNode owner_node = 4;
|
||||||
|
|
||||||
|
PreviousTransactionID previous_transaction_id = 5;
|
||||||
|
|
||||||
|
PreviousTransactionLedgerSequence previous_transaction_ledger_sequence = 6;
|
||||||
|
|
||||||
|
SendMax send_max = 7;
|
||||||
|
|
||||||
|
Sequence sequence = 8;
|
||||||
|
|
||||||
|
DestinationNode destination_node = 9;
|
||||||
|
|
||||||
|
DestinationTag destination_tag = 10;
|
||||||
|
|
||||||
|
Expiration expiration = 11;
|
||||||
|
|
||||||
|
InvoiceID invoice_id = 12;
|
||||||
|
|
||||||
|
SourceTag source_tag = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 7
|
||||||
|
message DepositPreauthObject
|
||||||
|
{
|
||||||
|
Account account = 1;
|
||||||
|
|
||||||
|
Authorize authorize = 2;
|
||||||
|
|
||||||
|
Flags flags = 3;
|
||||||
|
|
||||||
|
OwnerNode owner_node = 4;
|
||||||
|
|
||||||
|
PreviousTransactionID previous_transaction_id = 5;
|
||||||
|
|
||||||
|
PreviousTransactionLedgerSequence previous_transaction_ledger_sequence = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 11
|
||||||
|
message DirectoryNode
|
||||||
|
{
|
||||||
|
Flags flags = 1;
|
||||||
|
|
||||||
|
RootIndex root_index = 2;
|
||||||
|
|
||||||
|
repeated Index indexes = 3;
|
||||||
|
|
||||||
|
IndexNext index_next = 4;
|
||||||
|
|
||||||
|
IndexPrevious index_previous = 5;
|
||||||
|
|
||||||
|
Owner owner = 6;
|
||||||
|
|
||||||
|
TakerPaysCurrency taker_pays_currency = 7;
|
||||||
|
|
||||||
|
TakerPaysIssuer taker_pays_issuer = 8;
|
||||||
|
|
||||||
|
TakerGetsCurreny taker_gets_currency = 9;
|
||||||
|
|
||||||
|
TakerGetsIssuer taker_gets_issuer = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 14
|
||||||
|
message Escrow
|
||||||
|
{
|
||||||
|
Account account = 1;
|
||||||
|
|
||||||
|
Destination destination = 2;
|
||||||
|
|
||||||
|
Amount amount = 3;
|
||||||
|
|
||||||
|
Condition condition = 4;
|
||||||
|
|
||||||
|
CancelAfter cancel_after = 5;
|
||||||
|
|
||||||
|
FinishAfter finish_after = 6;
|
||||||
|
|
||||||
|
Flags flags = 7;
|
||||||
|
|
||||||
|
SourceTag source_tag = 8;
|
||||||
|
|
||||||
|
DestinationTag destination_tag = 9;
|
||||||
|
|
||||||
|
OwnerNode owner_node = 10;
|
||||||
|
|
||||||
|
DestinationNode destination_node = 11;
|
||||||
|
|
||||||
|
PreviousTransactionID previous_transaction_id = 12;
|
||||||
|
|
||||||
|
PreviousTransactionLedgerSequence previous_transaction_ledger_sequence = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 6
|
||||||
|
message FeeSettings
|
||||||
|
{
|
||||||
|
BaseFee base_fee = 1;
|
||||||
|
|
||||||
|
ReferenceFeeUnits reference_fee_units = 2;
|
||||||
|
|
||||||
|
ReserveBase reserve_base = 3;
|
||||||
|
|
||||||
|
ReserveIncrement reserve_increment = 4;
|
||||||
|
|
||||||
|
Flags flags = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 4
|
||||||
|
message LedgerHashes
|
||||||
|
{
|
||||||
|
LastLedgerSequence last_ledger_sequence = 1;
|
||||||
|
|
||||||
|
repeated Hash hashes = 2;
|
||||||
|
|
||||||
|
Flags flags = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 12
|
||||||
|
message Offer
|
||||||
|
{
|
||||||
|
Account account = 1;
|
||||||
|
|
||||||
|
Sequence sequence = 2;
|
||||||
|
|
||||||
|
Flags flags = 3;
|
||||||
|
|
||||||
|
TakerPays taker_pays = 4;
|
||||||
|
|
||||||
|
TakerGets taker_gets = 5;
|
||||||
|
|
||||||
|
BookDirectory book_directory = 6;
|
||||||
|
|
||||||
|
BookNode book_node = 7;
|
||||||
|
|
||||||
|
OwnerNode owner_node = 8;
|
||||||
|
|
||||||
|
Expiration expiration = 9;
|
||||||
|
|
||||||
|
PreviousTransactionID previous_transaction_id = 10;
|
||||||
|
|
||||||
|
PreviousTransactionLedgerSequence previous_transaction_ledger_sequence = 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 13
|
||||||
|
message PayChannel
|
||||||
|
{
|
||||||
|
Account account = 1;
|
||||||
|
|
||||||
|
Destination destination = 2;
|
||||||
|
|
||||||
|
Amount amount = 3;
|
||||||
|
|
||||||
|
Balance balance = 4;
|
||||||
|
|
||||||
|
PublicKey public_key = 5;
|
||||||
|
|
||||||
|
SettleDelay settle_delay = 6;
|
||||||
|
|
||||||
|
OwnerNode owner_node = 7;
|
||||||
|
|
||||||
|
PreviousTransactionID previous_transaction_id = 8;
|
||||||
|
|
||||||
|
PreviousTransactionLedgerSequence previous_transaction_ledger_sequence = 9;
|
||||||
|
|
||||||
|
Flags flags = 10;
|
||||||
|
|
||||||
|
Expiration expiration = 11;
|
||||||
|
|
||||||
|
CancelAfter cancel_after = 12;
|
||||||
|
|
||||||
|
SourceTag source_tag = 13;
|
||||||
|
|
||||||
|
DestinationTag destination_tag = 14;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 13
|
||||||
|
message RippleState
|
||||||
|
{
|
||||||
|
Balance balance = 1;
|
||||||
|
|
||||||
|
Flags flags = 2;
|
||||||
|
|
||||||
|
LowLimit low_limit = 3;
|
||||||
|
|
||||||
|
HighLimit high_limit = 4;
|
||||||
|
|
||||||
|
LowNode low_node = 5;
|
||||||
|
|
||||||
|
HighNode high_node = 6;
|
||||||
|
|
||||||
|
LowQualityIn low_quality_in = 7;
|
||||||
|
|
||||||
|
LowQualityOut low_quality_out = 8;
|
||||||
|
|
||||||
|
HighQualityIn high_quality_in = 9;
|
||||||
|
|
||||||
|
HighQualityOut high_quality_out = 10;
|
||||||
|
|
||||||
|
PreviousTransactionID previous_transaction_id = 11;
|
||||||
|
|
||||||
|
PreviousTransactionLedgerSequence previous_transaction_ledger_sequence = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 8
|
||||||
|
message SignerList
|
||||||
|
{
|
||||||
|
Flags flags = 1;
|
||||||
|
|
||||||
|
PreviousTransactionID previous_transaction_id = 2;
|
||||||
|
|
||||||
|
PreviousTransactionLedgerSequence previous_transaction_ledger_sequence = 3;
|
||||||
|
|
||||||
|
OwnerNode owner_node = 4;
|
||||||
|
|
||||||
|
repeated SignerEntry signer_entries = 5;
|
||||||
|
|
||||||
|
SignerListID signer_list_id = 6;
|
||||||
|
|
||||||
|
SignerQuorum signer_quorum = 7;
|
||||||
|
}
|
||||||
@@ -1,25 +1,32 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package rpc.v1;
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
import "rpc/v1/amount.proto";
|
import "org/xrpl/rpc/v1/ledger_objects.proto";
|
||||||
import "rpc/v1/ledger_objects.proto";
|
import "org/xrpl/rpc/v1/common.proto";
|
||||||
|
|
||||||
message Meta {
|
// Next field: 5
|
||||||
|
message Meta
|
||||||
|
{
|
||||||
// index in ledger
|
// index in ledger
|
||||||
uint64 transaction_index = 1;
|
uint64 transaction_index = 1 [jstype=JS_STRING];
|
||||||
|
|
||||||
// result code indicating whether the transaction succeeded or failed
|
// result code indicating whether the transaction succeeded or failed
|
||||||
TransactionResult transaction_result = 2;
|
TransactionResult transaction_result = 2;
|
||||||
|
|
||||||
repeated AffectedNode affected_nodes = 3;
|
repeated AffectedNode affected_nodes = 3;
|
||||||
|
|
||||||
CurrencyAmount delivered_amount = 4;
|
DeliveredAmount delivered_amount = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TransactionResult {
|
// Next field: 3
|
||||||
|
message TransactionResult
|
||||||
enum ResultType {
|
{
|
||||||
|
// Next field: 7
|
||||||
|
enum ResultType
|
||||||
|
{
|
||||||
RESULT_TYPE_UNSPECIFIED = 0;
|
RESULT_TYPE_UNSPECIFIED = 0;
|
||||||
// Claimed cost only
|
// Claimed cost only
|
||||||
RESULT_TYPE_TEC = 1;
|
RESULT_TYPE_TEC = 1;
|
||||||
@@ -42,41 +49,42 @@ message TransactionResult {
|
|||||||
string result = 2;
|
string result = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AffectedNode {
|
// Next field: 6
|
||||||
|
message AffectedNode
|
||||||
|
{
|
||||||
LedgerEntryType ledger_entry_type = 1;
|
LedgerEntryType ledger_entry_type = 1;
|
||||||
|
|
||||||
// 32 bytes
|
// 32 bytes
|
||||||
bytes ledger_index = 2;
|
bytes ledger_index = 2;
|
||||||
|
|
||||||
oneof node {
|
oneof node
|
||||||
|
{
|
||||||
CreatedNode created_node = 3;
|
CreatedNode created_node = 3;
|
||||||
DeletedNode deleted_node = 4;
|
DeletedNode deleted_node = 4;
|
||||||
ModifiedNode modified_node = 5;
|
ModifiedNode modified_node = 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message CreatedNode {
|
// Next field: 2
|
||||||
|
message CreatedNode
|
||||||
|
{
|
||||||
LedgerObject new_fields = 1;
|
LedgerObject new_fields = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeletedNode {
|
// Next field: 2
|
||||||
|
message DeletedNode
|
||||||
|
{
|
||||||
LedgerObject final_fields = 1;
|
LedgerObject final_fields = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Next field: 5
|
||||||
message ModifiedNode {
|
message ModifiedNode {
|
||||||
|
|
||||||
LedgerObject final_fields = 1;
|
LedgerObject final_fields = 1;
|
||||||
|
|
||||||
LedgerObject previous_fields = 2;
|
LedgerObject previous_fields = 2;
|
||||||
|
|
||||||
// 32 bytes
|
PreviousTransactionID previous_transaction_id = 3;
|
||||||
bytes previous_transaction_id = 3;
|
|
||||||
|
|
||||||
uint32 previous_transaction_ledger_sequence = 4;
|
|
||||||
|
|
||||||
|
PreviousTransactionLedgerSequence previous_transaction_ledger_sequence = 4;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package rpc.v1;
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
import "rpc/v1/meta.proto";
|
import "org/xrpl/rpc/v1/meta.proto";
|
||||||
|
|
||||||
// A request to submit the signed transaction to the ledger.
|
// A request to submit the signed transaction to the ledger.
|
||||||
message SubmitTransactionRequest {
|
// Next field: 3
|
||||||
|
message SubmitTransactionRequest
|
||||||
|
{
|
||||||
// The signed transaction to submit.
|
// The signed transaction to submit.
|
||||||
bytes signed_transaction = 1;
|
bytes signed_transaction = 1;
|
||||||
|
|
||||||
@@ -13,11 +17,14 @@ message SubmitTransactionRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A response when a signed transaction is submitted to the ledger.
|
// A response when a signed transaction is submitted to the ledger.
|
||||||
message SubmitTransactionResponse {
|
// Next field: 5
|
||||||
|
message SubmitTransactionResponse
|
||||||
|
{
|
||||||
// Code indicating the preliminary result of the transaction.
|
// Code indicating the preliminary result of the transaction.
|
||||||
TransactionResult engine_result = 1;
|
TransactionResult engine_result = 1;
|
||||||
|
|
||||||
// Numeric code indicating the preliminary result of the transaction, directly correlated to engine_result.
|
// Numeric code indicating the preliminary result of the transaction,
|
||||||
|
// directly correlated to engine_result.
|
||||||
int64 engine_result_code = 2;
|
int64 engine_result_code = 2;
|
||||||
|
|
||||||
// Human-readable explanation of the transaction's preliminary result.
|
// Human-readable explanation of the transaction's preliminary result.
|
||||||
319
src/ripple/proto/org/xrpl/rpc/v1/transaction.proto
Normal file
319
src/ripple/proto/org/xrpl/rpc/v1/transaction.proto
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import "org/xrpl/rpc/v1/common.proto";
|
||||||
|
import "org/xrpl/rpc/v1/amount.proto";
|
||||||
|
import "org/xrpl/rpc/v1/account.proto";
|
||||||
|
|
||||||
|
// A message encompassing all transaction types
|
||||||
|
// Next field: 30
|
||||||
|
message Transaction
|
||||||
|
{
|
||||||
|
Account account = 1;
|
||||||
|
|
||||||
|
XRPDropsAmount fee = 2;
|
||||||
|
|
||||||
|
Sequence sequence = 3;
|
||||||
|
|
||||||
|
// Data specific to the type of transaction
|
||||||
|
oneof transaction_data
|
||||||
|
{
|
||||||
|
Payment payment = 4;
|
||||||
|
|
||||||
|
AccountSet account_set = 13;
|
||||||
|
|
||||||
|
AccountDelete account_delete = 14;
|
||||||
|
|
||||||
|
CheckCancel check_cancel = 15;
|
||||||
|
|
||||||
|
CheckCash check_cash = 16;
|
||||||
|
|
||||||
|
CheckCreate check_create = 17;
|
||||||
|
|
||||||
|
DepositPreauth deposit_preauth = 18;
|
||||||
|
|
||||||
|
EscrowCancel escrow_cancel = 19;
|
||||||
|
|
||||||
|
EscrowCreate escrow_create = 20;
|
||||||
|
|
||||||
|
EscrowFinish escrow_finish = 21;
|
||||||
|
|
||||||
|
OfferCancel offer_cancel = 22;
|
||||||
|
|
||||||
|
OfferCreate offer_create = 23;
|
||||||
|
|
||||||
|
PaymentChannelClaim payment_channel_claim = 24;
|
||||||
|
|
||||||
|
PaymentChannelCreate payment_channel_create= 25;
|
||||||
|
|
||||||
|
PaymentChannelFund payment_channel_fund = 26;
|
||||||
|
|
||||||
|
SetRegularKey set_regular_key = 27;
|
||||||
|
|
||||||
|
SignerListSet signer_list_set = 28;
|
||||||
|
|
||||||
|
TrustSet trust_set = 29;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SigningPublicKey signing_public_key = 5;
|
||||||
|
|
||||||
|
TransactionSignature transaction_signature = 6;
|
||||||
|
|
||||||
|
Flags flags = 7;
|
||||||
|
|
||||||
|
LastLedgerSequence last_ledger_sequence = 8;
|
||||||
|
|
||||||
|
SourceTag source_tag = 9;
|
||||||
|
|
||||||
|
repeated Memo memos = 10;
|
||||||
|
|
||||||
|
repeated Signer signers = 11;
|
||||||
|
|
||||||
|
AccountTransactionID account_transaction_id = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 4
|
||||||
|
message Memo
|
||||||
|
{
|
||||||
|
MemoData memo_data = 1;
|
||||||
|
|
||||||
|
MemoFormat memo_format = 2;
|
||||||
|
|
||||||
|
MemoType memo_type = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 4
|
||||||
|
message Signer
|
||||||
|
{
|
||||||
|
Account account = 1;
|
||||||
|
|
||||||
|
TransactionSignature transaction_signature = 2;
|
||||||
|
|
||||||
|
SigningPublicKey signing_public_key = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 8
|
||||||
|
message AccountSet
|
||||||
|
{
|
||||||
|
ClearFlag clear_flag = 1;
|
||||||
|
|
||||||
|
Domain domain = 2;
|
||||||
|
|
||||||
|
EmailHash email_hash = 3;
|
||||||
|
|
||||||
|
MessageKey message_key = 4;
|
||||||
|
|
||||||
|
SetFlag set_flag = 5;
|
||||||
|
|
||||||
|
TransferRate transfer_rate = 6;
|
||||||
|
|
||||||
|
TickSize tick_size = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 3
|
||||||
|
message AccountDelete
|
||||||
|
{
|
||||||
|
Destination destination = 1;
|
||||||
|
|
||||||
|
DestinationTag destination_tag = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 2
|
||||||
|
message CheckCancel
|
||||||
|
{
|
||||||
|
CheckID check_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 4
|
||||||
|
message CheckCash
|
||||||
|
{
|
||||||
|
CheckID check_id = 1;
|
||||||
|
|
||||||
|
oneof amount_oneof
|
||||||
|
{
|
||||||
|
Amount amount = 2;
|
||||||
|
|
||||||
|
DeliverMin deliver_min = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 6
|
||||||
|
message CheckCreate
|
||||||
|
{
|
||||||
|
Destination destination = 1;
|
||||||
|
|
||||||
|
SendMax send_max = 2;
|
||||||
|
|
||||||
|
DestinationTag destination_tag = 3;
|
||||||
|
|
||||||
|
Expiration expiration = 4;
|
||||||
|
|
||||||
|
InvoiceID invoice_id = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 3
|
||||||
|
message DepositPreauth
|
||||||
|
{
|
||||||
|
oneof authorization_oneof
|
||||||
|
{
|
||||||
|
Authorize authorize = 1;
|
||||||
|
|
||||||
|
Unauthorize unauthorize = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 3
|
||||||
|
message EscrowCancel
|
||||||
|
{
|
||||||
|
Owner owner = 1;
|
||||||
|
|
||||||
|
OfferSequence offer_sequence = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 7
|
||||||
|
message EscrowCreate
|
||||||
|
{
|
||||||
|
Amount amount = 1;
|
||||||
|
|
||||||
|
Destination destination = 2;
|
||||||
|
|
||||||
|
CancelAfter cancel_after = 3;
|
||||||
|
|
||||||
|
FinishAfter finish_after = 4;
|
||||||
|
|
||||||
|
Condition condition = 5;
|
||||||
|
|
||||||
|
DestinationTag destination_tag = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 5
|
||||||
|
message EscrowFinish
|
||||||
|
{
|
||||||
|
Owner owner = 1;
|
||||||
|
|
||||||
|
OfferSequence offer_sequence = 2;
|
||||||
|
|
||||||
|
Condition condition = 3;
|
||||||
|
|
||||||
|
Fulfillment fulfillment = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 2
|
||||||
|
message OfferCancel
|
||||||
|
{
|
||||||
|
OfferSequence offer_sequence = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 5
|
||||||
|
message OfferCreate
|
||||||
|
{
|
||||||
|
Expiration expiration = 1;
|
||||||
|
|
||||||
|
OfferSequence offer_sequence = 2;
|
||||||
|
|
||||||
|
TakerGets taker_gets = 3;
|
||||||
|
|
||||||
|
TakerPays taker_pays = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 8
|
||||||
|
message Payment
|
||||||
|
{
|
||||||
|
// Next field: 4
|
||||||
|
message PathElement
|
||||||
|
{
|
||||||
|
AccountAddress account = 1;
|
||||||
|
|
||||||
|
Currency currency = 2;
|
||||||
|
|
||||||
|
AccountAddress issuer = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 2
|
||||||
|
message Path
|
||||||
|
{
|
||||||
|
repeated PathElement elements = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Amount amount = 1;
|
||||||
|
|
||||||
|
Destination destination = 2;
|
||||||
|
|
||||||
|
DestinationTag destination_tag = 3;
|
||||||
|
|
||||||
|
InvoiceID invoice_id = 4;
|
||||||
|
|
||||||
|
repeated Path paths = 5;
|
||||||
|
|
||||||
|
SendMax send_max = 6;
|
||||||
|
|
||||||
|
DeliverMin deliver_min = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 6
|
||||||
|
message PaymentChannelClaim
|
||||||
|
{
|
||||||
|
Channel channel = 1;
|
||||||
|
|
||||||
|
Balance balance = 2;
|
||||||
|
|
||||||
|
Amount amount = 3;
|
||||||
|
|
||||||
|
PaymentChannelSignature payment_channel_signature = 4;
|
||||||
|
|
||||||
|
PublicKey public_key = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 7
|
||||||
|
message PaymentChannelCreate
|
||||||
|
{
|
||||||
|
Amount amount = 1;
|
||||||
|
|
||||||
|
Destination destination = 2;
|
||||||
|
|
||||||
|
SettleDelay settle_delay = 3;
|
||||||
|
|
||||||
|
PublicKey public_key = 4;
|
||||||
|
|
||||||
|
CancelAfter cancel_after = 5;
|
||||||
|
|
||||||
|
DestinationTag destination_tag = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 4
|
||||||
|
message PaymentChannelFund
|
||||||
|
{
|
||||||
|
Channel channel = 1;
|
||||||
|
|
||||||
|
Amount amount = 2;
|
||||||
|
|
||||||
|
Expiration expiration = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 2
|
||||||
|
message SetRegularKey
|
||||||
|
{
|
||||||
|
RegularKey regular_key = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 3
|
||||||
|
message SignerListSet
|
||||||
|
{
|
||||||
|
SignerQuorum signer_quorum = 1;
|
||||||
|
|
||||||
|
repeated SignerEntry signer_entries = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next field: 4
|
||||||
|
message TrustSet
|
||||||
|
{
|
||||||
|
LimitAmount limit_amount = 1;
|
||||||
|
|
||||||
|
QualityIn quality_in = 2;
|
||||||
|
|
||||||
|
QualityOut quality_out = 3;
|
||||||
|
}
|
||||||
30
src/ripple/proto/org/xrpl/rpc/v1/xrp_ledger.proto
Normal file
30
src/ripple/proto/org/xrpl/rpc/v1/xrp_ledger.proto
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package org.xrpl.rpc.v1;
|
||||||
|
option java_package = "org.xrpl.rpc.v1";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import "org/xrpl/rpc/v1/get_account_info.proto";
|
||||||
|
import "org/xrpl/rpc/v1/get_fee.proto";
|
||||||
|
import "org/xrpl/rpc/v1/submit.proto";
|
||||||
|
import "org/xrpl/rpc/v1/get_transaction.proto";
|
||||||
|
import "org/xrpl/rpc/v1/get_account_transaction_history.proto";
|
||||||
|
|
||||||
|
|
||||||
|
// RPCs available to interact with the XRP Ledger.
|
||||||
|
service XRPLedgerAPIService {
|
||||||
|
|
||||||
|
// Get account info for an account on the XRP Ledger.
|
||||||
|
rpc GetAccountInfo (GetAccountInfoRequest) returns (GetAccountInfoResponse);
|
||||||
|
|
||||||
|
// Get the fee for a transaction on the XRP Ledger.
|
||||||
|
rpc GetFee (GetFeeRequest) returns (GetFeeResponse);
|
||||||
|
|
||||||
|
// Submit a signed transaction to the XRP Ledger.
|
||||||
|
rpc SubmitTransaction (SubmitTransactionRequest) returns (SubmitTransactionResponse);
|
||||||
|
|
||||||
|
// Get the status of a transaction
|
||||||
|
rpc GetTransaction(GetTransactionRequest) returns (GetTransactionResponse);
|
||||||
|
|
||||||
|
rpc GetAccountTransactionHistory(GetAccountTransactionHistoryRequest) returns (GetAccountTransactionHistoryResponse);
|
||||||
|
}
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package rpc.v1;
|
|
||||||
|
|
||||||
import "rpc/v1/amount.proto";
|
|
||||||
|
|
||||||
// A request for the current transaction fee on the ledger.
|
|
||||||
message GetFeeRequest {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Response to a GetFee RPC
|
|
||||||
message GetFeeResponse {
|
|
||||||
|
|
||||||
uint64 current_ledger_size = 1;
|
|
||||||
|
|
||||||
uint64 current_queue_size = 2;
|
|
||||||
|
|
||||||
Fee drops = 3;
|
|
||||||
|
|
||||||
uint64 expected_ledger_size = 4;
|
|
||||||
|
|
||||||
uint32 ledger_current_index = 5;
|
|
||||||
|
|
||||||
FeeLevels levels = 6;
|
|
||||||
|
|
||||||
uint64 max_queue_size = 7;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
message Fee {
|
|
||||||
|
|
||||||
XRPDropsAmount base_fee = 1;
|
|
||||||
|
|
||||||
XRPDropsAmount median_fee = 2;
|
|
||||||
|
|
||||||
XRPDropsAmount minimum_fee = 3;
|
|
||||||
|
|
||||||
XRPDropsAmount open_ledger_fee = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
message FeeLevels {
|
|
||||||
|
|
||||||
uint64 median_level = 1;
|
|
||||||
|
|
||||||
uint64 minimum_level = 2;
|
|
||||||
|
|
||||||
uint64 open_ledger_level = 3;
|
|
||||||
|
|
||||||
uint64 reference_level = 4;
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package rpc.v1;
|
|
||||||
|
|
||||||
import "rpc/v1/amount.proto";
|
|
||||||
|
|
||||||
message LedgerObject {
|
|
||||||
|
|
||||||
oneof object {
|
|
||||||
AccountRoot account_root = 1;
|
|
||||||
RippleState ripple_state = 2;
|
|
||||||
Offer offer = 3;
|
|
||||||
SignerList signer_list = 4;
|
|
||||||
DirectoryNode directory_node = 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LedgerEntryType {
|
|
||||||
LEDGER_ENTRY_TYPE_UNSPECIFIED = 0;
|
|
||||||
LEDGER_ENTRY_TYPE_ACCOUNT_ROOT = 1;
|
|
||||||
LEDGER_ENTRY_TYPE_AMENDMENTS = 2;
|
|
||||||
LEDGER_ENTRY_TYPE_CHECK = 3;
|
|
||||||
LEDGER_ENTRY_TYPE_DEPOSIT_PREAUTH = 4;
|
|
||||||
LEDGER_ENTRY_TYPE_DIRECTORY_NODE = 5;
|
|
||||||
LEDGER_ENTRY_TYPE_ESCROW = 6;
|
|
||||||
LEDGER_ENTRY_TYPE_FEE_SETTINGS = 7;
|
|
||||||
LEDGER_ENTRY_TYPE_LEDGER_HASHES = 8;
|
|
||||||
LEDGER_ENTRY_TYPE_OFFER = 9;
|
|
||||||
LEDGER_ENTRY_TYPE_PAY_CHANNEL = 10;
|
|
||||||
LEDGER_ENTRY_TYPE_RIPPLE_STATE = 11;
|
|
||||||
LEDGER_ENTRY_TYPE_SIGNER_LIST = 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
message DirectoryNode {
|
|
||||||
|
|
||||||
uint32 flags = 1;
|
|
||||||
|
|
||||||
// 32 bytes
|
|
||||||
bytes root_index = 2;
|
|
||||||
|
|
||||||
repeated bytes indexes = 3;
|
|
||||||
|
|
||||||
uint64 index_next = 4;
|
|
||||||
|
|
||||||
uint64 index_previous = 5;
|
|
||||||
|
|
||||||
string owner = 6;
|
|
||||||
|
|
||||||
Currency taker_pays_currency = 7;
|
|
||||||
|
|
||||||
// 20 bytes
|
|
||||||
bytes taker_pays_issuer = 8;
|
|
||||||
|
|
||||||
Currency taker_gets_currency = 9;
|
|
||||||
|
|
||||||
// 20 bytes
|
|
||||||
bytes taker_gets_issuer = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SignerList {
|
|
||||||
|
|
||||||
uint32 flags = 1;
|
|
||||||
|
|
||||||
// 32 bytes
|
|
||||||
bytes previous_txn_id = 2;
|
|
||||||
|
|
||||||
uint32 previous_transaction_ledger_sequence = 3;
|
|
||||||
|
|
||||||
uint64 owner_node = 4;
|
|
||||||
|
|
||||||
repeated SignerEntry signer_entries = 5;
|
|
||||||
|
|
||||||
uint32 signer_list_id = 6;
|
|
||||||
|
|
||||||
uint32 signer_quorum = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SignerEntry {
|
|
||||||
|
|
||||||
AccountAddress account = 1;
|
|
||||||
|
|
||||||
// this is actually uint16, but protobuf can't express uint16
|
|
||||||
uint32 signer_weight = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message AccountRoot {
|
|
||||||
|
|
||||||
AccountAddress account = 1;
|
|
||||||
|
|
||||||
XRPDropsAmount balance = 2;
|
|
||||||
|
|
||||||
uint32 sequence = 3;
|
|
||||||
|
|
||||||
uint32 flags = 4;
|
|
||||||
|
|
||||||
uint32 owner_count = 5;
|
|
||||||
|
|
||||||
// 32 bytes
|
|
||||||
bytes previous_transaction_id = 6;
|
|
||||||
|
|
||||||
uint32 previous_transaction_ledger_sequence = 7;
|
|
||||||
|
|
||||||
// 32 bytes
|
|
||||||
bytes account_transaction_id = 8;
|
|
||||||
|
|
||||||
// Variable length
|
|
||||||
bytes domain = 9;
|
|
||||||
|
|
||||||
// 16 bytes
|
|
||||||
bytes email_hash = 10;
|
|
||||||
|
|
||||||
// Variable length
|
|
||||||
bytes message_key = 11;
|
|
||||||
|
|
||||||
// base58 encoding
|
|
||||||
string regular_key = 12;
|
|
||||||
|
|
||||||
uint32 tick_size = 13;
|
|
||||||
|
|
||||||
uint32 transfer_rate = 14;
|
|
||||||
}
|
|
||||||
|
|
||||||
message RippleState {
|
|
||||||
|
|
||||||
CurrencyAmount balance = 1;
|
|
||||||
|
|
||||||
uint32 flags = 2;
|
|
||||||
|
|
||||||
CurrencyAmount low_limit = 3;
|
|
||||||
|
|
||||||
CurrencyAmount high_limit = 4;
|
|
||||||
|
|
||||||
uint64 low_node = 5;
|
|
||||||
|
|
||||||
uint64 high_node = 6;
|
|
||||||
|
|
||||||
uint32 low_quality_in = 7;
|
|
||||||
|
|
||||||
uint32 low_quality_out = 8;
|
|
||||||
|
|
||||||
uint32 high_quality_in = 9;
|
|
||||||
|
|
||||||
uint32 high_quality_out = 10;
|
|
||||||
|
|
||||||
// 32 bytes
|
|
||||||
bytes previous_transaction_id = 11;
|
|
||||||
|
|
||||||
uint32 previous_transaction_ledger_sequence = 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Offer {
|
|
||||||
|
|
||||||
string account = 1;
|
|
||||||
|
|
||||||
uint32 sequence = 2;
|
|
||||||
|
|
||||||
uint32 flags = 3;
|
|
||||||
|
|
||||||
CurrencyAmount taker_pays = 4;
|
|
||||||
|
|
||||||
CurrencyAmount taker_gets = 5;
|
|
||||||
|
|
||||||
bytes book_directory = 6;
|
|
||||||
|
|
||||||
uint64 book_node = 7;
|
|
||||||
|
|
||||||
uint64 owner_node = 8;
|
|
||||||
|
|
||||||
uint32 expiration = 9;
|
|
||||||
|
|
||||||
// 32 bytes
|
|
||||||
bytes previous_transaction_id = 10;
|
|
||||||
|
|
||||||
uint32 previous_transaction_ledger_sequence = 11;
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package rpc.v1;
|
|
||||||
|
|
||||||
import "rpc/v1/amount.proto";
|
|
||||||
|
|
||||||
// A class encompassing all transactions.
|
|
||||||
message Transaction {
|
|
||||||
// The account originating the transaction.
|
|
||||||
AccountAddress account = 1;
|
|
||||||
|
|
||||||
// The fee attached to the transaction.
|
|
||||||
XRPDropsAmount fee = 2;
|
|
||||||
|
|
||||||
// The sequence number for the transaction.
|
|
||||||
uint32 sequence = 3;
|
|
||||||
|
|
||||||
// Data specific to a the type of transaction being submitted.
|
|
||||||
oneof transaction_data {
|
|
||||||
Payment payment = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Public key of the account which signed the transaction. Variable length
|
|
||||||
bytes signing_public_key = 5;
|
|
||||||
|
|
||||||
// Variable length
|
|
||||||
bytes signature = 6;
|
|
||||||
|
|
||||||
uint32 flags = 7;
|
|
||||||
|
|
||||||
uint32 last_ledger_sequence = 8;
|
|
||||||
|
|
||||||
uint32 source_tag = 9;
|
|
||||||
|
|
||||||
repeated Memo memos = 10;
|
|
||||||
|
|
||||||
repeated Signer signers = 11;
|
|
||||||
|
|
||||||
bytes account_transaction_id = 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Memo {
|
|
||||||
|
|
||||||
// Variable length
|
|
||||||
bytes memo_data = 1;
|
|
||||||
|
|
||||||
// Variable length
|
|
||||||
bytes memo_format = 2;
|
|
||||||
|
|
||||||
// Variable length
|
|
||||||
bytes memo_type = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Signer {
|
|
||||||
|
|
||||||
AccountAddress account = 1;
|
|
||||||
|
|
||||||
// Variable length
|
|
||||||
bytes transaction_signature = 2;
|
|
||||||
|
|
||||||
// Variable length
|
|
||||||
bytes signing_public_key = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Payment {
|
|
||||||
// The amount of currency to pay, in either issued currency or XRP.
|
|
||||||
CurrencyAmount amount = 1;
|
|
||||||
|
|
||||||
// The destination of the payment.
|
|
||||||
AccountAddress destination = 2;
|
|
||||||
|
|
||||||
uint32 destination_tag = 3;
|
|
||||||
|
|
||||||
// 32 bytes
|
|
||||||
bytes invoice_id = 4;
|
|
||||||
|
|
||||||
repeated Path paths = 5;
|
|
||||||
|
|
||||||
CurrencyAmount send_max = 6;
|
|
||||||
|
|
||||||
CurrencyAmount deliver_min = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Path {
|
|
||||||
|
|
||||||
repeated PathElement elements = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message PathElement {
|
|
||||||
|
|
||||||
AccountAddress account = 1;
|
|
||||||
|
|
||||||
Currency currency = 2;
|
|
||||||
|
|
||||||
AccountAddress issuer = 3;
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package rpc.v1;
|
|
||||||
|
|
||||||
import "rpc/v1/transaction.proto";
|
|
||||||
import "rpc/v1/meta.proto";
|
|
||||||
|
|
||||||
message GetTxRequest {
|
|
||||||
// hash of the transaction. 32 bytes
|
|
||||||
bytes hash = 1;
|
|
||||||
|
|
||||||
// if true, return data in binary format
|
|
||||||
bool binary = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message GetTxResponse {
|
|
||||||
|
|
||||||
// The actual transaction
|
|
||||||
oneof serialized_transaction {
|
|
||||||
Transaction transaction = 1;
|
|
||||||
// Variable length
|
|
||||||
bytes transaction_binary = 2;
|
|
||||||
};
|
|
||||||
// Sequence number of ledger that contains this transaction
|
|
||||||
uint32 ledger_index = 3;
|
|
||||||
|
|
||||||
// 32 bytes
|
|
||||||
bytes hash = 4;
|
|
||||||
|
|
||||||
// whether the ledger has been validated
|
|
||||||
bool validated = 5;
|
|
||||||
|
|
||||||
// metadata about the transaction
|
|
||||||
oneof serialized_meta {
|
|
||||||
Meta meta = 6;
|
|
||||||
// Variable length
|
|
||||||
bytes meta_binary = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package rpc.v1;
|
|
||||||
|
|
||||||
import "rpc/v1/account_info.proto";
|
|
||||||
import "rpc/v1/fee.proto";
|
|
||||||
import "rpc/v1/submit.proto";
|
|
||||||
import "rpc/v1/tx.proto";
|
|
||||||
|
|
||||||
|
|
||||||
// RPCs available to interact with the XRP Ledger.
|
|
||||||
service XRPLedgerAPIService {
|
|
||||||
|
|
||||||
// Get account info for an account on the XRP Ledger.
|
|
||||||
rpc GetAccountInfo (GetAccountInfoRequest) returns (GetAccountInfoResponse);
|
|
||||||
|
|
||||||
// Get the fee for a transaction on the XRP Ledger.
|
|
||||||
rpc GetFee (GetFeeRequest) returns (GetFeeResponse);
|
|
||||||
|
|
||||||
// Submit a signed transaction to the XRP Ledger.
|
|
||||||
rpc SubmitTransaction (SubmitTransactionRequest) returns (SubmitTransactionResponse);
|
|
||||||
|
|
||||||
// Get the status of a transaction
|
|
||||||
rpc GetTx(GetTxRequest) returns (GetTxResponse);
|
|
||||||
}
|
|
||||||
@@ -20,8 +20,12 @@
|
|||||||
#ifndef RIPPLE_RPC_DELIVEREDAMOUNT_H_INCLUDED
|
#ifndef RIPPLE_RPC_DELIVEREDAMOUNT_H_INCLUDED
|
||||||
#define RIPPLE_RPC_DELIVEREDAMOUNT_H_INCLUDED
|
#define RIPPLE_RPC_DELIVEREDAMOUNT_H_INCLUDED
|
||||||
|
|
||||||
|
#include <org/xrpl/rpc/v1/amount.pb.h>
|
||||||
|
#include <ripple/protocol/STAmount.h>
|
||||||
|
#include <ripple/protocol/Protocol.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <rpc/v1/amount.pb.h>
|
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
class Value;
|
class Value;
|
||||||
@@ -53,23 +57,22 @@ void
|
|||||||
insertDeliveredAmount(
|
insertDeliveredAmount(
|
||||||
Json::Value& meta,
|
Json::Value& meta,
|
||||||
ReadView const&,
|
ReadView const&,
|
||||||
std::shared_ptr<STTx const> serializedTx,
|
std::shared_ptr<STTx const> const& serializedTx,
|
||||||
TxMeta const&);
|
TxMeta const&);
|
||||||
|
|
||||||
void
|
void
|
||||||
insertDeliveredAmount(
|
insertDeliveredAmount(
|
||||||
Json::Value& meta,
|
Json::Value& meta,
|
||||||
JsonContext&,
|
RPC::JsonContext const&,
|
||||||
std::shared_ptr<Transaction>,
|
std::shared_ptr<Transaction> const&,
|
||||||
TxMeta const&);
|
|
||||||
|
|
||||||
void
|
|
||||||
insertDeliveredAmount(
|
|
||||||
rpc::v1::CurrencyAmount& proto,
|
|
||||||
Context&,
|
|
||||||
std::shared_ptr<Transaction>,
|
|
||||||
TxMeta const&);
|
TxMeta const&);
|
||||||
|
|
||||||
|
std::optional<STAmount>
|
||||||
|
getDeliveredAmount(
|
||||||
|
RPC::Context const& context,
|
||||||
|
std::shared_ptr<STTx const> const& serializedTx,
|
||||||
|
TxMeta const& transactionMeta,
|
||||||
|
LedgerIndex const& ledgerIndex);
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
} // RPC
|
} // RPC
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include <ripple/rpc/Context.h>
|
#include <ripple/rpc/Context.h>
|
||||||
#include <grpcpp/grpcpp.h>
|
#include <grpcpp/grpcpp.h>
|
||||||
#include <rpc/v1/xrp_ledger.pb.h>
|
#include <org/xrpl/rpc/v1/xrp_ledger.pb.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
@@ -34,18 +34,22 @@ namespace ripple {
|
|||||||
* the status will be sent to the client, and the response will be ommitted
|
* the status will be sent to the client, and the response will be ommitted
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::pair<rpc::v1::GetAccountInfoResponse, grpc::Status>
|
std::pair<org::xrpl::rpc::v1::GetAccountInfoResponse, grpc::Status>
|
||||||
doAccountInfoGrpc(RPC::GRPCContext<rpc::v1::GetAccountInfoRequest>& context);
|
doAccountInfoGrpc(RPC::GRPCContext<org::xrpl::rpc::v1::GetAccountInfoRequest>& context);
|
||||||
|
|
||||||
std::pair<rpc::v1::GetFeeResponse, grpc::Status>
|
std::pair<org::xrpl::rpc::v1::GetFeeResponse, grpc::Status>
|
||||||
doFeeGrpc(RPC::GRPCContext<rpc::v1::GetFeeRequest>& context);
|
doFeeGrpc(RPC::GRPCContext<org::xrpl::rpc::v1::GetFeeRequest>& context);
|
||||||
|
|
||||||
std::pair<rpc::v1::SubmitTransactionResponse, grpc::Status>
|
std::pair<org::xrpl::rpc::v1::SubmitTransactionResponse, grpc::Status>
|
||||||
doSubmitGrpc(RPC::GRPCContext<rpc::v1::SubmitTransactionRequest>& context);
|
doSubmitGrpc(RPC::GRPCContext<org::xrpl::rpc::v1::SubmitTransactionRequest>& context);
|
||||||
|
|
||||||
// NOTE, this only supports Payment transactions at this time
|
// NOTE, this only supports Payment transactions at this time
|
||||||
std::pair<rpc::v1::GetTxResponse, grpc::Status>
|
std::pair<org::xrpl::rpc::v1::GetTransactionResponse, grpc::Status>
|
||||||
doTxGrpc(RPC::GRPCContext<rpc::v1::GetTxRequest>& context);
|
doTxGrpc(RPC::GRPCContext<org::xrpl::rpc::v1::GetTransactionRequest>& context);
|
||||||
|
|
||||||
|
std::pair<org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse, grpc::Status>
|
||||||
|
doAccountTxGrpc(
|
||||||
|
RPC::GRPCContext<org::xrpl::rpc::v1::GetAccountTransactionHistoryRequest>& context);
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ public:
|
|||||||
/** Apply the Status to a JsonObject
|
/** Apply the Status to a JsonObject
|
||||||
*/
|
*/
|
||||||
template <class Object>
|
template <class Object>
|
||||||
void inject (Object& object)
|
void inject (Object& object) const
|
||||||
{
|
{
|
||||||
if (auto ec = toErrorCode())
|
if (auto ec = toErrorCode())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <ripple/rpc/Context.h>
|
#include <ripple/rpc/Context.h>
|
||||||
#include <ripple/rpc/GRPCHandlers.h>
|
#include <ripple/rpc/GRPCHandlers.h>
|
||||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||||
|
#include <ripple/rpc/impl/GRPCHelpers.h>
|
||||||
#include <grpc/status.h>
|
#include <grpc/status.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -184,15 +185,15 @@ Json::Value doAccountInfo (RPC::JsonContext& context)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<rpc::v1::GetAccountInfoResponse, grpc::Status>
|
std::pair<org::xrpl::rpc::v1::GetAccountInfoResponse, grpc::Status>
|
||||||
doAccountInfoGrpc(RPC::GRPCContext<rpc::v1::GetAccountInfoRequest>& context)
|
doAccountInfoGrpc(RPC::GRPCContext<org::xrpl::rpc::v1::GetAccountInfoRequest>& context)
|
||||||
{
|
{
|
||||||
// Return values
|
// Return values
|
||||||
rpc::v1::GetAccountInfoResponse result;
|
org::xrpl::rpc::v1::GetAccountInfoResponse result;
|
||||||
grpc::Status status = grpc::Status::OK;
|
grpc::Status status = grpc::Status::OK;
|
||||||
|
|
||||||
// input
|
// input
|
||||||
rpc::v1::GetAccountInfoRequest& params = context.params;
|
org::xrpl::rpc::v1::GetAccountInfoRequest& params = context.params;
|
||||||
|
|
||||||
// get ledger
|
// get ledger
|
||||||
std::shared_ptr<ReadView const> ledger;
|
std::shared_ptr<ReadView const> ledger;
|
||||||
@@ -233,7 +234,7 @@ doAccountInfoGrpc(RPC::GRPCContext<rpc::v1::GetAccountInfoRequest>& context)
|
|||||||
auto const sleAccepted = ledger->read(keylet::account(accountID));
|
auto const sleAccepted = ledger->read(keylet::account(accountID));
|
||||||
if (sleAccepted)
|
if (sleAccepted)
|
||||||
{
|
{
|
||||||
RPC::populateAccountRoot(*result.mutable_account_data(), *sleAccepted);
|
RPC::convert(*result.mutable_account_data(), *sleAccepted);
|
||||||
|
|
||||||
// signer lists
|
// signer lists
|
||||||
if (params.signer_lists())
|
if (params.signer_lists())
|
||||||
@@ -241,9 +242,9 @@ doAccountInfoGrpc(RPC::GRPCContext<rpc::v1::GetAccountInfoRequest>& context)
|
|||||||
auto const sleSigners = ledger->read(keylet::signers(accountID));
|
auto const sleSigners = ledger->read(keylet::signers(accountID));
|
||||||
if (sleSigners)
|
if (sleSigners)
|
||||||
{
|
{
|
||||||
rpc::v1::SignerList& signerListProto =
|
org::xrpl::rpc::v1::SignerList& signerListProto =
|
||||||
*result.mutable_signer_list();
|
*result.mutable_signer_list();
|
||||||
RPC::populateSignerList(signerListProto, *sleSigners);
|
RPC::convert(signerListProto, *sleSigners);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,8 +260,8 @@ doAccountInfoGrpc(RPC::GRPCContext<rpc::v1::GetAccountInfoRequest>& context)
|
|||||||
}
|
}
|
||||||
auto const txs =
|
auto const txs =
|
||||||
context.app.getTxQ().getAccountTxs(accountID, *ledger);
|
context.app.getTxQ().getAccountTxs(accountID, *ledger);
|
||||||
rpc::v1::QueueData& queueData = *result.mutable_queue_data();
|
org::xrpl::rpc::v1::QueueData& queueData = *result.mutable_queue_data();
|
||||||
RPC::populateQueueData(queueData, txs);
|
RPC::convert(queueData, txs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -25,16 +25,481 @@
|
|||||||
#include <ripple/ledger/ReadView.h>
|
#include <ripple/ledger/ReadView.h>
|
||||||
#include <ripple/net/RPCErr.h>
|
#include <ripple/net/RPCErr.h>
|
||||||
#include <ripple/protocol/ErrorCodes.h>
|
#include <ripple/protocol/ErrorCodes.h>
|
||||||
#include <ripple/protocol/jss.h>
|
|
||||||
#include <ripple/protocol/UintTypes.h>
|
#include <ripple/protocol/UintTypes.h>
|
||||||
|
#include <ripple/protocol/jss.h>
|
||||||
#include <ripple/resource/Fees.h>
|
#include <ripple/resource/Fees.h>
|
||||||
#include <ripple/rpc/Context.h>
|
#include <ripple/rpc/Context.h>
|
||||||
#include <ripple/rpc/DeliveredAmount.h>
|
#include <ripple/rpc/DeliveredAmount.h>
|
||||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
|
||||||
#include <ripple/rpc/Role.h>
|
#include <ripple/rpc/Role.h>
|
||||||
|
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||||
|
#include <ripple/rpc/impl/GRPCHelpers.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <grpcpp/grpcpp.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
|
using LedgerSequence = uint32_t;
|
||||||
|
using LedgerHash = uint256;
|
||||||
|
using LedgerShortcut = RPC::LedgerShortcut;
|
||||||
|
|
||||||
|
using AccountTxMarker = NetworkOPs::AccountTxMarker;
|
||||||
|
|
||||||
|
struct LedgerRange
|
||||||
|
{
|
||||||
|
uint32_t min;
|
||||||
|
uint32_t max;
|
||||||
|
};
|
||||||
|
|
||||||
|
using LedgerSpecifier =
|
||||||
|
std::variant<LedgerRange, LedgerShortcut, LedgerSequence, LedgerHash>;
|
||||||
|
|
||||||
|
struct AccountTxArgs
|
||||||
|
{
|
||||||
|
AccountID account;
|
||||||
|
std::optional<LedgerSpecifier> ledger;
|
||||||
|
bool binary = false;
|
||||||
|
bool forward = false;
|
||||||
|
uint32_t limit = 0;
|
||||||
|
std::optional<AccountTxMarker> marker;
|
||||||
|
};
|
||||||
|
|
||||||
|
using TxnsData = NetworkOPs::AccountTxs;
|
||||||
|
using TxnsDataBinary = NetworkOPs::MetaTxsList;
|
||||||
|
using TxnDataBinary = NetworkOPs::txnMetaLedgerType;
|
||||||
|
|
||||||
|
struct AccountTxResult
|
||||||
|
{
|
||||||
|
std::variant<TxnsData, TxnsDataBinary> transactions;
|
||||||
|
LedgerRange ledgerRange;
|
||||||
|
uint32_t limit;
|
||||||
|
std::optional<AccountTxMarker> marker;
|
||||||
|
};
|
||||||
|
|
||||||
|
// parses args into a ledger specifier, or returns a grpc status object on error
|
||||||
|
std::variant<std::optional<LedgerSpecifier>, grpc::Status>
|
||||||
|
parseLedgerArgs(
|
||||||
|
org::xrpl::rpc::v1::GetAccountTransactionHistoryRequest const& params)
|
||||||
|
{
|
||||||
|
grpc::Status status;
|
||||||
|
if (params.has_ledger_range())
|
||||||
|
{
|
||||||
|
uint32_t min = params.ledger_range().ledger_index_min();
|
||||||
|
uint32_t max = params.ledger_range().ledger_index_max();
|
||||||
|
|
||||||
|
// if min is set but not max, need to set max
|
||||||
|
if (min != 0 && max == 0)
|
||||||
|
{
|
||||||
|
max = UINT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LedgerRange{min, max};
|
||||||
|
}
|
||||||
|
else if (params.has_ledger_specifier())
|
||||||
|
{
|
||||||
|
LedgerSpecifier ledger;
|
||||||
|
|
||||||
|
auto& specifier = params.ledger_specifier();
|
||||||
|
using LedgerCase = org::xrpl::rpc::v1::LedgerSpecifier::LedgerCase;
|
||||||
|
LedgerCase ledgerCase = specifier.ledger_case();
|
||||||
|
|
||||||
|
if (ledgerCase == LedgerCase::kShortcut)
|
||||||
|
{
|
||||||
|
using LedgerSpecifier = org::xrpl::rpc::v1::LedgerSpecifier;
|
||||||
|
|
||||||
|
if (specifier.shortcut() == LedgerSpecifier::SHORTCUT_VALIDATED)
|
||||||
|
ledger = LedgerShortcut::VALIDATED;
|
||||||
|
else if (specifier.shortcut() == LedgerSpecifier::SHORTCUT_CLOSED)
|
||||||
|
ledger = LedgerShortcut::CLOSED;
|
||||||
|
else if (specifier.shortcut() == LedgerSpecifier::SHORTCUT_CURRENT)
|
||||||
|
ledger = LedgerShortcut::CURRENT;
|
||||||
|
else
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
else if (ledgerCase == LedgerCase::kSequence)
|
||||||
|
{
|
||||||
|
ledger = specifier.sequence();
|
||||||
|
}
|
||||||
|
else if (ledgerCase == LedgerCase::kHash)
|
||||||
|
{
|
||||||
|
if (uint256::size() != specifier.hash().size())
|
||||||
|
{
|
||||||
|
grpc::Status errorStatus{grpc::StatusCode::INVALID_ARGUMENT,
|
||||||
|
"ledger hash malformed"};
|
||||||
|
return errorStatus;
|
||||||
|
}
|
||||||
|
ledger = uint256::fromVoid(specifier.hash().data());
|
||||||
|
}
|
||||||
|
return ledger;
|
||||||
|
}
|
||||||
|
return std::optional<LedgerSpecifier>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
// parses args into a ledger specifier, or returns a Json object on error
|
||||||
|
std::variant<std::optional<LedgerSpecifier>, Json::Value>
|
||||||
|
parseLedgerArgs(Json::Value const& params)
|
||||||
|
{
|
||||||
|
Json::Value response;
|
||||||
|
if (params.isMember(jss::ledger_index_min) ||
|
||||||
|
params.isMember(jss::ledger_index_max))
|
||||||
|
{
|
||||||
|
uint32_t min = params.isMember(jss::ledger_index_min) &&
|
||||||
|
params[jss::ledger_index_min].asInt() >= 0
|
||||||
|
? params[jss::ledger_index_min].asUInt()
|
||||||
|
: 0;
|
||||||
|
uint32_t max = params.isMember(jss::ledger_index_max) &&
|
||||||
|
params[jss::ledger_index_max].asInt() >= 0
|
||||||
|
? params[jss::ledger_index_max].asUInt()
|
||||||
|
: UINT32_MAX;
|
||||||
|
|
||||||
|
return LedgerRange{min, max};
|
||||||
|
}
|
||||||
|
else if (params.isMember(jss::ledger_hash))
|
||||||
|
{
|
||||||
|
auto& hashValue = params[jss::ledger_hash];
|
||||||
|
if (!hashValue.isString())
|
||||||
|
{
|
||||||
|
RPC::Status status{rpcINVALID_PARAMS, "ledgerHashNotString"};
|
||||||
|
status.inject(response);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
LedgerHash hash;
|
||||||
|
if (!hash.SetHex(hashValue.asString()))
|
||||||
|
{
|
||||||
|
RPC::Status status{rpcINVALID_PARAMS, "ledgerHashMalformed"};
|
||||||
|
status.inject(response);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
else if (params.isMember(jss::ledger_index))
|
||||||
|
{
|
||||||
|
LedgerSpecifier ledger;
|
||||||
|
if (params[jss::ledger_index].isNumeric())
|
||||||
|
ledger = params[jss::ledger_index].asInt();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string ledgerStr = params[jss::ledger_index].asString();
|
||||||
|
|
||||||
|
if (ledgerStr == "current" || ledgerStr.empty())
|
||||||
|
ledger = LedgerShortcut::CURRENT;
|
||||||
|
else if (ledgerStr == "closed")
|
||||||
|
ledger = LedgerShortcut::CLOSED;
|
||||||
|
else if (ledgerStr == "validated")
|
||||||
|
ledger = LedgerShortcut::VALIDATED;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RPC::Status status{rpcINVALID_PARAMS,
|
||||||
|
"ledger_index string malformed"};
|
||||||
|
status.inject(response);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ledger;
|
||||||
|
}
|
||||||
|
return std::optional<LedgerSpecifier>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::variant<LedgerRange, RPC::Status>
|
||||||
|
getLedgerRange(
|
||||||
|
RPC::Context& context,
|
||||||
|
std::optional<LedgerSpecifier> const& ledgerSpecifier)
|
||||||
|
{
|
||||||
|
std::uint32_t uValidatedMin;
|
||||||
|
std::uint32_t uValidatedMax;
|
||||||
|
bool bValidated =
|
||||||
|
context.ledgerMaster.getValidatedRange(uValidatedMin, uValidatedMax);
|
||||||
|
|
||||||
|
if (!bValidated)
|
||||||
|
{
|
||||||
|
// Don't have a validated ledger range.
|
||||||
|
return rpcLGR_IDXS_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t uLedgerMin = uValidatedMin;
|
||||||
|
std::uint32_t uLedgerMax = uValidatedMax;
|
||||||
|
// Does request specify a ledger or ledger range?
|
||||||
|
if (ledgerSpecifier)
|
||||||
|
{
|
||||||
|
auto const status = std::visit(
|
||||||
|
[&](auto const& ls) -> RPC::Status {
|
||||||
|
using T = std::decay_t<decltype(ls)>;
|
||||||
|
if constexpr (std::is_same_v<T, LedgerRange>)
|
||||||
|
{
|
||||||
|
if (ls.min > uValidatedMin)
|
||||||
|
{
|
||||||
|
uLedgerMin = ls.min;
|
||||||
|
}
|
||||||
|
if (ls.max < uValidatedMax)
|
||||||
|
{
|
||||||
|
uLedgerMax = ls.max;
|
||||||
|
}
|
||||||
|
if (uLedgerMax < uLedgerMin)
|
||||||
|
return rpcLGR_IDXS_INVALID;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::shared_ptr<ReadView const> ledgerView;
|
||||||
|
auto const status = getLedger(ledgerView, ls, context);
|
||||||
|
if (!ledgerView)
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool validated = RPC::isValidated(
|
||||||
|
context.ledgerMaster, *ledgerView, context.app);
|
||||||
|
|
||||||
|
if (!validated || ledgerView->info().seq > uValidatedMax ||
|
||||||
|
ledgerView->info().seq < uValidatedMin)
|
||||||
|
{
|
||||||
|
return rpcLGR_NOT_VALIDATED;
|
||||||
|
}
|
||||||
|
uLedgerMin = uLedgerMax = ledgerView->info().seq;
|
||||||
|
}
|
||||||
|
return RPC::Status::OK;
|
||||||
|
},
|
||||||
|
*ledgerSpecifier);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
return LedgerRange{uLedgerMin, uLedgerMax};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<AccountTxResult, RPC::Status>
|
||||||
|
doAccountTxHelp(RPC::Context& context, AccountTxArgs const& args)
|
||||||
|
{
|
||||||
|
AccountTxResult result;
|
||||||
|
context.loadType = Resource::feeMediumBurdenRPC;
|
||||||
|
|
||||||
|
auto lgrRange = getLedgerRange(context, args.ledger);
|
||||||
|
if (auto stat = std::get_if<RPC::Status>(&lgrRange))
|
||||||
|
{
|
||||||
|
// An error occurred getting the requested ledger range
|
||||||
|
return {result, *stat};
|
||||||
|
}
|
||||||
|
|
||||||
|
result.ledgerRange = std::get<LedgerRange>(lgrRange);
|
||||||
|
|
||||||
|
result.marker = args.marker;
|
||||||
|
if (args.binary)
|
||||||
|
{
|
||||||
|
result.transactions = context.netOps.getTxsAccountB(
|
||||||
|
args.account,
|
||||||
|
result.ledgerRange.min,
|
||||||
|
result.ledgerRange.max,
|
||||||
|
args.forward,
|
||||||
|
result.marker,
|
||||||
|
args.limit,
|
||||||
|
isUnlimited(context.role));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.transactions = context.netOps.getTxsAccount(
|
||||||
|
args.account,
|
||||||
|
result.ledgerRange.min,
|
||||||
|
result.ledgerRange.max,
|
||||||
|
args.forward,
|
||||||
|
result.marker,
|
||||||
|
args.limit,
|
||||||
|
isUnlimited(context.role));
|
||||||
|
}
|
||||||
|
|
||||||
|
result.limit = args.limit;
|
||||||
|
|
||||||
|
return {result, rpcSUCCESS};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<
|
||||||
|
org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse,
|
||||||
|
grpc::Status>
|
||||||
|
populateProtoResponse(
|
||||||
|
std::pair<AccountTxResult, RPC::Status> const& res,
|
||||||
|
AccountTxArgs const& args,
|
||||||
|
RPC::GRPCContext<
|
||||||
|
org::xrpl::rpc::v1::GetAccountTransactionHistoryRequest> const& context)
|
||||||
|
{
|
||||||
|
org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse response;
|
||||||
|
grpc::Status status = grpc::Status::OK;
|
||||||
|
|
||||||
|
RPC::Status const& error = res.second;
|
||||||
|
if (error.toErrorCode() != rpcSUCCESS)
|
||||||
|
{
|
||||||
|
if (error.toErrorCode() == rpcLGR_NOT_FOUND)
|
||||||
|
{
|
||||||
|
status = {grpc::StatusCode::NOT_FOUND, error.message()};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = {grpc::StatusCode::INVALID_ARGUMENT, error.message()};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AccountTxResult const& result = res.first;
|
||||||
|
|
||||||
|
// account_tx always returns validated data
|
||||||
|
response.set_validated(true);
|
||||||
|
response.set_limit(result.limit);
|
||||||
|
response.mutable_account()->set_address(
|
||||||
|
context.params.account().address());
|
||||||
|
response.set_ledger_index_min(result.ledgerRange.min);
|
||||||
|
response.set_ledger_index_max(result.ledgerRange.max);
|
||||||
|
|
||||||
|
if (auto txnsData = std::get_if<TxnsData>(&result.transactions))
|
||||||
|
{
|
||||||
|
assert(!args.binary);
|
||||||
|
for (auto const& [txn, txnMeta] : *txnsData)
|
||||||
|
{
|
||||||
|
if (txn)
|
||||||
|
{
|
||||||
|
auto txnProto = response.add_transactions();
|
||||||
|
|
||||||
|
RPC::convert(
|
||||||
|
*txnProto->mutable_transaction(),
|
||||||
|
txn->getSTransaction());
|
||||||
|
|
||||||
|
// account_tx always returns validated data
|
||||||
|
txnProto->set_validated(true);
|
||||||
|
txnProto->set_ledger_index(txn->getLedger());
|
||||||
|
auto& hash = txn->getID();
|
||||||
|
txnProto->set_hash(hash.data(), hash.size());
|
||||||
|
auto closeTime =
|
||||||
|
context.app.getLedgerMaster().getCloseTimeBySeq(
|
||||||
|
txn->getLedger());
|
||||||
|
if (closeTime)
|
||||||
|
txnProto->mutable_date()->set_value(
|
||||||
|
closeTime->time_since_epoch().count());
|
||||||
|
if (txnMeta)
|
||||||
|
{
|
||||||
|
if (!txnMeta->hasDeliveredAmount())
|
||||||
|
{
|
||||||
|
std::optional<STAmount> amount = getDeliveredAmount(
|
||||||
|
context,
|
||||||
|
txn->getSTransaction(),
|
||||||
|
*txnMeta,
|
||||||
|
txn->getLedger());
|
||||||
|
if (amount)
|
||||||
|
{
|
||||||
|
txnMeta->setDeliveredAmount(*amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RPC::convert(*txnProto->mutable_meta(), txnMeta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(args.binary);
|
||||||
|
|
||||||
|
for (auto const& binaryData :
|
||||||
|
std::get<TxnsDataBinary>(result.transactions))
|
||||||
|
{
|
||||||
|
auto txnProto = response.add_transactions();
|
||||||
|
Blob const& txnBlob = std::get<0>(binaryData);
|
||||||
|
txnProto->set_transaction_binary(
|
||||||
|
txnBlob.data(), txnBlob.size());
|
||||||
|
|
||||||
|
Blob const& metaBlob = std::get<1>(binaryData);
|
||||||
|
txnProto->set_meta_binary(metaBlob.data(), metaBlob.size());
|
||||||
|
|
||||||
|
txnProto->set_ledger_index(std::get<2>(binaryData));
|
||||||
|
|
||||||
|
// account_tx always returns validated data
|
||||||
|
txnProto->set_validated(true);
|
||||||
|
|
||||||
|
auto closeTime =
|
||||||
|
context.app.getLedgerMaster().getCloseTimeBySeq(
|
||||||
|
std::get<2>(binaryData));
|
||||||
|
if (closeTime)
|
||||||
|
txnProto->mutable_date()->set_value(
|
||||||
|
closeTime->time_since_epoch().count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.marker)
|
||||||
|
{
|
||||||
|
response.mutable_marker()->set_ledger_index(
|
||||||
|
result.marker->ledgerSeq);
|
||||||
|
response.mutable_marker()->set_account_sequence(
|
||||||
|
result.marker->txnSeq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {response, status};
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value
|
||||||
|
populateJsonResponse(
|
||||||
|
std::pair<AccountTxResult, RPC::Status> const& res,
|
||||||
|
AccountTxArgs const& args,
|
||||||
|
RPC::JsonContext const& context)
|
||||||
|
{
|
||||||
|
Json::Value response;
|
||||||
|
RPC::Status const& error = res.second;
|
||||||
|
if (error.toErrorCode() != rpcSUCCESS)
|
||||||
|
{
|
||||||
|
error.inject(response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AccountTxResult const& result = res.first;
|
||||||
|
response[jss::validated] = true;
|
||||||
|
response[jss::limit] = result.limit;
|
||||||
|
response[jss::account] = context.params[jss::account].asString();
|
||||||
|
response[jss::ledger_index_min] = result.ledgerRange.min;
|
||||||
|
response[jss::ledger_index_max] = result.ledgerRange.max;
|
||||||
|
|
||||||
|
Json::Value& jvTxns = (response[jss::transactions] = Json::arrayValue);
|
||||||
|
|
||||||
|
if (auto txnsData = std::get_if<TxnsData>(&result.transactions))
|
||||||
|
{
|
||||||
|
assert(!args.binary);
|
||||||
|
for (auto const& [txn, txnMeta] : *txnsData)
|
||||||
|
{
|
||||||
|
if (txn)
|
||||||
|
{
|
||||||
|
Json::Value& jvObj = jvTxns.append(Json::objectValue);
|
||||||
|
|
||||||
|
jvObj[jss::tx] = txn->getJson(JsonOptions::include_date);
|
||||||
|
if (txnMeta)
|
||||||
|
{
|
||||||
|
jvObj[jss::meta] =
|
||||||
|
txnMeta->getJson(JsonOptions::include_date);
|
||||||
|
jvObj[jss::validated] = true;
|
||||||
|
insertDeliveredAmount(
|
||||||
|
jvObj[jss::meta], context, txn, *txnMeta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(args.binary);
|
||||||
|
|
||||||
|
for (auto const& binaryData :
|
||||||
|
std::get<TxnsDataBinary>(result.transactions))
|
||||||
|
{
|
||||||
|
Json::Value& jvObj = jvTxns.append(Json::objectValue);
|
||||||
|
|
||||||
|
jvObj[jss::tx_blob] = strHex(std::get<0>(binaryData));
|
||||||
|
jvObj[jss::meta] = strHex(std::get<1>(binaryData));
|
||||||
|
jvObj[jss::ledger_index] = std::get<2>(binaryData);
|
||||||
|
jvObj[jss::validated] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.marker)
|
||||||
|
{
|
||||||
|
response[jss::marker] = Json::objectValue;
|
||||||
|
response[jss::marker][jss::ledger] = result.marker->ledgerSeq;
|
||||||
|
response[jss::marker][jss::seq] = result.marker->txnSeq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// account: account,
|
// account: account,
|
||||||
// ledger_index_min: ledger_index // optional, defaults to earliest
|
// ledger_index_min: ledger_index // optional, defaults to earliest
|
||||||
@@ -42,161 +507,107 @@ namespace ripple {
|
|||||||
// binary: boolean, // optional, defaults to false
|
// binary: boolean, // optional, defaults to false
|
||||||
// forward: boolean, // optional, defaults to false
|
// forward: boolean, // optional, defaults to false
|
||||||
// limit: integer, // optional
|
// limit: integer, // optional
|
||||||
// marker: opaque // optional, resume previous query
|
// marker: object {ledger: ledger_index, seq: txn_sequence} // optional,
|
||||||
|
// resume previous query
|
||||||
// }
|
// }
|
||||||
Json::Value doAccountTx (RPC::JsonContext& context)
|
Json::Value
|
||||||
|
doAccountTxJson(RPC::JsonContext& context)
|
||||||
{
|
{
|
||||||
auto& params = context.params;
|
auto& params = context.params;
|
||||||
|
AccountTxArgs args;
|
||||||
|
Json::Value response;
|
||||||
|
|
||||||
int limit = params.isMember (jss::limit) ?
|
args.limit = params.isMember(jss::limit) ? params[jss::limit].asUInt() : 0;
|
||||||
params[jss::limit].asUInt () : -1;
|
args.binary = params.isMember(jss::binary) && params[jss::binary].asBool();
|
||||||
bool bBinary = params.isMember (jss::binary) && params[jss::binary].asBool ();
|
args.forward =
|
||||||
bool bForward = params.isMember (jss::forward) && params[jss::forward].asBool ();
|
params.isMember(jss::forward) && params[jss::forward].asBool();
|
||||||
std::uint32_t uLedgerMin;
|
|
||||||
std::uint32_t uLedgerMax;
|
|
||||||
std::uint32_t uValidatedMin;
|
|
||||||
std::uint32_t uValidatedMax;
|
|
||||||
bool bValidated = context.ledgerMaster.getValidatedRange (
|
|
||||||
uValidatedMin, uValidatedMax);
|
|
||||||
|
|
||||||
if (!bValidated)
|
if (!params.isMember(jss::account))
|
||||||
|
return rpcError(rpcINVALID_PARAMS);
|
||||||
|
|
||||||
|
auto const account =
|
||||||
|
parseBase58<AccountID>(params[jss::account].asString());
|
||||||
|
if (!account)
|
||||||
|
return rpcError(rpcACT_MALFORMED);
|
||||||
|
|
||||||
|
args.account = *account;
|
||||||
|
|
||||||
|
auto parseRes = parseLedgerArgs(params);
|
||||||
|
if (auto jv = std::get_if<Json::Value>(&parseRes))
|
||||||
{
|
{
|
||||||
// Don't have a validated ledger range.
|
return *jv;
|
||||||
return rpcError (rpcLGR_IDXS_INVALID);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!params.isMember (jss::account))
|
|
||||||
return rpcError (rpcINVALID_PARAMS);
|
|
||||||
|
|
||||||
auto const account = parseBase58<AccountID>(
|
|
||||||
params[jss::account].asString());
|
|
||||||
if (! account)
|
|
||||||
return rpcError (rpcACT_MALFORMED);
|
|
||||||
|
|
||||||
context.loadType = Resource::feeMediumBurdenRPC;
|
|
||||||
|
|
||||||
if (params.isMember (jss::ledger_index_min) ||
|
|
||||||
params.isMember (jss::ledger_index_max))
|
|
||||||
{
|
|
||||||
std::int64_t iLedgerMin = params.isMember (jss::ledger_index_min)
|
|
||||||
? params[jss::ledger_index_min].asInt () : -1;
|
|
||||||
std::int64_t iLedgerMax = params.isMember (jss::ledger_index_max)
|
|
||||||
? params[jss::ledger_index_max].asInt () : -1;
|
|
||||||
|
|
||||||
uLedgerMin = iLedgerMin == -1 ? uValidatedMin :
|
|
||||||
((iLedgerMin >= uValidatedMin) ? iLedgerMin : uValidatedMin);
|
|
||||||
uLedgerMax = iLedgerMax == -1 ? uValidatedMax :
|
|
||||||
((iLedgerMax <= uValidatedMax) ? iLedgerMax : uValidatedMax);
|
|
||||||
|
|
||||||
if (uLedgerMax < uLedgerMin)
|
|
||||||
return rpcError (rpcLGR_IDXS_INVALID);
|
|
||||||
}
|
|
||||||
else if(params.isMember (jss::ledger_hash) ||
|
|
||||||
params.isMember (jss::ledger_index))
|
|
||||||
{
|
|
||||||
std::shared_ptr<ReadView const> ledger;
|
|
||||||
auto ret = RPC::lookupLedger (ledger, context);
|
|
||||||
|
|
||||||
if (! ledger)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (! ret[jss::validated].asBool() ||
|
|
||||||
(ledger->info().seq > uValidatedMax) ||
|
|
||||||
(ledger->info().seq < uValidatedMin))
|
|
||||||
{
|
|
||||||
return rpcError (rpcLGR_NOT_VALIDATED);
|
|
||||||
}
|
|
||||||
|
|
||||||
uLedgerMin = uLedgerMax = ledger->info().seq;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uLedgerMin = uValidatedMin;
|
args.ledger = std::get<std::optional<LedgerSpecifier>>(parseRes);
|
||||||
uLedgerMax = uValidatedMax;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value resumeToken;
|
|
||||||
|
|
||||||
if (params.isMember(jss::marker))
|
if (params.isMember(jss::marker))
|
||||||
resumeToken = params[jss::marker];
|
|
||||||
|
|
||||||
#ifndef DEBUG
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
#endif
|
auto& token = params[jss::marker];
|
||||||
Json::Value ret (Json::objectValue);
|
if (!token.isMember(jss::ledger) || !token.isMember(jss::seq) ||
|
||||||
|
!token[jss::ledger].isConvertibleTo(Json::ValueType::uintValue) ||
|
||||||
ret[jss::account] = context.app.accountIDCache().toBase58(*account);
|
!token[jss::seq].isConvertibleTo(Json::ValueType::uintValue))
|
||||||
Json::Value& jvTxns = (ret[jss::transactions] = Json::arrayValue);
|
|
||||||
|
|
||||||
if (bBinary)
|
|
||||||
{
|
{
|
||||||
auto txns = context.netOps.getTxsAccountB (
|
RPC::Status status{
|
||||||
*account, uLedgerMin, uLedgerMax, bForward, resumeToken, limit,
|
rpcINVALID_PARAMS,
|
||||||
isUnlimited (context.role));
|
"invalid marker. Provide ledger index via ledger field, and "
|
||||||
|
"transaction sequence number via seq field"};
|
||||||
for (auto& it: txns)
|
status.inject(response);
|
||||||
{
|
return response;
|
||||||
Json::Value& jvObj = jvTxns.append (Json::objectValue);
|
|
||||||
|
|
||||||
jvObj[jss::tx_blob] = std::get<0> (it);
|
|
||||||
jvObj[jss::meta] = std::get<1> (it);
|
|
||||||
|
|
||||||
std::uint32_t uLedgerIndex = std::get<2> (it);
|
|
||||||
|
|
||||||
jvObj[jss::ledger_index] = uLedgerIndex;
|
|
||||||
jvObj[jss::validated] = bValidated &&
|
|
||||||
uValidatedMin <= uLedgerIndex &&
|
|
||||||
uValidatedMax >= uLedgerIndex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
args.marker = {token[jss::ledger].asUInt(), token[jss::seq].asUInt()};
|
||||||
{
|
|
||||||
auto txns = context.netOps.getTxsAccount (
|
|
||||||
*account, uLedgerMin, uLedgerMax, bForward, resumeToken, limit,
|
|
||||||
isUnlimited (context.role));
|
|
||||||
|
|
||||||
for (auto const& [txn, txMeta]: txns)
|
|
||||||
{
|
|
||||||
Json::Value& jvObj = jvTxns.append (Json::objectValue);
|
|
||||||
|
|
||||||
if (txn)
|
|
||||||
jvObj[jss::tx] =
|
|
||||||
txn->getJson (JsonOptions::include_date);
|
|
||||||
|
|
||||||
if (txMeta)
|
|
||||||
{
|
|
||||||
auto metaJ = txMeta->getJson (JsonOptions::include_date);
|
|
||||||
insertDeliveredAmount (metaJ, context, txn, *txMeta);
|
|
||||||
jvObj[jss::meta] = std::move(metaJ);
|
|
||||||
|
|
||||||
std::uint32_t uLedgerIndex = txMeta->getLgrSeq ();
|
|
||||||
|
|
||||||
jvObj[jss::validated] = bValidated &&
|
|
||||||
uValidatedMin <= uLedgerIndex &&
|
|
||||||
uValidatedMax >= uLedgerIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Add information about the original query
|
|
||||||
ret[jss::ledger_index_min] = uLedgerMin;
|
|
||||||
ret[jss::ledger_index_max] = uLedgerMax;
|
|
||||||
if (params.isMember (jss::limit))
|
|
||||||
ret[jss::limit] = limit;
|
|
||||||
if (resumeToken)
|
|
||||||
ret[jss::marker] = resumeToken;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
#ifndef DEBUG
|
|
||||||
}
|
|
||||||
catch (std::exception const&)
|
|
||||||
{
|
|
||||||
return rpcError (rpcINTERNAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
auto res = doAccountTxHelp(context, args);
|
||||||
|
return populateJsonResponse(res, args, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // ripple
|
std::pair<
|
||||||
|
org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse,
|
||||||
|
grpc::Status>
|
||||||
|
doAccountTxGrpc(
|
||||||
|
RPC::GRPCContext<org::xrpl::rpc::v1::GetAccountTransactionHistoryRequest>&
|
||||||
|
context)
|
||||||
|
{
|
||||||
|
// return values
|
||||||
|
org::xrpl::rpc::v1::GetAccountTransactionHistoryResponse response;
|
||||||
|
grpc::Status status = grpc::Status::OK;
|
||||||
|
AccountTxArgs args;
|
||||||
|
|
||||||
|
auto& request = context.params;
|
||||||
|
|
||||||
|
auto const account = parseBase58<AccountID>(request.account().address());
|
||||||
|
if (!account)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
{},
|
||||||
|
{grpc::StatusCode::INVALID_ARGUMENT, "Could not decode account"}};
|
||||||
|
}
|
||||||
|
|
||||||
|
args.account = *account;
|
||||||
|
args.limit = request.limit();
|
||||||
|
args.binary = request.binary();
|
||||||
|
args.forward = request.forward();
|
||||||
|
|
||||||
|
if (request.has_marker())
|
||||||
|
{
|
||||||
|
args.marker = {request.marker().ledger_index(),
|
||||||
|
request.marker().account_sequence()};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parseRes = parseLedgerArgs(request);
|
||||||
|
if (auto stat = std::get_if<grpc::Status>(&parseRes))
|
||||||
|
{
|
||||||
|
return {response, *stat};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.ledger = std::get<std::optional<LedgerSpecifier>>(parseRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = doAccountTxHelp(context, args);
|
||||||
|
return populateProtoResponse(res, args, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ripple
|
||||||
|
|||||||
@@ -155,8 +155,8 @@ Json::Value doAccountTxOld (RPC::JsonContext& context)
|
|||||||
Json::Value& jvObj = jvTxns.append (Json::objectValue);
|
Json::Value& jvObj = jvTxns.append (Json::objectValue);
|
||||||
|
|
||||||
std::uint32_t uLedgerIndex = std::get<2> (*it);
|
std::uint32_t uLedgerIndex = std::get<2> (*it);
|
||||||
jvObj[jss::tx_blob] = std::get<0> (*it);
|
jvObj[jss::tx_blob] = strHex(std::get<0> (*it));
|
||||||
jvObj[jss::meta] = std::get<1> (*it);
|
jvObj[jss::meta] = strHex(std::get<1> (*it));
|
||||||
jvObj[jss::ledger_index] = uLedgerIndex;
|
jvObj[jss::ledger_index] = uLedgerIndex;
|
||||||
jvObj[jss::validated]
|
jvObj[jss::validated]
|
||||||
= bValidated
|
= bValidated
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
Json::Value doAccountTxOld (RPC::JsonContext& context);
|
Json::Value doAccountTxOld (RPC::JsonContext& context);
|
||||||
Json::Value doAccountTx (RPC::JsonContext& context);
|
Json::Value doAccountTxJson (RPC::JsonContext& context);
|
||||||
|
|
||||||
// Temporary switching code until the old account_tx is removed
|
// Temporary switching code until the old account_tx is removed
|
||||||
Json::Value doAccountTxSwitch (RPC::JsonContext& context)
|
Json::Value doAccountTxSwitch (RPC::JsonContext& context)
|
||||||
@@ -39,7 +39,7 @@ Json::Value doAccountTxSwitch (RPC::JsonContext& context)
|
|||||||
{
|
{
|
||||||
return doAccountTxOld(context);
|
return doAccountTxOld(context);
|
||||||
}
|
}
|
||||||
return doAccountTx(context);
|
return doAccountTxJson(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ namespace ripple
|
|||||||
return context.params;
|
return context.params;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<rpc::v1::GetFeeResponse, grpc::Status>
|
std::pair<org::xrpl::rpc::v1::GetFeeResponse, grpc::Status>
|
||||||
doFeeGrpc(RPC::GRPCContext<rpc::v1::GetFeeRequest>& context)
|
doFeeGrpc(RPC::GRPCContext<org::xrpl::rpc::v1::GetFeeRequest>& context)
|
||||||
{
|
{
|
||||||
rpc::v1::GetFeeResponse reply;
|
org::xrpl::rpc::v1::GetFeeResponse reply;
|
||||||
grpc::Status status = grpc::Status::OK;
|
grpc::Status status = grpc::Status::OK;
|
||||||
|
|
||||||
Application& app = context.app;
|
Application& app = context.app;
|
||||||
@@ -62,23 +62,23 @@ doFeeGrpc(RPC::GRPCContext<rpc::v1::GetFeeRequest>& context)
|
|||||||
reply.set_max_queue_size(*metrics.txQMaxSize);
|
reply.set_max_queue_size(*metrics.txQMaxSize);
|
||||||
|
|
||||||
// fee levels data
|
// fee levels data
|
||||||
rpc::v1::FeeLevels& levels = *reply.mutable_levels();
|
org::xrpl::rpc::v1::FeeLevels& levels = *reply.mutable_levels();
|
||||||
levels.set_median_level(metrics.medFeeLevel.fee());
|
levels.set_median_level(metrics.medFeeLevel.fee());
|
||||||
levels.set_minimum_level(metrics.minProcessingFeeLevel.fee());
|
levels.set_minimum_level(metrics.minProcessingFeeLevel.fee());
|
||||||
levels.set_open_ledger_level(metrics.openLedgerFeeLevel.fee());
|
levels.set_open_ledger_level(metrics.openLedgerFeeLevel.fee());
|
||||||
levels.set_reference_level(metrics.referenceFeeLevel.fee());
|
levels.set_reference_level(metrics.referenceFeeLevel.fee());
|
||||||
|
|
||||||
// fee data
|
// fee data
|
||||||
rpc::v1::Fee& drops = *reply.mutable_drops();
|
org::xrpl::rpc::v1::Fee& fee = *reply.mutable_fee();
|
||||||
auto const baseFee = view->fees().base;
|
auto const baseFee = view->fees().base;
|
||||||
drops.mutable_base_fee()->set_drops(
|
fee.mutable_base_fee()->set_drops(
|
||||||
toDrops(metrics.referenceFeeLevel, baseFee).second.drops());
|
toDrops(metrics.referenceFeeLevel, baseFee).second.drops());
|
||||||
drops.mutable_minimum_fee()->set_drops(
|
fee.mutable_minimum_fee()->set_drops(
|
||||||
toDrops(metrics.minProcessingFeeLevel, baseFee).second.drops());
|
toDrops(metrics.minProcessingFeeLevel, baseFee).second.drops());
|
||||||
drops.mutable_median_fee()->set_drops(
|
fee.mutable_median_fee()->set_drops(
|
||||||
toDrops(metrics.medFeeLevel, baseFee).second.drops());
|
toDrops(metrics.medFeeLevel, baseFee).second.drops());
|
||||||
|
|
||||||
drops.mutable_open_ledger_fee()->set_drops(
|
fee.mutable_open_ledger_fee()->set_drops(
|
||||||
(toDrops(metrics.openLedgerFeeLevel - FeeLevel64{1}, baseFee).second +
|
(toDrops(metrics.openLedgerFeeLevel - FeeLevel64{1}, baseFee).second +
|
||||||
1)
|
1)
|
||||||
.drops());
|
.drops());
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ Json::Value doAccountLines (RPC::JsonContext&);
|
|||||||
Json::Value doAccountChannels (RPC::JsonContext&);
|
Json::Value doAccountChannels (RPC::JsonContext&);
|
||||||
Json::Value doAccountObjects (RPC::JsonContext&);
|
Json::Value doAccountObjects (RPC::JsonContext&);
|
||||||
Json::Value doAccountOffers (RPC::JsonContext&);
|
Json::Value doAccountOffers (RPC::JsonContext&);
|
||||||
Json::Value doAccountTx (RPC::JsonContext&);
|
|
||||||
Json::Value doAccountTxSwitch (RPC::JsonContext&);
|
Json::Value doAccountTxSwitch (RPC::JsonContext&);
|
||||||
Json::Value doAccountTxOld (RPC::JsonContext&);
|
Json::Value doAccountTxOld (RPC::JsonContext&);
|
||||||
|
Json::Value doAccountTxJson (RPC::JsonContext&);
|
||||||
Json::Value doBookOffers (RPC::JsonContext&);
|
Json::Value doBookOffers (RPC::JsonContext&);
|
||||||
Json::Value doBlackList (RPC::JsonContext&);
|
Json::Value doBlackList (RPC::JsonContext&);
|
||||||
Json::Value doCanDelete (RPC::JsonContext&);
|
Json::Value doCanDelete (RPC::JsonContext&);
|
||||||
@@ -79,7 +79,7 @@ Json::Value doSubmit (RPC::JsonContext&);
|
|||||||
Json::Value doSubmitMultiSigned (RPC::JsonContext&);
|
Json::Value doSubmitMultiSigned (RPC::JsonContext&);
|
||||||
Json::Value doSubscribe (RPC::JsonContext&);
|
Json::Value doSubscribe (RPC::JsonContext&);
|
||||||
Json::Value doTransactionEntry (RPC::JsonContext&);
|
Json::Value doTransactionEntry (RPC::JsonContext&);
|
||||||
Json::Value doTx (RPC::JsonContext&);
|
Json::Value doTxJson (RPC::JsonContext&);
|
||||||
Json::Value doTxHistory (RPC::JsonContext&);
|
Json::Value doTxHistory (RPC::JsonContext&);
|
||||||
Json::Value doUnlList (RPC::JsonContext&);
|
Json::Value doUnlList (RPC::JsonContext&);
|
||||||
Json::Value doUnsubscribe (RPC::JsonContext&);
|
Json::Value doUnsubscribe (RPC::JsonContext&);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <ripple/rpc/impl/TransactionSign.h>
|
#include <ripple/rpc/impl/TransactionSign.h>
|
||||||
#include <ripple/rpc/GRPCHandlers.h>
|
#include <ripple/rpc/GRPCHandlers.h>
|
||||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||||
|
#include <ripple/rpc/impl/GRPCHelpers.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
@@ -183,11 +184,11 @@ Json::Value doSubmit (RPC::JsonContext& context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<rpc::v1::SubmitTransactionResponse, grpc::Status>
|
std::pair<org::xrpl::rpc::v1::SubmitTransactionResponse, grpc::Status>
|
||||||
doSubmitGrpc(RPC::GRPCContext<rpc::v1::SubmitTransactionRequest>& context)
|
doSubmitGrpc(RPC::GRPCContext<org::xrpl::rpc::v1::SubmitTransactionRequest>& context)
|
||||||
{
|
{
|
||||||
// return values
|
// return values
|
||||||
rpc::v1::SubmitTransactionResponse result;
|
org::xrpl::rpc::v1::SubmitTransactionResponse result;
|
||||||
grpc::Status status = grpc::Status::OK;
|
grpc::Status status = grpc::Status::OK;
|
||||||
|
|
||||||
// input
|
// input
|
||||||
@@ -261,8 +262,7 @@ doSubmitGrpc(RPC::GRPCContext<rpc::v1::SubmitTransactionRequest>& context)
|
|||||||
// return preliminary result
|
// return preliminary result
|
||||||
if (temUNCERTAIN != tpTrans->getResult())
|
if (temUNCERTAIN != tpTrans->getResult())
|
||||||
{
|
{
|
||||||
RPC::populateTransactionResultType(
|
RPC::convert(*result.mutable_engine_result(), tpTrans->getResult());
|
||||||
*result.mutable_engine_result(), tpTrans->getResult());
|
|
||||||
|
|
||||||
std::string sToken;
|
std::string sToken;
|
||||||
std::string sHuman;
|
std::string sHuman;
|
||||||
|
|||||||
@@ -27,7 +27,9 @@
|
|||||||
#include <ripple/rpc/Context.h>
|
#include <ripple/rpc/Context.h>
|
||||||
#include <ripple/rpc/DeliveredAmount.h>
|
#include <ripple/rpc/DeliveredAmount.h>
|
||||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||||
|
#include <ripple/rpc/impl/GRPCHelpers.h>
|
||||||
#include <ripple/rpc/GRPCHandlers.h>
|
#include <ripple/rpc/GRPCHandlers.h>
|
||||||
|
#include <ripple/basics/ToString.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
@@ -64,13 +66,6 @@ isValidated(LedgerMaster& ledgerMaster, std::uint32_t seq, uint256 const& hash)
|
|||||||
return ledgerMaster.getHashBySeq (seq) == hash;
|
return ledgerMaster.getHashBySeq (seq) == hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
bool
|
|
||||||
isValidated (RPC::JsonContext& context, std::uint32_t seq, uint256 const& hash)
|
|
||||||
{
|
|
||||||
return isValidated(context.ledgerMaster, seq, hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
getMetaHex (Ledger const& ledger,
|
getMetaHex (Ledger const& ledger,
|
||||||
uint256 const& transID, std::string& hex)
|
uint256 const& transID, std::string& hex)
|
||||||
@@ -91,206 +86,103 @@ getMetaHex (Ledger const& ledger,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value doTx (RPC::JsonContext& context)
|
enum class SearchedAll { no, yes, unknown };
|
||||||
|
|
||||||
|
struct TxResult
|
||||||
{
|
{
|
||||||
if (!context.params.isMember (jss::transaction))
|
Transaction::pointer txn;
|
||||||
return rpcError (rpcINVALID_PARAMS);
|
std::variant<std::shared_ptr<TxMeta>, Blob> meta;
|
||||||
|
bool validated = false;
|
||||||
|
SearchedAll searchedAll;
|
||||||
|
};
|
||||||
|
|
||||||
bool binary = context.params.isMember (jss::binary)
|
struct TxArgs
|
||||||
&& context.params[jss::binary].asBool ();
|
{
|
||||||
|
uint256 hash;
|
||||||
|
bool binary = false;
|
||||||
|
std::optional<std::pair<uint32_t,uint32_t>> ledgerRange;
|
||||||
|
};
|
||||||
|
|
||||||
auto const txid = context.params[jss::transaction].asString ();
|
std::pair<TxResult, RPC::Status>
|
||||||
|
doTxHelp(RPC::Context& context, TxArgs const& args)
|
||||||
if (!isHexTxID (txid))
|
{
|
||||||
return rpcError (rpcNOT_IMPL);
|
TxResult result;
|
||||||
|
|
||||||
ClosedInterval<uint32_t> range;
|
ClosedInterval<uint32_t> range;
|
||||||
|
|
||||||
auto rangeProvided = context.params.isMember (jss::min_ledger) &&
|
if (args.ledgerRange)
|
||||||
context.params.isMember (jss::max_ledger);
|
|
||||||
|
|
||||||
if (rangeProvided)
|
|
||||||
{
|
{
|
||||||
try
|
constexpr uint16_t MAX_RANGE = 1000;
|
||||||
{
|
|
||||||
auto const& min = context.params[jss::min_ledger].asUInt ();
|
|
||||||
auto const& max = context.params[jss::max_ledger].asUInt ();
|
|
||||||
|
|
||||||
constexpr uint16_t MAX_RANGE = 1000;
|
if (args.ledgerRange->second < args.ledgerRange->first)
|
||||||
|
return {result, rpcINVALID_LGR_RANGE};
|
||||||
|
|
||||||
if (max < min)
|
if (args.ledgerRange->second - args.ledgerRange->first > MAX_RANGE)
|
||||||
return rpcError (rpcINVALID_LGR_RANGE);
|
return {result, rpcEXCESSIVE_LGR_RANGE};
|
||||||
|
|
||||||
if (max - min > MAX_RANGE)
|
range = ClosedInterval<uint32_t>(
|
||||||
return rpcError (rpcEXCESSIVE_LGR_RANGE);
|
args.ledgerRange->first, args.ledgerRange->second);
|
||||||
|
|
||||||
range = ClosedInterval<uint32_t> (min, max);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
// One of the calls to `asUInt ()` failed.
|
|
||||||
return rpcError (rpcINVALID_LGR_RANGE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using pointer = Transaction::pointer;
|
std::shared_ptr<Transaction> txn;
|
||||||
|
|
||||||
auto ec {rpcSUCCESS};
|
|
||||||
pointer txn;
|
|
||||||
|
|
||||||
if (rangeProvided)
|
|
||||||
{
|
|
||||||
boost::variant<pointer, bool> v =
|
|
||||||
context.app.getMasterTransaction().fetch(
|
|
||||||
from_hex_text<uint256>(txid), range, ec);
|
|
||||||
|
|
||||||
if (v.which () == 1)
|
|
||||||
{
|
|
||||||
auto jvResult = Json::Value (Json::objectValue);
|
|
||||||
|
|
||||||
jvResult[jss::searched_all] = boost::get<bool> (v);
|
|
||||||
|
|
||||||
return rpcError (rpcTXN_NOT_FOUND, jvResult);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
txn = boost::get<pointer> (v);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
txn = context.app.getMasterTransaction().fetch(
|
|
||||||
from_hex_text<uint256>(txid), ec);
|
|
||||||
|
|
||||||
if (ec == rpcDB_DESERIALIZATION)
|
|
||||||
return rpcError (ec);
|
|
||||||
|
|
||||||
if (!txn)
|
|
||||||
return rpcError (rpcTXN_NOT_FOUND);
|
|
||||||
|
|
||||||
Json::Value ret = txn->getJson (JsonOptions::include_date, binary);
|
|
||||||
|
|
||||||
if (txn->getLedger () == 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (auto lgr = context.ledgerMaster.getLedgerBySeq (txn->getLedger ()))
|
|
||||||
{
|
|
||||||
bool okay = false;
|
|
||||||
|
|
||||||
if (binary)
|
|
||||||
{
|
|
||||||
std::string meta;
|
|
||||||
|
|
||||||
if (getMetaHex (*lgr, txn->getID (), meta))
|
|
||||||
{
|
|
||||||
ret[jss::meta] = meta;
|
|
||||||
okay = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto rawMeta = lgr->txRead (txn->getID()).second;
|
|
||||||
if (rawMeta)
|
|
||||||
{
|
|
||||||
auto txMeta = std::make_shared<TxMeta>(
|
|
||||||
txn->getID(), lgr->seq(), *rawMeta);
|
|
||||||
okay = true;
|
|
||||||
auto meta = txMeta->getJson (JsonOptions::none);
|
|
||||||
insertDeliveredAmount (meta, context, txn, *txMeta);
|
|
||||||
ret[jss::meta] = std::move(meta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (okay)
|
|
||||||
ret[jss::validated] = isValidated (
|
|
||||||
context, lgr->info().seq, lgr->info().hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<rpc::v1::GetTxResponse, grpc::Status>
|
|
||||||
doTxGrpc(RPC::GRPCContext<rpc::v1::GetTxRequest>& context)
|
|
||||||
{
|
|
||||||
// return values
|
|
||||||
rpc::v1::GetTxResponse result;
|
|
||||||
grpc::Status status = grpc::Status::OK;
|
|
||||||
|
|
||||||
// input
|
|
||||||
rpc::v1::GetTxRequest& request = context.params;
|
|
||||||
|
|
||||||
std::string const& hashBytes = request.hash();
|
|
||||||
uint256 hash = uint256::fromVoid(hashBytes.data());
|
|
||||||
|
|
||||||
// hash is included in the response
|
|
||||||
result.set_hash(request.hash());
|
|
||||||
|
|
||||||
auto ec{rpcSUCCESS};
|
auto ec{rpcSUCCESS};
|
||||||
|
|
||||||
// get the transaction
|
result.searchedAll = SearchedAll::unknown;
|
||||||
std::shared_ptr<Transaction> txn =
|
if (args.ledgerRange)
|
||||||
context.app.getMasterTransaction().fetch(hash, ec);
|
{
|
||||||
|
boost::variant<std::shared_ptr<Transaction>, bool> v =
|
||||||
|
context.app.getMasterTransaction().fetch(args.hash, range, ec);
|
||||||
|
|
||||||
|
if (v.which() == 1)
|
||||||
|
{
|
||||||
|
result.searchedAll =
|
||||||
|
boost::get<bool>(v) ? SearchedAll::yes : SearchedAll::no;
|
||||||
|
return {result, rpcTXN_NOT_FOUND};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
txn = boost::get<std::shared_ptr<Transaction>>(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
txn = context.app.getMasterTransaction().fetch(args.hash, ec);
|
||||||
|
}
|
||||||
|
|
||||||
if (ec == rpcDB_DESERIALIZATION)
|
if (ec == rpcDB_DESERIALIZATION)
|
||||||
{
|
{
|
||||||
auto errorInfo = RPC::get_error_info(ec);
|
return {result, ec};
|
||||||
grpc::Status errorStatus{grpc::StatusCode::INTERNAL,
|
|
||||||
errorInfo.message.c_str()};
|
|
||||||
return {result, errorStatus};
|
|
||||||
}
|
}
|
||||||
if (!txn)
|
if (!txn)
|
||||||
{
|
{
|
||||||
grpc::Status errorStatus{grpc::StatusCode::NOT_FOUND, "txn not found"};
|
return {result, rpcTXN_NOT_FOUND};
|
||||||
return {result, errorStatus};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<STTx const> stTxn = txn->getSTransaction();
|
|
||||||
if (stTxn->getTxnType() != ttPAYMENT)
|
|
||||||
{
|
|
||||||
auto getTypeStr = [&stTxn]() {
|
|
||||||
return TxFormats::getInstance()
|
|
||||||
.findByType(stTxn->getTxnType())
|
|
||||||
->getName();
|
|
||||||
};
|
|
||||||
|
|
||||||
grpc::Status errorStatus{grpc::StatusCode::UNIMPLEMENTED,
|
|
||||||
"txn type not supported: " + getTypeStr()};
|
|
||||||
return {result, errorStatus};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate transaction data
|
// populate transaction data
|
||||||
if (request.binary())
|
result.txn = txn;
|
||||||
|
if (txn->getLedger() == 0)
|
||||||
{
|
{
|
||||||
Serializer s = stTxn->getSerializer();
|
return {result, rpcSUCCESS};
|
||||||
result.set_transaction_binary(s.data(), s.size());
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
RPC::populateTransaction(*result.mutable_transaction(), stTxn);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.set_ledger_index(txn->getLedger());
|
|
||||||
|
|
||||||
std::shared_ptr<Ledger const> ledger =
|
std::shared_ptr<Ledger const> ledger =
|
||||||
context.ledgerMaster.getLedgerBySeq(txn->getLedger());
|
context.ledgerMaster.getLedgerBySeq(txn->getLedger());
|
||||||
// get meta data
|
// get meta data
|
||||||
if (ledger)
|
if (ledger)
|
||||||
{
|
{
|
||||||
if (request.binary())
|
bool ok = false;
|
||||||
|
if (args.binary)
|
||||||
{
|
{
|
||||||
SHAMapTreeNode::TNType type;
|
SHAMapTreeNode::TNType type;
|
||||||
auto const item = ledger->txMap().peekItem(txn->getID(), type);
|
auto const item = ledger->txMap().peekItem(txn->getID(), type);
|
||||||
|
|
||||||
if (item && type == SHAMapTreeNode::tnTRANSACTION_MD)
|
if (item && type == SHAMapTreeNode::tnTRANSACTION_MD)
|
||||||
{
|
{
|
||||||
|
ok = true;
|
||||||
SerialIter it(item->slice());
|
SerialIter it(item->slice());
|
||||||
it.skip(it.getVLDataLength()); // skip transaction
|
it.skip(it.getVLDataLength()); // skip transaction
|
||||||
Blob blob = it.getVL();
|
Blob blob = it.getVL();
|
||||||
Slice slice = makeSlice(blob);
|
result.meta = std::move(blob);
|
||||||
result.set_meta_binary(slice.data(), slice.size());
|
|
||||||
|
|
||||||
bool validated = isValidated(
|
|
||||||
context.ledgerMaster,
|
|
||||||
ledger->info().seq,
|
|
||||||
ledger->info().hash);
|
|
||||||
result.set_validated(validated);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -298,25 +190,239 @@ doTxGrpc(RPC::GRPCContext<rpc::v1::GetTxRequest>& context)
|
|||||||
auto rawMeta = ledger->txRead(txn->getID()).second;
|
auto rawMeta = ledger->txRead(txn->getID()).second;
|
||||||
if (rawMeta)
|
if (rawMeta)
|
||||||
{
|
{
|
||||||
auto txMeta = std::make_shared<TxMeta>(
|
ok = true;
|
||||||
|
result.meta = std::make_shared<TxMeta>(
|
||||||
txn->getID(), ledger->seq(), *rawMeta);
|
txn->getID(), ledger->seq(), *rawMeta);
|
||||||
|
|
||||||
bool validated = isValidated(
|
|
||||||
context.ledgerMaster,
|
|
||||||
ledger->info().seq,
|
|
||||||
ledger->info().hash);
|
|
||||||
result.set_validated(validated);
|
|
||||||
|
|
||||||
RPC::populateMeta(*result.mutable_meta(), txMeta);
|
|
||||||
insertDeliveredAmount(
|
|
||||||
*result.mutable_meta()->mutable_delivered_amount(),
|
|
||||||
context,
|
|
||||||
txn,
|
|
||||||
*txMeta);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
result.validated = isValidated(
|
||||||
|
context.ledgerMaster, ledger->info().seq, ledger->info().hash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {result, status};
|
|
||||||
|
return {result, rpcSUCCESS};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<org::xrpl::rpc::v1::GetTransactionResponse, grpc::Status>
|
||||||
|
populateProtoResponse(
|
||||||
|
std::pair<TxResult, RPC::Status> const& res,
|
||||||
|
TxArgs const& args,
|
||||||
|
RPC::GRPCContext<org::xrpl::rpc::v1::GetTransactionRequest> const& context)
|
||||||
|
{
|
||||||
|
org::xrpl::rpc::v1::GetTransactionResponse response;
|
||||||
|
grpc::Status status = grpc::Status::OK;
|
||||||
|
RPC::Status const& error = res.second;
|
||||||
|
TxResult const& result = res.first;
|
||||||
|
// handle errors
|
||||||
|
if (error.toErrorCode() != rpcSUCCESS)
|
||||||
|
{
|
||||||
|
if (error.toErrorCode() == rpcTXN_NOT_FOUND &&
|
||||||
|
result.searchedAll != SearchedAll::unknown)
|
||||||
|
{
|
||||||
|
status = {
|
||||||
|
grpc::StatusCode::NOT_FOUND,
|
||||||
|
"txn not found. searched_all = " +
|
||||||
|
to_string(
|
||||||
|
(result.searchedAll == SearchedAll::yes ? "true"
|
||||||
|
: "false"))};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (error.toErrorCode() == rpcTXN_NOT_FOUND)
|
||||||
|
status = {grpc::StatusCode::NOT_FOUND, "txn not found"};
|
||||||
|
else
|
||||||
|
status = {grpc::StatusCode::INTERNAL, error.message()};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no errors
|
||||||
|
else if (result.txn)
|
||||||
|
{
|
||||||
|
auto& txn = result.txn;
|
||||||
|
|
||||||
|
std::shared_ptr<STTx const> stTxn = txn->getSTransaction();
|
||||||
|
if (args.binary)
|
||||||
|
{
|
||||||
|
Serializer s = stTxn->getSerializer();
|
||||||
|
response.set_transaction_binary(s.data(), s.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RPC::convert(*response.mutable_transaction(), stTxn);
|
||||||
|
}
|
||||||
|
|
||||||
|
response.set_hash(context.params.hash());
|
||||||
|
|
||||||
|
auto ledgerIndex = txn->getLedger();
|
||||||
|
response.set_ledger_index(ledgerIndex);
|
||||||
|
if (ledgerIndex)
|
||||||
|
{
|
||||||
|
auto ct =
|
||||||
|
context.app.getLedgerMaster().getCloseTimeBySeq(ledgerIndex);
|
||||||
|
if (ct)
|
||||||
|
response.mutable_date()->set_value(
|
||||||
|
ct->time_since_epoch().count());
|
||||||
|
}
|
||||||
|
|
||||||
|
RPC::convert(
|
||||||
|
*response.mutable_meta()->mutable_transaction_result(),
|
||||||
|
txn->getResult());
|
||||||
|
response.mutable_meta()->mutable_transaction_result()->set_result(
|
||||||
|
transToken(txn->getResult()));
|
||||||
|
|
||||||
|
// populate binary metadata
|
||||||
|
if (auto blob = std::get_if<Blob>(&result.meta))
|
||||||
|
{
|
||||||
|
assert(args.binary);
|
||||||
|
Slice slice = makeSlice(*blob);
|
||||||
|
response.set_meta_binary(slice.data(), slice.size());
|
||||||
|
}
|
||||||
|
// populate meta data
|
||||||
|
else if (auto m = std::get_if<std::shared_ptr<TxMeta>>(&result.meta))
|
||||||
|
{
|
||||||
|
auto& meta = *m;
|
||||||
|
if (meta)
|
||||||
|
{
|
||||||
|
RPC::convert(*response.mutable_meta(), meta);
|
||||||
|
auto amt =
|
||||||
|
getDeliveredAmount(context, stTxn, *meta, txn->getLedger());
|
||||||
|
if (amt)
|
||||||
|
{
|
||||||
|
RPC::convert(
|
||||||
|
*response.mutable_meta()->mutable_delivered_amount(),
|
||||||
|
*amt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response.set_validated(result.validated);
|
||||||
|
}
|
||||||
|
return {response, status};
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value
|
||||||
|
populateJsonResponse(
|
||||||
|
std::pair<TxResult, RPC::Status> const& res,
|
||||||
|
TxArgs const& args,
|
||||||
|
RPC::JsonContext const& context)
|
||||||
|
{
|
||||||
|
Json::Value response;
|
||||||
|
RPC::Status const& error = res.second;
|
||||||
|
TxResult const& result = res.first;
|
||||||
|
// handle errors
|
||||||
|
if (error.toErrorCode() != rpcSUCCESS)
|
||||||
|
{
|
||||||
|
if (error.toErrorCode() == rpcTXN_NOT_FOUND &&
|
||||||
|
result.searchedAll != SearchedAll::unknown)
|
||||||
|
{
|
||||||
|
response = Json::Value(Json::objectValue);
|
||||||
|
response[jss::searched_all] =
|
||||||
|
(result.searchedAll == SearchedAll::yes);
|
||||||
|
error.inject(response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error.inject(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no errors
|
||||||
|
else if (result.txn)
|
||||||
|
{
|
||||||
|
response = result.txn->getJson(JsonOptions::include_date, args.binary);
|
||||||
|
|
||||||
|
// populate binary metadata
|
||||||
|
if (auto blob = std::get_if<Blob>(&result.meta))
|
||||||
|
{
|
||||||
|
assert(args.binary);
|
||||||
|
response[jss::meta] = strHex(makeSlice(*blob));
|
||||||
|
}
|
||||||
|
// populate meta data
|
||||||
|
else if (auto m = std::get_if<std::shared_ptr<TxMeta>>(&result.meta))
|
||||||
|
{
|
||||||
|
auto& meta = *m;
|
||||||
|
if (meta)
|
||||||
|
{
|
||||||
|
response[jss::meta] = meta->getJson(JsonOptions::none);
|
||||||
|
insertDeliveredAmount(
|
||||||
|
response[jss::meta], context, result.txn, *meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
response[jss::validated] = result.validated;
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value
|
||||||
|
doTxJson(RPC::JsonContext& context)
|
||||||
|
{
|
||||||
|
// Deserialize and validate JSON arguments
|
||||||
|
|
||||||
|
if (!context.params.isMember(jss::transaction))
|
||||||
|
return rpcError(rpcINVALID_PARAMS);
|
||||||
|
|
||||||
|
std::string txHash = context.params[jss::transaction].asString();
|
||||||
|
if (!isHexTxID(txHash))
|
||||||
|
return rpcError(rpcNOT_IMPL);
|
||||||
|
|
||||||
|
TxArgs args;
|
||||||
|
args.hash = from_hex_text<uint256>(txHash);
|
||||||
|
|
||||||
|
args.binary = context.params.isMember(jss::binary) &&
|
||||||
|
context.params[jss::binary].asBool();
|
||||||
|
|
||||||
|
if (context.params.isMember(jss::min_ledger) &&
|
||||||
|
context.params.isMember(jss::max_ledger))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
args.ledgerRange = std::make_pair(
|
||||||
|
context.params[jss::min_ledger].asUInt(),
|
||||||
|
context.params[jss::max_ledger].asUInt());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
// One of the calls to `asUInt ()` failed.
|
||||||
|
return rpcError(rpcINVALID_LGR_RANGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<TxResult, RPC::Status> res = doTxHelp(context, args);
|
||||||
|
return populateJsonResponse(res, args, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<org::xrpl::rpc::v1::GetTransactionResponse, grpc::Status>
|
||||||
|
doTxGrpc(RPC::GRPCContext<org::xrpl::rpc::v1::GetTransactionRequest>& context)
|
||||||
|
{
|
||||||
|
// return values
|
||||||
|
org::xrpl::rpc::v1::GetTransactionResponse response;
|
||||||
|
grpc::Status status = grpc::Status::OK;
|
||||||
|
|
||||||
|
// input
|
||||||
|
org::xrpl::rpc::v1::GetTransactionRequest& request = context.params;
|
||||||
|
|
||||||
|
TxArgs args;
|
||||||
|
|
||||||
|
std::string const& hashBytes = request.hash();
|
||||||
|
args.hash = uint256::fromVoid(hashBytes.data());
|
||||||
|
if (args.hash.size() != hashBytes.size())
|
||||||
|
{
|
||||||
|
grpc::Status errorStatus{grpc::StatusCode::INVALID_ARGUMENT,
|
||||||
|
"ledger hash malformed"};
|
||||||
|
return {response, errorStatus};
|
||||||
|
}
|
||||||
|
|
||||||
|
args.binary = request.binary();
|
||||||
|
|
||||||
|
if (request.ledger_range().ledger_index_min() != 0 &&
|
||||||
|
request.ledger_range().ledger_index_max() != 0)
|
||||||
|
{
|
||||||
|
args.ledgerRange = std::make_pair(
|
||||||
|
request.ledger_range().ledger_index_min(),
|
||||||
|
request.ledger_range().ledger_index_max());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<TxResult, RPC::Status> res = doTxHelp(context, args);
|
||||||
|
return populateProtoResponse(res, args, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ripple
|
} // namespace ripple
|
||||||
|
|||||||
@@ -39,43 +39,24 @@ namespace RPC {
|
|||||||
would be calculated even when not needed, and in some circumstances they are
|
would be calculated even when not needed, and in some circumstances they are
|
||||||
not trivial to compute.
|
not trivial to compute.
|
||||||
|
|
||||||
GetFix1623Enabled is a callable that returns a bool
|
|
||||||
GetLedgerIndex is a callable that returns a LedgerIndex
|
GetLedgerIndex is a callable that returns a LedgerIndex
|
||||||
GetCloseTime is a callable that returns a
|
GetCloseTime is a callable that returns a
|
||||||
boost::optional<NetClock::time_point>
|
boost::optional<NetClock::time_point>
|
||||||
*/
|
*/
|
||||||
template<class GetFix1623Enabled, class GetLedgerIndex, class GetCloseTime>
|
template <class GetLedgerIndex, class GetCloseTime>
|
||||||
void
|
std::optional<STAmount>
|
||||||
insertDeliveredAmount(
|
getDeliveredAmount(
|
||||||
Json::Value& meta,
|
|
||||||
GetFix1623Enabled const& getFix1623Enabled,
|
|
||||||
GetLedgerIndex const& getLedgerIndex,
|
GetLedgerIndex const& getLedgerIndex,
|
||||||
GetCloseTime const& getCloseTime,
|
GetCloseTime const& getCloseTime,
|
||||||
std::shared_ptr<STTx const> serializedTx,
|
std::shared_ptr<STTx const> const& serializedTx,
|
||||||
TxMeta const& transactionMeta)
|
TxMeta const& transactionMeta)
|
||||||
{
|
{
|
||||||
{
|
if (!serializedTx)
|
||||||
TxType const tt{serializedTx->getTxnType()};
|
return {};
|
||||||
if (tt != ttPAYMENT &&
|
|
||||||
tt != ttCHECK_CASH &&
|
|
||||||
tt != ttACCOUNT_DELETE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (tt == ttCHECK_CASH &&
|
|
||||||
!getFix1623Enabled())
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the transaction failed nothing could have been delivered.
|
|
||||||
if (transactionMeta.getResultTER() != tesSUCCESS)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (transactionMeta.hasDeliveredAmount())
|
if (transactionMeta.hasDeliveredAmount())
|
||||||
{
|
{
|
||||||
meta[jss::delivered_amount] =
|
return transactionMeta.getDeliveredAmount();
|
||||||
transactionMeta.getDeliveredAmount()
|
|
||||||
.getJson(JsonOptions::include_date);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serializedTx->isFieldPresent(sfAmount))
|
if (serializedTx->isFieldPresent(sfAmount))
|
||||||
@@ -93,156 +74,161 @@ insertDeliveredAmount(
|
|||||||
if (getLedgerIndex() >= 4594095 ||
|
if (getLedgerIndex() >= 4594095 ||
|
||||||
getCloseTime() > NetClock::time_point{446000000s})
|
getCloseTime() > NetClock::time_point{446000000s})
|
||||||
{
|
{
|
||||||
meta[jss::delivered_amount] =
|
return serializedTx->getFieldAmount(sfAmount);
|
||||||
serializedTx->getFieldAmount(sfAmount)
|
|
||||||
.getJson(JsonOptions::include_date);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// report "unavailable" which cannot be parsed into a sensible amount.
|
return {};
|
||||||
meta[jss::delivered_amount] = Json::Value("unavailable");
|
}
|
||||||
|
|
||||||
|
// Returns true if transaction meta could contain a delivered amount field,
|
||||||
|
// based on transaction type, transaction result and whether fix1623 is enabled
|
||||||
|
template <class GetFix1623Enabled>
|
||||||
|
bool
|
||||||
|
canHaveDeliveredAmountHelp(
|
||||||
|
GetFix1623Enabled const& getFix1623Enabled,
|
||||||
|
std::shared_ptr<STTx const> const& serializedTx,
|
||||||
|
TxMeta const& transactionMeta)
|
||||||
|
{
|
||||||
|
if (!serializedTx)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
{
|
||||||
|
TxType const tt{serializedTx->getTxnType()};
|
||||||
|
if (tt != ttPAYMENT && tt != ttCHECK_CASH && tt != ttACCOUNT_DELETE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (tt == ttCHECK_CASH && !getFix1623Enabled())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the transaction failed nothing could have been delivered.
|
||||||
|
if (transactionMeta.getResultTER() != tesSUCCESS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if transaction meta could contain a delivered amount field,
|
||||||
|
// based on transaction type, transaction result and whether fix1623 is enabled
|
||||||
|
bool
|
||||||
|
canHaveDeliveredAmount(
|
||||||
|
RPC::Context const& context,
|
||||||
|
std::shared_ptr<STTx const> const& serializedTx,
|
||||||
|
TxMeta const& transactionMeta)
|
||||||
|
{
|
||||||
|
// These lambdas are used to compute the values lazily
|
||||||
|
auto const getFix1623Enabled = [&context]() -> bool {
|
||||||
|
auto const view = context.app.openLedger().current();
|
||||||
|
if (!view)
|
||||||
|
return false;
|
||||||
|
return view->rules().enabled(fix1623);
|
||||||
|
};
|
||||||
|
|
||||||
|
return canHaveDeliveredAmountHelp(
|
||||||
|
getFix1623Enabled, serializedTx, transactionMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
insertDeliveredAmount(
|
insertDeliveredAmount(
|
||||||
Json::Value& meta,
|
Json::Value& meta,
|
||||||
ReadView const& ledger,
|
ReadView const& ledger,
|
||||||
std::shared_ptr<STTx const> serializedTx,
|
std::shared_ptr<STTx const> const& serializedTx,
|
||||||
TxMeta const& transactionMeta)
|
TxMeta const& transactionMeta)
|
||||||
{
|
{
|
||||||
if (!serializedTx)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto const info = ledger.info();
|
auto const info = ledger.info();
|
||||||
auto const getFix1623Enabled = [&ledger] {
|
auto const getFix1623Enabled = [&ledger] {
|
||||||
return ledger.rules().enabled(fix1623);
|
return ledger.rules().enabled(fix1623);
|
||||||
};
|
};
|
||||||
auto const getLedgerIndex = [&info] {
|
|
||||||
return info.seq;
|
|
||||||
};
|
|
||||||
auto const getCloseTime = [&info] {
|
|
||||||
return info.closeTime;
|
|
||||||
};
|
|
||||||
|
|
||||||
insertDeliveredAmount(
|
if (canHaveDeliveredAmountHelp(
|
||||||
meta,
|
getFix1623Enabled, serializedTx, transactionMeta))
|
||||||
getFix1623Enabled,
|
{
|
||||||
getLedgerIndex,
|
auto const getLedgerIndex = [&info] { return info.seq; };
|
||||||
getCloseTime,
|
auto const getCloseTime = [&info] { return info.closeTime; };
|
||||||
std::move(serializedTx),
|
|
||||||
transactionMeta);
|
auto amt = getDeliveredAmount(
|
||||||
|
getLedgerIndex,
|
||||||
|
getCloseTime,
|
||||||
|
std::move(serializedTx),
|
||||||
|
transactionMeta);
|
||||||
|
if (amt)
|
||||||
|
{
|
||||||
|
meta[jss::delivered_amount] =
|
||||||
|
amt->getJson(JsonOptions::include_date);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// report "unavailable" which cannot be parsed into a sensible
|
||||||
|
// amount.
|
||||||
|
meta[jss::delivered_amount] = Json::Value("unavailable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class GetLedgerIndex>
|
||||||
|
std::optional<STAmount>
|
||||||
|
getDeliveredAmount(
|
||||||
|
RPC::Context const& context,
|
||||||
|
std::shared_ptr<STTx const> const& serializedTx,
|
||||||
|
TxMeta const& transactionMeta,
|
||||||
|
GetLedgerIndex const& getLedgerIndex)
|
||||||
|
{
|
||||||
|
if (canHaveDeliveredAmount(context, serializedTx, transactionMeta))
|
||||||
|
{
|
||||||
|
auto const getCloseTime =
|
||||||
|
[&context,
|
||||||
|
&getLedgerIndex]() -> boost::optional<NetClock::time_point> {
|
||||||
|
return context.ledgerMaster.getCloseTimeBySeq(getLedgerIndex());
|
||||||
|
};
|
||||||
|
return getDeliveredAmount(
|
||||||
|
getLedgerIndex,
|
||||||
|
getCloseTime,
|
||||||
|
std::move(serializedTx),
|
||||||
|
transactionMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<STAmount>
|
||||||
|
getDeliveredAmount(
|
||||||
|
RPC::Context const& context,
|
||||||
|
std::shared_ptr<STTx const> const& serializedTx,
|
||||||
|
TxMeta const& transactionMeta,
|
||||||
|
LedgerIndex const& ledgerIndex)
|
||||||
|
{
|
||||||
|
return getDeliveredAmount(
|
||||||
|
context, serializedTx, transactionMeta, [&ledgerIndex]() {
|
||||||
|
return ledgerIndex;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
insertDeliveredAmount(
|
insertDeliveredAmount(
|
||||||
Json::Value& meta,
|
Json::Value& meta,
|
||||||
RPC::JsonContext& context,
|
RPC::JsonContext const& context,
|
||||||
std::shared_ptr<Transaction> transaction,
|
std::shared_ptr<Transaction> const& transaction,
|
||||||
TxMeta const& transactionMeta)
|
TxMeta const& transactionMeta)
|
||||||
{
|
{
|
||||||
if (!transaction)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto const serializedTx = transaction->getSTransaction ();
|
|
||||||
if (! serializedTx)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
// These lambdas are used to compute the values lazily
|
|
||||||
auto const getFix1623Enabled = [&context]() -> bool {
|
|
||||||
auto const view = context.app.openLedger().current();
|
|
||||||
if (!view)
|
|
||||||
return false;
|
|
||||||
return view->rules().enabled(fix1623);
|
|
||||||
};
|
|
||||||
auto const getLedgerIndex = [&transaction]() -> LedgerIndex {
|
|
||||||
return transaction->getLedger();
|
|
||||||
};
|
|
||||||
auto const getCloseTime =
|
|
||||||
[&context, &transaction]() -> boost::optional<NetClock::time_point> {
|
|
||||||
return context.ledgerMaster.getCloseTimeBySeq(transaction->getLedger());
|
|
||||||
};
|
|
||||||
|
|
||||||
insertDeliveredAmount(
|
|
||||||
meta,
|
|
||||||
getFix1623Enabled,
|
|
||||||
getLedgerIndex,
|
|
||||||
getCloseTime,
|
|
||||||
std::move(serializedTx),
|
|
||||||
transactionMeta);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO get rid of the code duplication between this function and the preceding
|
|
||||||
// function
|
|
||||||
void
|
|
||||||
insertDeliveredAmount(
|
|
||||||
rpc::v1::CurrencyAmount& proto,
|
|
||||||
RPC::Context& context,
|
|
||||||
std::shared_ptr<Transaction> transaction,
|
|
||||||
TxMeta const& transactionMeta)
|
|
||||||
{
|
|
||||||
if (!transaction)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto const serializedTx = transaction->getSTransaction();
|
auto const serializedTx = transaction->getSTransaction();
|
||||||
if (!serializedTx)
|
if (canHaveDeliveredAmount(context, serializedTx, transactionMeta))
|
||||||
return;
|
|
||||||
|
|
||||||
// These lambdas are used to compute the values lazily
|
|
||||||
auto const getFix1623Enabled = [&context]() -> bool {
|
|
||||||
auto const view = context.app.openLedger().current();
|
|
||||||
if (!view)
|
|
||||||
return false;
|
|
||||||
return view->rules().enabled(fix1623);
|
|
||||||
};
|
|
||||||
auto const getLedgerIndex = [&transaction]() -> LedgerIndex {
|
|
||||||
return transaction->getLedger();
|
|
||||||
};
|
|
||||||
auto const getCloseTime =
|
|
||||||
[&context, &transaction]() -> boost::optional<NetClock::time_point> {
|
|
||||||
return context.ledgerMaster.getCloseTimeBySeq(transaction->getLedger());
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
{
|
||||||
TxType const tt{serializedTx->getTxnType()};
|
auto amt = getDeliveredAmount(
|
||||||
if (tt != ttPAYMENT &&
|
context, serializedTx, transactionMeta, [&transaction]() {
|
||||||
tt != ttCHECK_CASH &&
|
return transaction->getLedger();
|
||||||
tt != ttACCOUNT_DELETE)
|
});
|
||||||
return;
|
|
||||||
|
|
||||||
if (tt == ttCHECK_CASH &&
|
if (amt)
|
||||||
!getFix1623Enabled())
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the transaction failed nothing could have been delivered.
|
|
||||||
if (transactionMeta.getResultTER() != tesSUCCESS)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (transactionMeta.hasDeliveredAmount())
|
|
||||||
{
|
|
||||||
populateAmount(proto, transactionMeta.getDeliveredAmount());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serializedTx->isFieldPresent(sfAmount))
|
|
||||||
{
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
|
|
||||||
// Ledger 4594095 is the first ledger in which the DeliveredAmount field
|
|
||||||
// was present when a partial payment was made and its absence indicates
|
|
||||||
// that the amount delivered is listed in the Amount field.
|
|
||||||
//
|
|
||||||
// If the ledger closed long after the DeliveredAmount code was deployed
|
|
||||||
// then its absence indicates that the amount delivered is listed in the
|
|
||||||
// Amount field. DeliveredAmount went live January 24, 2014.
|
|
||||||
// 446000000 is in Feb 2014, well after DeliveredAmount went live
|
|
||||||
if (getLedgerIndex() >= 4594095 ||
|
|
||||||
getCloseTime() > NetClock::time_point{446000000s})
|
|
||||||
{
|
{
|
||||||
populateAmount(proto, serializedTx->getFieldAmount(sfAmount));
|
meta[jss::delivered_amount] =
|
||||||
return;
|
amt->getJson(JsonOptions::include_date);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// report "unavailable" which cannot be parsed into a sensible
|
||||||
|
// amount.
|
||||||
|
meta[jss::delivered_amount] = Json::Value("unavailable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1779
src/ripple/rpc/impl/GRPCHelpers.cpp
Normal file
1779
src/ripple/rpc/impl/GRPCHelpers.cpp
Normal file
File diff suppressed because it is too large
Load Diff
87
src/ripple/rpc/impl/GRPCHelpers.h
Normal file
87
src/ripple/rpc/impl/GRPCHelpers.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
|
Copyright (c) 2020 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_RPC_GRPCHELPERS_H_INCLUDED
|
||||||
|
#define RIPPLE_RPC_GRPCHELPERS_H_INCLUDED
|
||||||
|
|
||||||
|
#include "org/xrpl/rpc/v1/get_account_info.pb.h"
|
||||||
|
#include "org/xrpl/rpc/v1/ledger_objects.pb.h"
|
||||||
|
#include "org/xrpl/rpc/v1/meta.pb.h"
|
||||||
|
#include "org/xrpl/rpc/v1/transaction.pb.h"
|
||||||
|
|
||||||
|
#include <ripple/app/misc/TxQ.h>
|
||||||
|
#include <ripple/ledger/TxMeta.h>
|
||||||
|
#include <ripple/protocol/Protocol.h>
|
||||||
|
#include <ripple/protocol/STAmount.h>
|
||||||
|
#include <ripple/protocol/STTx.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace RPC {
|
||||||
|
|
||||||
|
void
|
||||||
|
convert(org::xrpl::rpc::v1::Meta& to, std::shared_ptr<TxMeta> const& from);
|
||||||
|
|
||||||
|
void
|
||||||
|
convert(
|
||||||
|
org::xrpl::rpc::v1::QueueData& to,
|
||||||
|
std::map<TxSeq, TxQ::AccountTxDetails const> const& from);
|
||||||
|
|
||||||
|
void
|
||||||
|
convert(
|
||||||
|
org::xrpl::rpc::v1::Transaction& to,
|
||||||
|
std::shared_ptr<STTx const> const& from);
|
||||||
|
|
||||||
|
void
|
||||||
|
convert(org::xrpl::rpc::v1::TransactionResult& to, TER from);
|
||||||
|
|
||||||
|
void
|
||||||
|
convert(org::xrpl::rpc::v1::AccountRoot& to, STObject const& from);
|
||||||
|
|
||||||
|
void
|
||||||
|
convert(org::xrpl::rpc::v1::SignerList& to, STObject const& from);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
convert(T& to, STAmount const& from)
|
||||||
|
{
|
||||||
|
if (from.native())
|
||||||
|
{
|
||||||
|
to.mutable_value()->mutable_xrp_amount()->set_drops(from.xrp().drops());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Issue const& issue = from.issue();
|
||||||
|
|
||||||
|
org::xrpl::rpc::v1::IssuedCurrencyAmount* issued =
|
||||||
|
to.mutable_value()->mutable_issued_currency_amount();
|
||||||
|
|
||||||
|
issued->mutable_currency()->set_name(to_string(issue.currency));
|
||||||
|
issued->mutable_currency()->set_code(
|
||||||
|
issue.currency.data(), Currency::size());
|
||||||
|
issued->mutable_issuer()->set_address(toBase58(issue.account));
|
||||||
|
issued->set_value(to_string(from.iou()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace RPC
|
||||||
|
} // namespace ripple
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -65,7 +65,7 @@ Handler const handlerArray[] {
|
|||||||
{ "account_channels", byRef (&doAccountChannels), Role::USER, NO_CONDITION },
|
{ "account_channels", byRef (&doAccountChannels), Role::USER, NO_CONDITION },
|
||||||
{ "account_objects", byRef (&doAccountObjects), Role::USER, NO_CONDITION },
|
{ "account_objects", byRef (&doAccountObjects), Role::USER, NO_CONDITION },
|
||||||
{ "account_offers", byRef (&doAccountOffers), Role::USER, NO_CONDITION },
|
{ "account_offers", byRef (&doAccountOffers), Role::USER, NO_CONDITION },
|
||||||
{ "account_tx", byRef (&doAccountTxSwitch), Role::USER, NO_CONDITION },
|
{ "account_tx", byRef (&doAccountTxJson), Role::USER, NO_CONDITION },
|
||||||
{ "blacklist", byRef (&doBlackList), Role::ADMIN, NO_CONDITION },
|
{ "blacklist", byRef (&doBlackList), Role::ADMIN, NO_CONDITION },
|
||||||
{ "book_offers", byRef (&doBookOffers), Role::USER, NO_CONDITION },
|
{ "book_offers", byRef (&doBookOffers), Role::USER, NO_CONDITION },
|
||||||
{ "can_delete", byRef (&doCanDelete), Role::ADMIN, NO_CONDITION },
|
{ "can_delete", byRef (&doCanDelete), Role::ADMIN, NO_CONDITION },
|
||||||
@@ -112,7 +112,7 @@ Handler const handlerArray[] {
|
|||||||
{ "crawl_shards", byRef (&doCrawlShards), Role::ADMIN, NO_CONDITION },
|
{ "crawl_shards", byRef (&doCrawlShards), Role::ADMIN, NO_CONDITION },
|
||||||
{ "stop", byRef (&doStop), Role::ADMIN, NO_CONDITION },
|
{ "stop", byRef (&doStop), Role::ADMIN, NO_CONDITION },
|
||||||
{ "transaction_entry", byRef (&doTransactionEntry), Role::USER, NO_CONDITION },
|
{ "transaction_entry", byRef (&doTransactionEntry), Role::USER, NO_CONDITION },
|
||||||
{ "tx", byRef (&doTx), Role::USER, NEEDS_NETWORK_CONNECTION },
|
{ "tx", byRef (&doTxJson), Role::USER, NEEDS_NETWORK_CONNECTION },
|
||||||
{ "tx_history", byRef (&doTxHistory), Role::USER, NO_CONDITION },
|
{ "tx_history", byRef (&doTxHistory), Role::USER, NO_CONDITION },
|
||||||
{ "unl_list", byRef (&doUnlList), Role::ADMIN, NO_CONDITION },
|
{ "unl_list", byRef (&doUnlList), Role::ADMIN, NO_CONDITION },
|
||||||
{ "validation_create", byRef (&doValidationCreate), Role::ADMIN, NO_CONDITION },
|
{ "validation_create", byRef (&doValidationCreate), Role::ADMIN, NO_CONDITION },
|
||||||
|
|||||||
@@ -29,6 +29,8 @@
|
|||||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
#include <boost/algorithm/string/case_conv.hpp>
|
||||||
|
|
||||||
|
#include <ripple/rpc/impl/GRPCHelpers.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace RPC {
|
namespace RPC {
|
||||||
|
|
||||||
@@ -199,12 +201,10 @@ template <class T>
|
|||||||
Status
|
Status
|
||||||
ledgerFromRequest(T& ledger, JsonContext& context)
|
ledgerFromRequest(T& ledger, JsonContext& context)
|
||||||
{
|
{
|
||||||
static auto const minSequenceGap = 10;
|
|
||||||
|
|
||||||
ledger.reset();
|
ledger.reset();
|
||||||
|
|
||||||
auto& params = context.params;
|
auto& params = context.params;
|
||||||
auto& ledgerMaster = context.ledgerMaster;
|
|
||||||
|
|
||||||
auto indexValue = params[jss::ledger_index];
|
auto indexValue = params[jss::ledger_index];
|
||||||
auto hashValue = params[jss::ledger_hash];
|
auto hashValue = params[jss::ledger_hash];
|
||||||
@@ -225,74 +225,32 @@ ledgerFromRequest(T& ledger, JsonContext& context)
|
|||||||
return {rpcINVALID_PARAMS, "ledgerHashNotString"};
|
return {rpcINVALID_PARAMS, "ledgerHashNotString"};
|
||||||
|
|
||||||
uint256 ledgerHash;
|
uint256 ledgerHash;
|
||||||
if (! ledgerHash.SetHex (hashValue.asString ()))
|
if(!ledgerHash.SetHex (hashValue.asString ()))
|
||||||
return {rpcINVALID_PARAMS, "ledgerHashMalformed"};
|
return {rpcINVALID_PARAMS, "ledgerHashMalformed"};
|
||||||
|
return getLedger(ledger, ledgerHash, context);
|
||||||
ledger = ledgerMaster.getLedgerByHash (ledgerHash);
|
|
||||||
if (ledger == nullptr)
|
|
||||||
return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
|
|
||||||
}
|
}
|
||||||
else if (indexValue.isNumeric())
|
else if (indexValue.isNumeric())
|
||||||
{
|
{
|
||||||
ledger = ledgerMaster.getLedgerBySeq (indexValue.asInt ());
|
return getLedger(ledger, indexValue.asInt(),context);
|
||||||
|
|
||||||
if (ledger == nullptr)
|
|
||||||
{
|
|
||||||
auto cur = ledgerMaster.getCurrentLedger();
|
|
||||||
if (cur->info().seq == indexValue.asInt())
|
|
||||||
ledger = cur;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ledger == nullptr)
|
|
||||||
return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
|
|
||||||
|
|
||||||
if (ledger->info().seq > ledgerMaster.getValidLedgerIndex() &&
|
|
||||||
isValidatedOld(ledgerMaster, context.app.config().standalone()))
|
|
||||||
{
|
|
||||||
ledger.reset();
|
|
||||||
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (isValidatedOld (ledgerMaster, context.app.config().standalone()))
|
|
||||||
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
|
||||||
|
|
||||||
auto const index = indexValue.asString ();
|
auto const index = indexValue.asString ();
|
||||||
if (index == "validated")
|
if (index == "validated")
|
||||||
{
|
{
|
||||||
ledger = ledgerMaster.getValidatedLedger ();
|
return getLedger(ledger, LedgerShortcut::VALIDATED, context);
|
||||||
if (ledger == nullptr)
|
|
||||||
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
|
||||||
|
|
||||||
assert (! ledger->open());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (index.empty () || index == "current")
|
if (index.empty () || index == "current")
|
||||||
{
|
return getLedger(ledger, LedgerShortcut::CURRENT, context);
|
||||||
ledger = ledgerMaster.getCurrentLedger ();
|
|
||||||
assert (ledger->open());
|
|
||||||
}
|
|
||||||
else if (index == "closed")
|
else if (index == "closed")
|
||||||
{
|
return getLedger(ledger, LedgerShortcut::CLOSED, context);
|
||||||
ledger = ledgerMaster.getClosedLedger ();
|
|
||||||
assert (! ledger->open());
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
|
return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ledger == nullptr)
|
|
||||||
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
|
||||||
|
|
||||||
if (ledger->info().seq + minSequenceGap <
|
|
||||||
ledgerMaster.getValidLedgerIndex ())
|
|
||||||
{
|
|
||||||
ledger.reset ();
|
|
||||||
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,88 +262,49 @@ template <class T>
|
|||||||
Status
|
Status
|
||||||
ledgerFromRequest(
|
ledgerFromRequest(
|
||||||
T& ledger,
|
T& ledger,
|
||||||
GRPCContext<rpc::v1::GetAccountInfoRequest>& context)
|
GRPCContext<org::xrpl::rpc::v1::GetAccountInfoRequest>& context)
|
||||||
{
|
{
|
||||||
static auto const minSequenceGap = 10;
|
|
||||||
|
|
||||||
ledger.reset();
|
ledger.reset();
|
||||||
|
|
||||||
rpc::v1::GetAccountInfoRequest& request = context.params;
|
org::xrpl::rpc::v1::GetAccountInfoRequest& request = context.params;
|
||||||
auto& ledgerMaster = context.ledgerMaster;
|
|
||||||
|
|
||||||
using LedgerCase = rpc::v1::LedgerSpecifier::LedgerCase;
|
using LedgerCase = org::xrpl::rpc::v1::LedgerSpecifier::LedgerCase;
|
||||||
LedgerCase ledgerCase = request.ledger().ledger_case();
|
LedgerCase ledgerCase = request.ledger().ledger_case();
|
||||||
|
switch (ledgerCase)
|
||||||
if (ledgerCase == LedgerCase::kHash)
|
|
||||||
{
|
{
|
||||||
uint256 ledgerHash = uint256::fromVoid(request.ledger().hash().data());
|
case LedgerCase::kHash:
|
||||||
if (ledgerHash.size() != request.ledger().hash().size())
|
|
||||||
return {rpcINVALID_PARAMS, "ledgerHashMalformed"};
|
|
||||||
|
|
||||||
ledger = ledgerMaster.getLedgerByHash(ledgerHash);
|
|
||||||
if (ledger == nullptr)
|
|
||||||
return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
|
|
||||||
}
|
|
||||||
else if (ledgerCase == LedgerCase::kSequence)
|
|
||||||
{
|
|
||||||
ledger = ledgerMaster.getLedgerBySeq(request.ledger().sequence());
|
|
||||||
|
|
||||||
if (ledger == nullptr)
|
|
||||||
{
|
{
|
||||||
auto cur = ledgerMaster.getCurrentLedger();
|
uint256 ledgerHash =
|
||||||
if (cur->info().seq == request.ledger().sequence())
|
uint256::fromVoid(request.ledger().hash().data());
|
||||||
ledger = cur;
|
return getLedger(ledger, ledgerHash, context);
|
||||||
}
|
}
|
||||||
|
case LedgerCase::kSequence:
|
||||||
if (ledger == nullptr)
|
return getLedger(ledger, request.ledger().sequence(), context);
|
||||||
return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
|
case LedgerCase::kShortcut:
|
||||||
|
[[fallthrough]];
|
||||||
if (ledger->info().seq > ledgerMaster.getValidLedgerIndex() &&
|
case LedgerCase::LEDGER_NOT_SET:
|
||||||
isValidatedOld(ledgerMaster, context.app.config().standalone()))
|
|
||||||
{
|
{
|
||||||
ledger.reset();
|
auto const shortcut = request.ledger().shortcut();
|
||||||
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
if (shortcut ==
|
||||||
}
|
org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED)
|
||||||
}
|
return getLedger(ledger, LedgerShortcut::VALIDATED, context);
|
||||||
else if (
|
else
|
||||||
ledgerCase == LedgerCase::kShortcut ||
|
|
||||||
ledgerCase == LedgerCase::LEDGER_NOT_SET)
|
|
||||||
{
|
|
||||||
if (isValidatedOld(ledgerMaster, context.app.config().standalone()))
|
|
||||||
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
|
||||||
|
|
||||||
auto const shortcut = request.ledger().shortcut();
|
|
||||||
if (shortcut == rpc::v1::LedgerSpecifier::SHORTCUT_VALIDATED)
|
|
||||||
{
|
|
||||||
ledger = ledgerMaster.getValidatedLedger();
|
|
||||||
if (ledger == nullptr)
|
|
||||||
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
|
||||||
|
|
||||||
assert(!ledger->open());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// note, if unspecified, defaults to current ledger
|
|
||||||
if (shortcut == rpc::v1::LedgerSpecifier::SHORTCUT_UNSPECIFIED ||
|
|
||||||
shortcut == rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT)
|
|
||||||
{
|
{
|
||||||
ledger = ledgerMaster.getCurrentLedger();
|
// note, if unspecified, defaults to current ledger
|
||||||
assert(ledger->open());
|
if (shortcut ==
|
||||||
}
|
org::xrpl::rpc::v1::LedgerSpecifier::
|
||||||
else if (shortcut == rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED)
|
SHORTCUT_UNSPECIFIED ||
|
||||||
{
|
shortcut ==
|
||||||
ledger = ledgerMaster.getClosedLedger();
|
org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CURRENT)
|
||||||
assert(!ledger->open());
|
{
|
||||||
}
|
return getLedger(ledger, LedgerShortcut::CURRENT, context);
|
||||||
|
}
|
||||||
if (ledger == nullptr)
|
else if (
|
||||||
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
shortcut ==
|
||||||
|
org::xrpl::rpc::v1::LedgerSpecifier::SHORTCUT_CLOSED)
|
||||||
if (ledger->info().seq + minSequenceGap <
|
{
|
||||||
ledgerMaster.getValidLedgerIndex())
|
return getLedger(ledger, LedgerShortcut::CLOSED, context);
|
||||||
{
|
}
|
||||||
ledger.reset();
|
|
||||||
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,7 +316,103 @@ ledgerFromRequest(
|
|||||||
template Status
|
template Status
|
||||||
ledgerFromRequest<>(
|
ledgerFromRequest<>(
|
||||||
std::shared_ptr<ReadView const>&,
|
std::shared_ptr<ReadView const>&,
|
||||||
GRPCContext<rpc::v1::GetAccountInfoRequest>&);
|
GRPCContext<org::xrpl::rpc::v1::GetAccountInfoRequest>&);
|
||||||
|
|
||||||
|
Status
|
||||||
|
getLedger(
|
||||||
|
std::shared_ptr<ReadView const>& ledger,
|
||||||
|
uint256 const& ledgerHash,
|
||||||
|
Context& context)
|
||||||
|
{
|
||||||
|
ledger = context.ledgerMaster.getLedgerByHash(ledgerHash);
|
||||||
|
if (ledger == nullptr)
|
||||||
|
return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
|
||||||
|
return Status::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Status
|
||||||
|
getLedger(T& ledger, uint32_t ledgerIndex, Context& context)
|
||||||
|
{
|
||||||
|
ledger = context.ledgerMaster.getLedgerBySeq(ledgerIndex);
|
||||||
|
if (ledger == nullptr)
|
||||||
|
{
|
||||||
|
auto cur = context.ledgerMaster.getCurrentLedger();
|
||||||
|
if (cur->info().seq == ledgerIndex)
|
||||||
|
{
|
||||||
|
ledger = cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ledger == nullptr)
|
||||||
|
return {rpcLGR_NOT_FOUND, "ledgerNotFound"};
|
||||||
|
|
||||||
|
if (ledger->info().seq > context.ledgerMaster.getValidLedgerIndex() &&
|
||||||
|
isValidatedOld(context.ledgerMaster, context.app.config().standalone()))
|
||||||
|
{
|
||||||
|
ledger.reset();
|
||||||
|
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Status
|
||||||
|
getLedger(T& ledger, LedgerShortcut shortcut, Context& context)
|
||||||
|
{
|
||||||
|
if (isValidatedOld (context.ledgerMaster, context.app.config().standalone()))
|
||||||
|
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
||||||
|
|
||||||
|
if (shortcut == LedgerShortcut::VALIDATED)
|
||||||
|
{
|
||||||
|
ledger = context.ledgerMaster.getValidatedLedger ();
|
||||||
|
if (ledger == nullptr)
|
||||||
|
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
||||||
|
|
||||||
|
assert (! ledger->open());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (shortcut == LedgerShortcut::CURRENT)
|
||||||
|
{
|
||||||
|
ledger = context.ledgerMaster.getCurrentLedger ();
|
||||||
|
assert (ledger->open());
|
||||||
|
}
|
||||||
|
else if (shortcut == LedgerShortcut::CLOSED)
|
||||||
|
{
|
||||||
|
ledger = context.ledgerMaster.getClosedLedger ();
|
||||||
|
assert (! ledger->open());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {rpcINVALID_PARAMS, "ledgerIndexMalformed"};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ledger == nullptr)
|
||||||
|
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
||||||
|
|
||||||
|
static auto const minSequenceGap = 10;
|
||||||
|
|
||||||
|
if (ledger->info().seq + minSequenceGap <
|
||||||
|
context.ledgerMaster.getValidLedgerIndex ())
|
||||||
|
{
|
||||||
|
ledger.reset ();
|
||||||
|
return {rpcNO_NETWORK, "InsufficientNetworkMode"};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Status::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Explicit instantiaion of above three functions
|
||||||
|
template Status
|
||||||
|
getLedger<>(std::shared_ptr<ReadView const>&,
|
||||||
|
uint32_t, Context&);
|
||||||
|
|
||||||
|
template Status
|
||||||
|
getLedger<>(std::shared_ptr<ReadView const>&,
|
||||||
|
LedgerShortcut shortcut, Context&);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
isValidated(LedgerMaster& ledgerMaster, ReadView const& ledger,
|
isValidated(LedgerMaster& ledgerMaster, ReadView const& ledger,
|
||||||
@@ -823,672 +838,6 @@ chooseLedgerEntryType(Json::Value const& params)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
populateAccountRoot(rpc::v1::AccountRoot& proto, STObject const& obj)
|
|
||||||
{
|
|
||||||
if (obj.isFieldPresent(sfAccount))
|
|
||||||
{
|
|
||||||
AccountID account = obj.getAccountID(sfAccount);
|
|
||||||
proto.mutable_account()->set_address(toBase58(account));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfBalance))
|
|
||||||
{
|
|
||||||
STAmount amount = obj.getFieldAmount(sfBalance);
|
|
||||||
proto.mutable_balance()->set_drops(amount.xrp().drops());
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfSequence))
|
|
||||||
{
|
|
||||||
proto.set_sequence(obj.getFieldU32(sfSequence));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfFlags))
|
|
||||||
{
|
|
||||||
proto.set_flags(obj.getFieldU32(sfFlags));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfOwnerCount))
|
|
||||||
{
|
|
||||||
proto.set_owner_count(obj.getFieldU32(sfOwnerCount));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfPreviousTxnID))
|
|
||||||
{
|
|
||||||
auto field = obj.getFieldH256(sfPreviousTxnID);
|
|
||||||
proto.set_previous_transaction_id(field.data(), field.size());
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfPreviousTxnLgrSeq))
|
|
||||||
{
|
|
||||||
proto.set_previous_transaction_ledger_sequence(
|
|
||||||
obj.getFieldU32(sfPreviousTxnLgrSeq));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfAccountTxnID))
|
|
||||||
{
|
|
||||||
auto field = obj.getFieldH256(sfAccountTxnID);
|
|
||||||
proto.set_account_transaction_id(field.data(), field.size());
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfDomain))
|
|
||||||
{
|
|
||||||
auto field = obj.getFieldH256(sfDomain);
|
|
||||||
proto.set_domain(field.data(), field.size());
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfEmailHash))
|
|
||||||
{
|
|
||||||
auto field = obj.getFieldH128(sfEmailHash);
|
|
||||||
proto.set_email_hash(field.data(), field.size());
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfMessageKey))
|
|
||||||
{
|
|
||||||
auto field = obj.getFieldVL(sfMessageKey);
|
|
||||||
proto.set_message_key(field.data(), field.size());
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfRegularKey))
|
|
||||||
{
|
|
||||||
proto.set_regular_key(toBase58(obj.getAccountID(sfRegularKey)));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfTickSize))
|
|
||||||
{
|
|
||||||
proto.set_tick_size(obj.getFieldU8(sfTickSize));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfTransferRate))
|
|
||||||
{
|
|
||||||
proto.set_transfer_rate(obj.getFieldU32(sfTransferRate));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
populateRippleState(rpc::v1::RippleState& proto, STObject const& obj)
|
|
||||||
{
|
|
||||||
if (obj.isFieldPresent(sfBalance))
|
|
||||||
{
|
|
||||||
STAmount amount = obj.getFieldAmount(sfBalance);
|
|
||||||
populateAmount(*proto.mutable_balance(), amount);
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfFlags))
|
|
||||||
{
|
|
||||||
proto.set_flags(obj.getFieldU32(sfFlags));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfLowLimit))
|
|
||||||
{
|
|
||||||
STAmount amount = obj.getFieldAmount(sfLowLimit);
|
|
||||||
populateAmount(*proto.mutable_low_limit(), amount);
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfHighLimit))
|
|
||||||
{
|
|
||||||
STAmount amount = obj.getFieldAmount(sfHighLimit);
|
|
||||||
populateAmount(*proto.mutable_high_limit(), amount);
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfLowNode))
|
|
||||||
{
|
|
||||||
proto.set_low_node(obj.getFieldU64(sfLowNode));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfHighNode))
|
|
||||||
{
|
|
||||||
proto.set_high_node(obj.getFieldU64(sfHighNode));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfLowQualityIn))
|
|
||||||
{
|
|
||||||
proto.set_low_quality_in(obj.getFieldU32(sfLowQualityIn));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfLowQualityOut))
|
|
||||||
{
|
|
||||||
proto.set_low_quality_out(obj.getFieldU32(sfLowQualityOut));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfHighQualityIn))
|
|
||||||
{
|
|
||||||
proto.set_high_quality_in(obj.getFieldU32(sfHighQualityIn));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfHighQualityOut))
|
|
||||||
{
|
|
||||||
proto.set_high_quality_out(obj.getFieldU32(sfHighQualityOut));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
populateOffer(rpc::v1::Offer& proto, STObject const& obj)
|
|
||||||
{
|
|
||||||
if (obj.isFieldPresent(sfAccount))
|
|
||||||
{
|
|
||||||
AccountID account = obj.getAccountID(sfAccount);
|
|
||||||
proto.set_account(toBase58(account));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfSequence))
|
|
||||||
{
|
|
||||||
proto.set_sequence(obj.getFieldU32(sfSequence));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfFlags))
|
|
||||||
{
|
|
||||||
proto.set_flags(obj.getFieldU32(sfFlags));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfTakerPays))
|
|
||||||
{
|
|
||||||
STAmount amount = obj.getFieldAmount(sfTakerPays);
|
|
||||||
populateAmount(*proto.mutable_taker_pays(), amount);
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfTakerGets))
|
|
||||||
{
|
|
||||||
STAmount amount = obj.getFieldAmount(sfTakerGets);
|
|
||||||
populateAmount(*proto.mutable_taker_gets(), amount);
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfBookDirectory))
|
|
||||||
{
|
|
||||||
auto field = obj.getFieldVL(sfBookDirectory);
|
|
||||||
proto.set_book_directory(field.data(), field.size());
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfBookNode))
|
|
||||||
{
|
|
||||||
proto.set_book_node(obj.getFieldU64(sfBookNode));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfExpiration))
|
|
||||||
{
|
|
||||||
proto.set_expiration(obj.getFieldU32(sfExpiration));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
populateSignerList(rpc::v1::SignerList& proto, STObject const& obj)
|
|
||||||
{
|
|
||||||
proto.set_flags(obj.getFieldU32(sfFlags));
|
|
||||||
|
|
||||||
auto prevTxnID = obj.getFieldH256(sfPreviousTxnID);
|
|
||||||
proto.set_previous_txn_id(prevTxnID.data(), prevTxnID.size());
|
|
||||||
|
|
||||||
proto.set_previous_transaction_ledger_sequence(
|
|
||||||
obj.getFieldU32(sfPreviousTxnLgrSeq));
|
|
||||||
|
|
||||||
proto.set_owner_node(obj.getFieldU64(sfOwnerNode));
|
|
||||||
|
|
||||||
proto.set_signer_list_id(obj.getFieldU32(sfSignerListID));
|
|
||||||
|
|
||||||
proto.set_signer_quorum(obj.getFieldU32(sfSignerQuorum));
|
|
||||||
|
|
||||||
STArray const& signerEntries = obj.getFieldArray(sfSignerEntries);
|
|
||||||
|
|
||||||
for (auto it = signerEntries.begin(); it != signerEntries.end(); ++it)
|
|
||||||
{
|
|
||||||
rpc::v1::SignerEntry& signerEntryProto = *proto.add_signer_entries();
|
|
||||||
|
|
||||||
signerEntryProto.mutable_account()->set_address(
|
|
||||||
toBase58(it->getAccountID(sfAccount)));
|
|
||||||
signerEntryProto.set_signer_weight(it->getFieldU16(sfSignerWeight));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
populateQueueData(
|
|
||||||
rpc::v1::QueueData& proto,
|
|
||||||
std::map<TxSeq, TxQ::AccountTxDetails const> const& txs)
|
|
||||||
{
|
|
||||||
if (!txs.empty())
|
|
||||||
{
|
|
||||||
proto.set_txn_count(txs.size());
|
|
||||||
proto.set_lowest_sequence(txs.begin()->first);
|
|
||||||
proto.set_highest_sequence(txs.rbegin()->first);
|
|
||||||
|
|
||||||
boost::optional<bool> anyAuthChanged(false);
|
|
||||||
boost::optional<XRPAmount> totalSpend(0);
|
|
||||||
|
|
||||||
for (auto const& [txSeq, txDetails] : txs)
|
|
||||||
{
|
|
||||||
rpc::v1::QueuedTransaction& qt = *proto.add_transactions();
|
|
||||||
|
|
||||||
qt.set_sequence(txSeq);
|
|
||||||
qt.set_fee_level(txDetails.feeLevel.fee());
|
|
||||||
if (txDetails.lastValid)
|
|
||||||
qt.set_last_ledger_sequence(*txDetails.lastValid);
|
|
||||||
|
|
||||||
if (txDetails.consequences)
|
|
||||||
{
|
|
||||||
qt.mutable_fee()->set_drops(
|
|
||||||
txDetails.consequences->fee.drops());
|
|
||||||
auto spend = txDetails.consequences->potentialSpend +
|
|
||||||
txDetails.consequences->fee;
|
|
||||||
qt.mutable_max_spend_drops()->set_drops(spend.drops());
|
|
||||||
if (totalSpend)
|
|
||||||
*totalSpend += spend;
|
|
||||||
auto authChanged =
|
|
||||||
txDetails.consequences->category == TxConsequences::blocker;
|
|
||||||
if (authChanged)
|
|
||||||
anyAuthChanged.emplace(authChanged);
|
|
||||||
qt.set_auth_change(authChanged);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (anyAuthChanged && !*anyAuthChanged)
|
|
||||||
anyAuthChanged.reset();
|
|
||||||
totalSpend.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (anyAuthChanged)
|
|
||||||
proto.set_auth_change_queued(*anyAuthChanged);
|
|
||||||
if (totalSpend)
|
|
||||||
proto.mutable_max_spend_drops_total()->set_drops(
|
|
||||||
(*totalSpend).drops());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
populateDirectoryNode(rpc::v1::DirectoryNode& proto, STObject const& obj)
|
|
||||||
{
|
|
||||||
if (obj.isFieldPresent(sfOwner))
|
|
||||||
{
|
|
||||||
AccountID ownerAccount = obj.getAccountID(sfAccount);
|
|
||||||
proto.set_owner(toBase58(ownerAccount));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfTakerPaysCurrency))
|
|
||||||
{
|
|
||||||
uint160 tpCurr = obj.getFieldH160(sfTakerPaysCurrency);
|
|
||||||
proto.mutable_taker_pays_currency()->set_code(
|
|
||||||
tpCurr.data(), tpCurr.size());
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfTakerPaysIssuer))
|
|
||||||
{
|
|
||||||
uint160 tpIss = obj.getFieldH160(sfTakerPaysIssuer);
|
|
||||||
proto.set_taker_pays_issuer(tpIss.data(), tpIss.size());
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfTakerGetsCurrency))
|
|
||||||
{
|
|
||||||
uint160 tgCurr = obj.getFieldH160(sfTakerGetsCurrency);
|
|
||||||
proto.mutable_taker_gets_currency()->set_code(
|
|
||||||
tgCurr.data(), tgCurr.size());
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfTakerGetsIssuer))
|
|
||||||
{
|
|
||||||
uint160 tgIss = obj.getFieldH160(sfTakerGetsIssuer);
|
|
||||||
proto.set_taker_gets_issuer(tgIss.data(), tgIss.size());
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfIndexes))
|
|
||||||
{
|
|
||||||
const STVector256& vec = obj.getFieldV256(sfIndexes);
|
|
||||||
for (size_t i = 0; i < vec.size(); ++i)
|
|
||||||
{
|
|
||||||
uint256 const& elt = vec[i];
|
|
||||||
proto.add_indexes(elt.data(), elt.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfRootIndex))
|
|
||||||
{
|
|
||||||
uint256 rootIndex = obj.getFieldH256(sfRootIndex);
|
|
||||||
proto.set_root_index(rootIndex.data(), rootIndex.size());
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfIndexNext))
|
|
||||||
{
|
|
||||||
proto.set_index_next(obj.getFieldU64(sfIndexNext));
|
|
||||||
}
|
|
||||||
if (obj.isFieldPresent(sfIndexPrevious))
|
|
||||||
{
|
|
||||||
proto.set_index_previous(obj.getFieldU64(sfIndexPrevious));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
populateLedgerEntryType(rpc::v1::AffectedNode& proto, std::uint16_t lgrType)
|
|
||||||
{
|
|
||||||
switch (lgrType)
|
|
||||||
{
|
|
||||||
case ltACCOUNT_ROOT:
|
|
||||||
proto.set_ledger_entry_type(
|
|
||||||
rpc::v1::LEDGER_ENTRY_TYPE_ACCOUNT_ROOT);
|
|
||||||
break;
|
|
||||||
case ltDIR_NODE:
|
|
||||||
proto.set_ledger_entry_type(
|
|
||||||
rpc::v1::LEDGER_ENTRY_TYPE_DIRECTORY_NODE);
|
|
||||||
break;
|
|
||||||
case ltRIPPLE_STATE:
|
|
||||||
proto.set_ledger_entry_type(
|
|
||||||
rpc::v1::LEDGER_ENTRY_TYPE_RIPPLE_STATE);
|
|
||||||
break;
|
|
||||||
case ltSIGNER_LIST:
|
|
||||||
proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_SIGNER_LIST);
|
|
||||||
break;
|
|
||||||
case ltOFFER:
|
|
||||||
proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_OFFER);
|
|
||||||
break;
|
|
||||||
case ltLEDGER_HASHES:
|
|
||||||
proto.set_ledger_entry_type(
|
|
||||||
rpc::v1::LEDGER_ENTRY_TYPE_LEDGER_HASHES);
|
|
||||||
break;
|
|
||||||
case ltAMENDMENTS:
|
|
||||||
proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_AMENDMENTS);
|
|
||||||
break;
|
|
||||||
case ltFEE_SETTINGS:
|
|
||||||
proto.set_ledger_entry_type(
|
|
||||||
rpc::v1::LEDGER_ENTRY_TYPE_FEE_SETTINGS);
|
|
||||||
break;
|
|
||||||
case ltESCROW:
|
|
||||||
proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_ESCROW);
|
|
||||||
break;
|
|
||||||
case ltPAYCHAN:
|
|
||||||
proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_PAY_CHANNEL);
|
|
||||||
break;
|
|
||||||
case ltCHECK:
|
|
||||||
proto.set_ledger_entry_type(rpc::v1::LEDGER_ENTRY_TYPE_CHECK);
|
|
||||||
break;
|
|
||||||
case ltDEPOSIT_PREAUTH:
|
|
||||||
proto.set_ledger_entry_type(
|
|
||||||
rpc::v1::LEDGER_ENTRY_TYPE_DEPOSIT_PREAUTH);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void
|
|
||||||
populateFields(T& proto, STObject const& obj, std::uint16_t type)
|
|
||||||
{
|
|
||||||
if (type == ltACCOUNT_ROOT)
|
|
||||||
{
|
|
||||||
RPC::populateAccountRoot(*proto.mutable_account_root(), obj);
|
|
||||||
}
|
|
||||||
else if (type == ltRIPPLE_STATE)
|
|
||||||
{
|
|
||||||
RPC::populateRippleState(*proto.mutable_ripple_state(), obj);
|
|
||||||
}
|
|
||||||
else if (type == ltOFFER)
|
|
||||||
{
|
|
||||||
RPC::populateOffer(*proto.mutable_offer(), obj);
|
|
||||||
}
|
|
||||||
else if (type == ltDIR_NODE)
|
|
||||||
{
|
|
||||||
RPC::populateDirectoryNode(*proto.mutable_directory_node(), obj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Ledger object not supported by protobuf/grpc yet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
populateMeta(rpc::v1::Meta& proto, std::shared_ptr<TxMeta> txMeta)
|
|
||||||
{
|
|
||||||
proto.set_transaction_index(txMeta->getIndex());
|
|
||||||
|
|
||||||
populateTransactionResultType(
|
|
||||||
*proto.mutable_transaction_result(), txMeta->getResultTER());
|
|
||||||
proto.mutable_transaction_result()->set_result(
|
|
||||||
transToken(txMeta->getResultTER()));
|
|
||||||
|
|
||||||
STArray& nodes = txMeta->getNodes();
|
|
||||||
for (auto it = nodes.begin(); it != nodes.end(); ++it)
|
|
||||||
{
|
|
||||||
STObject& obj = *it;
|
|
||||||
rpc::v1::AffectedNode* node = proto.add_affected_nodes();
|
|
||||||
|
|
||||||
// ledger index
|
|
||||||
uint256 ledgerIndex = obj.getFieldH256(sfLedgerIndex);
|
|
||||||
node->set_ledger_index(ledgerIndex.data(), ledgerIndex.size());
|
|
||||||
|
|
||||||
// ledger entry type
|
|
||||||
std::uint16_t lgrType = obj.getFieldU16(sfLedgerEntryType);
|
|
||||||
populateLedgerEntryType(*node, lgrType);
|
|
||||||
|
|
||||||
// modified node
|
|
||||||
if (obj.getFName() == sfModifiedNode)
|
|
||||||
{
|
|
||||||
// final fields
|
|
||||||
if (obj.isFieldPresent(sfFinalFields))
|
|
||||||
{
|
|
||||||
STObject& finalFields =
|
|
||||||
obj.getField(sfFinalFields).downcast<STObject>();
|
|
||||||
|
|
||||||
rpc::v1::LedgerObject* finalFieldsProto =
|
|
||||||
node->mutable_modified_node()->mutable_final_fields();
|
|
||||||
|
|
||||||
populateFields(*finalFieldsProto, finalFields, lgrType);
|
|
||||||
}
|
|
||||||
// previous fields
|
|
||||||
if (obj.isFieldPresent(sfPreviousFields))
|
|
||||||
{
|
|
||||||
STObject& prevFields =
|
|
||||||
obj.getField(sfPreviousFields).downcast<STObject>();
|
|
||||||
|
|
||||||
rpc::v1::LedgerObject* prevFieldsProto =
|
|
||||||
node->mutable_modified_node()->mutable_previous_fields();
|
|
||||||
|
|
||||||
populateFields(*prevFieldsProto, prevFields, lgrType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prev txn id and prev txn ledger seq
|
|
||||||
uint256 prevTxnId = obj.getFieldH256(sfPreviousTxnID);
|
|
||||||
node->mutable_modified_node()->set_previous_transaction_id(
|
|
||||||
prevTxnId.data(), prevTxnId.size());
|
|
||||||
|
|
||||||
node->mutable_modified_node()
|
|
||||||
->set_previous_transaction_ledger_sequence(
|
|
||||||
obj.getFieldU32(sfPreviousTxnLgrSeq));
|
|
||||||
}
|
|
||||||
// created node
|
|
||||||
else if (obj.getFName() == sfCreatedNode)
|
|
||||||
{
|
|
||||||
// new fields
|
|
||||||
if (obj.isFieldPresent(sfNewFields))
|
|
||||||
{
|
|
||||||
STObject& newFields =
|
|
||||||
obj.getField(sfNewFields).downcast<STObject>();
|
|
||||||
|
|
||||||
rpc::v1::LedgerObject* newFieldsProto =
|
|
||||||
node->mutable_created_node()->mutable_new_fields();
|
|
||||||
|
|
||||||
populateFields(*newFieldsProto, newFields, lgrType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// deleted node
|
|
||||||
else if (obj.getFName() == sfDeletedNode)
|
|
||||||
{
|
|
||||||
// final fields
|
|
||||||
if (obj.isFieldPresent(sfFinalFields))
|
|
||||||
{
|
|
||||||
STObject& finalFields =
|
|
||||||
obj.getField(sfFinalFields).downcast<STObject>();
|
|
||||||
|
|
||||||
rpc::v1::LedgerObject* finalFieldsProto =
|
|
||||||
node->mutable_deleted_node()->mutable_final_fields();
|
|
||||||
|
|
||||||
populateFields(*finalFieldsProto, finalFields, lgrType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
populateAmount(rpc::v1::CurrencyAmount& proto, STAmount const& amount)
|
|
||||||
{
|
|
||||||
if (amount.native())
|
|
||||||
{
|
|
||||||
proto.mutable_xrp_amount()->set_drops(amount.xrp().drops());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rpc::v1::IssuedCurrencyAmount* issued =
|
|
||||||
proto.mutable_issued_currency_amount();
|
|
||||||
Issue const& issue = amount.issue();
|
|
||||||
Currency currency = issue.currency;
|
|
||||||
issued->mutable_currency()->set_name(to_string(issue.currency));
|
|
||||||
issued->mutable_currency()->set_code(currency.data(), currency.size());
|
|
||||||
issued->set_value(to_string(amount.iou()));
|
|
||||||
issued->mutable_issuer()->set_address(toBase58(issue.account));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
populateTransaction(
|
|
||||||
rpc::v1::Transaction& proto,
|
|
||||||
std::shared_ptr<STTx const> txnSt)
|
|
||||||
{
|
|
||||||
AccountID account = txnSt->getAccountID(sfAccount);
|
|
||||||
proto.mutable_account()->set_address(toBase58(account));
|
|
||||||
|
|
||||||
STAmount amount = txnSt->getFieldAmount(sfAmount);
|
|
||||||
populateAmount(*proto.mutable_payment()->mutable_amount(), amount);
|
|
||||||
|
|
||||||
AccountID accountDest = txnSt->getAccountID(sfDestination);
|
|
||||||
proto.mutable_payment()->mutable_destination()->set_address(
|
|
||||||
toBase58(accountDest));
|
|
||||||
|
|
||||||
STAmount fee = txnSt->getFieldAmount(sfFee);
|
|
||||||
proto.mutable_fee()->set_drops(fee.xrp().drops());
|
|
||||||
|
|
||||||
proto.set_sequence(txnSt->getFieldU32(sfSequence));
|
|
||||||
|
|
||||||
Blob signingPubKey = txnSt->getFieldVL(sfSigningPubKey);
|
|
||||||
proto.set_signing_public_key(signingPubKey.data(), signingPubKey.size());
|
|
||||||
|
|
||||||
proto.set_flags(txnSt->getFieldU32(sfFlags));
|
|
||||||
|
|
||||||
proto.set_last_ledger_sequence(txnSt->getFieldU32(sfLastLedgerSequence));
|
|
||||||
|
|
||||||
Blob blob = txnSt->getFieldVL(sfTxnSignature);
|
|
||||||
proto.set_signature(blob.data(), blob.size());
|
|
||||||
|
|
||||||
if (txnSt->isFieldPresent(sfSourceTag))
|
|
||||||
{
|
|
||||||
proto.set_source_tag(txnSt->getFieldU32(sfSourceTag));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (txnSt->isFieldPresent(sfAccountTxnID))
|
|
||||||
{
|
|
||||||
auto field = txnSt->getFieldH256(sfAccountTxnID);
|
|
||||||
proto.set_account_transaction_id(field.data(), field.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (txnSt->isFieldPresent(sfMemos))
|
|
||||||
{
|
|
||||||
auto memos = txnSt->getFieldArray(sfMemos);
|
|
||||||
for (auto it = memos.begin(); it != memos.end(); ++it)
|
|
||||||
{
|
|
||||||
rpc::v1::Memo* elt = proto.add_memos();
|
|
||||||
auto memo = it->getField(sfMemo).downcast<STObject>();
|
|
||||||
if (memo.isFieldPresent(sfMemoData))
|
|
||||||
{
|
|
||||||
auto memoData = memo.getFieldVL(sfMemoData);
|
|
||||||
elt->set_memo_data(memoData.data(), memoData.size());
|
|
||||||
}
|
|
||||||
if (memo.isFieldPresent(sfMemoFormat))
|
|
||||||
{
|
|
||||||
auto memoFormat = memo.getFieldVL(sfMemoFormat);
|
|
||||||
elt->set_memo_format(memoFormat.data(), memoFormat.size());
|
|
||||||
}
|
|
||||||
if (memo.isFieldPresent(sfMemoType))
|
|
||||||
{
|
|
||||||
auto memoType = memo.getFieldVL(sfMemoType);
|
|
||||||
elt->set_memo_type(memoType.data(), memoType.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (txnSt->isFieldPresent(sfSigners))
|
|
||||||
{
|
|
||||||
auto signers = txnSt->getFieldArray(sfSigners);
|
|
||||||
|
|
||||||
for (auto it = signers.begin(); it != signers.end(); ++it)
|
|
||||||
{
|
|
||||||
rpc::v1::Signer* elt = proto.add_signers();
|
|
||||||
auto signer = it->getField(sfSigner).downcast<STObject>();
|
|
||||||
if (signer.isFieldPresent(sfAccount))
|
|
||||||
{
|
|
||||||
elt->mutable_account()->set_address(
|
|
||||||
toBase58(signer.getAccountID(sfAccount)));
|
|
||||||
}
|
|
||||||
if (signer.isFieldPresent(sfTxnSignature))
|
|
||||||
{
|
|
||||||
auto sig = signer.getFieldVL(sfTxnSignature);
|
|
||||||
elt->set_transaction_signature(sig.data(), sig.size());
|
|
||||||
}
|
|
||||||
if (signer.isFieldPresent(sfSigningPubKey))
|
|
||||||
{
|
|
||||||
auto pubKey = signer.getFieldVL(sfSigningPubKey);
|
|
||||||
elt->set_signing_public_key(pubKey.data(), pubKey.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (safe_cast<TxType>(txnSt->getFieldU16(sfTransactionType)) ==
|
|
||||||
TxType::ttPAYMENT)
|
|
||||||
{
|
|
||||||
if (txnSt->isFieldPresent(sfSendMax))
|
|
||||||
{
|
|
||||||
STAmount const& sendMax = txnSt->getFieldAmount(sfSendMax);
|
|
||||||
populateAmount(
|
|
||||||
*proto.mutable_payment()->mutable_send_max(), sendMax);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (txnSt->isFieldPresent(sfInvoiceID))
|
|
||||||
{
|
|
||||||
auto invoice = txnSt->getFieldH256(sfInvoiceID);
|
|
||||||
proto.mutable_payment()->set_invoice_id(
|
|
||||||
invoice.data(), invoice.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (txnSt->isFieldPresent(sfDestinationTag))
|
|
||||||
{
|
|
||||||
proto.mutable_payment()->set_destination_tag(
|
|
||||||
txnSt->getFieldU32(sfDestinationTag));
|
|
||||||
}
|
|
||||||
|
|
||||||
// populate path data
|
|
||||||
STPathSet const& pathset = txnSt->getFieldPathSet(sfPaths);
|
|
||||||
for (auto it = pathset.begin(); it < pathset.end(); ++it)
|
|
||||||
{
|
|
||||||
STPath const& path = *it;
|
|
||||||
|
|
||||||
rpc::v1::Path* protoPath = proto.mutable_payment()->add_paths();
|
|
||||||
|
|
||||||
for (auto it2 = path.begin(); it2 != path.end(); ++it2)
|
|
||||||
{
|
|
||||||
rpc::v1::PathElement* protoElement = protoPath->add_elements();
|
|
||||||
STPathElement const& elt = *it2;
|
|
||||||
|
|
||||||
if (elt.isOffer())
|
|
||||||
{
|
|
||||||
if (elt.hasCurrency())
|
|
||||||
{
|
|
||||||
Currency const& currency = elt.getCurrency();
|
|
||||||
protoElement->mutable_currency()->set_name(
|
|
||||||
to_string(currency));
|
|
||||||
}
|
|
||||||
if (elt.hasIssuer())
|
|
||||||
{
|
|
||||||
AccountID const& issuer = elt.getIssuerID();
|
|
||||||
protoElement->mutable_issuer()->set_address(
|
|
||||||
toBase58(issuer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AccountID const& pathAccount = elt.getAccountID();
|
|
||||||
protoElement->mutable_account()->set_address(
|
|
||||||
toBase58(pathAccount));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
populateTransactionResultType(rpc::v1::TransactionResult& proto, TER result)
|
|
||||||
{
|
|
||||||
if (isTecClaim(result))
|
|
||||||
{
|
|
||||||
proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TEC);
|
|
||||||
}
|
|
||||||
if (isTefFailure(result))
|
|
||||||
{
|
|
||||||
proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TEF);
|
|
||||||
}
|
|
||||||
if (isTelLocal(result))
|
|
||||||
{
|
|
||||||
proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TEL);
|
|
||||||
}
|
|
||||||
if (isTemMalformed(result))
|
|
||||||
{
|
|
||||||
proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TEM);
|
|
||||||
}
|
|
||||||
if (isTerRetry(result))
|
|
||||||
{
|
|
||||||
proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TER);
|
|
||||||
}
|
|
||||||
if (isTesSuccess(result))
|
|
||||||
{
|
|
||||||
proto.set_result_type(rpc::v1::TransactionResult::RESULT_TYPE_TES);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
beast::SemanticVersion const firstVersion("1.0.0");
|
beast::SemanticVersion const firstVersion("1.0.0");
|
||||||
beast::SemanticVersion const goodVersion("1.0.0");
|
beast::SemanticVersion const goodVersion("1.0.0");
|
||||||
beast::SemanticVersion const lastVersion("1.0.0");
|
beast::SemanticVersion const lastVersion("1.0.0");
|
||||||
|
|||||||
@@ -29,9 +29,9 @@
|
|||||||
#include <ripple/rpc/Status.h>
|
#include <ripple/rpc/Status.h>
|
||||||
#include <ripple/app/misc/NetworkOPs.h>
|
#include <ripple/app/misc/NetworkOPs.h>
|
||||||
#include <ripple/app/misc/TxQ.h>
|
#include <ripple/app/misc/TxQ.h>
|
||||||
#include <rpc/v1/xrp_ledger.pb.h>
|
#include <org/xrpl/rpc/v1/xrp_ledger.pb.h>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <rpc/v1/xrp_ledger.pb.h>
|
#include <org/xrpl/rpc/v1/xrp_ledger.pb.h>
|
||||||
|
|
||||||
namespace Json {
|
namespace Json {
|
||||||
class Value;
|
class Value;
|
||||||
@@ -82,6 +82,37 @@ getAccountObjects (ReadView const& ledger, AccountID const& account,
|
|||||||
boost::optional<std::vector<LedgerEntryType>> const& typeFilter, uint256 dirIndex,
|
boost::optional<std::vector<LedgerEntryType>> const& typeFilter, uint256 dirIndex,
|
||||||
uint256 const& entryIndex, std::uint32_t const limit, Json::Value& jvResult);
|
uint256 const& entryIndex, std::uint32_t const limit, Json::Value& jvResult);
|
||||||
|
|
||||||
|
/** Get ledger by hash
|
||||||
|
If there is no error in the return value, the ledger pointer will have
|
||||||
|
been filled
|
||||||
|
*/
|
||||||
|
Status
|
||||||
|
getLedger(std::shared_ptr<ReadView const>& ledger, uint256 const & ledgerHash, Context& context);
|
||||||
|
|
||||||
|
|
||||||
|
/** Get ledger by sequence
|
||||||
|
If there is no error in the return value, the ledger pointer will have
|
||||||
|
been filled
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
Status
|
||||||
|
getLedger(T& ledger, uint32_t ledgerIndex, Context& context);
|
||||||
|
|
||||||
|
enum LedgerShortcut
|
||||||
|
{
|
||||||
|
CURRENT,
|
||||||
|
CLOSED,
|
||||||
|
VALIDATED
|
||||||
|
};
|
||||||
|
/** Get ledger specified in shortcut.
|
||||||
|
If there is no error in the return value, the ledger pointer will have
|
||||||
|
been filled
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
Status
|
||||||
|
getLedger(T& ledger, LedgerShortcut shortcut, Context& context);
|
||||||
|
|
||||||
|
|
||||||
/** Look up a ledger from a request and fill a Json::Result with either
|
/** Look up a ledger from a request and fill a Json::Result with either
|
||||||
an error, or data representing a ledger.
|
an error, or data representing a ledger.
|
||||||
|
|
||||||
@@ -103,7 +134,7 @@ template <class T>
|
|||||||
Status
|
Status
|
||||||
ledgerFromRequest(
|
ledgerFromRequest(
|
||||||
T& ledger,
|
T& ledger,
|
||||||
GRPCContext<rpc::v1::GetAccountInfoRequest>& context);
|
GRPCContext<org::xrpl::rpc::v1::GetAccountInfoRequest>& context);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
isValidated(LedgerMaster& ledgerMaster, ReadView const& ledger,
|
isValidated(LedgerMaster& ledgerMaster, ReadView const& ledger,
|
||||||
@@ -204,45 +235,6 @@ std::pair<RPC::Status, LedgerEntryType>
|
|||||||
*/
|
*/
|
||||||
unsigned int getAPIVersionNumber(const Json::Value & value);
|
unsigned int getAPIVersionNumber(const Json::Value & value);
|
||||||
|
|
||||||
/*
|
|
||||||
* For all of the below populate* functions, the proto argument is an
|
|
||||||
* output parameter, and is populated with the data stored in the
|
|
||||||
* serialized object
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
populateAccountRoot(rpc::v1::AccountRoot& proto, STObject const& obj);
|
|
||||||
|
|
||||||
void
|
|
||||||
populateRippleState(rpc::v1::RippleState& proto, STObject const& obj);
|
|
||||||
|
|
||||||
void
|
|
||||||
populateOffer(rpc::v1::Offer& proto, STObject const& obj);
|
|
||||||
|
|
||||||
void
|
|
||||||
populateSignerList(rpc::v1::SignerList& proto, STObject const& obj);
|
|
||||||
|
|
||||||
void
|
|
||||||
populateQueueData(
|
|
||||||
rpc::v1::QueueData& proto,
|
|
||||||
std::map<TxSeq, TxQ::AccountTxDetails const> const& txs);
|
|
||||||
|
|
||||||
void
|
|
||||||
populateDirectoryNode(rpc::v1::DirectoryNode& proto, STObject const& obj);
|
|
||||||
|
|
||||||
void
|
|
||||||
populateMeta(rpc::v1::Meta& proto, std::shared_ptr<TxMeta> txMeta);
|
|
||||||
|
|
||||||
void
|
|
||||||
populateTransaction(
|
|
||||||
rpc::v1::Transaction& proto,
|
|
||||||
std::shared_ptr<STTx const> txnSt);
|
|
||||||
|
|
||||||
void
|
|
||||||
populateAmount(rpc::v1::CurrencyAmount& proto, STAmount const& amount);
|
|
||||||
|
|
||||||
void
|
|
||||||
populateTransactionResultType(rpc::v1::TransactionResult& proto, TER result);
|
|
||||||
|
|
||||||
} // RPC
|
} // RPC
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|
||||||
|
|||||||
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 jtx
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <ripple/json/to_string.h>
|
#include <ripple/json/to_string.h>
|
||||||
#include <test/jtx/Account.h>
|
#include <test/jtx/Account.h>
|
||||||
|
#include <test/jtx/account_txn_id.h>
|
||||||
#include <test/jtx/acctdelete.h>
|
#include <test/jtx/acctdelete.h>
|
||||||
#include <test/jtx/amount.h>
|
#include <test/jtx/amount.h>
|
||||||
#include <test/jtx/balance.h>
|
#include <test/jtx/balance.h>
|
||||||
@@ -34,8 +35,10 @@
|
|||||||
#include <test/jtx/Env_ss.h>
|
#include <test/jtx/Env_ss.h>
|
||||||
#include <test/jtx/fee.h>
|
#include <test/jtx/fee.h>
|
||||||
#include <test/jtx/flags.h>
|
#include <test/jtx/flags.h>
|
||||||
|
#include <test/jtx/invoice_id.h>
|
||||||
#include <test/jtx/jtx_json.h>
|
#include <test/jtx/jtx_json.h>
|
||||||
#include <test/jtx/JTx.h>
|
#include <test/jtx/JTx.h>
|
||||||
|
#include <test/jtx/last_ledger_sequence.h>
|
||||||
#include <test/jtx/memo.h>
|
#include <test/jtx/memo.h>
|
||||||
#include <test/jtx/multisign.h>
|
#include <test/jtx/multisign.h>
|
||||||
#include <test/jtx/noop.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
|
class GetAccountInfoClient : public GRPCTestClientBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
rpc::v1::GetAccountInfoRequest request;
|
org::xrpl::rpc::v1::GetAccountInfoRequest request;
|
||||||
rpc::v1::GetAccountInfoResponse reply;
|
org::xrpl::rpc::v1::GetAccountInfoResponse reply;
|
||||||
|
|
||||||
explicit GetAccountInfoClient(std::string const& port)
|
explicit GetAccountInfoClient(std::string const& port)
|
||||||
: GRPCTestClientBase(port)
|
: GRPCTestClientBase(port)
|
||||||
@@ -358,11 +358,10 @@ public:
|
|||||||
client.GetAccountInfo();
|
client.GetAccountInfo();
|
||||||
if (!BEAST_EXPECT(client.status.ok()))
|
if (!BEAST_EXPECT(client.status.ok()))
|
||||||
{
|
{
|
||||||
std::cout << client.reply.DebugString() << std::endl;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
client.reply.account_data().account().address() ==
|
client.reply.account_data().account().value().address() ==
|
||||||
alice.human());
|
alice.human());
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -374,13 +373,13 @@ public:
|
|||||||
if (!BEAST_EXPECT(client.status.ok()))
|
if (!BEAST_EXPECT(client.status.ok()))
|
||||||
return;
|
return;
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
client.reply.account_data().balance().drops() ==
|
client.reply.account_data().balance().value().xrp_amount().drops() ==
|
||||||
1000 * 1000 * 1000);
|
1000 * 1000 * 1000);
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
client.reply.account_data().account().address() ==
|
client.reply.account_data().account().value().address() ==
|
||||||
alice.human());
|
alice.human());
|
||||||
BEAST_EXPECT(
|
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);
|
BEAST_EXPECT(client.reply.queue_data().txn_count() == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -473,7 +472,7 @@ public:
|
|||||||
{
|
{
|
||||||
return;
|
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);
|
BEAST_EXPECT(client.reply.signer_list().signer_entries_size() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,16 +517,16 @@ public:
|
|||||||
{
|
{
|
||||||
return;
|
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();
|
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);
|
BEAST_EXPECT(signerList.signer_entries_size() == 8);
|
||||||
for (int i = 0; i < 8; ++i)
|
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(
|
BEAST_EXPECT(
|
||||||
accounts.erase(
|
accounts.erase(
|
||||||
signerList.signer_entries(i).account().address()) == 1);
|
signerList.signer_entries(i).account().value().address()) == 1);
|
||||||
}
|
}
|
||||||
BEAST_EXPECT(accounts.size() == 0);
|
BEAST_EXPECT(accounts.size() == 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,13 +23,13 @@
|
|||||||
#include <ripple/core/DatabaseCon.h>
|
#include <ripple/core/DatabaseCon.h>
|
||||||
#include <ripple/protocol/ErrorCodes.h>
|
#include <ripple/protocol/ErrorCodes.h>
|
||||||
#include <ripple/protocol/jss.h>
|
#include <ripple/protocol/jss.h>
|
||||||
|
#include <ripple/rpc/GRPCHandlers.h>
|
||||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||||
|
#include <test/rpc/GRPCTestClientBase.h>
|
||||||
#include <test/jtx.h>
|
#include <test/jtx.h>
|
||||||
#include <test/jtx/Env.h>
|
#include <test/jtx/Env.h>
|
||||||
#include <test/jtx/envconfig.h>
|
#include <test/jtx/envconfig.h>
|
||||||
|
|
||||||
#include <ripple/rpc/GRPCHandlers.h>
|
|
||||||
#include <test/rpc/GRPCTestClientBase.h>
|
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace test {
|
namespace test {
|
||||||
@@ -39,8 +39,8 @@ class Fee_test : public beast::unit_test::suite
|
|||||||
class GrpcFeeClient : public GRPCTestClientBase
|
class GrpcFeeClient : public GRPCTestClientBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
rpc::v1::GetFeeRequest request;
|
org::xrpl::rpc::v1::GetFeeRequest request;
|
||||||
rpc::v1::GetFeeResponse reply;
|
org::xrpl::rpc::v1::GetFeeResponse reply;
|
||||||
|
|
||||||
explicit GrpcFeeClient(std::string const& grpcPort)
|
explicit GrpcFeeClient(std::string const& grpcPort)
|
||||||
: GRPCTestClientBase(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)
|
grpcGetFee(std::string const& grpcPort)
|
||||||
{
|
{
|
||||||
GrpcFeeClient client(grpcPort);
|
GrpcFeeClient client(grpcPort);
|
||||||
client.GetFee();
|
client.GetFee();
|
||||||
return std::pair<bool, rpc::v1::GetFeeResponse>(
|
return std::pair<bool, org::xrpl::rpc::v1::GetFeeResponse>(
|
||||||
client.status.ok(), client.reply);
|
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);
|
BEAST_EXPECT(reply.max_queue_size() == *metrics.txQMaxSize);
|
||||||
|
|
||||||
// fee levels data
|
// 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.median_level() == metrics.medFeeLevel);
|
||||||
BEAST_EXPECT(levels.minimum_level() == metrics.minProcessingFeeLevel);
|
BEAST_EXPECT(levels.minimum_level() == metrics.minProcessingFeeLevel);
|
||||||
BEAST_EXPECT(levels.open_ledger_level() == metrics.openLedgerFeeLevel);
|
BEAST_EXPECT(levels.open_ledger_level() == metrics.openLedgerFeeLevel);
|
||||||
BEAST_EXPECT(levels.reference_level() == metrics.referenceFeeLevel);
|
BEAST_EXPECT(levels.reference_level() == metrics.referenceFeeLevel);
|
||||||
|
|
||||||
// fee data
|
// fee data
|
||||||
rpc::v1::Fee& drops = *reply.mutable_drops();
|
org::xrpl::rpc::v1::Fee& fee = *reply.mutable_fee();
|
||||||
auto const baseFee = view->fees().base;
|
auto const baseFee = view->fees().base;
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
drops.base_fee().drops() ==
|
fee.base_fee().drops() ==
|
||||||
toDrops(metrics.referenceFeeLevel, baseFee).second);
|
toDrops(metrics.referenceFeeLevel, baseFee).second);
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
drops.minimum_fee().drops() ==
|
fee.minimum_fee().drops() ==
|
||||||
toDrops(metrics.minProcessingFeeLevel, baseFee).second);
|
toDrops(metrics.minProcessingFeeLevel, baseFee).second);
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
drops.median_fee().drops() ==
|
fee.median_fee().drops() ==
|
||||||
toDrops(metrics.medFeeLevel, baseFee).second);
|
toDrops(metrics.medFeeLevel, baseFee).second);
|
||||||
auto openLedgerFee =
|
auto openLedgerFee =
|
||||||
toDrops(metrics.openLedgerFeeLevel - FeeLevel64{1}, baseFee)
|
toDrops(metrics.openLedgerFeeLevel - FeeLevel64{1}, baseFee)
|
||||||
.second +
|
.second +
|
||||||
1;
|
1;
|
||||||
BEAST_EXPECT(drops.open_ledger_fee().drops() == openLedgerFee.drops());
|
BEAST_EXPECT(fee.open_ledger_fee().drops() == openLedgerFee.drops());
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#ifndef RIPPLED_GRPCTESTCLIENTBASE_H
|
#ifndef RIPPLED_GRPCTESTCLIENTBASE_H
|
||||||
#define 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>
|
#include <test/jtx/envconfig.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -29,7 +29,7 @@ namespace test {
|
|||||||
struct GRPCTestClientBase
|
struct GRPCTestClientBase
|
||||||
{
|
{
|
||||||
explicit GRPCTestClientBase(std::string const& port)
|
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(
|
beast::IP::Endpoint(
|
||||||
boost::asio::ip::make_address(getEnvLocalhostAddr()),
|
boost::asio::ip::make_address(getEnvLocalhostAddr()),
|
||||||
std::stoi(port))
|
std::stoi(port))
|
||||||
@@ -40,7 +40,7 @@ struct GRPCTestClientBase
|
|||||||
|
|
||||||
grpc::Status status;
|
grpc::Status status;
|
||||||
grpc::ClientContext context;
|
grpc::ClientContext context;
|
||||||
std::unique_ptr<rpc::v1::XRPLedgerAPIService::Stub> stub_;
|
std::unique_ptr<org::xrpl::rpc::v1::XRPLedgerAPIService::Stub> stub_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ public:
|
|||||||
class SubmitClient : public GRPCTestClientBase
|
class SubmitClient : public GRPCTestClientBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
rpc::v1::SubmitTransactionRequest request;
|
org::xrpl::rpc::v1::SubmitTransactionRequest request;
|
||||||
rpc::v1::SubmitTransactionResponse reply;
|
org::xrpl::rpc::v1::SubmitTransactionResponse reply;
|
||||||
|
|
||||||
explicit SubmitClient(std::string const& port)
|
explicit SubmitClient(std::string const& port)
|
||||||
: GRPCTestClientBase(port)
|
: GRPCTestClientBase(port)
|
||||||
|
|||||||
@@ -29,9 +29,12 @@
|
|||||||
#include <test/jtx/envconfig.h>
|
#include <test/jtx/envconfig.h>
|
||||||
|
|
||||||
#include <ripple/rpc/GRPCHandlers.h>
|
#include <ripple/rpc/GRPCHandlers.h>
|
||||||
|
#include <ripple/rpc/impl/GRPCHelpers.h>
|
||||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||||
#include <test/rpc/GRPCTestClientBase.h>
|
#include <test/rpc/GRPCTestClientBase.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
@@ -46,16 +49,23 @@ class Tx_test : public beast::unit_test::suite
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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 (amount.native())
|
||||||
{
|
{
|
||||||
|
if (!BEAST_EXPECT(proto_amount.has_xrp_amount()))
|
||||||
|
return;
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
proto_amount.xrp_amount().drops() == amount.xrp().drops());
|
proto_amount.xrp_amount().drops() == amount.xrp().drops());
|
||||||
}
|
}
|
||||||
else
|
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();
|
proto_amount.issued_currency_amount();
|
||||||
Issue const& issue = amount.issue();
|
Issue const& issue = amount.issue();
|
||||||
Currency currency = issue.currency;
|
Currency currency = issue.currency;
|
||||||
@@ -70,60 +80,183 @@ class Tx_test : public beast::unit_test::suite
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
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);
|
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);
|
AccountID accountDest = txnSt->getAccountID(sfDestination);
|
||||||
|
if (!BEAST_EXPECT(proto.payment().has_destination()))
|
||||||
|
return;
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
proto.payment().destination().address() == toBase58(accountDest));
|
proto.payment().destination().value().address() ==
|
||||||
|
toBase58(accountDest));
|
||||||
|
|
||||||
STAmount fee = txnSt->getFieldAmount(sfFee);
|
STAmount fee = txnSt->getFieldAmount(sfFee);
|
||||||
|
if (!BEAST_EXPECT(proto.has_fee()))
|
||||||
|
return;
|
||||||
BEAST_EXPECT(proto.fee().drops() == fee.xrp().drops());
|
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);
|
Blob signingPubKey = txnSt->getFieldVL(sfSigningPubKey);
|
||||||
BEAST_EXPECT(proto.signing_public_key() == toByteString(signingPubKey));
|
|
||||||
|
|
||||||
BEAST_EXPECT(proto.flags() == txnSt->getFieldU32(sfFlags));
|
|
||||||
|
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
proto.last_ledger_sequence() ==
|
proto.signing_public_key().value() == toByteString(signingPubKey));
|
||||||
txnSt->getFieldU32(sfLastLedgerSequence));
|
|
||||||
|
|
||||||
Blob blob = txnSt->getFieldVL(sfTxnSignature);
|
if (txnSt->isFieldPresent(sfFlags))
|
||||||
BEAST_EXPECT(proto.signature() == toByteString(blob));
|
{
|
||||||
|
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 (txnSt->isFieldPresent(sfSendMax))
|
||||||
{
|
{
|
||||||
|
if (!BEAST_EXPECT(proto.payment().has_send_max()))
|
||||||
|
return;
|
||||||
STAmount const& send_max = txnSt->getFieldAmount(sfSendMax);
|
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 (txnSt->isFieldPresent(sfAccountTxnID))
|
||||||
{
|
{
|
||||||
|
if (!BEAST_EXPECT(proto.has_account_transaction_id()))
|
||||||
|
return;
|
||||||
auto field = txnSt->getFieldH256(sfAccountTxnID);
|
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);
|
STPathSet const& pathset = txnSt->getFieldPathSet(sfPaths);
|
||||||
|
if (!BEAST_EXPECT(pathset.size() == proto.payment().paths_size()))
|
||||||
|
return;
|
||||||
|
|
||||||
int ind = 0;
|
int ind = 0;
|
||||||
for (auto it = pathset.begin(); it < pathset.end(); ++it)
|
for (auto it = pathset.begin(); it < pathset.end(); ++it)
|
||||||
{
|
{
|
||||||
STPath const& path = *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;
|
int ind2 = 0;
|
||||||
for (auto it2 = path.begin(); it2 != path.end(); ++it2)
|
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++);
|
protoPath.elements(ind2++);
|
||||||
STPathElement const& elt = *it2;
|
STPathElement const& elt = *it2;
|
||||||
|
|
||||||
@@ -132,47 +265,224 @@ class Tx_test : public beast::unit_test::suite
|
|||||||
if (elt.hasCurrency())
|
if (elt.hasCurrency())
|
||||||
{
|
{
|
||||||
Currency const& currency = elt.getCurrency();
|
Currency const& currency = elt.getCurrency();
|
||||||
BEAST_EXPECT(
|
if (BEAST_EXPECT(protoElement.has_currency()))
|
||||||
protoElement.currency().name() ==
|
{
|
||||||
to_string(currency));
|
BEAST_EXPECT(
|
||||||
|
protoElement.currency().name() ==
|
||||||
|
to_string(currency));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(!protoElement.has_currency());
|
||||||
}
|
}
|
||||||
if (elt.hasIssuer())
|
if (elt.hasIssuer())
|
||||||
{
|
{
|
||||||
AccountID const& issuer = elt.getIssuerID();
|
AccountID const& issuer = elt.getIssuerID();
|
||||||
BEAST_EXPECT(
|
if (BEAST_EXPECT(protoElement.has_issuer()))
|
||||||
protoElement.issuer().address() ==
|
{
|
||||||
toBase58(issuer));
|
BEAST_EXPECT(
|
||||||
|
protoElement.issuer().address() ==
|
||||||
|
toBase58(issuer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BEAST_EXPECT(!protoElement.has_issuer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AccountID const& path_account = elt.getAccountID();
|
if (BEAST_EXPECT(protoElement.has_account()))
|
||||||
BEAST_EXPECT(
|
{
|
||||||
protoElement.account().address() ==
|
AccountID const& path_account = elt.getAccountID();
|
||||||
toBase58(path_account));
|
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
|
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_index() == txMeta->getIndex());
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
proto.transaction_result().result() ==
|
proto.transaction_result().result() ==
|
||||||
transToken(txMeta->getResultTER()));
|
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(
|
BEAST_EXPECT(
|
||||||
proto.transaction_result().result_type() == r.result_type());
|
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
|
class GrpcTxClient : public GRPCTestClientBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
rpc::v1::GetTxRequest request;
|
org::xrpl::rpc::v1::GetTransactionRequest request;
|
||||||
rpc::v1::GetTxResponse reply;
|
org::xrpl::rpc::v1::GetTransactionResponse reply;
|
||||||
|
|
||||||
explicit GrpcTxClient(std::string const& port)
|
explicit GrpcTxClient(std::string const& port)
|
||||||
: GRPCTestClientBase(port)
|
: GRPCTestClientBase(port)
|
||||||
@@ -191,7 +501,7 @@ class Tx_test : public beast::unit_test::suite
|
|||||||
void
|
void
|
||||||
Tx()
|
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");
|
std::string grpcPort = *(*config)["port_grpc"].get<std::string>("port");
|
||||||
Env env(*this, std::move(config));
|
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) {
|
auto grpcTx = [&grpcPort](auto hash, auto binary) {
|
||||||
GrpcTxClient client(grpcPort);
|
GrpcTxClient client(grpcPort);
|
||||||
client.request.set_hash(&hash, sizeof(hash));
|
client.request.set_hash(&hash, sizeof(hash));
|
||||||
client.request.set_binary(binary);
|
client.request.set_binary(binary);
|
||||||
client.Tx();
|
client.Tx();
|
||||||
return std::pair<bool, rpc::v1::GetTxResponse>(
|
return std::pair<bool, org::xrpl::rpc::v1::GetTransactionResponse>(
|
||||||
client.status.ok(), client.reply);
|
client.status.ok(), client.reply);
|
||||||
};
|
};
|
||||||
|
|
||||||
Account A1{"A1"};
|
Account A1{"A1"};
|
||||||
Account A2{"A2"};
|
Account A2{"A2"};
|
||||||
|
Account A3{"A3"};
|
||||||
env.fund(XRP(10000), A1);
|
env.fund(XRP(10000), A1);
|
||||||
env.fund(XRP(10000), A2);
|
env.fund(XRP(10000), A2);
|
||||||
env.close();
|
env.close();
|
||||||
env.trust(A2["USD"](1000), A1);
|
env.trust(A2["USD"](1000), A1);
|
||||||
env.close();
|
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;
|
std::vector<std::shared_ptr<STTx const>> txns;
|
||||||
auto const startLegSeq = env.current()->info().seq;
|
auto const startLegSeq = env.current()->info().seq;
|
||||||
|
|
||||||
|
uint256 prevHash;
|
||||||
for (int i = 0; i < 14; ++i)
|
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)
|
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
|
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());
|
txns.emplace_back(env.tx());
|
||||||
|
prevHash = txns.back()->getTransactionID();
|
||||||
env.close();
|
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;
|
auto const endLegSeq = env.closed()->info().seq;
|
||||||
|
|
||||||
// Find the existing transactions
|
// Find the existing transactions
|
||||||
@@ -257,7 +671,7 @@ class Tx_test : public beast::unit_test::suite
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cmpTx(result.second.transaction(), tx);
|
cmpPaymentTx(result.second.transaction(), tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ledger && !b)
|
if (ledger && !b)
|
||||||
@@ -269,6 +683,11 @@ class Tx_test : public beast::unit_test::suite
|
|||||||
id, ledger->seq(), *rawMeta);
|
id, ledger->seq(), *rawMeta);
|
||||||
|
|
||||||
cmpMeta(result.second.meta(), txMeta);
|
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);
|
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:
|
public:
|
||||||
|
|||||||
Reference in New Issue
Block a user