diff --git a/src/ripple/app/hook/impl/HookAPI.cpp b/src/ripple/app/hook/impl/HookAPI.cpp index e8107cdfe..92e45e86a 100644 --- a/src/ripple/app/hook/impl/HookAPI.cpp +++ b/src/ripple/app/hook/impl/HookAPI.cpp @@ -3017,7 +3017,11 @@ HookAPI::get_stobject_length( if (type < 1 || type > 19 || (type >= 9 && type <= 13)) return Unexpected(pe_unknown_type_early); - bool is_vl = (type == 8 /*ACCID*/ || type == 7 || type == 18 || type == 19); + bool is_vl = + (type == SerializedTypeID::STI_ACCOUNT || + type == SerializedTypeID::STI_VL || + type == SerializedTypeID::STI_PATHSET || + type == SerializedTypeID::STI_VECTOR256); int length = -1; if (is_vl) @@ -3052,23 +3056,35 @@ HookAPI::get_stobject_length( } else if ((type >= 1 && type <= 5) || type == 16 || type == 17) { - length = - (type == 1 - ? 2 - : (type == 2 - ? 4 - : (type == 3 - ? 8 - : (type == 4 - ? 16 - : (type == 5 - ? 32 - : (type == 16 - ? 1 - : (type == 17 ? 20 - : -1))))))); + switch (type) + { + case SerializedTypeID::STI_UINT16: + length = 2; + break; + case SerializedTypeID::STI_UINT32: + length = 4; + break; + case SerializedTypeID::STI_UINT64: + length = 8; + break; + case SerializedTypeID::STI_UINT128: + length = 16; + break; + case SerializedTypeID::STI_UINT256: + length = 32; + break; + case SerializedTypeID::STI_UINT8: + length = 1; + break; + case SerializedTypeID::STI_UINT160: + length = 20; + break; + default: + length = -1; + break; + } } - else if (type == 6) /* AMOUNT */ + else if (type == SerializedTypeID::STI_AMOUNT) { length = (*upto >> 6 == 1) ? 8 : 48; if (upto >= end) @@ -3092,7 +3108,8 @@ HookAPI::get_stobject_length( return length + (upto - start); } - if (type == 15 || type == 14) /* Object / Array */ + if (type == SerializedTypeID::STI_OBJECT || + type == SerializedTypeID::STI_ARRAY) { payload_start = upto - start; diff --git a/src/test/app/HookAPI_test.cpp b/src/test/app/HookAPI_test.cpp index 621d65657..0b96ae470 100644 --- a/src/test/app/HookAPI_test.cpp +++ b/src/test/app/HookAPI_test.cpp @@ -3321,7 +3321,382 @@ public: { testcase("Test sto_emplace"); - BEAST_EXPECT(true); + using namespace jtx; + using namespace hook; + using namespace hook_api; + + auto const alice = Account{"alice"}; + Env env{*this, features}; + STTx invokeTx = STTx(ttINVOKE, [&](STObject& obj) {}); + OpenView ov{*env.current()}; + ApplyContext applyCtx = createApplyContext(env, ov, invokeTx); + auto hookCtx = + makeStubHookContext(applyCtx, alice.id(), alice.id(), {}); + hook::HookAPI api(hookCtx); + + { + // Invalid argument (wrong source_object size) + auto const small = Bytes(1, 0); + auto const large = Bytes(1024 * 16 + 1, 0); + + auto const small_result = + api.sto_emplace(small, std::nullopt, sfAccount.getCode()); + BEAST_EXPECT(!small_result.has_value()); + BEAST_EXPECT(small_result.error() == TOO_SMALL); + + auto const large_result = + api.sto_emplace(large, std::nullopt, sfAccount.getCode()); + BEAST_EXPECT(!large_result.has_value()); + BEAST_EXPECT(large_result.error() == TOO_BIG); + } + + { + // Invalid argument (wrong field_object size) + auto const source = Bytes(16, 0); + auto const small = Bytes(1, 0); + auto const large = Bytes(4096 + 1, 0); + + auto const small_result = + api.sto_emplace(source, small, sfAccount.getCode()); + BEAST_EXPECT(!small_result.has_value()); + BEAST_EXPECT(small_result.error() == TOO_SMALL); + + auto const large_result = + api.sto_emplace(source, large, sfAccount.getCode()); + BEAST_EXPECT(!large_result.has_value()); + BEAST_EXPECT(large_result.error() == TOO_BIG); + } + + { + // TODO: test parse error + } + + { + // Success + auto const source_object = + Bytes({0x81U, 0x14U, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + // Account: "" + auto const field_object = + Bytes({0x24U, 0x00U, 0x00U, 0x00U, 0x00U}); + // Sequence: 0 + + auto const result = api.sto_emplace( + source_object, field_object, sfSequence.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + BEAST_EXPECT( + result.value() == + Bytes({0x24U, 0x00U, 0x00U, 0x00U, 0x00U, 0x81U, 0x14U, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0})); + } + + auto const _source_object = + Bytes({0x81U, 0x14U, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + { + // use UINT16 + auto source_object = _source_object; + auto field_object = Bytes({0x10U, 0x10U, 0x00U, 0x01U}); + // Version: 1 + + auto const result = api.sto_emplace( + source_object, field_object, sfVersion.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + field_object.insert( + field_object.end(), source_object.begin(), source_object.end()); + BEAST_EXPECT(result.value() == field_object); + } + + { + // use UINT32 + auto source_object = _source_object; + auto field_object = Bytes({0x24U, 0x00U, 0x00U, 0x00U, 0x01U}); + // Sequence: 1 + + auto const result = api.sto_emplace( + source_object, field_object, sfSequence.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + field_object.insert( + field_object.end(), source_object.begin(), source_object.end()); + BEAST_EXPECT(result.value() == field_object); + } + + { + // use UINT64 + auto source_object = _source_object; + auto field_object = Bytes( + {0x36U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x01U}); + // ExchangeRate: 1 + + auto const result = api.sto_emplace( + source_object, field_object, sfExchangeRate.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + field_object.insert( + field_object.end(), source_object.begin(), source_object.end()); + BEAST_EXPECT(result.value() == field_object); + } + + { + // use UINT128 + auto source_object = _source_object; + auto field_object = Bytes( + {0x41U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U}); + // EmailHash: 1 + + auto const result = api.sto_emplace( + source_object, field_object, sfEmailHash.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + field_object.insert( + field_object.end(), source_object.begin(), source_object.end()); + BEAST_EXPECT(result.value() == field_object); + } + + { + // use UINT256 + auto source_object = _source_object; + auto field_object = Bytes( + {0x5EU, 0x00U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + // ObjectID: + // "0000000000000000000000000000000000000000000000000000000000000000" + + auto const result = api.sto_emplace( + source_object, field_object, sfObjectID.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + field_object.insert( + field_object.end(), source_object.begin(), source_object.end()); + BEAST_EXPECT(result.value() == field_object); + } + + { + // use AMOUNT + auto source_object = _source_object; + + auto nativeamount = Bytes( + {0x61U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, + 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, + 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, + 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, + 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, 0x99U, + 0x99U, 0x99U, 0x99U, 0x99U, 0x99U}); + auto iouamount = Bytes( + {0x61U, + 0x99U, + 0x99U, + 0x99U, + 0x99U, + 0x99U, + 0x99U, + 0x99U, + 0x99U}); + + for (auto field_object : {nativeamount, iouamount}) + { + auto const result = api.sto_emplace( + source_object, field_object, sfAmount.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + field_object.insert( + field_object.end(), + source_object.begin(), + source_object.end()); + BEAST_EXPECT(result.value() == field_object); + } + } + + { + // OBJECT + auto source_object = _source_object; + auto field_object = Bytes( + {0xE0U, + 0x5BU, + 0x61U, + 0x40U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x00U, + 0x64U, + 0xE1U}); + // {"AmountEntry": {"Amount": "100"}} + + auto const result = api.sto_emplace( + source_object, field_object, sfAmountEntry.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + source_object.insert( + source_object.end(), field_object.begin(), field_object.end()); + BEAST_EXPECT(result.value() == source_object); + } + + { + // ARRAY + auto source_object = _source_object; + auto field_object = Bytes( + {0xF9U, + 0xEAU, + 0x7DU, + 0x04U, + 0xDEU, + 0xADU, + 0xBEU, + 0xEFU, + 0xE1U, + 0xF1U}); + // {"Memos": [{"Memo":{ "MemoData": "DEADBEEF" }}]} + + auto const result = + api.sto_emplace(source_object, field_object, sfMemos.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + source_object.insert( + source_object.end(), field_object.begin(), field_object.end()); + BEAST_EXPECT(result.value() == source_object); + } + + { + // UINT8 + auto source_object = _source_object; + auto field_object = Bytes({0x00U, 0x10U, 0x10U, 0x01U}); + // {"TickSize": 1} + + auto const result = api.sto_emplace( + source_object, field_object, sfTickSize.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + source_object.insert( + source_object.end(), field_object.begin(), field_object.end()); + BEAST_EXPECT(result.value() == source_object); + } + + { + // UINT160 + auto source_object = _source_object; + auto field_object = + Bytes({0x01U, 0x11U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x55U, 0x53U, + 0x44U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U}); + // {"TakerPaysCurrency": "0000000000000000000000005553440000000000"} + + auto const result = api.sto_emplace( + source_object, field_object, sfTakerPaysCurrency.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + source_object.insert( + source_object.end(), field_object.begin(), field_object.end()); + BEAST_EXPECT(result.value() == source_object); + } + + { + // PATHSET + auto source_object = _source_object; + auto field_object = Bytes( + {0x01U, 0x12U, 0x30U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x55U, 0x53U, 0x44U, + 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x05U, 0x4FU, 0x6FU, 0x78U, + 0x4AU, 0x58U, 0xF9U, 0xEFU, 0xB0U, 0xA9U, 0xEBU, 0x90U, 0xB8U, + 0x34U, 0x64U, 0xF9U, 0xD1U, 0x66U, 0x46U, 0x19U, 0x00U}); + // {"Paths": [[{ "currency": "USD", "issuer": + // "rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc" }]]} + + auto const result = + api.sto_emplace(source_object, field_object, sfPaths.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + source_object.insert( + source_object.end(), field_object.begin(), field_object.end()); + BEAST_EXPECT(result.value() == source_object); + } + + { + // VECTOR256 + auto source_object = _source_object; + auto field_object = Bytes( + {0x03U, 0x13U, 0x20U, 0x42U, 0x42U, 0x6CU, 0x4DU, 0x4FU, 0x10U, + 0x09U, 0xEEU, 0x67U, 0x08U, 0x0AU, 0x9BU, 0x79U, 0x65U, 0xB4U, + 0x46U, 0x56U, 0xD7U, 0x71U, 0x4DU, 0x10U, 0x4AU, 0x72U, 0xF9U, + 0xB4U, 0x36U, 0x9FU, 0x97U, 0xABU, 0xF0U, 0x44U, 0xEEU}); + // {"Amendments":["42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE"]} + + auto const result = + api.sto_emplace(source_object, field_object, sfPaths.getCode()); + BEAST_EXPECT(result.has_value()); + BEAST_EXPECT( + result.value().size() == + source_object.size() + field_object.size()); + source_object.insert( + source_object.end(), field_object.begin(), field_object.end()); + BEAST_EXPECT(result.value() == source_object); + } + + { + // UINT96 + } + + { + // UINT384 + } + + { + // UINT512 + } } void