@@ -80,7 +80,7 @@ abstract contract Pyth is
80
80
updateData[i].length > 4 &&
81
81
UnsafeBytesLib.toUint32 (updateData[i], 0 ) == ACCUMULATOR_MAGIC
82
82
) {
83
- updatePricesUsingAccumulator (updateData[i]);
83
+ updatePriceInfosFromAccumulatorUpdate (updateData[i]);
84
84
} else {
85
85
updatePriceBatchFromVm (updateData[i]);
86
86
}
@@ -432,84 +432,131 @@ abstract contract Pyth is
432
432
}
433
433
434
434
priceFeeds = new PythStructs.PriceFeed [](priceIds.length );
435
-
436
435
for (uint i = 0 ; i < updateData.length ; i++ ) {
437
- bytes memory encoded;
438
-
439
- {
440
- IWormhole.VM memory vm = parseAndVerifyBatchAttestationVM (
441
- updateData[i]
442
- );
443
- encoded = vm.payload;
444
- }
436
+ if (
437
+ updateData[i].length > 4 &&
438
+ UnsafeBytesLib.toUint32 (updateData[i], 0 ) ==
439
+ ACCUMULATOR_MAGIC
440
+ ) {
441
+ (
442
+ PythInternalStructs.PriceInfo[]
443
+ memory accumulatorPriceInfos ,
444
+ bytes32 [] memory accumulatorPriceIds
445
+ ) = extractPriceInfosFromAccumulatorUpdate (updateData[i]);
446
+
447
+ for (
448
+ uint accDataIdx = 0 ;
449
+ accDataIdx < accumulatorPriceIds.length ;
450
+ accDataIdx++
451
+ ) {
452
+ bytes32 accumulatorPriceId = accumulatorPriceIds[
453
+ accDataIdx
454
+ ];
455
+ // check whether caller requested for this data
456
+ uint k = findIndexOfPriceId (
457
+ priceIds,
458
+ accumulatorPriceId
459
+ );
445
460
446
- (
447
- uint index ,
448
- uint nAttestations ,
449
- uint attestationSize
450
- ) = parseBatchAttestationHeader (encoded);
451
-
452
- // Deserialize each attestation
453
- for (uint j = 0 ; j < nAttestations; j++ ) {
454
- // NOTE: We don't advance the global index immediately.
455
- // attestationIndex is an attestation-local offset used
456
- // for readability and easier debugging.
457
- uint attestationIndex = 0 ;
458
-
459
- // Unused bytes32 product id
460
- attestationIndex += 32 ;
461
-
462
- bytes32 priceId = UnsafeBytesLib.toBytes32 (
463
- encoded,
464
- index + attestationIndex
465
- );
461
+ // If priceFeed[k].id != 0 then it means that there was a valid
462
+ // update for priceIds[k] and we don't need to process this one.
463
+ if (k == priceIds.length || priceFeeds[k].id != 0 ) {
464
+ continue ;
465
+ }
466
466
467
- // Check whether the caller requested for this data.
468
- uint k = 0 ;
469
- for (; k < priceIds.length ; k++ ) {
470
- if (priceIds[k] == priceId) {
471
- break ;
467
+ PythInternalStructs.PriceInfo
468
+ memory info = accumulatorPriceInfos[accDataIdx];
469
+
470
+ uint publishTime = uint (info.publishTime);
471
+ // Check the publish time of the price is within the given range
472
+ // and only fill the priceFeedsInfo if it is.
473
+ // If is not, default id value of 0 will still be set and
474
+ // this will allow other updates for this price id to be processed.
475
+ if (
476
+ publishTime >= minPublishTime &&
477
+ publishTime <= maxPublishTime
478
+ ) {
479
+ fillPriceFeedFromPriceInfo (
480
+ priceFeeds,
481
+ k,
482
+ accumulatorPriceId,
483
+ info,
484
+ publishTime
485
+ );
472
486
}
473
487
}
474
-
475
- // If priceFeed[k].id != 0 then it means that there was a valid
476
- // update for priceIds[k] and we don't need to process this one.
477
- if (k == priceIds.length || priceFeeds[k].id != 0 ) {
478
- index += attestationSize;
479
- continue ;
488
+ } else {
489
+ bytes memory encoded;
490
+ {
491
+ IWormhole.VM
492
+ memory vm = parseAndVerifyBatchAttestationVM (
493
+ updateData[i]
494
+ );
495
+ encoded = vm.payload;
480
496
}
481
497
498
+ /** Batch price logic */
499
+ // TODO: gas optimization
482
500
(
483
- PythInternalStructs.PriceInfo memory info ,
484
-
485
- ) = parseSingleAttestationFromBatch (
501
+ uint index ,
502
+ uint nAttestations ,
503
+ uint attestationSize
504
+ ) = parseBatchAttestationHeader (encoded);
505
+
506
+ // Deserialize each attestation
507
+ for (uint j = 0 ; j < nAttestations; j++ ) {
508
+ // NOTE: We don't advance the global index immediately.
509
+ // attestationIndex is an attestation-local offset used
510
+ // for readability and easier debugging.
511
+ uint attestationIndex = 0 ;
512
+
513
+ // Unused bytes32 product id
514
+ attestationIndex += 32 ;
515
+
516
+ bytes32 priceId = UnsafeBytesLib.toBytes32 (
486
517
encoded,
487
- index,
488
- attestationSize
518
+ index + attestationIndex
489
519
);
490
520
491
- priceFeeds[k].id = priceId;
492
- priceFeeds[k].price.price = info.price;
493
- priceFeeds[k].price.conf = info.conf;
494
- priceFeeds[k].price.expo = info.expo;
495
- priceFeeds[k].price.publishTime = uint (info.publishTime);
496
- priceFeeds[k].emaPrice.price = info.emaPrice;
497
- priceFeeds[k].emaPrice.conf = info.emaConf;
498
- priceFeeds[k].emaPrice.expo = info.expo;
499
- priceFeeds[k].emaPrice.publishTime = uint (info.publishTime);
500
-
501
- // Check the publish time of the price is within the given range
502
- // if it is not, then set the id to 0 to indicate that this price id
503
- // still does not have a valid price feed. This will allow other updates
504
- // for this price id to be processed.
505
- if (
506
- priceFeeds[k].price.publishTime < minPublishTime ||
507
- priceFeeds[k].price.publishTime > maxPublishTime
508
- ) {
509
- priceFeeds[k].id = 0 ;
510
- }
521
+ // check whether caller requested for this data
522
+ uint k = findIndexOfPriceId (priceIds, priceId);
523
+
524
+ // If priceFeed[k].id != 0 then it means that there was a valid
525
+ // update for priceIds[k] and we don't need to process this one.
526
+ if (k == priceIds.length || priceFeeds[k].id != 0 ) {
527
+ index += attestationSize;
528
+ continue ;
529
+ }
530
+
531
+ (
532
+ PythInternalStructs.PriceInfo memory info ,
533
+
534
+ ) = parseSingleAttestationFromBatch (
535
+ encoded,
536
+ index,
537
+ attestationSize
538
+ );
539
+
540
+ uint publishTime = uint (info.publishTime);
541
+ // Check the publish time of the price is within the given range
542
+ // and only fill the priceFeedsInfo if it is.
543
+ // If is not, default id value of 0 will still be set and
544
+ // this will allow other updates for this price id to be processed.
545
+ if (
546
+ publishTime >= minPublishTime &&
547
+ publishTime <= maxPublishTime
548
+ ) {
549
+ fillPriceFeedFromPriceInfo (
550
+ priceFeeds,
551
+ k,
552
+ priceId,
553
+ info,
554
+ publishTime
555
+ );
556
+ }
511
557
512
- index += attestationSize;
558
+ index += attestationSize;
559
+ }
513
560
}
514
561
}
515
562
@@ -521,6 +568,38 @@ abstract contract Pyth is
521
568
}
522
569
}
523
570
571
+ function findIndexOfPriceId (
572
+ bytes32 [] calldata priceIds ,
573
+ bytes32 targetPriceId
574
+ ) private pure returns (uint index ) {
575
+ uint k = 0 ;
576
+ uint len = priceIds.length ;
577
+ for (; k < len; k++ ) {
578
+ if (priceIds[k] == targetPriceId) {
579
+ break ;
580
+ }
581
+ }
582
+ return k;
583
+ }
584
+
585
+ function fillPriceFeedFromPriceInfo (
586
+ PythStructs.PriceFeed[] memory priceFeeds ,
587
+ uint k ,
588
+ bytes32 priceId ,
589
+ PythInternalStructs.PriceInfo memory info ,
590
+ uint publishTime
591
+ ) private pure {
592
+ priceFeeds[k].id = priceId;
593
+ priceFeeds[k].price.price = info.price;
594
+ priceFeeds[k].price.conf = info.conf;
595
+ priceFeeds[k].price.expo = info.expo;
596
+ priceFeeds[k].price.publishTime = publishTime;
597
+ priceFeeds[k].emaPrice.price = info.emaPrice;
598
+ priceFeeds[k].emaPrice.conf = info.emaConf;
599
+ priceFeeds[k].emaPrice.expo = info.expo;
600
+ priceFeeds[k].emaPrice.publishTime = publishTime;
601
+ }
602
+
524
603
function queryPriceFeed (
525
604
bytes32 id
526
605
) public view override returns (PythStructs.PriceFeed memory priceFeed ) {
0 commit comments