Modify PriceInfo struct for gas optimization (#373)
This PR removes unneeded PriceInfo fields and rearranges the struct in a way that it takes less storage.
This commit is contained in:
parent
61b84c84ac
commit
61651a10f2
|
@ -41,14 +41,14 @@ abstract contract Pyth is PythGetters, PythSetters, AbstractPyth {
|
|||
PythInternalStructs.PriceInfo memory latestPrice = latestPriceInfo(attestation.priceId);
|
||||
|
||||
bool fresh = false;
|
||||
if(newPriceInfo.priceFeed.price.publishTime > latestPrice.priceFeed.price.publishTime) {
|
||||
if(newPriceInfo.price.publishTime > latestPrice.price.publishTime) {
|
||||
freshPrices += 1;
|
||||
fresh = true;
|
||||
setLatestPriceInfo(attestation.priceId, newPriceInfo);
|
||||
}
|
||||
|
||||
emit PriceFeedUpdate(attestation.priceId, fresh, vm.emitterChainId, vm.sequence, latestPrice.priceFeed.price.publishTime,
|
||||
newPriceInfo.priceFeed.price.publishTime, newPriceInfo.priceFeed.price.price, newPriceInfo.priceFeed.price.conf);
|
||||
emit PriceFeedUpdate(attestation.priceId, fresh, vm.emitterChainId, vm.sequence, latestPrice.price.publishTime,
|
||||
newPriceInfo.price.publishTime, newPriceInfo.price.price, newPriceInfo.price.conf);
|
||||
}
|
||||
|
||||
emit BatchPriceFeedUpdate(vm.emitterChainId, vm.sequence, batch.attestations.length, freshPrices);
|
||||
|
@ -76,32 +76,27 @@ abstract contract Pyth is PythGetters, PythSetters, AbstractPyth {
|
|||
return singleUpdateFeeInWei() * updateData.length;
|
||||
}
|
||||
|
||||
function createNewPriceInfo(PythInternalStructs.PriceAttestation memory pa) private view returns (PythInternalStructs.PriceInfo memory info) {
|
||||
info.attestationTime = pa.attestationTime;
|
||||
info.arrivalTime = block.timestamp;
|
||||
info.arrivalBlock = block.number;
|
||||
info.priceFeed.id = pa.priceId;
|
||||
|
||||
function createNewPriceInfo(PythInternalStructs.PriceAttestation memory pa) private pure returns (PythInternalStructs.PriceInfo memory info) {
|
||||
PythInternalStructs.PriceAttestationStatus status = PythInternalStructs.PriceAttestationStatus(pa.status);
|
||||
if (status == PythInternalStructs.PriceAttestationStatus.TRADING) {
|
||||
info.priceFeed.price.price = pa.price;
|
||||
info.priceFeed.price.conf = pa.conf;
|
||||
info.priceFeed.price.publishTime = pa.publishTime;
|
||||
info.priceFeed.emaPrice.publishTime = pa.publishTime;
|
||||
info.price.price = pa.price;
|
||||
info.price.conf = pa.conf;
|
||||
info.price.publishTime = pa.publishTime;
|
||||
info.emaPrice.publishTime = pa.publishTime;
|
||||
} else {
|
||||
info.priceFeed.price.price = pa.prevPrice;
|
||||
info.priceFeed.price.conf = pa.prevConf;
|
||||
info.priceFeed.price.publishTime = pa.prevPublishTime;
|
||||
info.price.price = pa.prevPrice;
|
||||
info.price.conf = pa.prevConf;
|
||||
info.price.publishTime = pa.prevPublishTime;
|
||||
|
||||
// The EMA is last updated when the aggregate had trading status,
|
||||
// so, we use prev_publish_time (the time when the aggregate last had trading status).
|
||||
info.priceFeed.emaPrice.publishTime = pa.prevPublishTime;
|
||||
info.emaPrice.publishTime = pa.prevPublishTime;
|
||||
}
|
||||
|
||||
info.priceFeed.price.expo = pa.expo;
|
||||
info.priceFeed.emaPrice.price = pa.emaPrice;
|
||||
info.priceFeed.emaPrice.conf = pa.emaConf;
|
||||
info.priceFeed.emaPrice.expo = pa.expo;
|
||||
info.price.expo = pa.expo;
|
||||
info.emaPrice.price = pa.emaPrice;
|
||||
info.emaPrice.conf = pa.emaConf;
|
||||
info.emaPrice.expo = pa.expo;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
@ -226,14 +221,23 @@ abstract contract Pyth is PythGetters, PythSetters, AbstractPyth {
|
|||
function queryPriceFeed(bytes32 id) public view override returns (PythStructs.PriceFeed memory priceFeed){
|
||||
// Look up the latest price info for the given ID
|
||||
PythInternalStructs.PriceInfo memory info = latestPriceInfo(id);
|
||||
require(info.priceFeed.id != 0, "price feed for the given id is not pushed or does not exist");
|
||||
require(info.price.publishTime != 0, "price feed for the given id is not pushed or does not exist");
|
||||
|
||||
return info.priceFeed;
|
||||
priceFeed.id = id;
|
||||
priceFeed.price.price = info.price.price;
|
||||
priceFeed.price.conf = info.price.conf;
|
||||
priceFeed.price.expo = info.price.expo;
|
||||
priceFeed.price.publishTime = uint(info.price.publishTime);
|
||||
|
||||
priceFeed.emaPrice.price = info.emaPrice.price;
|
||||
priceFeed.emaPrice.conf = info.emaPrice.conf;
|
||||
priceFeed.emaPrice.expo = info.emaPrice.expo;
|
||||
priceFeed.emaPrice.publishTime = uint(info.emaPrice.publishTime);
|
||||
}
|
||||
|
||||
function priceFeedExists(bytes32 id) public override view returns (bool) {
|
||||
PythInternalStructs.PriceInfo memory info = latestPriceInfo(id);
|
||||
return (info.priceFeed.id != 0);
|
||||
return (info.price.publishTime != 0);
|
||||
}
|
||||
|
||||
function getValidTimePeriod() public override view returns (uint) {
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
|
||||
// contracts/PythDeprecatedStructs.sol
|
||||
// SPDX-License-Identifier: Apache 2
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
// This contract contains self contained structs of all our deprecated structs.
|
||||
// When deprecating the structs, make sure that there be no dependency to
|
||||
// the sdk as the sdk might change.
|
||||
//
|
||||
// By storing these structs, we keep deprecated fields definitions correctly. Then,
|
||||
// in the future, we can use them to cleanup their storage and redeem some gas back.
|
||||
contract PythDeprecatedStructs {
|
||||
// Structs related to the _deprecatedLatestPriceInfoV1
|
||||
enum DeprecatedPriceStatusV1 {
|
||||
UNKNOWN,
|
||||
TRADING,
|
||||
HALTED,
|
||||
AUCTION
|
||||
}
|
||||
|
||||
struct DeprecatedPriceFeedV1 {
|
||||
// The price ID.
|
||||
bytes32 id;
|
||||
// Product account key.
|
||||
bytes32 productId;
|
||||
// The current price.
|
||||
int64 price;
|
||||
// Confidence interval around the price.
|
||||
uint64 conf;
|
||||
// Price exponent.
|
||||
int32 expo;
|
||||
// Status of price.
|
||||
DeprecatedPriceStatusV1 status;
|
||||
// Maximum number of allowed publishers that can contribute to a price.
|
||||
uint32 maxNumPublishers;
|
||||
// Number of publishers that made up current aggregate.
|
||||
uint32 numPublishers;
|
||||
// Exponentially moving average price.
|
||||
int64 emaPrice;
|
||||
// Exponentially moving average confidence interval.
|
||||
uint64 emaConf;
|
||||
// Unix timestamp describing when the price was published
|
||||
uint64 publishTime;
|
||||
// Price of previous price with TRADING status
|
||||
int64 prevPrice;
|
||||
// Confidence interval of previous price with TRADING status
|
||||
uint64 prevConf;
|
||||
// Unix timestamp describing when the previous price with TRADING status was published
|
||||
uint64 prevPublishTime;
|
||||
}
|
||||
|
||||
struct DeprecatedPriceInfoV1 {
|
||||
uint256 attestationTime;
|
||||
uint256 arrivalTime;
|
||||
uint256 arrivalBlock;
|
||||
DeprecatedPriceFeedV1 priceFeed;
|
||||
}
|
||||
|
||||
// Structs related to the _deprecatedLatestPriceInfoV2
|
||||
struct DeprecatedPriceV2 {
|
||||
// Price
|
||||
int64 price;
|
||||
// Confidence interval around the price
|
||||
uint64 conf;
|
||||
// Price exponent
|
||||
int32 expo;
|
||||
// Unix timestamp describing when the price was published
|
||||
uint publishTime;
|
||||
}
|
||||
|
||||
// PriceFeed represents a current aggregate price from pyth publisher feeds.
|
||||
struct DeprecatedPriceFeedV2 {
|
||||
// The price ID.
|
||||
bytes32 id;
|
||||
// Latest available price
|
||||
DeprecatedPriceV2 price;
|
||||
// Latest available exponentially-weighted moving average price
|
||||
DeprecatedPriceV2 emaPrice;
|
||||
}
|
||||
|
||||
|
||||
struct DeprecatedPriceInfoV2 {
|
||||
uint256 attestationTime;
|
||||
uint256 arrivalTime;
|
||||
uint256 arrivalBlock;
|
||||
DeprecatedPriceFeedV2 priceFeed;
|
||||
}
|
||||
}
|
|
@ -43,11 +43,19 @@ contract PythInternalStructs {
|
|||
uint64 prevConf;
|
||||
}
|
||||
|
||||
struct InternalPrice {
|
||||
int64 price;
|
||||
uint64 conf;
|
||||
uint64 publishTime;
|
||||
int32 expo;
|
||||
}
|
||||
|
||||
struct PriceInfo {
|
||||
uint256 attestationTime;
|
||||
uint256 arrivalTime;
|
||||
uint256 arrivalBlock;
|
||||
PythStructs.PriceFeed priceFeed;
|
||||
// slot 1
|
||||
InternalPrice price;
|
||||
|
||||
// slot 2
|
||||
InternalPrice emaPrice;
|
||||
}
|
||||
|
||||
struct DataSource {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
pragma solidity ^0.8.0;
|
||||
|
||||
import "./PythInternalStructs.sol";
|
||||
import "./PythDeprecatedStructs.sol";
|
||||
|
||||
contract PythStorage {
|
||||
struct State {
|
||||
|
@ -12,7 +13,7 @@ contract PythStorage {
|
|||
bytes32 _deprecatedPyth2WormholeEmitter; // Ditto
|
||||
|
||||
// After a backward-incompatible change in PriceFeed this mapping got deprecated.
|
||||
mapping(bytes32 => PythInternalStructs.PriceInfo) _deprecatedLatestPriceInfo;
|
||||
mapping(bytes32 => PythDeprecatedStructs.DeprecatedPriceInfoV1) _deprecatedLatestPriceInfoV1;
|
||||
|
||||
// For tracking all active emitter/chain ID pairs
|
||||
PythInternalStructs.DataSource[] validDataSources;
|
||||
|
@ -38,11 +39,15 @@ contract PythStorage {
|
|||
|
||||
// Mapping of cached price information
|
||||
// priceId => PriceInfo
|
||||
mapping(bytes32 => PythInternalStructs.PriceInfo) latestPriceInfo;
|
||||
mapping(bytes32 => PythDeprecatedStructs.DeprecatedPriceInfoV2) _deprecatedLatestPriceInfoV2;
|
||||
|
||||
// Index of the governance data source, increased each time the governance data source
|
||||
// changes.
|
||||
uint32 governanceDataSourceIndex;
|
||||
|
||||
// Mapping of cached price information
|
||||
// priceId => PriceInfo
|
||||
mapping(bytes32 => PythInternalStructs.PriceInfo) latestPriceInfo;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue