diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index e8fc5327d78..26fe3365317 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -891,6 +891,7 @@ if (tests) src/test/protocol/InnerObjectFormats_test.cpp src/test/protocol/Issue_test.cpp src/test/protocol/KnownFormatToGRPC_test.cpp + src/test/protocol/Hooks_test.cpp src/test/protocol/PublicKey_test.cpp src/test/protocol/Quality_test.cpp src/test/protocol/STAccount_test.cpp diff --git a/src/ripple/protocol/SField.h b/src/ripple/protocol/SField.h index f9278ea73fc..28da73436b8 100644 --- a/src/ripple/protocol/SField.h +++ b/src/ripple/protocol/SField.h @@ -341,6 +341,7 @@ extern SF_UINT8 const sfMethod; extern SF_UINT8 const sfTransactionResult; extern SF_UINT8 const sfTickSize; extern SF_UINT8 const sfUNLModifyDisabling; +extern SF_UINT8 const sfHookResult; // 16-bit integers extern SF_UINT16 const sfLedgerEntryType; @@ -349,6 +350,10 @@ extern SF_UINT16 const sfSignerWeight; // 16-bit integers (uncommon) extern SF_UINT16 const sfVersion; +extern SF_UINT16 const sfHookStateChangeCount; +extern SF_UINT16 const sfHookEmitCount; +extern SF_UINT16 const sfHookExecutionIndex; +extern SF_UINT16 const sfHookApiVersion; // 32-bit integers (common) extern SF_UINT32 const sfFlags; @@ -392,6 +397,8 @@ extern SF_UINT32 const sfSignerListID; extern SF_UINT32 const sfSettleDelay; extern SF_UINT32 const sfTicketCount; extern SF_UINT32 const sfTicketSequence; +extern SF_UINT32 const sfHookStateCount; +extern SF_UINT32 const sfEmitGeneration; // 64-bit integers extern SF_UINT64 const sfIndexNext; @@ -405,6 +412,11 @@ extern SF_UINT64 const sfHighNode; extern SF_UINT64 const sfDestinationNode; extern SF_UINT64 const sfCookie; extern SF_UINT64 const sfServerVersion; +extern SF_UINT64 const sfHookOn; +extern SF_UINT64 const sfHookInstructionCount; +extern SF_UINT64 const sfEmitBurden; +extern SF_UINT64 const sfHookReturnCode; +extern SF_UINT64 const sfReferenceCount; // 128-bit extern SF_HASH128 const sfEmailHash; @@ -425,6 +437,9 @@ extern SF_HASH256 const sfLedgerIndex; extern SF_HASH256 const sfWalletLocator; extern SF_HASH256 const sfRootIndex; extern SF_HASH256 const sfAccountTxnID; +extern SF_HASH256 const sfEmitParentTxnID; +extern SF_HASH256 const sfEmitNonce; +extern SF_HASH256 const sfEmitHookHash; // 256-bit (uncommon) extern SF_HASH256 const sfBookDirectory; @@ -436,6 +451,10 @@ extern SF_HASH256 const sfChannel; extern SF_HASH256 const sfConsensusHash; extern SF_HASH256 const sfCheckID; extern SF_HASH256 const sfValidatedHash; +extern SF_HASH256 const sfHookStateKey; +extern SF_HASH256 const sfHookHash; +extern SF_HASH256 const sfHookNamespace; +extern SF_HASH256 const sfHookSetTxnID; // currency amount (common) extern SF_AMOUNT const sfAmount; @@ -476,6 +495,10 @@ extern SF_VL const sfMasterSignature; extern SF_VL const sfUNLModifyValidator; extern SF_VL const sfValidatorToDisable; extern SF_VL const sfValidatorToReEnable; +extern SF_VL const sfHookStateData; +extern SF_VL const sfHookReturnString; +extern SF_VL const sfHookParameterName; +extern SF_VL const sfHookParameterValue; // account extern SF_ACCOUNT const sfAccount; @@ -486,6 +509,10 @@ extern SF_ACCOUNT const sfAuthorize; extern SF_ACCOUNT const sfUnauthorize; extern SF_ACCOUNT const sfTarget; extern SF_ACCOUNT const sfRegularKey; +extern SF_ACCOUNT const sfEmitCallback; + +// account (uncommon) +extern SF_ACCOUNT const sfHookAccount; // path set extern SField const sfPaths; @@ -510,6 +537,11 @@ extern SField const sfSignerEntry; extern SField const sfSigner; extern SField const sfMajority; extern SField const sfDisabledValidator; +extern SField const sfEmittedTxn; +extern SField const sfHook; +extern SField const sfHookDefinition; +extern SField const sfHookParameter; +extern SField const sfHookGrant; // array of objects // ARRAY/1 is reserved for end of array @@ -523,6 +555,13 @@ extern SField const sfAffectedNodes; extern SField const sfMemos; extern SField const sfMajorities; extern SField const sfDisabledValidators; +extern SField const sfEmitDetails; +extern SField const sfHookExecutions; +extern SField const sfHookExecution; +extern SField const sfHookParameters; +extern SField const sfHooks; +extern SField const sfHookGrants; + //------------------------------------------------------------------------------ } // namespace ripple diff --git a/src/ripple/protocol/impl/SField.cpp b/src/ripple/protocol/impl/SField.cpp index 590ffeb65a4..679248dea6e 100644 --- a/src/ripple/protocol/impl/SField.cpp +++ b/src/ripple/protocol/impl/SField.cpp @@ -88,6 +88,7 @@ CONSTRUCT_TYPED_SFIELD(sfTransactionResult, "TransactionResult", UINT8, // 8-bit integers (uncommon) CONSTRUCT_TYPED_SFIELD(sfTickSize, "TickSize", UINT8, 16); CONSTRUCT_TYPED_SFIELD(sfUNLModifyDisabling, "UNLModifyDisabling", UINT8, 17); +CONSTRUCT_TYPED_SFIELD(sfHookResult, "HookResult", UINT8, 18); // 16-bit integers CONSTRUCT_TYPED_SFIELD(sfLedgerEntryType, "LedgerEntryType", UINT16, 1, SField::sMD_Never); @@ -96,6 +97,10 @@ CONSTRUCT_TYPED_SFIELD(sfSignerWeight, "SignerWeight", UINT16, // 16-bit integers (uncommon) CONSTRUCT_TYPED_SFIELD(sfVersion, "Version", UINT16, 16); +CONSTRUCT_TYPED_SFIELD(sfHookStateChangeCount, "HookStateChangeCount", UINT16, 17); +CONSTRUCT_TYPED_SFIELD(sfHookEmitCount, "HookEmitCount", UINT16, 18); +CONSTRUCT_TYPED_SFIELD(sfHookExecutionIndex, "HookExecutionIndex", UINT16, 19); +CONSTRUCT_TYPED_SFIELD(sfHookApiVersion, "HookApiVersion", UINT16, 20); // 32-bit integers (common) CONSTRUCT_TYPED_SFIELD(sfFlags, "Flags", UINT32, 2); @@ -139,6 +144,8 @@ CONSTRUCT_TYPED_SFIELD(sfSignerListID, "SignerListID", UINT32, CONSTRUCT_TYPED_SFIELD(sfSettleDelay, "SettleDelay", UINT32, 39); CONSTRUCT_TYPED_SFIELD(sfTicketCount, "TicketCount", UINT32, 40); CONSTRUCT_TYPED_SFIELD(sfTicketSequence, "TicketSequence", UINT32, 41); +CONSTRUCT_TYPED_SFIELD(sfHookStateCount, "HookStateCount", UINT32, 45); +CONSTRUCT_TYPED_SFIELD(sfEmitGeneration, "EmitGeneration", UINT32, 46); // 64-bit integers CONSTRUCT_TYPED_SFIELD(sfIndexNext, "IndexNext", UINT64, 1); @@ -152,6 +159,11 @@ CONSTRUCT_TYPED_SFIELD(sfHighNode, "HighNode", UINT64, CONSTRUCT_TYPED_SFIELD(sfDestinationNode, "DestinationNode", UINT64, 9); CONSTRUCT_TYPED_SFIELD(sfCookie, "Cookie", UINT64, 10); CONSTRUCT_TYPED_SFIELD(sfServerVersion, "ServerVersion", UINT64, 11); +CONSTRUCT_TYPED_SFIELD(sfEmitBurden, "EmitBurden", UINT64, 13); +CONSTRUCT_TYPED_SFIELD(sfHookOn, "HookOn", UINT64, 16); +CONSTRUCT_TYPED_SFIELD(sfHookInstructionCount, "HookInstructionCount", UINT64, 17); +CONSTRUCT_TYPED_SFIELD(sfHookReturnCode, "HookReturnCode", UINT64, 18); +CONSTRUCT_TYPED_SFIELD(sfReferenceCount, "ReferenceCount", UINT64, 19); // 128-bit CONSTRUCT_TYPED_SFIELD(sfEmailHash, "EmailHash", HASH128, 1); @@ -172,6 +184,9 @@ CONSTRUCT_TYPED_SFIELD(sfLedgerIndex, "LedgerIndex", HASH256, CONSTRUCT_TYPED_SFIELD(sfWalletLocator, "WalletLocator", HASH256, 7); CONSTRUCT_TYPED_SFIELD(sfRootIndex, "RootIndex", HASH256, 8, SField::sMD_Always); CONSTRUCT_TYPED_SFIELD(sfAccountTxnID, "AccountTxnID", HASH256, 9); +CONSTRUCT_TYPED_SFIELD(sfEmitParentTxnID, "EmitParentTxnID", HASH256, 11); +CONSTRUCT_TYPED_SFIELD(sfEmitNonce, "EmitNonce", HASH256, 12); +CONSTRUCT_TYPED_SFIELD(sfEmitHookHash, "EmitHookHash", HASH256, 13); // 256-bit (uncommon) CONSTRUCT_TYPED_SFIELD(sfBookDirectory, "BookDirectory", HASH256, 16); @@ -184,6 +199,10 @@ CONSTRUCT_TYPED_SFIELD(sfChannel, "Channel", HASH256, CONSTRUCT_TYPED_SFIELD(sfConsensusHash, "ConsensusHash", HASH256, 23); CONSTRUCT_TYPED_SFIELD(sfCheckID, "CheckID", HASH256, 24); CONSTRUCT_TYPED_SFIELD(sfValidatedHash, "ValidatedHash", HASH256, 25); +CONSTRUCT_TYPED_SFIELD(sfHookStateKey, "HookStateKey", HASH256, 30); +CONSTRUCT_TYPED_SFIELD(sfHookHash, "HookHash", HASH256, 31); +CONSTRUCT_TYPED_SFIELD(sfHookNamespace, "HookNamespace", HASH256, 32); +CONSTRUCT_TYPED_SFIELD(sfHookSetTxnID, "HookSetTxnID", HASH256, 33); // currency amount (common) CONSTRUCT_TYPED_SFIELD(sfAmount, "Amount", AMOUNT, 1); @@ -225,6 +244,10 @@ CONSTRUCT_TYPED_SFIELD(sfMasterSignature, "MasterSignature", VL, CONSTRUCT_TYPED_SFIELD(sfUNLModifyValidator, "UNLModifyValidator", VL, 19); CONSTRUCT_TYPED_SFIELD(sfValidatorToDisable, "ValidatorToDisable", VL, 20); CONSTRUCT_TYPED_SFIELD(sfValidatorToReEnable, "ValidatorToReEnable", VL, 21); +CONSTRUCT_TYPED_SFIELD(sfHookStateData, "HookStateData", VL, 22); +CONSTRUCT_TYPED_SFIELD(sfHookReturnString, "HookReturnString", VL, 23); +CONSTRUCT_TYPED_SFIELD(sfHookParameterName, "HookParameterName", VL, 24); +CONSTRUCT_TYPED_SFIELD(sfHookParameterValue, "HookParameterValue", VL, 25); // account CONSTRUCT_TYPED_SFIELD(sfAccount, "Account", ACCOUNT, 1); @@ -235,6 +258,10 @@ CONSTRUCT_TYPED_SFIELD(sfAuthorize, "Authorize", ACCOUNT, CONSTRUCT_TYPED_SFIELD(sfUnauthorize, "Unauthorize", ACCOUNT, 6); // 7 is currently unused CONSTRUCT_TYPED_SFIELD(sfRegularKey, "RegularKey", ACCOUNT, 8); +CONSTRUCT_TYPED_SFIELD(sfEmitCallback, "EmitCallback", ACCOUNT, 10); + +// account (uncommon) +CONSTRUCT_TYPED_SFIELD(sfHookAccount, "HookAccount", ACCOUNT, 16); // vector of 256-bit CONSTRUCT_TYPED_SFIELD(sfIndexes, "Indexes", VECTOR256, 1, SField::sMD_Never); @@ -256,12 +283,19 @@ CONSTRUCT_UNTYPED_SFIELD(sfNewFields, "NewFields", OBJECT, CONSTRUCT_UNTYPED_SFIELD(sfTemplateEntry, "TemplateEntry", OBJECT, 9); CONSTRUCT_UNTYPED_SFIELD(sfMemo, "Memo", OBJECT, 10); CONSTRUCT_UNTYPED_SFIELD(sfSignerEntry, "SignerEntry", OBJECT, 11); +CONSTRUCT_UNTYPED_SFIELD(sfEmitDetails, "EmitDetails", OBJECT, 13); +CONSTRUCT_UNTYPED_SFIELD(sfHook, "Hook", OBJECT, 14); // inner object (uncommon) CONSTRUCT_UNTYPED_SFIELD(sfSigner, "Signer", OBJECT, 16); // 17 has not been used yet CONSTRUCT_UNTYPED_SFIELD(sfMajority, "Majority", OBJECT, 18); CONSTRUCT_UNTYPED_SFIELD(sfDisabledValidator, "DisabledValidator", OBJECT, 19); +CONSTRUCT_UNTYPED_SFIELD(sfEmittedTxn, "EmittedTxn", OBJECT, 20); +CONSTRUCT_UNTYPED_SFIELD(sfHookExecution, "HookExecution", OBJECT, 21); +CONSTRUCT_UNTYPED_SFIELD(sfHookDefinition, "HookDefinition", OBJECT, 22); +CONSTRUCT_UNTYPED_SFIELD(sfHookParameter, "HookParameter", OBJECT, 23); +CONSTRUCT_UNTYPED_SFIELD(sfHookGrant, "HookGrant", OBJECT, 24); // array of objects // ARRAY/1 is reserved for end of array @@ -273,10 +307,14 @@ CONSTRUCT_UNTYPED_SFIELD(sfNecessary, "Necessary", ARRAY, CONSTRUCT_UNTYPED_SFIELD(sfSufficient, "Sufficient", ARRAY, 7); CONSTRUCT_UNTYPED_SFIELD(sfAffectedNodes, "AffectedNodes", ARRAY, 8); CONSTRUCT_UNTYPED_SFIELD(sfMemos, "Memos", ARRAY, 9); +CONSTRUCT_UNTYPED_SFIELD(sfHooks, "Hooks", ARRAY, 11); // array of objects (uncommon) CONSTRUCT_UNTYPED_SFIELD(sfMajorities, "Majorities", ARRAY, 16); CONSTRUCT_UNTYPED_SFIELD(sfDisabledValidators, "DisabledValidators", ARRAY, 17); +CONSTRUCT_UNTYPED_SFIELD(sfHookExecutions, "HookExecutions", ARRAY, 18); +CONSTRUCT_UNTYPED_SFIELD(sfHookParameters, "HookParameters", ARRAY, 19); +CONSTRUCT_UNTYPED_SFIELD(sfHookGrants, "HookGrants", ARRAY, 20); // clang-format on diff --git a/src/test/protocol/Hooks_test.cpp b/src/test/protocol/Hooks_test.cpp new file mode 100644 index 00000000000..161404195a4 --- /dev/null +++ b/src/test/protocol/Hooks_test.cpp @@ -0,0 +1,197 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012-2017 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. +*/ +//============================================================================== + +#include +#include +#include +#include +#include + +namespace ripple { + +class Hooks_test : public beast::unit_test::suite +{ + /** + * This unit test was requested here: + * https://github.com/ripple/rippled/pull/4089#issuecomment-1050274539 + * These are tests that exercise facilities that are reserved for when Hooks + * is merged in the future. + **/ + + void + testHookFields() + { + testcase("Test Hooks fields"); + + using namespace test::jtx; + + std::vector> fields_to_test = { + sfHookResult, + sfHookStateChangeCount, + sfHookEmitCount, + sfHookExecutionIndex, + sfHookApiVersion, + sfHookStateCount, + sfEmitGeneration, + sfHookOn, + sfHookInstructionCount, + sfEmitBurden, + sfHookReturnCode, + sfReferenceCount, + sfEmitParentTxnID, + sfEmitNonce, + sfEmitHookHash, + sfHookStateKey, + sfHookHash, + sfHookNamespace, + sfHookSetTxnID, + sfHookStateData, + sfHookReturnString, + sfHookParameterName, + sfHookParameterValue, + sfEmitCallback, + sfHookAccount, + sfEmittedTxn, + sfHook, + sfHookDefinition, + sfHookParameter, + sfHookGrant, + sfEmitDetails, + sfHookExecutions, + sfHookExecution, + sfHookParameters, + sfHooks, + sfHookGrants}; + + for (auto const& rf : fields_to_test) + { + SField const& f = rf.get(); + + STObject dummy{sfGeneric}; + + BEAST_EXPECT(!dummy.isFieldPresent(f)); + + switch (f.fieldType) + { + case STI_UINT8: { + dummy.setFieldU8(f, 0); + BEAST_EXPECT(dummy.getFieldU8(f) == 0); + + dummy.setFieldU8(f, 255); + BEAST_EXPECT(dummy.getFieldU8(f) == 255); + + BEAST_EXPECT(dummy.isFieldPresent(f)); + break; + } + + case STI_UINT16: { + dummy.setFieldU16(f, 0); + BEAST_EXPECT(dummy.getFieldU16(f) == 0); + + dummy.setFieldU16(f, 0xFFFFU); + BEAST_EXPECT(dummy.getFieldU16(f) == 0xFFFFU); + + BEAST_EXPECT(dummy.isFieldPresent(f)); + break; + } + + case STI_UINT32: { + dummy.setFieldU32(f, 0); + BEAST_EXPECT(dummy.getFieldU32(f) == 0); + + dummy.setFieldU32(f, 0xFFFFFFFFU); + BEAST_EXPECT(dummy.getFieldU32(f) == 0xFFFFFFFFU); + + BEAST_EXPECT(dummy.isFieldPresent(f)); + break; + } + + case STI_UINT64: { + dummy.setFieldU64(f, 0); + BEAST_EXPECT(dummy.getFieldU64(f) == 0); + + dummy.setFieldU64(f, 0xFFFFFFFFFFFFFFFFU); + BEAST_EXPECT(dummy.getFieldU64(f) == 0xFFFFFFFFFFFFFFFFU); + + BEAST_EXPECT(dummy.isFieldPresent(f)); + break; + } + + case STI_HASH256: { + uint256 u = uint256::fromVoid( + "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBE" + "EFDEADBEEF"); + dummy.setFieldH256(f, u); + BEAST_EXPECT(dummy.getFieldH256(f) == u); + BEAST_EXPECT(dummy.isFieldPresent(f)); + break; + } + + case STI_VL: { + std::vector v{1, 2, 3}; + dummy.setFieldVL(f, v); + BEAST_EXPECT(dummy.getFieldVL(f) == v); + BEAST_EXPECT(dummy.isFieldPresent(f)); + break; + } + + case STI_ACCOUNT: { + AccountID id = *parseBase58( + "rwfSjJNK2YQuN64bSWn7T2eY9FJAyAPYJT"); + dummy.setAccountID(f, id); + BEAST_EXPECT(dummy.getAccountID(f) == id); + BEAST_EXPECT(dummy.isFieldPresent(f)); + break; + } + + case STI_OBJECT: { + dummy.emplace_back(STObject{f}); + BEAST_EXPECT(dummy.getField(f).getFName() == f); + BEAST_EXPECT(dummy.isFieldPresent(f)); + break; + } + + case STI_ARRAY: { + STArray dummy2{f, 2}; + dummy2.push_back(STObject{sfGeneric}); + dummy2.push_back(STObject{sfGeneric}); + dummy.setFieldArray(f, dummy2); + BEAST_EXPECT(dummy.getFieldArray(f) == dummy2); + BEAST_EXPECT(dummy.isFieldPresent(f)); + break; + } + + default: + BEAST_EXPECT(false); + } + } + } + +public: + void + run() override + { + using namespace test::jtx; + testHookFields(); + } +}; + +BEAST_DEFINE_TESTSUITE(Hooks, protocol, ripple); + +} // namespace ripple