Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 67 additions & 42 deletions target_chains/ethereum/contracts/contracts/pyth/Pyth.sol
Original file line number Diff line number Diff line change
Expand Up @@ -438,53 +438,79 @@ abstract contract Pyth is
UnsafeBytesLib.toUint32(updateData[i], 0) ==
ACCUMULATOR_MAGIC
) {
(
PythInternalStructs.PriceInfo[]
memory accumulatorPriceInfos,
bytes32[] memory accumulatorPriceIds
) = extractPriceInfosFromAccumulatorUpdate(updateData[i]);

for (
uint accDataIdx = 0;
accDataIdx < accumulatorPriceIds.length;
accDataIdx++
) {
bytes32 accumulatorPriceId = accumulatorPriceIds[
accDataIdx
];
// check whether caller requested for this data
uint k = findIndexOfPriceId(
priceIds,
accumulatorPriceId
bytes memory accumulatorUpdate = updateData[i];
uint offset;
{
UpdateType updateType;
(
offset,
updateType
) = extractUpdateTypeFromAccumulatorHeader(
accumulatorUpdate
);

// If priceFeed[k].id != 0 then it means that there was a valid
// update for priceIds[k] and we don't need to process this one.
if (k == priceIds.length || priceFeeds[k].id != 0) {
continue;
if (updateType != UpdateType.WormholeMerkle) {
revert PythErrors.InvalidUpdateData();
}
}
bytes20 digest;
uint8 numUpdates;
bytes memory encoded = UnsafeBytesLib.slice(
accumulatorUpdate,
offset,
accumulatorUpdate.length - offset
);

PythInternalStructs.PriceInfo
memory info = accumulatorPriceInfos[accDataIdx];
(
offset,
digest,
numUpdates
) = extractWormholeMerkleHeaderDigestAndNumUpdates(encoded);

uint publishTime = uint(info.publishTime);
// Check the publish time of the price is within the given range
// and only fill the priceFeedsInfo if it is.
// If is not, default id value of 0 will still be set and
// this will allow other updates for this price id to be processed.
if (
publishTime >= minPublishTime &&
publishTime <= maxPublishTime
) {
fillPriceFeedFromPriceInfo(
priceFeeds,
k,
accumulatorPriceId,
info,
publishTime
);
for (uint j = 0; j < numUpdates; j++) {
PythInternalStructs.PriceInfo memory info;
bytes32 priceId;

(
offset,
info,
priceId
) = extractPriceInfoFromMerkleProof(
digest,
encoded,
offset
);
{
// check whether caller requested for this data
uint k = findIndexOfPriceId(priceIds, priceId);

// If priceFeed[k].id != 0 then it means that there was a valid
// update for priceIds[k] and we don't need to process this one.
if (k == priceIds.length || priceFeeds[k].id != 0) {
continue;
}

uint publishTime = uint(info.publishTime);
// Check the publish time of the price is within the given range
// and only fill the priceFeedsInfo if it is.
// If is not, default id value of 0 will still be set and
// this will allow other updates for this price id to be processed.
if (
publishTime >= minPublishTime &&
publishTime <= maxPublishTime
) {
fillPriceFeedFromPriceInfo(
priceFeeds,
k,
priceId,
info,
publishTime
);
}
}
}
if (offset != encoded.length)
revert PythErrors.InvalidUpdateData();
} else {
bytes memory encoded;
{
Expand Down Expand Up @@ -573,8 +599,7 @@ abstract contract Pyth is
bytes32 targetPriceId
) private pure returns (uint index) {
uint k = 0;
uint len = priceIds.length;
for (; k < len; k++) {
for (; k < priceIds.length; k++) {
if (priceIds[k] == targetPriceId) {
break;
}
Expand Down
126 changes: 22 additions & 104 deletions target_chains/ethereum/contracts/contracts/pyth/PythAccumulator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,33 +42,6 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
revert PythErrors.InvalidUpdateDataSource();
}

function extractPriceInfosFromAccumulatorUpdate(
bytes memory accumulatorUpdate
)
internal
view
returns (
PythInternalStructs.PriceInfo[] memory priceInfos,
bytes32[] memory priceIds
)
{
(
uint offset,
UpdateType updateType
) = extractUpdateTypeFromAccumulatorHeader(accumulatorUpdate);

if (updateType != UpdateType.WormholeMerkle) {
revert PythErrors.InvalidUpdateData();
}
(priceInfos, priceIds) = extractPriceInfosFromWormholeMerkle(
UnsafeBytesLib.slice(
accumulatorUpdate,
offset,
accumulatorUpdate.length - offset
)
);
}

function extractUpdateTypeFromAccumulatorHeader(
bytes memory accumulatorUpdate
) internal pure returns (uint offset, UpdateType updateType) {
Expand Down Expand Up @@ -134,37 +107,6 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
}
}

function extractPriceInfosFromWormholeMerkle(
bytes memory encoded
)
internal
view
returns (
PythInternalStructs.PriceInfo[] memory priceInfos,
bytes32[] memory priceIds
)
{
unchecked {
(
uint offset,
bytes20 digest,
uint8 numUpdates
) = extractWormholeMerkleHeaderDigestAndNumUpdates(encoded);

priceInfos = new PythInternalStructs.PriceInfo[](numUpdates);
priceIds = new bytes32[](numUpdates);
for (uint i = 0; i < numUpdates; i++) {
(
offset,
priceInfos[i],
priceIds[i]
) = extractPriceFeedFromMerkleProof(digest, encoded, offset);
}

if (offset != encoded.length) revert PythErrors.InvalidUpdateData();
}
}

function extractWormholeMerkleHeaderDigestAndNumUpdates(
bytes memory encoded
) internal view returns (uint offset, bytes20 digest, uint8 numUpdates) {
Expand Down Expand Up @@ -228,12 +170,12 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
}
}

function extractPriceFeedFromMerkleProof(
function extractPriceInfoFromMerkleProof(
bytes20 digest,
bytes memory encoded,
uint offset
)
private
internal
pure
returns (
uint endOffset,
Expand All @@ -249,7 +191,9 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
digest
);

(priceInfo, priceId) = extractPriceFeedMessage(encodedMessage);
(priceInfo, priceId) = extractPriceInfoAndIdFromPriceFeedMessage(
encodedMessage
);

return (endOffset, priceInfo, priceId);
}
Expand Down Expand Up @@ -284,15 +228,17 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
}
}

function extractPriceFeedMessage(
function extractPriceInfoAndIdFromPriceFeedMessage(
bytes memory encodedMessage
)
private
pure
returns (PythInternalStructs.PriceInfo memory info, bytes32 priceId)
{
unchecked {
MessageType messageType = getMessageType(encodedMessage);
MessageType messageType = MessageType(
UnsafeBytesLib.toUint8(encodedMessage, 0)
);
if (messageType == MessageType.PriceFeed) {
(info, priceId) = parsePriceFeedMessage(
UnsafeBytesLib.slice(
Expand All @@ -307,12 +253,6 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
}
}

function getMessageType(
bytes memory encodedMessage
) private pure returns (MessageType messageType) {
return MessageType(UnsafeBytesLib.toUint8(encodedMessage, 0));
}

function parsePriceFeedMessage(
bytes memory encodedPriceFeed
)
Expand Down Expand Up @@ -402,47 +342,25 @@ abstract contract PythAccumulator is PythGetters, PythSetters, AbstractPyth {
) = extractWormholeMerkleHeaderDigestAndNumUpdates(encoded);

for (uint i = 0; i < numUpdates; i++) {
offset = verifyAndUpdatePriceFeedFromMerkleProof(
PythInternalStructs.PriceInfo memory priceInfo;
bytes32 priceId;
(offset, priceInfo, priceId) = extractPriceInfoFromMerkleProof(
digest,
encoded,
offset
);
uint64 latestPublishTime = latestPriceInfoPublishTime(priceId);
if (priceInfo.publishTime > latestPublishTime) {
setLatestPriceInfo(priceId, priceInfo);
emit PriceFeedUpdate(
priceId,
priceInfo.publishTime,
priceInfo.price,
priceInfo.conf
);
}
}

if (offset != encoded.length) revert PythErrors.InvalidUpdateData();
}
}

function verifyAndUpdatePriceFeedFromMerkleProof(
bytes20 digest,
bytes memory encoded,
uint offset
) private returns (uint endOffset) {
PythInternalStructs.PriceInfo memory priceInfo;
bytes32 priceId;
(offset, priceInfo, priceId) = extractPriceFeedFromMerkleProof(
digest,
encoded,
offset
);
processMessage(priceInfo, priceId);

return offset;
}

function processMessage(
PythInternalStructs.PriceInfo memory info,
bytes32 priceId
) private {
uint64 latestPublishTime = latestPriceInfoPublishTime(priceId);
if (info.publishTime > latestPublishTime) {
setLatestPriceInfo(priceId, info);
emit PriceFeedUpdate(
priceId,
info.publishTime,
info.price,
info.conf
);
}
}
}
Loading