JTx sign-and-submit mode support

This commit is contained in:
Edward Hennis
2016-06-06 20:51:41 -04:00
committed by Miguel Portilla
parent 2d53ee4051
commit 119d5c1e47
7 changed files with 231 additions and 8 deletions

View File

@@ -3531,6 +3531,8 @@
</ClInclude>
<ClInclude Include="..\..\src\ripple\test\jtx\Env.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\test\jtx\Env_ss.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\test\jtx\fee.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\test\jtx\flags.h">

View File

@@ -4005,6 +4005,9 @@
<ClInclude Include="..\..\src\ripple\test\jtx\Env.h">
<Filter>ripple\test\jtx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\test\jtx\Env_ss.h">
<Filter>ripple\test\jtx</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\test\jtx\fee.h">
<Filter>ripple\test\jtx</Filter>
</ClInclude>

View File

@@ -28,6 +28,7 @@
#include <ripple/test/jtx/balance.h>
#include <ripple/test/jtx/delivermin.h>
#include <ripple/test/jtx/Env.h>
#include <ripple/test/jtx/Env_ss.h>
#include <ripple/test/jtx/fee.h>
#include <ripple/test/jtx/flags.h>
#include <ripple/test/jtx/jtx_json.h>

View File

@@ -381,6 +381,12 @@ public:
jtx::required(args...)(*this);
}
/** Gets the TER result and `didApply` flag from a RPC Json result object.
*/
static
std::pair<TER, bool>
parseResult(Json::Value const& jr);
/** Submit an existing JTx.
This calls postconditions.
*/
@@ -388,6 +394,12 @@ public:
void
submit (JTx const& jt);
/** Use the submit RPC command with a provided JTx object.
This calls postconditions.
*/
void
sign_and_submit(JTx const& jt, Json::Value params = Json::nullValue);
/** Check expected postconditions
of JTx submission.
*/
@@ -407,8 +419,7 @@ public:
template <class JsonValue,
class... FN>
void
operator()(JsonValue&& jv,
FN const&... fN)
operator()(JsonValue&& jv, FN const&... fN)
{
apply(std::forward<
JsonValue>(jv), fN...);
@@ -433,6 +444,20 @@ public:
std::shared_ptr<STObject const>
meta();
/** Return the tx data for the last JTx.
Effects:
The tx data for the last transaction
ID, if any, is returned. No side
effects.
@note Only necessary for JTx submitted
with via sign-and-submit method.
*/
std::shared_ptr<STTx const>
tx() const;
private:
void
fund (bool setDefaultRipple,

View File

@@ -0,0 +1,86 @@
//------------------------------------------------------------------------------
/*
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_ENV_SS_H_INCLUDED
#define RIPPLE_TEST_JTX_ENV_SS_H_INCLUDED
#include <ripple/test/jtx/Env.h>
namespace ripple {
namespace test {
namespace jtx {
/** A transaction testing environment wrapper.
Transactions submitted in sign-and-submit mode
by default.
*/
class Env_ss
{
private:
Env& env_;
private:
class SignSubmitRunner
{
public:
SignSubmitRunner(SignSubmitRunner&&) = default;
SignSubmitRunner& operator= (SignSubmitRunner&&) = delete;
SignSubmitRunner(Env& env, JTx&& jt)
: env_(env)
, jt_(jt)
{
}
void operator()(Json::Value const& params = Json::nullValue)
{
env_.sign_and_submit(jt_, params);
}
private:
Env& env_;
JTx const jt_;
};
public:
Env_ss (Env_ss const&) = delete;
Env_ss& operator= (Env_ss const&) = delete;
Env_ss (Env& env)
: env_(env)
{
}
template <class JsonValue,
class... FN>
SignSubmitRunner
operator()(JsonValue&& jv, FN const&... fN)
{
auto jtx = env_.jt(std::forward<
JsonValue>(jv), fN...);
return SignSubmitRunner(env_, std::move(jtx));
}
};
} // jtx
} // test
} // ripple
#endif

View File

@@ -345,6 +345,20 @@ Env::trust (STAmount const& amount,
test.expect(balance(account) == start);
}
std::pair<TER, bool>
Env::parseResult(Json::Value const& jr)
{
TER ter;
if (jr.isObject() && jr.isMember(jss::result) &&
jr[jss::result].isMember(jss::engine_result_code))
ter = static_cast<TER>(
jr[jss::result][jss::engine_result_code].asInt());
else
ter = temINVALID;
return std::make_pair(ter,
isTesSuccess(ter) || isTecClaim(ter));
}
void
Env::submit (JTx const& jt)
{
@@ -355,12 +369,8 @@ Env::submit (JTx const& jt)
Serializer s;
jt.stx->add(s);
auto const jr = rpc("submit", strHex(s.slice()));
if (jr["result"].isMember("engine_result_code"))
ter_ = static_cast<TER>(
jr["result"]["engine_result_code"].asInt());
else
ter_ = temINVALID;
didApply = isTesSuccess(ter_) || isTecClaim(ter_);
std::tie(ter_, didApply) = parseResult(jr);
}
else
{
@@ -372,6 +382,46 @@ Env::submit (JTx const& jt)
return postconditions(jt, ter_, didApply);
}
void
Env::sign_and_submit(JTx const& jt, Json::Value params)
{
bool didApply;
auto const account =
lookup(jt.jv[jss::Account].asString());
auto const& passphrase = account.name();
Json::Value jr;
if (params.isNull())
{
// Use the command line interface
auto const jv = boost::lexical_cast<std::string>(jt.jv);
jr = rpc("submit", passphrase, jv);
}
else
{
// Use the provided parameters, and go straight
// to the (RPC) client.
assert(params.isObject());
if (!params.isMember(jss::secret) &&
!params.isMember(jss::key_type) &&
!params.isMember(jss::seed) &&
!params.isMember(jss::seed_hex) &&
!params.isMember(jss::passphrase))
{
params[jss::secret] = passphrase;
}
params[jss::tx_json] = jt.jv;
jr = client().invoke("submit", params);
}
txid_.SetHex(
jr[jss::result][jss::tx_json][jss::hash].asString());
std::tie(ter_, didApply) = parseResult(jr);
return postconditions(jt, ter_, didApply);
}
void
Env::postconditions(JTx const& jt, TER ter, bool didApply)
{
@@ -404,6 +454,12 @@ Env::meta()
return item.second;
}
std::shared_ptr<STTx const>
Env::tx() const
{
return current()->txRead(txid_).first;
}
void
Env::autofill_sig (JTx& jt)
{

View File

@@ -22,6 +22,7 @@
#include <ripple/test/jtx.h>
#include <ripple/json/to_string.h>
#include <ripple/protocol/Feature.h>
#include <ripple/protocol/JsonFields.h>
#include <ripple/protocol/TxFlags.h>
#include <ripple/beast/hash/uhash.h>
#include <ripple/beast/unit_test.h>
@@ -578,6 +579,54 @@ public:
env (jt);
}
void testSignAndSubmit()
{
using namespace jtx;
Env env(*this);
Env_ss envs(env);
auto const alice = Account("alice");
env.fund(XRP(10000), alice);
{
envs(noop(alice), fee(none), seq(none))();
// Make sure we get the right account back.
auto tx = env.tx();
if (expect(tx))
{
expect(tx->getAccountID(sfAccount) == alice.id());
expect(tx->getTxnType() == ttACCOUNT_SET);
}
}
{
auto params = Json::Value(Json::nullValue);
envs(noop(alice), fee(none), seq(none))(params);
// Make sure we get the right account back.
auto tx = env.tx();
if (expect(tx))
{
expect(tx->getAccountID(sfAccount) == alice.id());
expect(tx->getTxnType() == ttACCOUNT_SET);
}
}
{
auto params = Json::Value(Json::objectValue);
// Force the factor low enough to fail
params[jss::fee_mult_max] = 1;
params[jss::fee_div_max] = 2;
// RPC errors result in temINVALID
envs(noop(alice), fee(none),
seq(none), ter(temINVALID))(params);
auto tx = env.tx();
expect(!tx);
}
}
void
run()
{
@@ -598,6 +647,7 @@ public:
testClose();
testPath();
testResignSigned();
testSignAndSubmit();
}
};