mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-02 16:26:48 +00:00
Merge remote-tracking branch 'upstream/ripple/smart-escrow' into ripple/se/supported
This commit is contained in:
@@ -123,6 +123,7 @@ enum TEMcodes : TERUnderlyingType {
|
||||
temINVALID_INNER_BATCH,
|
||||
|
||||
temBAD_WASM,
|
||||
temTEMP_DISABLED,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -202,6 +202,7 @@ transResults()
|
||||
MAKE_ERROR(temBAD_TRANSFER_FEE, "Malformed: Transfer fee is outside valid range."),
|
||||
MAKE_ERROR(temINVALID_INNER_BATCH, "Malformed: Invalid inner batch transaction."),
|
||||
MAKE_ERROR(temBAD_WASM, "Malformed: Provided WASM code is invalid."),
|
||||
MAKE_ERROR(temTEMP_DISABLED, "The transaction requires logic that is currently temporarily disabled."),
|
||||
|
||||
MAKE_ERROR(terRETRY, "Retry transaction."),
|
||||
MAKE_ERROR(terFUNDS_SPENT, "DEPRECATED."),
|
||||
|
||||
@@ -32,23 +32,22 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
|
||||
// Tests whether the ledger index is >= 5
|
||||
// getLedgerSqn() >= 5}
|
||||
static auto wasmHex = ledgerSqnWasmHex;
|
||||
|
||||
{
|
||||
// featureSmartEscrow disabled
|
||||
Env env(*this, features - featureSmartEscrow);
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
XRPAmount const txnFees = env.current()->fees().base + 1000;
|
||||
auto escrowCreate = escrow::create(alice, carol, XRP(1000));
|
||||
auto const escrowCreate = escrow::create(alice, carol, XRP(1000));
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(wasmHex),
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::cancel_time(env.now() + 100s),
|
||||
fee(txnFees),
|
||||
ter(temDISABLED));
|
||||
env.close();
|
||||
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(wasmHex),
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::cancel_time(env.now() + 100s),
|
||||
escrow::data("00112233"),
|
||||
fee(txnFees),
|
||||
@@ -69,10 +68,10 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
// create escrow
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
|
||||
auto escrowCreate = escrow::create(alice, carol, XRP(500));
|
||||
auto const escrowCreate = escrow::create(alice, carol, XRP(500));
|
||||
|
||||
// 11-byte string
|
||||
std::string longWasmHex = "00112233445566778899AA";
|
||||
std::string const longWasmHex = "00112233445566778899AA";
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(longWasmHex),
|
||||
escrow::cancel_time(env.now() + 100s),
|
||||
@@ -81,6 +80,62 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
env.close();
|
||||
}
|
||||
|
||||
{
|
||||
// compute limit set to 0
|
||||
Env env(
|
||||
*this,
|
||||
envconfig([](std::unique_ptr<Config> cfg) {
|
||||
// WASM runtime disabled
|
||||
cfg->FEES.extension_compute_limit = 0;
|
||||
return cfg;
|
||||
}),
|
||||
features);
|
||||
XRPAmount const txnFees = env.current()->fees().base + 1000;
|
||||
// create escrow
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
|
||||
auto const escrowCreate = escrow::create(alice, carol, XRP(500));
|
||||
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::cancel_time(env.now() + 100s),
|
||||
escrow::comp_allowance(100),
|
||||
fee(txnFees),
|
||||
ter(temMALFORMED));
|
||||
env.close();
|
||||
}
|
||||
|
||||
{
|
||||
// size limit set to 0
|
||||
Env env(
|
||||
*this,
|
||||
envconfig([](std::unique_ptr<Config> cfg) {
|
||||
cfg->FEES.extension_size_limit = 0; // WASM upload disabled
|
||||
return cfg;
|
||||
}),
|
||||
features);
|
||||
XRPAmount const txnFees = env.current()->fees().base + 1000;
|
||||
// create escrow
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
|
||||
auto const escrowCreate = escrow::create(alice, carol, XRP(500));
|
||||
|
||||
// 2-byte string
|
||||
env(escrowCreate,
|
||||
escrow::finish_function("AA"),
|
||||
escrow::cancel_time(env.now() + 100s),
|
||||
fee(txnFees),
|
||||
ter(temTEMP_DISABLED));
|
||||
env.close();
|
||||
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::cancel_time(env.now() + 100s),
|
||||
fee(txnFees),
|
||||
ter(temTEMP_DISABLED));
|
||||
env.close();
|
||||
}
|
||||
|
||||
{
|
||||
// Data without FinishFunction
|
||||
Env env(*this, features);
|
||||
@@ -88,9 +143,9 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
// create escrow
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
|
||||
auto escrowCreate = escrow::create(alice, carol, XRP(500));
|
||||
auto const escrowCreate = escrow::create(alice, carol, XRP(500));
|
||||
|
||||
std::string longData(4, 'A');
|
||||
std::string const longData(4, 'A');
|
||||
env(escrowCreate,
|
||||
escrow::data(longData),
|
||||
escrow::finish_time(env.now() + 100s),
|
||||
@@ -106,13 +161,13 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
// create escrow
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
|
||||
auto escrowCreate = escrow::create(alice, carol, XRP(500));
|
||||
auto const escrowCreate = escrow::create(alice, carol, XRP(500));
|
||||
|
||||
// string of length maxWasmDataLength * 2 + 2
|
||||
std::string longData(maxWasmDataLength * 2 + 2, 'B');
|
||||
std::string const longData((maxWasmDataLength + 1) * 2, 'B');
|
||||
env(escrowCreate,
|
||||
escrow::data(longData),
|
||||
escrow::finish_function(wasmHex),
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::cancel_time(env.now() + 100s),
|
||||
fee(txnFees),
|
||||
ter(temMALFORMED));
|
||||
@@ -126,7 +181,7 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
return cfg;
|
||||
}),
|
||||
features);
|
||||
XRPAmount const txnFees = env.current()->fees().base * 10 + wasmHex.size() / 2 * 5;
|
||||
XRPAmount const txnFees = env.current()->fees().base * 10 + ledgerSqnWasmHex.size() / 2 * 5;
|
||||
// create escrow
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
|
||||
@@ -135,13 +190,16 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
// Success situations
|
||||
{
|
||||
// FinishFunction + CancelAfter
|
||||
env(escrowCreate, escrow::finish_function(wasmHex), escrow::cancel_time(env.now() + 20s), fee(txnFees));
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::cancel_time(env.now() + 20s),
|
||||
fee(txnFees));
|
||||
env.close();
|
||||
}
|
||||
{
|
||||
// FinishFunction + Condition + CancelAfter
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(wasmHex),
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::cancel_time(env.now() + 30s),
|
||||
escrow::condition(escrow::cb1),
|
||||
fee(txnFees));
|
||||
@@ -150,7 +208,7 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
{
|
||||
// FinishFunction + FinishAfter + CancelAfter
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(wasmHex),
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::cancel_time(env.now() + 40s),
|
||||
escrow::finish_time(env.now() + 2s),
|
||||
fee(txnFees));
|
||||
@@ -159,7 +217,7 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
{
|
||||
// FinishFunction + FinishAfter + Condition + CancelAfter
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(wasmHex),
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::cancel_time(env.now() + 50s),
|
||||
escrow::condition(escrow::cb1),
|
||||
escrow::finish_time(env.now() + 2s),
|
||||
@@ -170,13 +228,13 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
// Failure situations (i.e. all other combinations)
|
||||
{
|
||||
// only FinishFunction
|
||||
env(escrowCreate, escrow::finish_function(wasmHex), fee(txnFees), ter(temBAD_EXPIRATION));
|
||||
env(escrowCreate, escrow::finish_function(ledgerSqnWasmHex), fee(txnFees), ter(temBAD_EXPIRATION));
|
||||
env.close();
|
||||
}
|
||||
{
|
||||
// FinishFunction + FinishAfter
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(wasmHex),
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::finish_time(env.now() + 2s),
|
||||
fee(txnFees),
|
||||
ter(temBAD_EXPIRATION));
|
||||
@@ -185,7 +243,7 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
{
|
||||
// FinishFunction + Condition
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(wasmHex),
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::condition(escrow::cb1),
|
||||
fee(txnFees),
|
||||
ter(temBAD_EXPIRATION));
|
||||
@@ -194,7 +252,7 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
{
|
||||
// FinishFunction + FinishAfter + Condition
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(wasmHex),
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::condition(escrow::cb1),
|
||||
escrow::finish_time(env.now() + 2s),
|
||||
fee(txnFees),
|
||||
@@ -213,7 +271,7 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
{
|
||||
// Not enough fees
|
||||
env(escrowCreate,
|
||||
escrow::finish_function(wasmHex),
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::cancel_time(env.now() + 70s),
|
||||
fee(txnFees - 1),
|
||||
ter(telINSUF_FEE_P));
|
||||
@@ -257,13 +315,12 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
|
||||
// Tests whether the ledger index is >= 5
|
||||
// getLedgerSqn() >= 5}
|
||||
static auto wasmHex = ledgerSqnWasmHex;
|
||||
|
||||
{
|
||||
// featureSmartEscrow disabled
|
||||
Env env(*this, features - featureSmartEscrow);
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
XRPAmount const txnFees = env.current()->fees().base * 10 + wasmHex.size() / 2 * 5;
|
||||
XRPAmount const txnFees = env.current()->fees().base * 10 + ledgerSqnWasmHex.size() / 2 * 5;
|
||||
env(escrow::finish(carol, alice, 1), fee(txnFees), escrow::comp_allowance(4), ter(temDISABLED));
|
||||
env.close();
|
||||
}
|
||||
@@ -291,6 +348,56 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
ter(temBAD_LIMIT));
|
||||
}
|
||||
|
||||
{
|
||||
// WASM compute disabled
|
||||
using namespace test::jtx;
|
||||
using namespace std::chrono;
|
||||
Env env{*this, envconfig([](std::unique_ptr<Config> cfg) {
|
||||
cfg->FEES.extension_compute_limit = 0;
|
||||
return cfg;
|
||||
})};
|
||||
|
||||
Account const alice{"alice"};
|
||||
env.fund(XRP(1000), alice);
|
||||
env.close();
|
||||
|
||||
auto const seq = env.seq(alice);
|
||||
auto const keylet = keylet::escrow(alice.id(), seq);
|
||||
env(noop(alice)); // to align sequence numbers
|
||||
|
||||
// This adds the Escrow ledger object by hand, bypassing normal
|
||||
// transaction processing This is necessary because the config
|
||||
// cannot be updated in the middle of a test, and we cannot easily
|
||||
// create a Smart Escrow while the compute limit is set to 0
|
||||
env.app().openLedger().modify([&](OpenView& view, beast::Journal j) {
|
||||
auto sle = std::make_shared<SLE>(keylet);
|
||||
|
||||
sle->setAccountID(sfAccount, alice.id());
|
||||
sle->setFieldAmount(sfAmount, XRP(100));
|
||||
sle->setFieldU32(sfCancelAfter, 110);
|
||||
sle->setAccountID(sfDestination, alice.id());
|
||||
sle->setFieldVL(sfFinishFunction, strUnHex(ledgerSqnWasmHex).value());
|
||||
sle->setFieldU32(sfFlags, 0);
|
||||
sle->setFieldU64(sfOwnerNode, 0);
|
||||
uint256 tmp;
|
||||
BEAST_EXPECT(
|
||||
tmp.parseHex("F63D1A452A96C19EFD77901FB37D236C59EAA746771A6"
|
||||
"85D1BBA57A2238B9401"));
|
||||
sle->setFieldH256(sfPreviousTxnID, tmp);
|
||||
sle->setFieldU32(sfPreviousTxnLgrSeq, 4);
|
||||
sle->setFieldU32(sfSequence, seq);
|
||||
|
||||
view.rawInsert(sle);
|
||||
return true;
|
||||
});
|
||||
BEAST_EXPECT(env.le(keylet));
|
||||
|
||||
env(escrow::finish(alice, alice, seq),
|
||||
escrow::comp_allowance(1000),
|
||||
fee(env.current()->fees().base + 1000),
|
||||
ter(temTEMP_DISABLED));
|
||||
}
|
||||
|
||||
Env env(*this, features);
|
||||
|
||||
// Run past the flag ledger so that a Fee change vote occurs and
|
||||
@@ -299,13 +406,13 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
for (auto i = env.current()->seq(); i <= 257; ++i)
|
||||
env.close();
|
||||
|
||||
XRPAmount const txnFees = env.current()->fees().base * 10 + wasmHex.size() / 2 * 5;
|
||||
XRPAmount const txnFees = env.current()->fees().base * 10 + ledgerSqnWasmHex.size() / 2 * 5;
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
|
||||
// create escrow
|
||||
auto const seq = env.seq(alice);
|
||||
env(escrow::create(alice, carol, XRP(500)),
|
||||
escrow::finish_function(wasmHex),
|
||||
escrow::finish_function(ledgerSqnWasmHex),
|
||||
escrow::cancel_time(env.now() + 100s),
|
||||
fee(txnFees));
|
||||
env.close();
|
||||
@@ -778,7 +885,6 @@ struct EscrowSmart_test : public beast::unit_test::suite
|
||||
using namespace jtx;
|
||||
using namespace std::chrono;
|
||||
|
||||
// TODO: create wasm module for all host functions
|
||||
Account const alice{"alice"};
|
||||
Account const carol{"carol"};
|
||||
|
||||
|
||||
@@ -23,13 +23,11 @@ pushLeb128(std::vector<uint8_t>& buf, uint32_t val)
|
||||
}
|
||||
|
||||
// Helper: append bytes from a C-style array to a vector
|
||||
// Uses a loop to avoid GCC false positive -Werror=stringop-overflow with insert()
|
||||
template <std::size_t N>
|
||||
void
|
||||
appendBytes(std::vector<uint8_t>& buf, uint8_t const (&arr)[N])
|
||||
{
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
buf.push_back(arr[i]);
|
||||
buf.insert(buf.end(), &arr[0], &arr[N]);
|
||||
}
|
||||
|
||||
// Helper: append bytes from a vector to a vector
|
||||
@@ -59,6 +57,7 @@ std::vector<uint8_t>
|
||||
generateCodeBlob(uint32_t num_instructions)
|
||||
{
|
||||
std::vector<uint8_t> wasm;
|
||||
wasm.reserve(sizeof(WASM_HEADER) + sizeof(TYPE_EMPTY_FUNC) + sizeof(FUNC_TYPE0) + sizeof(EXPORT_FINISH));
|
||||
appendBytes(wasm, WASM_HEADER);
|
||||
appendBytes(wasm, TYPE_EMPTY_FUNC);
|
||||
appendBytes(wasm, FUNC_TYPE0);
|
||||
@@ -82,6 +81,7 @@ std::vector<uint8_t>
|
||||
generateDataBlob(uint32_t data_size)
|
||||
{
|
||||
std::vector<uint8_t> wasm;
|
||||
wasm.reserve(sizeof(WASM_HEADER) + sizeof(TYPE_EMPTY_FUNC) + sizeof(FUNC_TYPE0));
|
||||
appendBytes(wasm, WASM_HEADER);
|
||||
appendBytes(wasm, TYPE_EMPTY_FUNC);
|
||||
appendBytes(wasm, FUNC_TYPE0);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
namespace wasm_constants {
|
||||
|
||||
// Magic + version header
|
||||
static constexpr uint8_t WASM_HEADER[] = {
|
||||
uint8_t const WASM_HEADER[] = {
|
||||
0x00,
|
||||
0x61,
|
||||
0x73,
|
||||
@@ -22,31 +22,31 @@ static constexpr uint8_t WASM_HEADER[] = {
|
||||
};
|
||||
|
||||
// Type section: () -> ()
|
||||
static constexpr uint8_t TYPE_EMPTY_FUNC[] = {0x01, 0x04, 0x01, 0x60, 0x00, 0x00};
|
||||
uint8_t const TYPE_EMPTY_FUNC[] = {0x01, 0x04, 0x01, 0x60, 0x00, 0x00};
|
||||
|
||||
// Function section: one function using type 0
|
||||
static constexpr uint8_t FUNC_TYPE0[] = {0x03, 0x02, 0x01, 0x00};
|
||||
uint8_t const FUNC_TYPE0[] = {0x03, 0x02, 0x01, 0x00};
|
||||
|
||||
// Export section: export func 0 as "finish"
|
||||
static constexpr uint8_t EXPORT_FINISH[] = {0x07, 0x0a, 0x01, 0x06, 'f', 'i', 'n', 'i', 's', 'h', 0x00, 0x00};
|
||||
uint8_t const EXPORT_FINISH[] = {0x07, 0x0a, 0x01, 0x06, 'f', 'i', 'n', 'i', 's', 'h', 0x00, 0x00};
|
||||
|
||||
// Empty function body: 0 locals, end
|
||||
static constexpr uint8_t EMPTY_BODY[] = {0x00, 0x0b};
|
||||
uint8_t const EMPTY_BODY[] = {0x00, 0x0b};
|
||||
|
||||
// Data segment offset: i32.const 0, end
|
||||
static constexpr uint8_t DATA_OFFSET_ZERO[] = {0x41, 0x00, 0x0b};
|
||||
uint8_t const DATA_OFFSET_ZERO[] = {0x41, 0x00, 0x0b};
|
||||
|
||||
// Section IDs
|
||||
static constexpr uint8_t SECTION_MEMORY = 0x05;
|
||||
static constexpr uint8_t SECTION_CODE = 0x0a;
|
||||
static constexpr uint8_t SECTION_DATA = 0x0b;
|
||||
uint8_t const SECTION_MEMORY = 0x05;
|
||||
uint8_t const SECTION_CODE = 0x0a;
|
||||
uint8_t const SECTION_DATA = 0x0b;
|
||||
|
||||
// Instructions
|
||||
static constexpr uint8_t INSTR_NOP = 0x01;
|
||||
static constexpr uint8_t INSTR_END = 0x0b;
|
||||
uint8_t const INSTR_NOP = 0x01;
|
||||
uint8_t const INSTR_END = 0x0b;
|
||||
|
||||
// Fill byte for data section bloat
|
||||
static constexpr uint8_t DATA_FILL_BYTE = 0xEE;
|
||||
uint8_t const DATA_FILL_BYTE = 0xEE;
|
||||
|
||||
// Generator for WASM module with large code section (many NOPs)
|
||||
std::vector<uint8_t>
|
||||
|
||||
@@ -197,12 +197,32 @@ EscrowCreate::preflight(PreflightContext const& ctx)
|
||||
|
||||
if (ctx.tx.isFieldPresent(sfFinishFunction))
|
||||
{
|
||||
if (ctx.app.config().FEES.extension_size_limit == 0 || ctx.app.config().FEES.extension_compute_limit == 0)
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "WASM runtime deactivated by fee voting";
|
||||
return temTEMP_DISABLED;
|
||||
}
|
||||
|
||||
auto const code = ctx.tx.getFieldVL(sfFinishFunction);
|
||||
if (code.size() == 0 || code.size() > ctx.app.config().FEES.extension_size_limit)
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "EscrowCreate.FinishFunction bad size " << code.size();
|
||||
return temMALFORMED;
|
||||
}
|
||||
// actual validity of WASM code happens in `preflightSigValidated`
|
||||
// (after the signature is checked)
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
NotTEC
|
||||
EscrowCreate::preflightSigValidated(PreflightContext const& ctx)
|
||||
{
|
||||
if (ctx.tx.isFieldPresent(sfFinishFunction))
|
||||
{
|
||||
auto const code = ctx.tx.getFieldVL(sfFinishFunction);
|
||||
// basic checks happen in `preflight`
|
||||
|
||||
auto mock(std::make_shared<HostFunctions>(ctx.j));
|
||||
auto const re = preflightEscrowWasm(code, mock, ESCROW_FUNCTION_NAME);
|
||||
@@ -622,6 +642,27 @@ EscrowFinish::preflight(PreflightContext const& ctx)
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (auto const allowance = ctx.tx[~sfComputationAllowance]; allowance)
|
||||
{
|
||||
if (ctx.app.config().FEES.extension_compute_limit == 0)
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "WASM runtime deactivated by fee voting";
|
||||
return temTEMP_DISABLED;
|
||||
}
|
||||
if (*allowance == 0)
|
||||
{
|
||||
return temBAD_LIMIT;
|
||||
}
|
||||
if (*allowance > ctx.app.config().FEES.extension_compute_limit)
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "ComputationAllowance too large: " << *allowance;
|
||||
return temBAD_LIMIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto const err = credentials::checkFields(ctx.tx, ctx.j); !isTesSuccess(err))
|
||||
return err;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -650,22 +691,6 @@ EscrowFinish::preflightSigValidated(PreflightContext const& ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if (auto const allowance = ctx.tx[~sfComputationAllowance]; allowance)
|
||||
{
|
||||
if (*allowance == 0)
|
||||
{
|
||||
return temBAD_LIMIT;
|
||||
}
|
||||
if (*allowance > ctx.app.config().FEES.extension_compute_limit)
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "ComputationAllowance too large: " << *allowance;
|
||||
return temBAD_LIMIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto const err = credentials::checkFields(ctx.tx, ctx.j); !isTesSuccess(err))
|
||||
return err;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@ public:
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflightSigValidated(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user