@@ -85,6 +85,24 @@ contract PythWormholeMerkleAccumulatorTest is
85
85
assertEq (emaPrice.publishTime, priceFeed.emaPrice.publishTime);
86
86
}
87
87
88
+ function assertPriceFeedEqual (
89
+ PythStructs.PriceFeed memory priceFeed1 ,
90
+ PythStructs.PriceFeed memory priceFeed2
91
+ ) internal {
92
+ assertEq (priceFeed1.id, priceFeed2.id);
93
+ assertEq (priceFeed1.price.price, priceFeed2.price.price);
94
+ assertEq (priceFeed1.price.conf, priceFeed2.price.conf);
95
+ assertEq (priceFeed1.price.expo, priceFeed2.price.expo);
96
+ assertEq (priceFeed1.price.publishTime, priceFeed2.price.publishTime);
97
+ assertEq (priceFeed1.emaPrice.price, priceFeed2.emaPrice.price);
98
+ assertEq (priceFeed1.emaPrice.conf, priceFeed2.emaPrice.conf);
99
+ assertEq (priceFeed1.emaPrice.expo, priceFeed2.emaPrice.expo);
100
+ assertEq (
101
+ priceFeed1.emaPrice.publishTime,
102
+ priceFeed2.emaPrice.publishTime
103
+ );
104
+ }
105
+
88
106
function generateRandomPriceFeedMessage (
89
107
uint numPriceFeeds
90
108
) internal returns (PriceFeedMessage[] memory priceFeedMessages ) {
@@ -120,6 +138,36 @@ contract PythWormholeMerkleAccumulatorTest is
120
138
updateFee = pyth.getUpdateFee (updateData);
121
139
}
122
140
141
+ /// @notice This method creates a forward compatible wormhole update data by using a newer minor version,
142
+ /// setting a trailing header size and generating additional trailing header data of size `trailingHeaderSize`
143
+ function createFowardCompatibleWormholeMerkleUpdateData (
144
+ PriceFeedMessage[] memory priceFeedMessages ,
145
+ uint8 minorVersion ,
146
+ uint8 trailingHeaderSize
147
+ ) internal returns (bytes [] memory updateData , uint updateFee ) {
148
+ updateData = new bytes [](1 );
149
+
150
+ uint8 depth = 0 ;
151
+ while ((1 << depth) < priceFeedMessages.length ) {
152
+ depth++ ;
153
+ }
154
+
155
+ depth += getRandUint8 () % 3 ;
156
+ bytes memory trailingHeaderData = new bytes (uint8 (0 ));
157
+ for (uint i = 0 ; i < trailingHeaderSize; i++ ) {
158
+ trailingHeaderData = abi.encodePacked (trailingHeaderData, uint8 (i));
159
+ }
160
+ updateData[0 ] = generateForwardCompatibleWhMerkleUpdate (
161
+ priceFeedMessages,
162
+ depth,
163
+ 1 ,
164
+ minorVersion,
165
+ trailingHeaderData
166
+ );
167
+
168
+ updateFee = pyth.getUpdateFee (updateData);
169
+ }
170
+
123
171
/// Testing update price feeds method using wormhole merkle update type.
124
172
function testUpdatePriceFeedWithWormholeMerkleWorks (uint seed ) public {
125
173
setRandSeed (seed);
@@ -947,6 +995,77 @@ contract PythWormholeMerkleAccumulatorTest is
947
995
assertEq (updateFee, SINGLE_UPDATE_FEE_IN_WEI * numPriceFeeds);
948
996
}
949
997
950
- //TODO: add some tests of forward compatibility.
951
- // I.e., create a message where each part that can be expanded in size is expanded and make sure that parsing still works
998
+ function testParsePriceFeedUpdatesWithWhMerkleUpdateWorksForForwardCompatibility ()
999
+ public
1000
+ {
1001
+ uint numPriceFeeds = (getRandUint () % 10 ) + 1 ;
1002
+ PriceFeedMessage[]
1003
+ memory priceFeedMessages = generateRandomPriceFeedMessage (
1004
+ numPriceFeeds
1005
+ );
1006
+ (
1007
+ bytes [] memory updateData ,
1008
+ uint updateFee
1009
+ ) = createWormholeMerkleUpdateData (priceFeedMessages);
1010
+
1011
+ bytes32 [] memory priceIds = new bytes32 [](numPriceFeeds);
1012
+ for (uint i = 0 ; i < numPriceFeeds; i++ ) {
1013
+ priceIds[i] = priceFeedMessages[i].priceId;
1014
+ }
1015
+ PythStructs.PriceFeed[] memory priceFeeds = pyth.parsePriceFeedUpdates {
1016
+ value: updateFee
1017
+ }(updateData, priceIds, 0 , MAX_UINT64);
1018
+ uint8 futureMinorVersion = uint8 (2 );
1019
+ uint8 futureTrailingHeaderSize = uint8 (20 );
1020
+ (
1021
+ bytes [] memory updateDataFromFuture ,
1022
+ uint updateFeeFromFuture
1023
+ ) = createFowardCompatibleWormholeMerkleUpdateData (
1024
+ priceFeedMessages,
1025
+ futureMinorVersion,
1026
+ futureTrailingHeaderSize
1027
+ );
1028
+
1029
+ PythStructs.PriceFeed[] memory priceFeedsFromFutureUpdateData = pyth
1030
+ .parsePriceFeedUpdates {value: updateFeeFromFuture}(
1031
+ updateDataFromFuture,
1032
+ priceIds,
1033
+ 0 ,
1034
+ MAX_UINT64
1035
+ );
1036
+ assertEq (updateFee, updateFeeFromFuture);
1037
+
1038
+ for (uint i = 0 ; i < priceFeeds.length ; i++ ) {
1039
+ assertPriceFeedEqual (
1040
+ priceFeeds[i],
1041
+ priceFeedsFromFutureUpdateData[i]
1042
+ );
1043
+ }
1044
+ }
1045
+
1046
+ function testUpdatePriceFeedUpdatesWithWhMerkleUpdateWorksForForwardCompatibility ()
1047
+ public
1048
+ {
1049
+ uint numPriceFeeds = (getRandUint () % 10 ) + 1 ;
1050
+ PriceFeedMessage[]
1051
+ memory priceFeedMessages = generateRandomPriceFeedMessage (
1052
+ numPriceFeeds
1053
+ );
1054
+ uint8 futureMinorVersion = uint8 (2 );
1055
+ uint8 futureTrailingHeaderSize = uint8 (20 );
1056
+ (
1057
+ bytes [] memory forwardCompatibleUpdateData ,
1058
+ uint updateFee
1059
+ ) = createFowardCompatibleWormholeMerkleUpdateData (
1060
+ priceFeedMessages,
1061
+ futureMinorVersion,
1062
+ futureTrailingHeaderSize
1063
+ );
1064
+
1065
+ pyth.updatePriceFeeds {value: updateFee}(forwardCompatibleUpdateData);
1066
+
1067
+ for (uint i = 0 ; i < priceFeedMessages.length ; i++ ) {
1068
+ assertPriceFeedMessageStored (priceFeedMessages[i]);
1069
+ }
1070
+ }
952
1071
}
0 commit comments