Skip to content

Commit

Permalink
informative error message if you try to rewind before min(blockheight)
Browse files Browse the repository at this point in the history
  • Loading branch information
chessai committed Aug 25, 2023
1 parent 0903fd3 commit c49cf8e
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 15 deletions.
17 changes: 17 additions & 0 deletions src/Chainweb/Pact/Backend/RelationalCheckpointer.hs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ initRelationalCheckpointer' bstate sqlenv loggr v cid = do
_cpRestore = doRestore v cid db
, _cpSave = doSave db
, _cpDiscard = doDiscard db
, _cpGetEarliestBlock = doGetEarliest db
, _cpGetLatestBlock = doGetLatest db
, _cpBeginCheckpointerBatch = doBeginBatch db
, _cpCommitCheckpointerBatch = doCommitBatch db
Expand Down Expand Up @@ -231,6 +232,22 @@ doDiscard dbenv = runBlockEnv dbenv $ do
--
commitSavepoint Block

doGetEarliest :: Db logger -> IO (Maybe (BlockHeight, BlockHash))
doGetEarliest dbenv =
runBlockEnv dbenv $ callDb "getEarliestBlock" $ \db -> do
r <- qry_ db qtext [RInt, RBlob] >>= mapM go
case r of
[] -> return Nothing
(!o:_) -> return (Just o)
where
qtext = "SELECT blockheight, hash FROM BlockHistory \
\ ORDER BY blockheight ASC LIMIT 1"

go [SInt hgt, SBlob blob] =
let hash = either error id $ runGetEitherS decodeBlockHash blob
in return (fromIntegral hgt, hash)
go _ = fail "impossible"

doGetLatest :: Db logger -> IO (Maybe (BlockHeight, BlockHash))
doGetLatest dbenv =
runBlockEnv dbenv $ callDb "getLatestBlock" $ \db -> do
Expand Down
3 changes: 3 additions & 0 deletions src/Chainweb/Pact/Backend/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,9 @@ data Checkpointer logger = Checkpointer
-- ^ commits pending modifications to block, with the given blockhash
, _cpDiscard :: !(IO ())
-- ^ discard pending block changes
, _cpGetEarliestBlock :: !(IO (Maybe (BlockHeight, BlockHash)))
-- ^ get the checkpointer's idea of the earliest block. The block height
-- is the height of the block of the block hash.
, _cpGetLatestBlock :: !(IO (Maybe (BlockHeight, BlockHash)))
-- ^ get the checkpointer's idea of the latest block. The block height is
-- is the height of the block of the block hash.
Expand Down
32 changes: 20 additions & 12 deletions src/Chainweb/Pact/PactService/Checkpointer.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ module Chainweb.Pact.PactService.Checkpointer
-- There are two function for restoring the checkpointer for evaluation of back
-- code:
--
-- * 'withCheckPointerRewind' and
-- * 'withCheckpointerRewind' and
-- * 'withCurrentCheckpointer'.
--
-- 'withCheckPointerRewind' rewinds the checkpointer to the provided parent
-- 'withCheckpointerRewind' rewinds the checkpointer to the provided parent
-- header. 'withCurrentCheckpointer' evaluates the pact transaction within the
-- context of the current checkpointer state. Both functions update the value of
-- '_psParentHeader' at the beginning and the end of each call.
Expand Down Expand Up @@ -171,7 +171,7 @@ data WithCheckpointerResult a
--
-- This function assumes that '_psParentHeader' has been updated to match the
-- latest block in the checkpointers. This is guaranteed to be the case after
-- calling any of 'rewindTo', 'syncParentHeader', 'withCheckPointerRewind',
-- calling any of 'rewindTo', 'syncParentHeader', 'withCheckpointerRewind',
-- 'withCheckPointerWithoutRewind', or 'withCurrentCheckpointer'.
--
-- /NOTE:/
Expand Down Expand Up @@ -273,7 +273,7 @@ withCheckpointerRewind rewindLimit p caller act = do

-- | Run a batch of checkpointer operations, possibly involving the evaluation
-- transactions accross several blocks using more than a single call of
-- 'withCheckPointerRewind' or 'withCurrentCheckpointer', and persist the final
-- 'withCheckpointerRewind' or 'withCurrentCheckpointer', and persist the final
-- state. In case of an failure, the checkpointer is reverted to the initial
-- state.
--
Expand Down Expand Up @@ -308,7 +308,7 @@ withBatchIO runPact act = mask $ \umask -> do

-- | Run a batch of checkpointer operations, possibly involving the evaluation
-- transactions accross several blocks using more than a single call of
-- 'withCheckPointerRewind' or 'withCurrentCheckpointer', and discard the final
-- 'withCheckpointerRewind' or 'withCurrentCheckpointer', and discard the final
-- state at the end.
--
withDiscardedBatch :: PactServiceM logger tbl a -> PactServiceM logger tbl a
Expand Down Expand Up @@ -645,11 +645,19 @@ failOnTooLowRequestedHeight
-> Maybe RewindLimit
-> BlockHeader
-> PactServiceM logger tbl ()
failOnTooLowRequestedHeight parent (Just limit) lastHeader
| parentHeight + 1 + limitHeight < lastHeight = -- need to stick with addition because Word64
throwM $ RewindLimitExceeded limit parentHeight lastHeight parent
where
limitHeight = BlockHeight $ _rewindLimit limit
parentHeight = _blockHeight parent
lastHeight = _blockHeight lastHeader
failOnTooLowRequestedHeight parent (Just limit) lastHeader = do
let limitHeight = BlockHeight $ _rewindLimit limit
let parentHeight = _blockHeight parent
let lastHeight = _blockHeight lastHeader
when (parentHeight + 1 + limitHeight < lastHeight) $ do -- need to stick with addition because Word64
throwM $ RewindLimitExceeded limit parentHeight lastHeight parent

cp <- getCheckpointer
mEarliestBlock <- liftIO $ _cpGetEarliestBlock cp
case mEarliestBlock of
Nothing -> error ""
Just (minBlockHeight, _) -> do
when (parentHeight < minBlockHeight) $ do
throwM $ RewindPastMinBlockHeight parentHeight parent minBlockHeight

failOnTooLowRequestedHeight _ _ _ = return ()
4 changes: 2 additions & 2 deletions src/Chainweb/Pact/PactService/ExecBlock.hs
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ setParentHeader msg ph@(ParentHeader bh) = do
-- /NOTE:/
--
-- Any call of this function must occur within a dedicated call to
-- 'withChwithCheckpointerRewind', 'withCurrentCheckpointer' or
-- 'withCheckPointerWithoutRewind'.
-- 'withCheckpointerRewind', 'withCurrentCheckpointer' or
-- 'withCheckpointerWithoutRewind'.
--
execBlock
:: (CanReadablePayloadCas tbl, Logger logger)
Expand Down
13 changes: 13 additions & 0 deletions src/Chainweb/Pact/Service/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,14 @@ data PactException
, _rewindExceededTarget :: !BlockHeader
-- ^ target header
}
| RewindPastMinBlockHeight
{ _rewindPastMinParentHeight :: !BlockHeight
-- ^ parent block height
, _rewindPastMinParentHeader :: !BlockHeader
-- ^ parent block header
, _rewindPastMinMinBlockHeight :: !BlockHeight
-- ^ min block height @SELECT MIN(blockheight) FROM BlockHistory@
}
| BlockHeaderLookupFailure !Text
| BuyGasFailure !GasPurchaseFailure
| MempoolFillFailure !Text
Expand Down Expand Up @@ -230,6 +238,11 @@ instance J.Encode PactException where
, "_rewindExceededForkHeight" J..= J.Aeson @Int (fromIntegral $ _rewindExceededForkHeight o)
, "_rewindExceededTarget" J..= J.encodeWithAeson (_rewindExceededTarget o)
]
build o@(RewindPastMinBlockHeight{}) = tagged "RewindPastMinBlockHeight" $ J.object
[ "_rewindPastMinParentHeight" J..= J.Aeson @Int (fromIntegral $ _rewindPastMinParentHeight o)
, "_rewindPastMinParentHeader" J..= J.encodeWithAeson (_rewindPastMinParentHeader o)
, "_rewindPastMinMinBlockHeight" J..= J.Aeson @Int (fromIntegral $ _rewindPastMinMinBlockHeight o)
]
build (BlockHeaderLookupFailure msg) = tagged "BlockHeaderLookupFailure" msg
build (BuyGasFailure failure) = tagged "BuyGasFailure" failure
build (MempoolFillFailure msg) = tagged "MempoolFillFailure" msg
Expand Down
1 change: 0 additions & 1 deletion src/Chainweb/Pact/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,6 @@ execPactServiceM
execPactServiceM st env act
= execStateT (runReaderT (_unPactServiceM act) env) st


getCheckpointer :: PactServiceM logger tbl (Checkpointer logger)
getCheckpointer = view psCheckpointer

Expand Down

0 comments on commit c49cf8e

Please sign in to comment.