From 946f79f0e3e3ea80269ee8dda8edf9bcc3274d31 Mon Sep 17 00:00:00 2001 From: pascal Date: Thu, 28 Sep 2023 16:56:38 +0200 Subject: [PATCH 1/2] scribe: Adds deprecated Chainlink::latestAnswer() function --- .gas-snapshot | 116 ++++++++++++++++++++------------------- src/IScribe.sol | 7 +++ src/Scribe.sol | 7 +++ src/ScribeOptimistic.sol | 14 +++++ test/IScribeTest.sol | 14 +++++ 5 files changed, 101 insertions(+), 57 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 0ba2410..9fd277d 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -10,66 +10,68 @@ ScribeInvariantTest:invariant_pubKeys_AtIndexZeroIsZeroPoint() (runs: 256, calls ScribeInvariantTest:invariant_pubKeys_LengthIsStrictlyMonotonicallyIncreasing() (runs: 256, calls: 3840, reverts: 0) ScribeInvariantTest:invariant_pubKeys_NonZeroPubKeyExistsAtMostOnce() (runs: 256, calls: 3840, reverts: 0) ScribeInvariantTest:invariant_pubKeys_ZeroPointIsNeverAddedAsPubKey() (runs: 256, calls: 3840, reverts: 0) -ScribeOptimisticTest:test_Deployment() (gas: 56925) -ScribeOptimisticTest:test_afterAuthedAction_1_drop() (gas: 248716) -ScribeOptimisticTest:test_afterAuthedAction_1_setBar() (gas: 295527) -ScribeOptimisticTest:test_afterAuthedAction_1_setChallengePeriod() (gas: 294070) -ScribeOptimisticTest:test_afterAuthedAction_2_drop() (gas: 325609) -ScribeOptimisticTest:test_afterAuthedAction_2_setBar() (gas: 384647) -ScribeOptimisticTest:test_afterAuthedAction_2_setChallengePeriod() (gas: 384247) -ScribeOptimisticTest:test_afterAuthedAction_3_drop() (gas: 251331) -ScribeOptimisticTest:test_afterAuthedAction_3_setBar() (gas: 298667) -ScribeOptimisticTest:test_afterAuthedAction_3_setChallengePeriod() (gas: 298140) -ScribeOptimisticTest:test_afterAuthedAction_4_drop() (gas: 327074) -ScribeOptimisticTest:test_afterAuthedAction_4_setBar() (gas: 385846) -ScribeOptimisticTest:test_afterAuthedAction_4_setChallengePeriod() (gas: 384610) +ScribeOptimisticTest:test_Deployment() (gas: 59359) +ScribeOptimisticTest:test_afterAuthedAction_1_drop() (gas: 248804) +ScribeOptimisticTest:test_afterAuthedAction_1_setBar() (gas: 295659) +ScribeOptimisticTest:test_afterAuthedAction_1_setChallengePeriod() (gas: 294180) +ScribeOptimisticTest:test_afterAuthedAction_2_drop() (gas: 325741) +ScribeOptimisticTest:test_afterAuthedAction_2_setBar() (gas: 384823) +ScribeOptimisticTest:test_afterAuthedAction_2_setChallengePeriod() (gas: 384423) +ScribeOptimisticTest:test_afterAuthedAction_3_drop() (gas: 251454) +ScribeOptimisticTest:test_afterAuthedAction_3_setBar() (gas: 298843) +ScribeOptimisticTest:test_afterAuthedAction_3_setChallengePeriod() (gas: 298316) +ScribeOptimisticTest:test_afterAuthedAction_4_drop() (gas: 327250) +ScribeOptimisticTest:test_afterAuthedAction_4_setBar() (gas: 386044) +ScribeOptimisticTest:test_afterAuthedAction_4_setChallengePeriod() (gas: 384786) ScribeOptimisticTest:test_drop_IndexZero() (gas: 44243) -ScribeOptimisticTest:test_drop_Multiple_IsAuthProtected() (gas: 14726) -ScribeOptimisticTest:test_drop_Single_IsAuthProtected() (gas: 12760) -ScribeOptimisticTest:test_latestRoundData_isTollProtected() (gas: 13986) -ScribeOptimisticTest:test_lift_Multiple_FailsIf_ECDSADataInvalid() (gas: 106951) -ScribeOptimisticTest:test_lift_Multiple_FailsIf_MaxFeedsReached() (gas: 20286905) -ScribeOptimisticTest:test_lift_Multiple_IsAuthProtected() (gas: 16446) -ScribeOptimisticTest:test_lift_Single_FailsIf_ECDSADataInvalid() (gas: 22113) -ScribeOptimisticTest:test_lift_Single_FailsIf_MaxFeedsReached() (gas: 19731467) +ScribeOptimisticTest:test_drop_Multiple_IsAuthProtected() (gas: 14770) +ScribeOptimisticTest:test_drop_Single_IsAuthProtected() (gas: 12782) +ScribeOptimisticTest:test_latestAnswer_isTollProtected() (gas: 12505) +ScribeOptimisticTest:test_latestRoundData_isTollProtected() (gas: 14030) +ScribeOptimisticTest:test_lift_Multiple_FailsIf_ECDSADataInvalid() (gas: 106973) +ScribeOptimisticTest:test_lift_Multiple_FailsIf_MaxFeedsReached() (gas: 20286949) +ScribeOptimisticTest:test_lift_Multiple_IsAuthProtected() (gas: 16490) +ScribeOptimisticTest:test_lift_Single_FailsIf_ECDSADataInvalid() (gas: 22135) +ScribeOptimisticTest:test_lift_Single_FailsIf_MaxFeedsReached() (gas: 19731489) ScribeOptimisticTest:test_lift_Single_IsAuthProtected() (gas: 12905) -ScribeOptimisticTest:test_opChallenge_FailsIf_CalledSubsequently() (gas: 311597) -ScribeOptimisticTest:test_opChallenge_FailsIf_InvalidSchnorrDataGiven() (gas: 283188) -ScribeOptimisticTest:test_opChallenge_FailsIf_NoOpPokeToChallenge() (gas: 14853) -ScribeOptimisticTest:test_peek_isTollProtected() (gas: 12826) -ScribeOptimisticTest:test_peep_isTollProtected() (gas: 13178) -ScribeOptimisticTest:test_poke_Initial_FailsIf_AgeIsZero() (gas: 242731) +ScribeOptimisticTest:test_opChallenge_FailsIf_CalledSubsequently() (gas: 311729) +ScribeOptimisticTest:test_opChallenge_FailsIf_InvalidSchnorrDataGiven() (gas: 283298) +ScribeOptimisticTest:test_opChallenge_FailsIf_NoOpPokeToChallenge() (gas: 14897) +ScribeOptimisticTest:test_peek_isTollProtected() (gas: 12870) +ScribeOptimisticTest:test_peep_isTollProtected() (gas: 13200) +ScribeOptimisticTest:test_poke_Initial_FailsIf_AgeIsZero() (gas: 242775) ScribeOptimisticTest:test_readWithAge_isTollProtected() (gas: 12357) -ScribeOptimisticTest:test_read_isTollProtected() (gas: 11801) -ScribeOptimisticTest:test_setBar_FailsIf_BarIsZero() (gas: 11771) -ScribeOptimisticTest:test_setBar_IsAuthProtected() (gas: 13686) -ScribeOptimisticTest:test_setMaxChallengeReward_IsAuthProtected() (gas: 13686) -ScribeOptimisticTest:test_setOpChallengePeriod_DropsFinalizedOpPoke_If_NonFinalizedAfterUpdate() (gas: 299610) -ScribeOptimisticTest:test_setOpChallengePeriod_FailsIf_OpChallengePeriodIsZero() (gas: 11545) -ScribeOptimisticTest:test_setOpChallengePeriod_IsAuthProtected() (gas: 12310) -ScribeOptimisticTest:test_toll_diss_IsAuthProtected() (gas: 13216) -ScribeOptimisticTest:test_toll_kiss_IsAuthProtected() (gas: 12397) -ScribeOptimisticTest:test_tryReadWithAge_isTollProtected() (gas: 13702) -ScribeOptimisticTest:test_tryRead_isTollProtected() (gas: 12964) -ScribeTest:test_Deployment() (gas: 40852) +ScribeOptimisticTest:test_read_isTollProtected() (gas: 11823) +ScribeOptimisticTest:test_setBar_FailsIf_BarIsZero() (gas: 11793) +ScribeOptimisticTest:test_setBar_IsAuthProtected() (gas: 13730) +ScribeOptimisticTest:test_setMaxChallengeReward_IsAuthProtected() (gas: 13730) +ScribeOptimisticTest:test_setOpChallengePeriod_DropsFinalizedOpPoke_If_NonFinalizedAfterUpdate() (gas: 299764) +ScribeOptimisticTest:test_setOpChallengePeriod_FailsIf_OpChallengePeriodIsZero() (gas: 11567) +ScribeOptimisticTest:test_setOpChallengePeriod_IsAuthProtected() (gas: 12332) +ScribeOptimisticTest:test_toll_diss_IsAuthProtected() (gas: 13260) +ScribeOptimisticTest:test_toll_kiss_IsAuthProtected() (gas: 12419) +ScribeOptimisticTest:test_tryReadWithAge_isTollProtected() (gas: 13746) +ScribeOptimisticTest:test_tryRead_isTollProtected() (gas: 12986) +ScribeTest:test_Deployment() (gas: 42326) ScribeTest:test_drop_IndexZero() (gas: 16904) -ScribeTest:test_drop_Multiple_IsAuthProtected() (gas: 13750) -ScribeTest:test_drop_Single_IsAuthProtected() (gas: 12126) -ScribeTest:test_latestRoundData_isTollProtected() (gas: 13088) -ScribeTest:test_lift_Multiple_FailsIf_ECDSADataInvalid() (gas: 106604) -ScribeTest:test_lift_Multiple_FailsIf_MaxFeedsReached() (gas: 20286231) -ScribeTest:test_lift_Multiple_IsAuthProtected() (gas: 15561) -ScribeTest:test_lift_Single_FailsIf_ECDSADataInvalid() (gas: 21415) -ScribeTest:test_lift_Single_FailsIf_MaxFeedsReached() (gas: 19732296) +ScribeTest:test_drop_Multiple_IsAuthProtected() (gas: 13794) +ScribeTest:test_drop_Single_IsAuthProtected() (gas: 12148) +ScribeTest:test_latestAnswer_isTollProtected() (gas: 12092) +ScribeTest:test_latestRoundData_isTollProtected() (gas: 13132) +ScribeTest:test_lift_Multiple_FailsIf_ECDSADataInvalid() (gas: 106626) +ScribeTest:test_lift_Multiple_FailsIf_MaxFeedsReached() (gas: 20286275) +ScribeTest:test_lift_Multiple_IsAuthProtected() (gas: 15605) +ScribeTest:test_lift_Single_FailsIf_ECDSADataInvalid() (gas: 21437) +ScribeTest:test_lift_Single_FailsIf_MaxFeedsReached() (gas: 19732318) ScribeTest:test_lift_Single_IsAuthProtected() (gas: 12535) -ScribeTest:test_peek_isTollProtected() (gas: 12329) -ScribeTest:test_peep_isTollProtected() (gas: 12439) -ScribeTest:test_poke_Initial_FailsIf_AgeIsZero() (gas: 239291) +ScribeTest:test_peek_isTollProtected() (gas: 12373) +ScribeTest:test_peep_isTollProtected() (gas: 12461) +ScribeTest:test_poke_Initial_FailsIf_AgeIsZero() (gas: 239335) ScribeTest:test_readWithAge_isTollProtected() (gas: 11969) -ScribeTest:test_read_isTollProtected() (gas: 11673) -ScribeTest:test_setBar_FailsIf_BarIsZero() (gas: 11370) -ScribeTest:test_setBar_IsAuthProtected() (gas: 12779) -ScribeTest:test_toll_diss_IsAuthProtected() (gas: 12489) -ScribeTest:test_toll_kiss_IsAuthProtected() (gas: 12066) -ScribeTest:test_tryReadWithAge_isTollProtected() (gas: 12827) -ScribeTest:test_tryRead_isTollProtected() (gas: 12265) \ No newline at end of file +ScribeTest:test_read_isTollProtected() (gas: 11695) +ScribeTest:test_setBar_FailsIf_BarIsZero() (gas: 11392) +ScribeTest:test_setBar_IsAuthProtected() (gas: 12823) +ScribeTest:test_toll_diss_IsAuthProtected() (gas: 12533) +ScribeTest:test_toll_kiss_IsAuthProtected() (gas: 12088) +ScribeTest:test_tryReadWithAge_isTollProtected() (gas: 12871) +ScribeTest:test_tryRead_isTollProtected() (gas: 12287) \ No newline at end of file diff --git a/src/IScribe.sol b/src/IScribe.sol index 443eb26..d78406e 100644 --- a/src/IScribe.sol +++ b/src/IScribe.sol @@ -128,6 +128,13 @@ interface IScribe is IChronicle { uint80 answeredInRound ); + /// @notice Returns the oracle's latest value. + /// @dev Provides partial compatibility with Chainlink's + /// IAggregatorV3Interface. + /// @custom:deprecated See https://docs.chain.link/data-feeds/api-reference/#latestanswer. + /// @return answer The oracle's latest value. + function latestAnswer() external view returns (int); + /// @notice Pokes the oracle. /// @dev Expects `pokeData`'s age to be greater than the timestamp of the /// last successful poke. diff --git a/src/Scribe.sol b/src/Scribe.sol index 76f71aa..307b3a9 100644 --- a/src/Scribe.sol +++ b/src/Scribe.sol @@ -326,6 +326,13 @@ contract Scribe is IScribe, Auth, Toll { answeredInRound = roundId; } + /// @inheritdoc IScribe + /// @dev Only callable by toll'ed address. + function latestAnswer() external view virtual toll returns (int) { + uint val = _pokeData.val; + return int(val); + } + // -- Public Read Functionality -- /// @inheritdoc IScribe diff --git a/src/ScribeOptimistic.sol b/src/ScribeOptimistic.sol index 0307a35..3f154c8 100644 --- a/src/ScribeOptimistic.sol +++ b/src/ScribeOptimistic.sol @@ -415,6 +415,20 @@ contract ScribeOptimistic is IScribeOptimistic, Scribe { answeredInRound = roundId; } + /// @inheritdoc IScribe + /// @dev Only callable by toll'ed address. + function latestAnswer() + external + view + virtual + override(IScribe, Scribe) + toll + returns (int) + { + uint val = _currentPokeData().val; + return int(val); + } + function _currentPokeData() internal view returns (PokeData memory) { // Load pokeData slots from storage. PokeData memory pokeData = _pokeData; diff --git a/test/IScribeTest.sol b/test/IScribeTest.sol index 2ff54f5..90ec0bf 100644 --- a/test/IScribeTest.sol +++ b/test/IScribeTest.sol @@ -122,6 +122,9 @@ abstract contract IScribeTest is Test { assertEq(startedAt, 0); assertEq(updatedAt, wantAge); assertEq(uint(answeredInRound), 1); + + answer = scribe.latestAnswer(); + assertEq(uint(answer), wantVal); } // -- Test: Deployment -- @@ -191,6 +194,9 @@ abstract contract IScribeTest is Test { assertEq(startedAt, 0); assertEq(updatedAt, 0); assertEq(answeredInRound, 1); + + // latestAnswer()(int) returns zero. + assertEq(scribe.latestAnswer(), int(0)); } // -- Test: Schnorr Verification -- @@ -940,4 +946,12 @@ abstract contract IScribeTest is Test { ); scribe.latestRoundData(); } + + function test_latestAnswer_isTollProtected() public { + vm.prank(address(0xbeef)); + vm.expectRevert( + abi.encodeWithSelector(IToll.NotTolled.selector, address(0xbeef)) + ); + scribe.latestAnswer(); + } } From ca89ecbd3aebfdc7aa0d6644b5c646abf1e98bcd Mon Sep 17 00:00:00 2001 From: pascal Date: Fri, 29 Sep 2023 10:35:30 +0200 Subject: [PATCH 2/2] chaincheck: Adds latestAnswer invariant check --- script/chaincheck/IScribeChaincheck.sol | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/script/chaincheck/IScribeChaincheck.sol b/script/chaincheck/IScribeChaincheck.sol index fece080..8ad7b6d 100644 --- a/script/chaincheck/IScribeChaincheck.sol +++ b/script/chaincheck/IScribeChaincheck.sol @@ -504,6 +504,16 @@ contract IScribeChaincheck is Chaincheck { logs.push(log); } + // Note that latestAnswer()(int) was added in v1.2.0 and may not be + // supported by every deployed Scribe(Optimistic) instance. + try self.latestAnswer() returns (int val) { + if (uint(val) != valWant) { + logs.push(log); + } + } catch { + // Scribe instance has version