diff --git a/src/ripple/app/hook/Enum.h b/src/ripple/app/hook/Enum.h index 25196412e..67f3d0e36 100644 --- a/src/ripple/app/hook/Enum.h +++ b/src/ripple/app/hook/Enum.h @@ -169,7 +169,9 @@ namespace hook_api EMITTED_TXN = 22, NFT_OFFER = 23, HOOK_DEFINITION = 24, - LAST_KLTYPE = HOOK_DEFINITION + HOOK_STATE_DIR = 25, + LAST_KLTYPE_V0 = HOOK_DEFINITION, + LAST_KLTYPE_V1 = HOOK_STATE_DIR, }; } @@ -324,5 +326,11 @@ namespace hook_api {"otxn_param",{0x7EU,0x7FU,0x7FU,0x7FU,0x7FU}}, {"meta_slot",{0x7EU,0x7FU}} }; + + // featureHooks1 + static const std::map> import_whitelist_1 + { + + }; }; #endif diff --git a/src/ripple/app/hook/Guard.h b/src/ripple/app/hook/Guard.h index 16af09fb0..16b11b037 100644 --- a/src/ripple/app/hook/Guard.h +++ b/src/ripple/app/hook/Guard.h @@ -759,7 +759,8 @@ std::pair< validateGuards( std::vector const& wasm, GuardLog guardLog, - std::string guardLogAccStr) + std::string guardLogAccStr, + uint64_t rulesVersion = 0) { uint64_t byteCount = wasm.size(); @@ -915,11 +916,19 @@ validateGuards( } else if (hook_api::import_whitelist.find(import_name) == hook_api::import_whitelist.end()) { - GUARDLOG(hook::log::IMPORT_ILLEGAL) - << "Malformed transaction. " - << "Hook attempted to import a function that does not " - << "appear in the hook_api function set: `" << import_name << "`" << "\n"; - return {}; + if (rulesVersion > 0 && + hook_api::import_whitelist_1.find(import_name) != hook_api::import_whitelist_1.end()) + { + // PASS, this is a version 1 api + } + else + { + GUARDLOG(hook::log::IMPORT_ILLEGAL) + << "Malformed transaction. " + << "Hook attempted to import a function that does not " + << "appear in the hook_api function set: `" << import_name << "`" << "\n"; + return {}; + } } // add to import map diff --git a/src/ripple/app/hook/guard_checker.cpp b/src/ripple/app/hook/guard_checker.cpp index 629a68bfe..66f19d2cb 100644 --- a/src/ripple/app/hook/guard_checker.cpp +++ b/src/ripple/app/hook/guard_checker.cpp @@ -76,7 +76,7 @@ int main(int argc, char** argv) close(fd); auto result = - validateGuards(hook, std::cout, ""); + validateGuards(hook, std::cout, "", 1); if (!result) { diff --git a/src/ripple/app/hook/impl/applyHook.cpp b/src/ripple/app/hook/impl/applyHook.cpp index aeb38856f..d2e51d56d 100644 --- a/src/ripple/app/hook/impl/applyHook.cpp +++ b/src/ripple/app/hook/impl/applyHook.cpp @@ -2605,7 +2605,14 @@ DEFINE_HOOK_FUNCTION( if (write_len < 34) return TOO_SMALL; - if (keylet_type < 1 || keylet_type > keylet_code::LAST_KLTYPE) + bool const v1 = applyCtx.view().rules().enabled(featureHooksUpdate1); + + if (keylet_type == 0) + return INVALID_ARGUMENT; + + auto const last = v1 ? keylet_code::LAST_KLTYPE_V1 : keylet_code::LAST_KLTYPE_V0; + + if (keylet_type > last) return INVALID_ARGUMENT; try @@ -2799,6 +2806,31 @@ DEFINE_HOOK_FUNCTION( return serialize_keylet(kl, memory, write_ptr, write_len); } + case keylet_code::HOOK_STATE_DIR: + { + if (a == 0 || b == 0 || c == 0 || d == 0) + return INVALID_ARGUMENT; + + if (e != 0 || f != 0) + return INVALID_ARGUMENT; + + uint32_t aread_ptr = a, aread_len = b, nread_ptr = c, nread_len = d; + + if (NOT_IN_BOUNDS(aread_ptr, aread_len, memory_length) || + NOT_IN_BOUNDS(nread_ptr, nread_len, memory_length)) + return OUT_OF_BOUNDS; + + if (aread_len != 20 || nread_len != 32) + return INVALID_ARGUMENT; + + ripple::Keylet kl = + ripple::keylet::hookStateDir( + AccountID::fromVoid(memory + aread_ptr), + ripple::base_uint<256>::fromVoid(memory + nread_ptr)); + + return serialize_keylet(kl, memory, write_ptr, write_len); + } + // skip is overloaded, has a single, optional 4 byte argument case keylet_code::SKIP: diff --git a/src/ripple/app/tx/impl/Change.cpp b/src/ripple/app/tx/impl/Change.cpp index 48583c55f..e24aa16a3 100644 --- a/src/ripple/app/tx/impl/Change.cpp +++ b/src/ripple/app/tx/impl/Change.cpp @@ -493,7 +493,8 @@ Change::activateXahauGenesis() validateGuards( wasmBytes, // wasm to verify loggerStream, - "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" + "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", + ctx_.view().rules().enabled(featureHooksUpdate1) ? 1 : 0 ); if (!result) diff --git a/src/ripple/app/tx/impl/SetHook.cpp b/src/ripple/app/tx/impl/SetHook.cpp index 05e19a914..63ef2691e 100644 --- a/src/ripple/app/tx/impl/SetHook.cpp +++ b/src/ripple/app/tx/impl/SetHook.cpp @@ -450,7 +450,8 @@ SetHook::validateHookSetEntry(SetHookCtx& ctx, STObject const& hookSetObj) validateGuards( hook, // wasm to verify logger, - hsacc + hsacc, + ctx.rules.enabled(featureHooksUpdate1) ? 1 : 0 ); if (ctx.j.trace()) @@ -627,7 +628,8 @@ SetHook::preflight(PreflightContext const& ctx) { .j = ctx.j, .tx = ctx.tx, - .app = ctx.app + .app = ctx.app, + .rules = ctx.rules }; bool allBlank = true; @@ -1092,7 +1094,8 @@ SetHook::setHook() { .j = ctx_.app.journal("View"), .tx = ctx_.tx, - .app = ctx_.app + .app = ctx_.app, + .rules = ctx_.view().rules() }; const int blobMax = hook::maxHookWasmSize(); diff --git a/src/ripple/app/tx/impl/SetHook.h b/src/ripple/app/tx/impl/SetHook.h index 4590288fb..91a759a9c 100644 --- a/src/ripple/app/tx/impl/SetHook.h +++ b/src/ripple/app/tx/impl/SetHook.h @@ -35,6 +35,7 @@ #include #include #include +#include namespace ripple { @@ -52,6 +53,7 @@ struct SetHookCtx beast::Journal j; STTx const& tx; Application& app; + Rules const& rules; }; class SetHook : public Transactor diff --git a/src/ripple/protocol/Feature.h b/src/ripple/protocol/Feature.h index 67c309c04..29914aa5a 100644 --- a/src/ripple/protocol/Feature.h +++ b/src/ripple/protocol/Feature.h @@ -74,7 +74,7 @@ namespace detail { // Feature.cpp. Because it's only used to reserve storage, and determine how // large to make the FeatureBitset, it MAY be larger. It MUST NOT be less than // the actual number of amendments. A LogicError on startup will verify this. -static constexpr std::size_t numFeatures = 64; +static constexpr std::size_t numFeatures = 65; /** Amendments that this server supports and the default voting behavior. Whether they are enabled depends on the Rules defined in the validated @@ -352,6 +352,7 @@ extern uint256 const fixNonFungibleTokensV1_2; extern uint256 const fixNFTokenRemint; extern uint256 const featureImport; extern uint256 const featureXahauGenesis; +extern uint256 const featureHooksUpdate1; } // namespace ripple diff --git a/src/ripple/protocol/impl/Feature.cpp b/src/ripple/protocol/impl/Feature.cpp index 2475745db..1fdfff1d9 100644 --- a/src/ripple/protocol/impl/Feature.cpp +++ b/src/ripple/protocol/impl/Feature.cpp @@ -458,6 +458,8 @@ REGISTER_FEATURE(PaychanAndEscrowForTokens, Supported::yes, VoteBehavior::De REGISTER_FEATURE(URIToken, Supported::yes, VoteBehavior::DefaultYes); REGISTER_FEATURE(Import, Supported::yes, VoteBehavior::DefaultNo); REGISTER_FEATURE(XahauGenesis, Supported::yes, VoteBehavior::DefaultNo); +REGISTER_FEATURE(HooksUpdate1, Supported::yes, VoteBehavior::DefaultNo); + // The following amendments are obsolete, but must remain supported // because they could potentially get enabled.