mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
PoC Smart Escrows (#5340)
* wasmedge in unittest * add WashVM.h and cpp * accountID comparison (vector<u8>) working * json decode tx and ledger object with two buffers working * wasm return a buffer working * add a failure test case to P2P3 * host function return ledger sqn * instruction gas and host function gas * basics * add scaffold * add amendment check * working PoC * get test working * fix clang-format * prototype #2 * p2p3 * [WIP] P4 * P5 * add calculateBaseFee * add FinishFunction preflight checks (+ tests) * additional reserve for sfFinishFunction * higher fees for EscrowFinish * rename amendment to SmartEscrow * make fee voting changes, add basic tests * clean up * clean up * clean up * more cleanup * add subscribe tests * add more tests * undo formatting * undo formatting * remove bad comment * more debugging statements * fix clang-format * fix rebase issues * fix more rebase issues * more rebase fixes * add source code for wasm * respond to comments * add const --------- Co-authored-by: Peng Wang <pwang200@gmail.com>
This commit is contained in:
@@ -1519,7 +1519,7 @@ struct Escrow_test : public beast::unit_test::suite
|
||||
Account const alice{"alice"};
|
||||
Account const bob{"bob"};
|
||||
Account const carol{"carol"};
|
||||
Account const dillon{"dillon "};
|
||||
Account const dillon{"dillon"};
|
||||
Account const zelda{"zelda"};
|
||||
|
||||
const char credType[] = "abcde";
|
||||
@@ -1656,6 +1656,370 @@ struct Escrow_test : public beast::unit_test::suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testFinishFunctionPreflight()
|
||||
{
|
||||
testcase("Test preflight checks involving FinishFunction");
|
||||
|
||||
using namespace jtx;
|
||||
using namespace std::chrono;
|
||||
|
||||
Account const alice{"alice"};
|
||||
Account const carol{"carol"};
|
||||
|
||||
// Tests whether the ledger index is >= 5
|
||||
// #[no_mangle]
|
||||
// pub fn ready() -> bool {
|
||||
// unsafe { host_lib::get_ledger_sqn() >= 5}
|
||||
// }
|
||||
static auto wasmHex =
|
||||
"0061736d010000000105016000017f021b0108686f73745f6c69620e6765745f6c"
|
||||
"65646765725f73716e0000030201000405017001010105030100100619037f0141"
|
||||
"8080c0000b7f00418080c0000b7f00418080c0000b072d04066d656d6f72790200"
|
||||
"05726561647900010a5f5f646174615f656e6403010b5f5f686561705f62617365"
|
||||
"03020a0d010b0010808080800041044a0b006e046e616d65000e0d7761736d5f6c"
|
||||
"69622e7761736d01430200395f5a4e387761736d5f6c696238686f73745f6c6962"
|
||||
"31346765745f6c65646765725f73716e3137686663383539386237646539633036"
|
||||
"64624501057265616479071201000f5f5f737461636b5f706f696e746572005509"
|
||||
"70726f64756365727302086c616e6775616765010452757374000c70726f636573"
|
||||
"7365642d62790105727573746325312e38332e302d6e696768746c792028633266"
|
||||
"37346333663920323032342d30392d30392900490f7461726765745f6665617475"
|
||||
"726573042b0a6d756c746976616c75652b0f6d757461626c652d676c6f62616c73"
|
||||
"2b0f7265666572656e63652d74797065732b087369676e2d657874";
|
||||
|
||||
{
|
||||
// featureSmartEscrow disabled
|
||||
Env env(*this, supported_amendments() - featureSmartEscrow);
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
XRPAmount const txnFees = env.current()->fees().base + 1000;
|
||||
auto escrowCreate = escrow(alice, carol, XRP(1000));
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
cancel_time(env.now() + 100s),
|
||||
fee(txnFees),
|
||||
ter(temDISABLED));
|
||||
env.close();
|
||||
}
|
||||
|
||||
Env env(*this);
|
||||
XRPAmount const txnFees = env.current()->fees().base + 1000;
|
||||
// create escrow
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
|
||||
auto escrowCreate = escrow(alice, carol, XRP(1000));
|
||||
|
||||
// Success situations
|
||||
{
|
||||
// FinishFunction + CancelAfter
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
cancel_time(env.now() + 100s),
|
||||
fee(txnFees));
|
||||
env.close();
|
||||
}
|
||||
{
|
||||
// FinishFunction + Condition + CancelAfter
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
cancel_time(env.now() + 100s),
|
||||
condition(cb1),
|
||||
fee(txnFees));
|
||||
env.close();
|
||||
}
|
||||
{
|
||||
// FinishFunction + FinishAfter + CancelAfter
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
cancel_time(env.now() + 100s),
|
||||
finish_time(env.now() + 2s),
|
||||
fee(txnFees));
|
||||
env.close();
|
||||
}
|
||||
{
|
||||
// FinishFunction + FinishAfter + Condition + CancelAfter
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
cancel_time(env.now() + 100s),
|
||||
condition(cb1),
|
||||
finish_time(env.now() + 2s),
|
||||
fee(txnFees));
|
||||
env.close();
|
||||
}
|
||||
|
||||
// Failure situations (i.e. all other combinations)
|
||||
{
|
||||
// only FinishFunction
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
fee(txnFees),
|
||||
ter(temBAD_EXPIRATION));
|
||||
env.close();
|
||||
}
|
||||
{
|
||||
// FinishFunction + FinishAfter
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
finish_time(env.now() + 2s),
|
||||
fee(txnFees),
|
||||
ter(temBAD_EXPIRATION));
|
||||
env.close();
|
||||
}
|
||||
{
|
||||
// FinishFunction + Condition
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
condition(cb1),
|
||||
fee(txnFees),
|
||||
ter(temBAD_EXPIRATION));
|
||||
env.close();
|
||||
}
|
||||
{
|
||||
// FinishFunction + FinishAfter + Condition
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
condition(cb1),
|
||||
finish_time(env.now() + 2s),
|
||||
fee(txnFees),
|
||||
ter(temBAD_EXPIRATION));
|
||||
env.close();
|
||||
}
|
||||
{
|
||||
// FinishFunction 0 length
|
||||
env(escrowCreate,
|
||||
finish_function(""),
|
||||
cancel_time(env.now() + 100s),
|
||||
fee(txnFees),
|
||||
ter(temMALFORMED));
|
||||
env.close();
|
||||
}
|
||||
// {
|
||||
// // FinishFunction > max length
|
||||
// std::string longWasmHex = "00";
|
||||
// // TODO: fix to use the config setting
|
||||
// // TODO: make this test more efficient
|
||||
// // uncomment when that's done
|
||||
// for (int i = 0; i < 4294967295; i++)
|
||||
// {
|
||||
// longWasmHex += "11";
|
||||
// }
|
||||
// env(escrowCreate,
|
||||
// finish_function(longWasmHex),
|
||||
// cancel_time(env.now() + 100s),
|
||||
// fee(txnFees),
|
||||
// ter(temMALFORMED));
|
||||
// env.close();
|
||||
// }
|
||||
}
|
||||
|
||||
void
|
||||
testFinishFunction()
|
||||
{
|
||||
testcase("PoC escrow function");
|
||||
|
||||
using namespace jtx;
|
||||
using namespace std::chrono;
|
||||
|
||||
Account const alice{"alice"};
|
||||
Account const carol{"carol"};
|
||||
|
||||
// Tests whether the ledger index is >= 5
|
||||
// #[no_mangle]
|
||||
// pub fn ready() -> bool {
|
||||
// unsafe { host_lib::get_ledger_sqn() >= 5}
|
||||
// }
|
||||
static auto wasmHex =
|
||||
"0061736d010000000105016000017f021b0108686f73745f6c69620e6765745f6c"
|
||||
"65646765725f73716e0000030201000405017001010105030100100619037f0141"
|
||||
"8080c0000b7f00418080c0000b7f00418080c0000b072d04066d656d6f72790200"
|
||||
"05726561647900010a5f5f646174615f656e6403010b5f5f686561705f62617365"
|
||||
"03020a0d010b0010808080800041044a0b006e046e616d65000e0d7761736d5f6c"
|
||||
"69622e7761736d01430200395f5a4e387761736d5f6c696238686f73745f6c6962"
|
||||
"31346765745f6c65646765725f73716e3137686663383539386237646539633036"
|
||||
"64624501057265616479071201000f5f5f737461636b5f706f696e746572005509"
|
||||
"70726f64756365727302086c616e6775616765010452757374000c70726f636573"
|
||||
"7365642d62790105727573746325312e38332e302d6e696768746c792028633266"
|
||||
"37346333663920323032342d30392d30392900490f7461726765745f6665617475"
|
||||
"726573042b0a6d756c746976616c75652b0f6d757461626c652d676c6f62616c73"
|
||||
"2b0f7265666572656e63652d74797065732b087369676e2d657874";
|
||||
|
||||
{
|
||||
// basic FinishFunction situation
|
||||
Env env(*this);
|
||||
// create escrow
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
auto const seq = env.seq(alice);
|
||||
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
|
||||
auto escrowCreate = escrow(alice, carol, XRP(1000));
|
||||
XRPAmount txnFees = env.current()->fees().base + 1000;
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
cancel_time(env.now() + 100s),
|
||||
fee(txnFees));
|
||||
env.close();
|
||||
|
||||
if (BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 2))
|
||||
{
|
||||
env.require(balance(alice, XRP(4000) - txnFees));
|
||||
env.require(balance(carol, XRP(5000)));
|
||||
|
||||
env(finish(carol, alice, seq),
|
||||
fee(txnFees),
|
||||
ter(tecWASM_REJECTED));
|
||||
env(finish(alice, alice, seq),
|
||||
fee(txnFees),
|
||||
ter(tecWASM_REJECTED));
|
||||
env(finish(alice, alice, seq),
|
||||
fee(txnFees),
|
||||
ter(tecWASM_REJECTED));
|
||||
env(finish(carol, alice, seq),
|
||||
fee(txnFees),
|
||||
ter(tecWASM_REJECTED));
|
||||
env(finish(carol, alice, seq),
|
||||
fee(txnFees),
|
||||
ter(tecWASM_REJECTED));
|
||||
env.close();
|
||||
env(finish(alice, alice, seq), fee(txnFees), ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// FinishFunction + Condition
|
||||
Env env(*this);
|
||||
// create escrow
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
auto const seq = env.seq(alice);
|
||||
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
|
||||
auto escrowCreate = escrow(alice, carol, XRP(1000));
|
||||
XRPAmount txnFees = env.current()->fees().base + 1000;
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
condition(cb1),
|
||||
cancel_time(env.now() + 100s),
|
||||
fee(txnFees));
|
||||
env.close();
|
||||
|
||||
if (BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 2))
|
||||
{
|
||||
env.require(balance(alice, XRP(4000) - txnFees));
|
||||
env.require(balance(carol, XRP(5000)));
|
||||
|
||||
// no fulfillment provided, function fails
|
||||
env(finish(carol, alice, seq),
|
||||
fee(txnFees),
|
||||
ter(tecCRYPTOCONDITION_ERROR));
|
||||
// fulfillment provided, function fails
|
||||
env(finish(carol, alice, seq),
|
||||
condition(cb1),
|
||||
fulfillment(fb1),
|
||||
fee(txnFees),
|
||||
ter(tecWASM_REJECTED));
|
||||
env.close();
|
||||
// no fulfillment provided, function succeeds
|
||||
env(finish(alice, alice, seq),
|
||||
fee(txnFees),
|
||||
ter(tecCRYPTOCONDITION_ERROR));
|
||||
// wrong fulfillment provided, function succeeds
|
||||
env(finish(alice, alice, seq),
|
||||
condition(cb1),
|
||||
fulfillment(fb2),
|
||||
fee(txnFees),
|
||||
ter(tecCRYPTOCONDITION_ERROR));
|
||||
// fulfillment provided, function succeeds, tx succeeds
|
||||
env(finish(alice, alice, seq),
|
||||
condition(cb1),
|
||||
fulfillment(fb1),
|
||||
fee(txnFees),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// FinishFunction + FinishAfter
|
||||
Env env(*this);
|
||||
// create escrow
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
auto const seq = env.seq(alice);
|
||||
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
|
||||
auto escrowCreate = escrow(alice, carol, XRP(1000));
|
||||
XRPAmount txnFees = env.current()->fees().base + 1000;
|
||||
auto const ts = env.now() + 97s;
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
finish_time(ts),
|
||||
cancel_time(env.now() + 1000s),
|
||||
fee(txnFees));
|
||||
env.close();
|
||||
|
||||
if (BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 2))
|
||||
{
|
||||
env.require(balance(alice, XRP(4000) - txnFees));
|
||||
env.require(balance(carol, XRP(5000)));
|
||||
|
||||
// finish time hasn't passed, function fails
|
||||
env(finish(carol, alice, seq),
|
||||
fee(txnFees + 1),
|
||||
ter(tecNO_PERMISSION));
|
||||
env.close();
|
||||
// finish time hasn't passed, function succeeds
|
||||
for (; env.now() < ts; env.close())
|
||||
env(finish(carol, alice, seq),
|
||||
fee(txnFees + 2),
|
||||
ter(tecNO_PERMISSION));
|
||||
|
||||
env(finish(carol, alice, seq),
|
||||
fee(txnFees + 1),
|
||||
ter(tesSUCCESS));
|
||||
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// FinishFunction + FinishAfter #2
|
||||
Env env(*this);
|
||||
// create escrow
|
||||
env.fund(XRP(5000), alice, carol);
|
||||
auto const seq = env.seq(alice);
|
||||
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
|
||||
auto escrowCreate = escrow(alice, carol, XRP(1000));
|
||||
XRPAmount txnFees = env.current()->fees().base + 1000;
|
||||
env(escrowCreate,
|
||||
finish_function(wasmHex),
|
||||
finish_time(env.now() + 2s),
|
||||
cancel_time(env.now() + 100s),
|
||||
fee(txnFees));
|
||||
// Don't close the ledger here
|
||||
|
||||
if (BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 2))
|
||||
{
|
||||
env.require(balance(alice, XRP(4000) - txnFees));
|
||||
env.require(balance(carol, XRP(5000)));
|
||||
|
||||
// finish time hasn't passed, function fails
|
||||
env(finish(carol, alice, seq),
|
||||
fee(txnFees),
|
||||
ter(tecNO_PERMISSION));
|
||||
env.close();
|
||||
|
||||
// finish time has passed, function fails
|
||||
env(finish(carol, alice, seq),
|
||||
fee(txnFees),
|
||||
ter(tecWASM_REJECTED));
|
||||
env.close();
|
||||
// finish time has passed, function succeeds, tx succeeds
|
||||
env(finish(carol, alice, seq), fee(txnFees), ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
BEAST_EXPECT((*env.le(alice))[sfOwnerCount] == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@@ -1671,6 +2035,8 @@ struct Escrow_test : public beast::unit_test::suite
|
||||
testConsequences();
|
||||
testEscrowWithTickets();
|
||||
testCredentials();
|
||||
testFinishFunctionPreflight();
|
||||
testFinishFunction();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user