-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PriceOracle
: Price Oracle (XLS-47d)
#4789
Conversation
I get this error when I try to compile locally (Mac M1):
|
Thanks. I built with the |
src/ripple/app/tx/impl/SetOracle.cpp
Outdated
auto const sleSetter = | ||
ctx.view.read(keylet::account(ctx.tx.getAccountID(sfAccount))); | ||
if (!sleSetter) | ||
return {terNO_ACCOUNT}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return {terNO_ACCOUNT}; | |
return terNO_ACCOUNT; |
src/ripple/app/tx/impl/SetOracle.cpp
Outdated
// lastUpdateTime must be within 30 seconds of the last closed ledger | ||
using namespace std::chrono; | ||
std::size_t const closeTime = | ||
duration_cast<seconds>(ctx.view.info().closeTime.time_since_epoch()) | ||
.count(); | ||
std::size_t const lastUpdateTime = ctx.tx[sfLastUpdateTime]; | ||
if (lastUpdateTime < closeTime || | ||
lastUpdateTime > (closeTime + maxLastUpdateTimeDelta)) | ||
return tecINVALID_UPDATE_TIME; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the ledger slows down and there are a couple of minutes between ledgers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be. What is a reasonable range to use for the validation? 30 seconds is roughly 6 times of the expected 5 seconds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A thought: is this field necessary? Seems like the same info is provided by PreviousTxnLgrSeq
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is PreviousTxnLgrSeq
providing the same info as LastUpdateTime
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It provides the ledger that the object was last updated in - my understanding is that that's basically providing the same information. But perhaps I'm misunderstanding the objective of that field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it's the ledger sequence, not the time. How do we get the time out of it: sequence * avg close time? This gives an estimate, but not the actual time. LastUpdateTime
provides an accurate time up to a second.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I'd look up that specific ledger's close time, which will be accurate within 10 seconds (possibly more accurate than LastUpdateTime
, if a few ledgers go by before it's accepted).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mvadari Additionally, the PriceOracle Set transaction might not get included in the next ledger due to problems in consensus, network health, etc. We will need to account for arbitrary delays in the publication of the oracle data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's indirection and 10 seconds might not be good enough.
I find the description of the
In the spec, the list following "The transaction fails if" includes:
But the section describing the
Which is correct? Can we fix it in the spec? I find this explanation unclear:
"If an object with the ID exists, then the new token pairs are added..." I'm assuming "new token pairs" are ones that do not appear in the "In this case the missing token pair..." What missing token pair? The token pairs that are in the object, but not the transaction? If yes, then what is meant by "[they] will not include I feel like there is an implied behavior for this transaction that is not well described by the existing language. Here is how I would describe that behavior. Is it correct?
A side note on formatting. I think the presentation in the section on |
@thejohnfreeman thanks for the feedback on the specs. I copied your comments and responded on XRPLF/XRPL-Standards#138. |
src/ripple/net/impl/RPCCall.cpp
Outdated
@@ -1207,6 +1207,7 @@ class RPCParser | |||
{"fetch_info", &RPCParser::parseFetchInfo, 0, 1}, | |||
{"gateway_balances", &RPCParser::parseGatewayBalances, 1, -1}, | |||
{"get_counts", &RPCParser::parseGetCounts, 0, 1}, | |||
{"get_aggregate_price", &RPCParser::parseAsIs, 3, 5}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
regarding the naming of the function, can we keep it as &RPCParser::parseGetAggPrice
or something like that? I feel this name is more readable.
if there is some other reason for using parseAsIs
, please let me know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We just need to get the RPC parameters. There is no need go have any kind of transformation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the parse function is only needed when using the command-line versions of RPCs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering now if it makes sense to have get_aggregate_price
as the command line option. There are too many parameters that have to be provided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll delete it.
src/ripple/app/tx/impl/SetOracle.cpp
Outdated
auto invalidLength = [&](auto const& sField, std::size_t length) { | ||
return ctx.tx.isFieldPresent(sField) && | ||
ctx.tx[sField].length() > length; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the fields allowed to be empty strings? Should there be an error in that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The empty string doesn't make much sense but these fields are not validated in any way. Say how is a
any more valid than '' in URI
? It's up to the oracle's user to interpret. The '' might make some meaning. I'll change if you feel strongly about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added check for 0 length.
for (auto const& entry : ctx.tx.getFieldArray(sfPriceDataSeries)) | ||
{ | ||
if (!entry.isFieldPresent(sfAssetPrice)) | ||
return temMALFORMED; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why doesn't this check happen in preflight
? Ditto with the other tem
checks in this function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to reduce the number of redundant iterations. The other tem
checks require the ledger access, which is usually done in preclaim
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't the check being done in preflight
not override the need for an extra set of iterations, since preflight
is done on the submission node instead of waiting to be broadcast?
Also, shouldn't any check requiring ledger access return a tec
code instead of a tem
code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can move some checks to preflight
: check if AssetPrice
is included and if there are duplicate entries.
I wouldn't need to repeat this in preclaim
in case of create but in case of update I still need to iterate over submitted array to see if there are token pairs that are going to be added so I could check the array size and the reserve. The double iteration can't be avoided in case of update. In reality it's not a big deal, since the submitted array size is less or equal to ten. Would you rather have it handled this way? I'd have to iterate in doApply
but again it's such a small array size that I don't think it matters. As for tec
and tem
code, I don't think it's a hard core rule that tem
can't appear in preclaim
. For instance, CreateOffer
, CancelOffer
, and NFTokenAcceptOffer
return tem
in preclaim
.
Env env(*this); | ||
env.fund( | ||
env.current()->fees().accountReserve(1) + | ||
env.current()->fees().base * 2, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apart from the Account Reserve
, why is the second component of the fees necessary? I don't understand why we need that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just factoring in the transaction fee. There is create and set to should have enough fee for two tx.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, that makes sense 👍
src/ripple/app/tx/impl/SetOracle.cpp
Outdated
duration_cast<seconds>(ctx.view.info().closeTime.time_since_epoch()) | ||
.count(); | ||
std::size_t const lastUpdateTime = ctx.tx[sfLastUpdateTime]; | ||
if (lastUpdateTime <= epoch_offset.count()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this condition precludes any pre-1 Jan, 2000
date from being used in the PriceDataSeries
. I couldn't test this with the unit tests because the lastUpdateTime
is automatically set to current date/time.
Is my understanding correct? This would make it difficult to work with historical data (like old stock market prices).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and there is also a validation in place, which is not going you allow to set the time stamp older than the last closed ledger. If someone is interested in the prices predating 1/1/2000 then they need to look at some other databases and not use the blockchain's Price Oracle for this. The Price Oracle is reflecting the current market price and that's what dApps are going to use it for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LastUpdateTime
also must be within 30 seconds of the last ledger close time, so before 1/1/2000 is a moot issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i agree, I was thinking about the limitations of the PriceOracle model
} | ||
|
||
TER | ||
DeleteOracle::doApply() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like AccountDelete
doesn't handle oracles - are they a deletion blocker or should they be deleted with the account? IMO they probably should be deleted with the account.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice observation!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be deleted. Thanks for pointing it out. Will update.
src/ripple/net/impl/RPCCall.cpp
Outdated
@@ -1207,6 +1207,7 @@ class RPCParser | |||
{"fetch_info", &RPCParser::parseFetchInfo, 0, 1}, | |||
{"gateway_balances", &RPCParser::parseGatewayBalances, 1, -1}, | |||
{"get_counts", &RPCParser::parseGetCounts, 0, 1}, | |||
{"get_aggregate_price", &RPCParser::parseAsIs, 3, 5}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This RPC should be added to the help
message in Main.cpp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are not going to offer this command in cli. Will delete.
try | ||
{ | ||
uNodeIndex = beast::zero; | ||
auto const& oracle = context.params[jss::oracle]; | ||
auto const sequence = | ||
oracle[jss::oracle_sequence].isConvertibleTo( | ||
Json::ValueType::uintValue) | ||
? std::make_optional( | ||
oracle[jss::oracle_sequence].asUInt()) | ||
: std::nullopt; | ||
auto const account = | ||
parseBase58<AccountID>(oracle[jss::account].asString()); | ||
if (!account || account->isZero()) | ||
jvResult[jss::error] = "malformedAddress"; | ||
else if (!sequence) | ||
jvResult[jss::error] = "malformedSequence"; | ||
else | ||
uNodeIndex = keylet::oracle(*account, *sequence).key; | ||
} | ||
catch (std::runtime_error const&) | ||
{ | ||
jvResult[jss::error] = "malformedRequest"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this in a big try block? Why not handle each specific issue individually?
Or is this more of a just-in-case thing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this try/catch is needed. Thanks for pointing it out. I'll delete.
src/ripple/app/tx/impl/SetOracle.cpp
Outdated
if (ctx.tx.isFieldPresent(sfProvider) || | ||
ctx.tx.isFieldPresent(sfAssetClass)) | ||
return temMALFORMED; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer that this check makes sure that if these fields exist then they match what's already in the object, because otherwise it becomes more difficult to use - you have to include these fields the first time you update the oracle (when you create the object), but you have to remove them for every subsequent update.
Otherwise, I'd rather have one OracleCreate
transaction that sets all these fields, and a separate OracleUpdate
transaction that updates the prices.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will update per first suggestion.
src/ripple/app/tx/impl/SetOracle.cpp
Outdated
if (ctx.tx[sfAccount] != sle->getAccountID(sfOwner)) | ||
return tecNO_PERMISSION; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this already a given, since the keylet is owner + document ID?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The keylet is obtained by ctx.tx.getAccountID(sfAccount)
. It doesn't have to be identical to sle->getAccountID(sfOwner)
right?
I can try to update your PriceOracle
object with an OracleSet
transaction. In that case, your account would be sfOwner
and I would be the sfAccount
field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mvadari is right. If we can get sle
for the Account
then this account is the Owner
. This check is redundant.
src/ripple/app/tx/impl/SetOracle.cpp
Outdated
for (auto const& entry : sle->getFieldArray(sfPriceDataSeries)) | ||
{ | ||
auto const hash = tokenPairHash(entry); | ||
if (!pairs.contains(hash)) | ||
pairs.emplace(hash); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be simpler to just do this test in doApply
as you're making the modificaions instead of doing it again in preclaim
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to check the array size, which could grow during the update and consequently the reserve.
} | ||
else | ||
{ | ||
// add a token pair with the price |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do I remove a token pair? Seems like you can only add them. One example usecase for this: FTX goes under and you no longer want a pair with FTT.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Decided not to have this option. If you delete and then create again then is it really the same pair or different? How to treat the historical data in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Decided to add delete option after discussing with PM. A token pair is going to be deleted on update if it doesn't include the AssetPrice
.
src/ripple/app/tx/impl/SetOracle.cpp
Outdated
sle->setFieldArray(sfPriceDataSeries, updatedSeries); | ||
if (ctx_.tx.isFieldPresent(sfURI)) | ||
sle->setFieldVL(sfURI, ctx_.tx[sfURI]); | ||
// LastUpdateTime is Unix time, store internally as Ripple Epoch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why convert? Seems more confusing to have it be different in the object and the transaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought you suggested to store it internally as Ripple Epoch or did I misunderstand? See: XRPLF/XRPL-Standards#138 (review)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant it should be Ripple Epoch in both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oracle providers don't deal with Ripple Epoch and Unix Time makes a lot of sense for them. This is why it was changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought was that it's easy enough to convert on the tooling side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there's any other transaction that takes Unix Time as a parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there transactions that take epoch time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, EscrowCreate
and PaymentChannelCreate
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me check with Jazzi if she is ok with changing to Ripple Epoch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though these transactions have more to do with ripple, where is price oracle is an external data. So I'm not sure other transactions is a precedent that has to be followed.
|
Is it available on devnet? |
No. I would suggest running it in a new Devnet (similar to what was done with amm-devnet). If that isn't possible, then we can do a custom build with this branch and give it a special version number, like |
Is someone scheduled to work on this? It would be good if the partners could start testing this. |
@thejohnfreeman could you please review when you get a chance? There is a minor patch to fix |
per the request for a quick re-review (see above), this is awaiting @thejohnfreeman |
Performance sign-off The Price Oracle feature testing on XRPL confirmed its good performance and reliability under simulated MainNet conditions. The Additionally, running More detailed report can be found here |
69012ec
to
f52425d
Compare
Implement native support for Price Oracles. A Price Oracle is used to bring real-world data, such as market prices, onto the blockchain, enabling dApps to access and utilize information that resides outside the blockchain. Add Price Oracle functionality: - OracleSet: create or update the Oracle object - OracleDelete: delete the Oracle object To support this functionality add: - New RPC method, `get_aggregate_price`, to calculate aggregate price for a token pair of the specified oracles - `ltOracle` object The `ltOracle` object maintains: - Oracle Owner's account - Oracle's metadata - Up to ten token pairs with the scaled price - The last update time the token pairs were updated Add Oracle unit-tests
f52425d
to
f839070
Compare
* Price Oracle (XLS-47d): (XRPLF#4789) (XRPLF#4789) Implement native support for Price Oracles. A Price Oracle is used to bring real-world data, such as market prices, onto the blockchain, enabling dApps to access and utilize information that resides outside the blockchain. Add Price Oracle functionality: - OracleSet: create or update the Oracle object - OracleDelete: delete the Oracle object To support this functionality add: - New RPC method, `get_aggregate_price`, to calculate aggregate price for a token pair of the specified oracles - `ltOracle` object The `ltOracle` object maintains: - Oracle Owner's account - Oracle's metadata - Up to ten token pairs with the scaled price - The last update time the token pairs were updated Add Oracle unit-tests * fix compile error on gcc 13: (XRPLF#4932) The compilation fails due to an issue in the initializer list of an optional argument, which holds a vector of pairs. The code compiles correctly on earlier gcc versions, but fails on gcc 13. * Set version to 2.2.0-b1 * Remove default ctors from SecretKey and PublicKey: (XRPLF#4607) * It is now an invariant that all constructed Public Keys are valid, non-empty and contain 33 bytes of data. * Additionally, the memory footprint of the PublicKey class is reduced. The size_ data member is declared as static. * Distinguish and identify the PublisherList retrieved from the local config file, versus the ones obtained from other validators. * Fixes XRPLF#2942 * Fast base58 codec: (XRPLF#4327) This algorithm is about an order of magnitude faster than the existing algorithm (about 10x faster for encoding and about 15x faster for decoding - including the double hash for the checksum). The algorithms use gcc's int128 (fast MS version will have to wait, in the meantime MS falls back to the slow code). * feat: add user version of `feature` RPC (XRPLF#4781) * uses same formatting as admin RPC * hides potentially sensitive data * build: add STCurrency.h to xrpl_core to fix clio build (XRPLF#4939) * Embed patched recipe for RocksDB 6.29.5 (XRPLF#4947) * fix: order book update variable swap: (XRPLF#4890) This is likely the result of a typo when the code was simplified. * Fix workflows (XRPLF#4948) The problem was `CONAN_USERNAME` environment variable, which Conan 1.x uses as the default user in package references. * Upgrade to xxhash 0.8.2 as a Conan requirement, enable SIMD hashing (XRPLF#4893) We are currently using old version 0.6.2 of `xxhash`, as a verbatim copy and paste of its header file `xxhash.h`. Switch to the more recent version 0.8.2. Since this version is in Conan Center (and properly protects its ABI by keeping the state object incomplete), add it as a Conan requirement. Switch to the SIMD instructions (in the new `XXH3` family) supported by the new version. * Update remaining actions (XRPLF#4949) Downgrade {upload,download}-artifact action to v3 because of unreliability with v4. * Install more public headers (XRPLF#4940) Fixes some mistakes in XRPLF#4885 * test: Env unit test RPC errors return a unique result: (XRPLF#4877) * telENV_RPC_FAILED is a new code, reserved exclusively for unit tests when RPC fails. This will make those types of errors distinct and easier to test for when expected and/or diagnose when not. * Output RPC command result when result is not expected. * Fix workflows (XRPLF#4951) - Update container for Doxygen workflow. Matches Linux workflow, with newer GLIBC version required by newer actions. - Fixes macOS workflow to install and configure Conan correctly. Still fails on tests, but that does not seem attributable to the workflow. * perf: improve `account_tx` SQL query: (XRPLF#4955) The witness server makes heavily use of the `account_tx` RPC command. Perf testing showed that the SQL query used by `account_tx` became unacceptably slow when the DB was large and there was a `marker` parameter. The plan for the query showed only indexed reads. This appears to be an issue with the internal SQLite optimizer. This patch rewrote the query to use `UNION` instead of `OR` and significantly improves performance. See RXI-896 and RIPD-1847 for more details. * `fixEmptyDID`: fix amendment to handle empty DID edge case: (XRPLF#4950) This amendment fixes an edge case where an empty DID object can be created. It adds an additional check to ensure that DIDs are non-empty when created, and returns a `tecEMPTY_DID` error if the DID would be empty. * Enforce no duplicate slots from incoming connections: (XRPLF#4944) We do not currently enforce that incoming peer connection does not have remote_endpoint which is already used (either by incoming or outgoing connection), hence already stored in slots_. If we happen to receive a connection from such a duplicate remote_endpoint, it will eventually result in a crash (when disconnecting) or weird behavior (when updating slot state), as a result of an apparently matching remote_endpoint in slots_ being used by a different connection. * Remove zaphod.alloy.ee hub from default server list: (XRPLF#4903) Remove the zaphod.alloy.ee hubs from the bootstrap and default configuration after 5 years. It has been an honor to run these servers, but it is now time for another entity to step into this role. The zaphod servers will be taken offline in a phased manner keeping all those who have peering arrangements informed. These would be the preferred attributes of a boostrap set of hubs: 1. Commitment to run the hubs for a minimum of 2 years 2. Highly available 3. Geographically dispersed 4. Secure and up to date 5. Committed to ensure that peering information is kept private * Write improved `forAllApiVersions` used in NetworkOPs (XRPLF#4833) * Don't reach consensus as quickly if no other proposals seen: (XRPLF#4763) This fixes a case where a peer can desync under a certain timing circumstance--if it reaches a certain point in consensus before it receives proposals. This was noticed under high transaction volumes. Namely, when we arrive at the point of deciding whether consensus is reached after minimum establish phase duration but before having received any proposals. This could be caused by finishing the previous round slightly faster and/or having some delay in receiving proposals. Existing behavior arrives at consensus immediately after the minimum establish duration with no proposals. This causes us to desync because we then close a non-validated ledger. The change in this PR causes us to wait for a configured threshold before making the decision to arrive at consensus with no proposals. This allows validators to catch up and for brief delays in receiving proposals to be absorbed. There should be no drawback since, with no proposals coming in, we needn't be in a huge rush to jump ahead. * fixXChainRewardRounding: round reward shares down: (XRPLF#4933) When calculating reward shares, the amount should always be rounded down. If the `fixUniversalNumber` amendment is not active, this works correctly. If it is not active, then the amount is incorrectly rounded up. This patch introduces an amendment so it will be rounded down. * Remove unused files * Remove packaging scripts * Consolidate external libraries * Simplify protobuf generation * Rename .hpp to .h * Format formerly .hpp files * Rewrite includes $ find src/ripple/ src/test/ -type f -exec sed -i 's:include\s*["<]ripple/\(.*\)\.h\(pp\)\?[">]:include <ripple/\1.h>:' {} + * Fix source lists * Add markers around source lists * fix: improper handling of large synthetic AMM offers: A large synthetic offer was not handled correctly in the payment engine. This patch fixes that issue and introduces a new invariant check while processing synthetic offers. * Set version to 2.1.1 * chore: change Github Action triggers for build/test jobs (XRPLF#4956) Github Actions for the build/test jobs (nix.yml, mac.yml, windows.yml) will only run on branches that build packages (develop, release, master), and branches with names starting with "ci/". This is intended as a compromise between disabling CI jobs on personal forks entirely, and having the jobs run as a free-for-all. Note that it will not affect PR jobs at all. * Address compiler warnings * Fix search for protoc * chore: Default validator-keys-tool to master branch: (XRPLF#4943) * master is the default branch for that project. There's no point in using develop. * Remove unused lambdas from MultiApiJson_test * fix Conan component reference typo * Set version to 2.2.0-b2 * bump version * 2.2.3 * 2.2.4 * 2.2.5 --------- Co-authored-by: Gregory Tsipenyuk <[email protected]> Co-authored-by: seelabs <[email protected]> Co-authored-by: Chenna Keshava B S <[email protected]> Co-authored-by: Mayukha Vadari <[email protected]> Co-authored-by: John Freeman <[email protected]> Co-authored-by: Bronek Kozicki <[email protected]> Co-authored-by: Ed Hennis <[email protected]> Co-authored-by: Olek <[email protected]> Co-authored-by: Alloy Networks <[email protected]> Co-authored-by: Mark Travis <[email protected]> Co-authored-by: Gregory Tsipenyuk <[email protected]>
This reverts commit e718378 in order to add input validation in get_aggregate_price and make consistent error handling in Oracle API's.
Implement native support for Price Oracles. A Price Oracle is used to bring real-world data, such as market prices, onto the blockchain, enabling dApps to access and utilize information that resides outside the blockchain. Add Price Oracle functionality: - OracleSet: create or update the Oracle object - OracleDelete: delete the Oracle object To support this functionality add: - New RPC method, `get_aggregate_price`, to calculate aggregate price for a token pair of the specified oracles - `ltOracle` object The `ltOracle` object maintains: - Oracle Owner's account - Oracle's metadata - Up to ten token pairs with the scaled price - The last update time the token pairs were updated Add Oracle unit-tests
Updated description for `LastUpdateTime` field as per the (PR comments)[XRPLF/rippled#4789 (review)]. This field accepts UNIX time instead of Ripple time because it must integrate with third party systems that may not measure time in Ripple time.
High Level Overview of Change
Implement native support for Price Oracles
Add a new ledger object: Oracle
Add two new transactions:
Add one new API
Context of Change
Notes for reviewers:
PriceOracle
: Price Oracle (XLS-47d) #4789. XLS-47d specificationType of Change
.gitignore
, formatting, dropping support for older tooling)API Impact
libxrpl
change (any change that may affectlibxrpl
or dependents oflibxrpl
)Test Plan
Added tests for the new features: