Skip to content

Commit 40316e2

Browse files
committed
Add typechecking for arguments that map to contructors
1 parent e4c692d commit 40316e2

File tree

2 files changed

+47
-28
lines changed

2 files changed

+47
-28
lines changed

src/Act/HEVM.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -833,7 +833,7 @@ pruneContractState entryaddr cmap =
833833
getAddrs (EVM.ConcreteStore _) = error $ "Internal error: unexpected storage shape"
834834
getAddrs (EVM.AbstractStore {}) = []
835835
getAddrs _ = error $ "Internal error: unexpected storage shape"
836-
836+
837837

838838
-- | Check if two contract maps are isomorphic
839839
-- Perform a breadth first traversal and try to find a bijection between the addresses of the two stores

src/Act/Type.hs

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,11 @@ lookupVars = foldMap $ \case
140140
addSlot l = zipWith (\(name, typ) slot -> (name, (typ, slot))) l [0..]
141141

142142

143-
lookupConstructors :: [U.Contract] -> Map Id [AbiType]
143+
lookupConstructors :: [U.Contract] -> Map Id [(AbiType, Maybe Id)]
144144
lookupConstructors = foldMap $ \case
145-
U.Contract (U.Definition _ contract (Interface _ decls) _ _ _ _ _) _ ->
146-
Map.singleton contract (map (\(Decl t _) -> t) decls)
145+
U.Contract (U.Definition _ contract (Interface _ decls) pointers _ _ _ _) _ ->
146+
let ptrs = Map.fromList $ map (\(PointsTo _ x c) -> (x, c)) pointers in
147+
Map.singleton contract (map (\(Decl t x) -> (t, Map.lookup x ptrs)) decls)
147148

148149
-- | Extracts what we need to build a 'Store' and to verify that its names are unique.
149150
-- Kind of stupid return type but it makes it easier to use the same function
@@ -155,12 +156,12 @@ fromAssign (U.AssignStruct _ _) = error "TODO: assignstruct"
155156

156157
-- | The type checking environment.
157158
data Env = Env
158-
{ contract :: Id -- ^ The name of the current contract.
159-
, store :: Map Id SlotType -- ^ This contract's storage entry names and their types.
160-
, theirs :: Store -- ^ Mapping from contract names to a map of their entry names and their types.
161-
, calldata :: Map Id AbiType -- ^ The calldata var names and their types.
162-
, pointers :: Map Id Id -- ^ Maps address calldata variables to their contract type.
163-
, constructors :: Map Id [AbiType] -- ^ Interfaces of contract contructors (we only allow constructor calls ATM)
159+
{ contract :: Id -- ^ The name of the current contract.
160+
, store :: Map Id SlotType -- ^ This contract's storage entry names and their types.
161+
, theirs :: Store -- ^ Mapping from contract names to a map of their entry names and their types.
162+
, calldata :: Map Id AbiType -- ^ The calldata var names and their types.
163+
, pointers :: Map Id Id -- ^ Maps address calldata variables to their contract type.
164+
, constructors :: Map Id [(AbiType, Maybe Id)] -- ^ Interfaces of contract contructors together with points to contraints
164165
}
165166

166167
-- typing of eth env variables
@@ -182,7 +183,7 @@ defaultStore =
182183
]
183184

184185

185-
mkEnv :: Id -> Store -> Map Id [AbiType] -> Env
186+
mkEnv :: Id -> Store -> Map Id [(AbiType, Maybe Id)] -> Env
186187
mkEnv contract store constructors = Env
187188
{ contract = contract
188189
, store = Map.map fst $ fromMaybe mempty (Map.lookup contract store)
@@ -204,7 +205,7 @@ addPointers decls env = env{ pointers = ptrs }
204205
where
205206
ptrs = Map.fromList $ map (\(PointsTo _ x c) -> (x, c)) decls
206207

207-
checkContract :: Store -> Map Id [AbiType] -> U.Contract -> Err Contract
208+
checkContract :: Store -> Map Id [(AbiType, Maybe Id)] -> U.Contract -> Err Contract
208209
checkContract store constructors (U.Contract constr@(U.Definition _ cid _ _ _ _ _ _) trans) =
209210
Contract <$> checkDefinition env constr <*> (concat <$> traverse (checkTransition env) trans) <* namesConsistent
210211
where
@@ -314,7 +315,7 @@ noStorageRead store expr = for_ (keys store) $ \name ->
314315
checkAssign :: Env -> U.Assign -> Err [StorageUpdate]
315316
checkAssign env@Env{contract,store} (U.AssignVal (U.StorageVar pn (StorageValue vt@(FromVType typ)) name) expr)
316317
= sequenceA [checkExpr env typ expr `bindValidation` \te ->
317-
checkContractType env typ te `bindValidation` \ctyp ->
318+
findContractType env te `bindValidation` \ctyp ->
318319
_Update (_Item vt (SVar pn contract name)) te <$ validContractType pn vt ctyp]
319320
<* noStorageRead store expr
320321

@@ -426,7 +427,7 @@ checkStorageExpr :: Env -> U.Entry -> U.Expr -> Err StorageUpdate
426427
checkStorageExpr env entry expr =
427428
validateEntry env entry `bindValidation` \(vt@(FromVType typ), ref) ->
428429
checkExpr env typ expr `bindValidation` \te ->
429-
checkContractType env typ te `bindValidation` \ctyp ->
430+
findContractType env te `bindValidation` \ctyp ->
430431
_Update (_Item vt ref) te <$ validContractType (getPosn expr) vt ctyp
431432

432433

@@ -437,6 +438,13 @@ validContractType pn (ContractType c1) Nothing =
437438
throw (pn, "Assignment to storage variable was expected to have contract type " <> c1)
438439
validContractType _ _ _ = pure ()
439440

441+
-- findContractTypes :: Pn -> -> Maybe Id -> Err ()
442+
-- findContractTypes pn (Just c1) (Just c2) =
443+
-- assert (pn, "Assignment to storage variable was expected to have contract type " <> c1 <> " but has contract type " <> c2) (c1 == c2)
444+
-- validContractType pn (Just c1) Nothing =
445+
-- throw (pn, "Assignment to storage variable was expected to have contract type " <> c1)
446+
-- validContractType _ _ _ = pure ()
447+
440448

441449
checkIffs :: Env -> [U.IffH] -> Err [Exp ABoolean Untimed]
442450
checkIffs env = foldr check (pure [])
@@ -506,14 +514,18 @@ checkExpr env@Env{constructors} typ e = case (typ, e) of
506514
(SInteger, U.IntLit p v1) -> pure $ LitInt p v1
507515
-- Constructor calls
508516
(SInteger, U.ECreate p c args) -> case Map.lookup c constructors of
509-
-- TODO check contract types
510-
Just typs -> Create p c <$> checkIxs env p args (fmap PrimitiveType typs)
517+
Just ctrs ->
518+
let (typs, ptrs) = unzip ctrs in
519+
checkIxs env p args (fmap PrimitiveType typs) `bindValidation` (\args ->
520+
pure (Create p c args) <* traverse_ (\(e, t) -> checkContractType env e t) (zip args ptrs))
511521
Nothing -> throw (p, "Unknown constructor " <> show c)
512-
-- Control
522+
523+
-- Control
513524
(_, U.EITE p v1 v2 v3) ->
514525
((,) <$> checkExpr env typ v2 <*> checkExpr env typ v3) `bindValidation` (\(e1, e2) -> do
515526
b <- checkExpr env SBoolean v1
516527
pure $ ITE p b e1 e2)
528+
517529
-- Environment variables
518530
(SInteger, U.EnvExp p v1) -> case lookup v1 defaultStore of
519531
Just AInteger -> pure $ IntEnv p v1
@@ -523,8 +535,8 @@ checkExpr env@Env{constructors} typ e = case (typ, e) of
523535
Just AInteger -> throw (p, "Environment variable " <> show v1 <> " has type integer but an expression of type bytestring is expected.")
524536
Just AByteStr -> pure $ ByEnv p v1
525537
_ -> throw (p, "Unknown environment variable " <> show v1)
526-
-- Variable references
527538

539+
-- Variable references
528540
(_, U.EUTEntry entry) | isCalldataEntry env entry -> validateVar env entry `bindValidation` \(vt@(FromVType typ'), ref) ->
529541
checkTime (getPosEntry entry) <*> (Var (getPosEntry entry) Neither typ vt ref <$ checkEq (getPosEntry entry) typ typ')
530542
(_, U.EPreEntry entry) | isCalldataEntry env entry -> error "Not supported"
@@ -566,19 +578,26 @@ checkExpr env@Env{constructors} typ e = case (typ, e) of
566578

567579

568580
-- | Find the contract id of an expression with contract type
569-
checkContractType :: Env -> SType a -> Exp a t -> Err (Maybe Id)
570-
checkContractType env SInteger (ITE p _ a b) =
571-
checkContractType env SInteger a `bindValidation` \oc1 ->
572-
checkContractType env SInteger b `bindValidation` \oc2 ->
581+
findContractType :: Env -> Exp a t -> Err (Maybe Id)
582+
findContractType env (ITE p _ a b) =
583+
findContractType env a `bindValidation` \oc1 ->
584+
findContractType env b `bindValidation` \oc2 ->
573585
case (oc1, oc2) of
574586
(Just c1, Just c2) -> Just c1 <$ assert (p, "Type of if-then-else branches does not match") (c1 == c2)
575587
(_, _ )-> pure Nothing
576-
checkContractType _ SInteger (Create _ c _) = pure $ Just c
577-
checkContractType _ _ (Var _ _ _ (ContractType c) _) = pure $ Just c
578-
checkContractType _ _ (TEntry _ _ (Item _ (ContractType c) _)) = pure $ Just c
579-
checkContractType _ SInteger _ = pure Nothing
580-
checkContractType _ SBoolean _ = pure Nothing
581-
checkContractType _ SByteStr _ = pure Nothing
588+
findContractType _ (Create _ c _) = pure $ Just c
589+
findContractType _ (Var _ _ _ (ContractType c) _) = pure $ Just c
590+
findContractType _ (TEntry _ _ (Item _ (ContractType c) _)) = pure $ Just c
591+
findContractType _ _ = pure Nothing
592+
593+
-- | Check if an expression has the expected contract id, if any
594+
checkContractType :: Env -> TypedExp t -> Maybe Id -> Err ()
595+
checkContractType _ _ Nothing = pure ()
596+
checkContractType env (TExp _ e) (Just c) =
597+
findContractType env e `bindValidation` \oc ->
598+
case oc of -- TODO fix position
599+
Just c' -> assert (nowhere, "Expression was expected to have contract type " <> c <> " but has contract type " <> c') (c == c')
600+
Nothing -> throw (nowhere, "Expression was expected to have contract type " <> c)
582601

583602
checkEq :: forall a b. Pn -> SType a -> SType b -> Err ()
584603
checkEq p t1 t2 = maybe err (\Refl -> pure ()) $ testEquality t1 t2

0 commit comments

Comments
 (0)