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);
|
PythInternalStructs.PriceInfo memory latestPrice = latestPriceInfo(attestation.priceId);
|
||||||
|
|
||||||
bool fresh = false;
|
bool fresh = false;
|
||||||
if(newPriceInfo.priceFeed.price.publishTime > latestPrice.priceFeed.price.publishTime) {
|
if(newPriceInfo.price.publishTime > latestPrice.price.publishTime) {
|
||||||
freshPrices += 1;
|
freshPrices += 1;
|
||||||
fresh = true;
|
fresh = true;
|
||||||
setLatestPriceInfo(attestation.priceId, newPriceInfo);
|
setLatestPriceInfo(attestation.priceId, newPriceInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit PriceFeedUpdate(attestation.priceId, fresh, vm.emitterChainId, vm.sequence, latestPrice.priceFeed.price.publishTime,
|
emit PriceFeedUpdate(attestation.priceId, fresh, vm.emitterChainId, vm.sequence, latestPrice.price.publishTime,
|
||||||
newPriceInfo.priceFeed.price.publishTime, newPriceInfo.priceFeed.price.price, newPriceInfo.priceFeed.price.conf);
|
newPriceInfo.price.publishTime, newPriceInfo.price.price, newPriceInfo.price.conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit BatchPriceFeedUpdate(vm.emitterChainId, vm.sequence, batch.attestations.length, freshPrices);
|
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;
|
return singleUpdateFeeInWei() * updateData.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNewPriceInfo(PythInternalStructs.PriceAttestation memory pa) private view returns (PythInternalStructs.PriceInfo memory info) {
|
function createNewPriceInfo(PythInternalStructs.PriceAttestation memory pa) private pure returns (PythInternalStructs.PriceInfo memory info) {
|
||||||
info.attestationTime = pa.attestationTime;
|
|
||||||
info.arrivalTime = block.timestamp;
|
|
||||||
info.arrivalBlock = block.number;
|
|
||||||
info.priceFeed.id = pa.priceId;
|
|
||||||
|
|
||||||
PythInternalStructs.PriceAttestationStatus status = PythInternalStructs.PriceAttestationStatus(pa.status);
|
PythInternalStructs.PriceAttestationStatus status = PythInternalStructs.PriceAttestationStatus(pa.status);
|
||||||
if (status == PythInternalStructs.PriceAttestationStatus.TRADING) {
|
if (status == PythInternalStructs.PriceAttestationStatus.TRADING) {
|
||||||
info.priceFeed.price.price = pa.price;
|
info.price.price = pa.price;
|
||||||
info.priceFeed.price.conf = pa.conf;
|
info.price.conf = pa.conf;
|
||||||
info.priceFeed.price.publishTime = pa.publishTime;
|
info.price.publishTime = pa.publishTime;
|
||||||
info.priceFeed.emaPrice.publishTime = pa.publishTime;
|
info.emaPrice.publishTime = pa.publishTime;
|
||||||
} else {
|
} else {
|
||||||
info.priceFeed.price.price = pa.prevPrice;
|
info.price.price = pa.prevPrice;
|
||||||
info.priceFeed.price.conf = pa.prevConf;
|
info.price.conf = pa.prevConf;
|
||||||
info.priceFeed.price.publishTime = pa.prevPublishTime;
|
info.price.publishTime = pa.prevPublishTime;
|
||||||
|
|
||||||
// The EMA is last updated when the aggregate had trading status,
|
// 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).
|
// 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.price.expo = pa.expo;
|
||||||
info.priceFeed.emaPrice.price = pa.emaPrice;
|
info.emaPrice.price = pa.emaPrice;
|
||||||
info.priceFeed.emaPrice.conf = pa.emaConf;
|
info.emaPrice.conf = pa.emaConf;
|
||||||
info.priceFeed.emaPrice.expo = pa.expo;
|
info.emaPrice.expo = pa.expo;
|
||||||
|
|
||||||
return info;
|
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){
|
function queryPriceFeed(bytes32 id) public view override returns (PythStructs.PriceFeed memory priceFeed){
|
||||||
// Look up the latest price info for the given ID
|
// Look up the latest price info for the given ID
|
||||||
PythInternalStructs.PriceInfo memory info = latestPriceInfo(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) {
|
function priceFeedExists(bytes32 id) public override view returns (bool) {
|
||||||
PythInternalStructs.PriceInfo memory info = latestPriceInfo(id);
|
PythInternalStructs.PriceInfo memory info = latestPriceInfo(id);
|
||||||
return (info.priceFeed.id != 0);
|
return (info.price.publishTime != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getValidTimePeriod() public override view returns (uint) {
|
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;
|
uint64 prevConf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct InternalPrice {
|
||||||
|
int64 price;
|
||||||
|
uint64 conf;
|
||||||
|
uint64 publishTime;
|
||||||
|
int32 expo;
|
||||||
|
}
|
||||||
|
|
||||||
struct PriceInfo {
|
struct PriceInfo {
|
||||||
uint256 attestationTime;
|
// slot 1
|
||||||
uint256 arrivalTime;
|
InternalPrice price;
|
||||||
uint256 arrivalBlock;
|
|
||||||
PythStructs.PriceFeed priceFeed;
|
// slot 2
|
||||||
|
InternalPrice emaPrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DataSource {
|
struct DataSource {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
pragma solidity ^0.8.0;
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
import "./PythInternalStructs.sol";
|
import "./PythInternalStructs.sol";
|
||||||
|
import "./PythDeprecatedStructs.sol";
|
||||||
|
|
||||||
contract PythStorage {
|
contract PythStorage {
|
||||||
struct State {
|
struct State {
|
||||||
|
@ -12,7 +13,7 @@ contract PythStorage {
|
||||||
bytes32 _deprecatedPyth2WormholeEmitter; // Ditto
|
bytes32 _deprecatedPyth2WormholeEmitter; // Ditto
|
||||||
|
|
||||||
// After a backward-incompatible change in PriceFeed this mapping got deprecated.
|
// 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
|
// For tracking all active emitter/chain ID pairs
|
||||||
PythInternalStructs.DataSource[] validDataSources;
|
PythInternalStructs.DataSource[] validDataSources;
|
||||||
|
@ -38,11 +39,15 @@ contract PythStorage {
|
||||||
|
|
||||||
// Mapping of cached price information
|
// Mapping of cached price information
|
||||||
// priceId => PriceInfo
|
// 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
|
// Index of the governance data source, increased each time the governance data source
|
||||||
// changes.
|
// changes.
|
||||||
uint32 governanceDataSourceIndex;
|
uint32 governanceDataSourceIndex;
|
||||||
|
|
||||||
|
// Mapping of cached price information
|
||||||
|
// priceId => PriceInfo
|
||||||
|
mapping(bytes32 => PythInternalStructs.PriceInfo) latestPriceInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue