Skip to content

Commit b9d632a

Browse files
committed
Guard the validSchemes for Pact5
1 parent 373ca26 commit b9d632a

File tree

5 files changed

+33
-20
lines changed

5 files changed

+33
-20
lines changed

src/Chainweb/Pact/PactService.hs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,11 @@ execLocal cwtx preflight sigVerify rdepth = pactLabel "execLocal" $ do
860860

861861
let localPact5 = do
862862
ph <- view psParentHeader
863-
let pact5RequestKey = Pact5.RequestKey (Pact5.Hash $ Pact4.unHash $ Pact4.toUntypedHash $ Pact4._cmdHash cwtx)
863+
let txCtx = Pact5.TxContext ph noMiner
864+
bh = Pact5.ctxCurrentBlockHeight txCtx
865+
pact5RequestKey = Pact5.RequestKey (Pact5.Hash $ Pact4.unHash $ Pact4.toUntypedHash $ Pact4._cmdHash cwtx)
866+
spvSupport = Pact5.pactSPV bhdb (_parentHeader ph)
867+
864868
evalContT $ withEarlyReturn $ \earlyReturn -> do
865869
pact5Cmd <- case Pact5.parsePact4Command cwtx of
866870
Left (Left errText) -> do
@@ -903,14 +907,12 @@ execLocal cwtx preflight sigVerify rdepth = pactLabel "execLocal" $ do
903907
review _MetadataValidationFailure $ NonEmpty.singleton $ Text.pack err
904908
Right _ -> return ()
905909
_ -> do
906-
let validated = Pact5.assertCommand pact5Cmd
910+
let validated = Pact5.assertCommand pact5Cmd (validPPKSchemes v cid bh)
907911
case validated of
908912
Left err -> earlyReturn $
909913
review _MetadataValidationFailure (pure $ displayAssertCommandError err)
910914
Right () -> return ()
911915

912-
let txCtx = Pact5.TxContext ph noMiner
913-
let spvSupport = Pact5.pactSPV bhdb (_parentHeader ph)
914916
case preflight of
915917
Just PreflightSimulation -> do
916918
-- preflight needs to do additional checks on the metadata

src/Chainweb/Pact/PactService/Pact5/ExecBlock.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ validateParsedChainwebTx _logger v cid db _blockHandle txValidationTime bh isGen
531531

532532
checkTxSigs :: Pact5.Transaction -> ExceptT InsertError IO ()
533533
checkTxSigs t = do
534-
case Pact5.assertValidateSigs hsh signers sigs of
534+
case Pact5.assertValidateSigs (validPPKSchemes v cid bh) hsh signers sigs of
535535
Right _ -> do
536536
pure ()
537537
Left err -> do

src/Chainweb/Pact/RestAPI/Server.hs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -737,15 +737,18 @@ validateCommand v cid (fmap encodeUtf8 -> cmdBs) = case parsedCmd of
737737

738738
-- TODO: all of the functions in this module can instead grab the current block height from consensus
739739
-- and pass it here to get a better estimate of what behavior is correct.
740-
validatePact5Command :: ChainwebVersion -> Pact5.Command Text -> Either String Pact5.Transaction
741-
validatePact5Command _v cmdText = case parsedCmd of
740+
validatePact5Command :: ChainwebVersion -> ChainId -> Pact5.Command Text -> Either String Pact5.Transaction
741+
validatePact5Command _v cid cmdText = case parsedCmd of
742742
Right (commandParsed :: Pact5.Transaction) ->
743-
if isRight (Pact5.assertCommand commandParsed)
743+
if isRight $ Pact5.assertCommand commandParsed $ validPPKSchemes _v cid bh
744744
then Right commandParsed
745745
else Left "Command failed validation"
746746
Left e -> Left $ "Pact parsing error: " ++ Pact5.renderCompactString e
747747
where
748748
parsedCmd = Pact5.parseCommand cmdText
749+
-- For Pact5, we take the highest possible BlockHeight
750+
bh = maxBound :: BlockHeight
751+
749752

750753
-- | Validate the length of the request key's underlying hash.
751754
--

src/Chainweb/Pact5/Validations.hs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import qualified Pact.Core.Gas.Types as P
5858
import qualified Pact.Core.Hash as P
5959
import qualified Chainweb.Pact5.Transaction as P
6060
import qualified Pact.Types.Gas as Pact4
61+
import Chainweb.Version.Guards (PactPPKScheme(..), validPPKSchemes)
6162
import qualified Pact.Parse as Pact4
6263
import Chainweb.Pact5.Types
6364
import qualified Chainweb.Pact5.Transaction as Pact5
@@ -79,6 +80,7 @@ assertPreflightMetadata cmd@(P.Command pay sigs hsh) txCtx sigVerify = do
7980
let P.PublicMeta pcid _ gl gp _ _ = P._pMeta pay
8081
nid = P._pNetworkId pay
8182
signers = P._pSigners pay
83+
validSchemes = validPPKSchemes v cid $ ctxCurrentBlockHeight txCtx
8284

8385
let errs = catMaybes
8486
[ eUnless "Chain id mismatch" $ assertChainId cid pcid
@@ -88,17 +90,17 @@ assertPreflightMetadata cmd@(P.Command pay sigs hsh) txCtx sigVerify = do
8890
, eUnless "Gas price decimal precision too high" $ assertGasPrice gp
8991
, eUnless "Network id mismatch" $ assertNetworkId v nid
9092
, eUnless "Signature list size too big" $ assertSigSize sigs
91-
, eUnless "Invalid transaction signatures" $ sigValidate signers
93+
, eUnless "Invalid transaction signatures" $ sigValidate validSchemes signers
9294
, eUnless "Tx time outside of valid range" $ assertTxTimeRelativeToParent pct cmd
9395
]
9496

9597
pure $ case nonEmpty errs of
9698
Nothing -> Right ()
9799
Just vs -> Left vs
98100
where
99-
sigValidate signers
101+
sigValidate validSchemes signers
100102
| Just NoVerify <- sigVerify = True
101-
| otherwise = isRight $ assertValidateSigs hsh signers sigs
103+
| otherwise = isRight $ assertValidateSigs validSchemes hsh signers sigs
102104

103105
pct = ParentCreationTime
104106
. view blockCreationTime
@@ -153,11 +155,12 @@ assertTxSize initialGas gasLimit = P.GasLimit initialGas < gasLimit
153155
-- transaction hash.
154156
--
155157
assertValidateSigs :: ()
156-
=> P.Hash
158+
=> [PactPPKScheme]
159+
-> P.Hash
157160
-> [P.Signer]
158161
-> [P.UserSig]
159162
-> Either AssertValidateSigsError ()
160-
assertValidateSigs hsh signers sigs = do
163+
assertValidateSigs validSchemes hsh signers sigs = do
161164
let signersLength = length signers
162165
let sigsLength = length sigs
163166
ebool_
@@ -168,6 +171,9 @@ assertValidateSigs hsh signers sigs = do
168171
(signersLength == sigsLength)
169172

170173
iforM_ (zip sigs signers) $ \pos (sig, signer) -> do
174+
ebool_ (InvalidSignerScheme pos)
175+
((SchemeV5 $ fromMaybe P.ED25519 $ P._siScheme signer) `elem` validSchemes)
176+
171177
case P.verifyUserSig hsh sig signer of
172178
Left errMsg -> Left (InvalidUserSig pos (Text.pack errMsg))
173179
Right () -> Right ()
@@ -209,10 +215,10 @@ assertTxNotInFuture (ParentCreationTime (BlockCreationTime txValidationTime)) tx
209215

210216
-- | Assert that the command hash matches its payload and
211217
-- its signatures are valid, without parsing the payload.
212-
assertCommand :: Pact5.Transaction -> Either AssertCommandError ()
213-
assertCommand cmd = do
218+
assertCommand :: Pact5.Transaction -> [PactPPKScheme] -> Either AssertCommandError ()
219+
assertCommand cmd ppkSchemePassList = do
214220
_ <- assertHash & _Left .~ InvalidPayloadHash
215-
assertValidateSigs hsh signers (P._cmdSigs cmd) & _Left %~ AssertValidateSigsError
221+
assertValidateSigs ppkSchemePassList hsh signers (P._cmdSigs cmd) & _Left %~ AssertValidateSigsError
216222
where
217223
hsh = P._cmdHash cmd
218224
pwt = P._cmdPayload cmd

test/lib/Chainweb/Test/Pact5/CmdBuilder.hs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,12 @@ defaultCmd cid = CmdBuilder
189189
-- | Build parsed + verified Pact command
190190
-- TODO: Use the new `assertPact4Command` function.
191191
buildCwCmd :: (MonadThrow m, MonadIO m) => ChainwebVersion -> CmdBuilder -> m Pact5.Transaction
192-
buildCwCmd v cmd = buildTextCmd v cmd >>= \(c :: Command Text) ->
193-
case validatePact5Command v c of
194-
Left err -> throwM $ userError $ "buildCwCmd failed: " ++ err
195-
Right cmd' -> return cmd'
192+
buildCwCmd v cmd = do
193+
cid <- Chainweb.chainIdFromText $ _cbChainId cmd
194+
cmd' <- buildTextCmd v cmd
195+
case validatePact5Command v cid cmd' of
196+
Left err -> throwM $ userError $ "buildCwCmd failed: " ++ err
197+
Right validatedCmd -> return validatedCmd
196198

197199
-- | Build a Pact4 command without parsing it. This can be useful for inserting txs directly into the mempool for testing.
198200
buildCwCmdNoParse :: forall m. (MonadThrow m, MonadIO m) => ChainwebVersion -> CmdBuilder -> m Pact4.UnparsedTransaction

0 commit comments

Comments
 (0)