Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remote read immutables #1220

Open
wants to merge 40 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
b26795d
Add is_mutable entry to RemoteLoad and RemoteMapGet
jjcnn Nov 10, 2022
f6903a4
Merge and fix make dev issues
jjcnn Nov 14, 2022
3dd25bb
Added concrete syntax
jjcnn Nov 16, 2022
ecab758
Merge branch 'master' of github.com:Zilliqa/scilla into 1035_remote_r…
jjcnn Nov 16, 2022
b10894d
Change mutability from bool to new field_mutability type
jjcnn Nov 16, 2022
1cf0b70
Save game - adding immutable fields to address types
jjcnn Nov 18, 2022
f380a66
Add removal of TODO.txt to TODO.txt
jjcnn Nov 18, 2022
8b953f6
Added immutable fields to address types
jjcnn Nov 21, 2022
b9f3072
Merge branch 'master' of github.com:Zilliqa/scilla into 1035_remote_r…
jjcnn Nov 29, 2022
df9aedb
Merge branch 'master' of github.com:Zilliqa/scilla into 1035_remote_r…
jjcnn Dec 2, 2022
9c45131
pp_typ_helper should treat mutables as mutables and immutables as imm…
jjcnn Dec 2, 2022
139d233
Fix formatting of address types
jjcnn Dec 2, 2022
c9ea969
Keep mutables and immutables separate in address types
jjcnn Dec 7, 2022
6734c74
Merge with old branch code
jjcnn Dec 7, 2022
c95aa4d
address_field_type to support immutable fields
jjcnn Dec 9, 2022
b82e4f5
Merge branch 'master' of github.com:Zilliqa/scilla into 1035_remote_r…
jjcnn Dec 14, 2022
0b2eb53
Merge
jjcnn Dec 14, 2022
58ae50f
Remove outdated comment
jjcnn Dec 19, 2022
db83e7c
Test cparam remote reads in scilla-checker
jjcnn Dec 19, 2022
911e0a5
EvalUtil should treat special fields (_balance and such) as mutable
jjcnn Dec 20, 2022
4882b2e
Fix most of EvalUtil and StateService
jjcnn Dec 21, 2022
32b4c4e
Pass is_mutable in protobuf call
jjcnn Jan 16, 2023
4ef4133
is_mutable added to ProtoScillaQuery type
jjcnn Jan 17, 2023
c1b464f
Add contract parameters to external contracts in test suite
jjcnn Jan 18, 2023
437ab6f
StateService should only keep track of cparams for external contracts
jjcnn Jan 19, 2023
a87d7b8
Change fold to map in jobj_to_statevar
jjcnn Jan 20, 2023
4d85d8f
Fix incorrect comment
jjcnn Jan 20, 2023
82d1389
Make StateIPCTest.ml recognise cparams entry in state jsons
jjcnn Jan 20, 2023
f336562
Deployment tests of remote_state_reads_cparam.scilla
jjcnn Jan 24, 2023
0f789d8
First couple of positive tests
jjcnn Jan 24, 2023
2c6f275
Most of the positive test cases added. Still need a few more, and nee…
jjcnn Jan 26, 2023
be1cc48
Remaining test cases
jjcnn Jan 27, 2023
015674e
Update existing type_cast tests
jjcnn Jan 30, 2023
adf90ab
Type cast test cases added
jjcnn Jan 30, 2023
e8c7f04
feat(dcd): Support immutable reads
jubnzv Feb 26, 2023
21550ee
feat(merge): Add tests
jubnzv Feb 26, 2023
678580a
fix(formatter): Typo
jubnzv Feb 26, 2023
9a142fe
feat(formatter): Add test for immutable reads
jubnzv Feb 26, 2023
9350beb
Merge remote-tracking branch 'zilliqa/master' into 1035_remote_read_i…
jubnzv Feb 27, 2023
4e007b0
fix(tests): Update cram tests for JSON
jubnzv Feb 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
16 changes: 9 additions & 7 deletions src/base/Cashflow.ml
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,12 @@ struct
match s with
| Load (x, y) ->
CFSyntax.Load (add_noinfo_to_ident x, add_noinfo_to_ident y)
| RemoteLoad (x, adr, y) ->
| RemoteLoad (x, adr, y, mutability) ->
CFSyntax.RemoteLoad
( add_noinfo_to_ident x,
add_noinfo_to_ident adr,
add_noinfo_to_ident y )
add_noinfo_to_ident y,
mutability)
| Store (x, y) ->
CFSyntax.Store (add_noinfo_to_ident x, add_noinfo_to_ident y)
| Bind (x, e) -> CFSyntax.Bind (add_noinfo_to_ident x, cf_init_tag_expr e)
Expand All @@ -208,11 +209,12 @@ struct
add_noinfo_to_ident m,
List.map ~f:add_noinfo_to_ident ks,
retrieve )
| RemoteMapGet (x, adr, m, ks, retrieve) ->
| RemoteMapGet (x, adr, m, mutability, ks, retrieve) ->
CFSyntax.RemoteMapGet
( add_noinfo_to_ident x,
add_noinfo_to_ident adr,
add_noinfo_to_ident m,
mutability,
List.map ~f:add_noinfo_to_ident ks,
retrieve )
| MatchStmt (x, pss) ->
Expand Down Expand Up @@ -1629,13 +1631,13 @@ struct
(not @@ [%equal: ECFR.money_tag] (get_id_tag new_x) (get_id_tag x))
|| not
@@ [%equal: ECFR.money_tag] (get_id_tag new_f) (get_id_tag f) )
| RemoteLoad (x, adr, f) ->
| RemoteLoad (x, adr, f, mutability) ->
(* TODO - see Load case for inspiration *)
(* x is no longer in scope, so remove from local_env *)
let new_local_env =
AssocDictionary.remove (CFIdentifier.as_string x) local_env
in
( RemoteLoad (x, adr, f),
( RemoteLoad (x, adr, f, mutability),
param_env,
field_env,
new_local_env,
Expand Down Expand Up @@ -1767,13 +1769,13 @@ struct
(not @@ [%equal: ECFR.money_tag] (get_id_tag x) new_x_tag)
|| (not @@ [%equal: ECFR.money_tag] (get_id_tag m) m_tag)
|| (not @@ [%equal: _] new_ks ks) )
| RemoteMapGet (x, adr, m, ks, fetch) ->
| RemoteMapGet (x, adr, m, mutability, ks, fetch) ->
(* TODO - see MapGet case for inspiration *)
(* x is no longer in scope, so remove from local_env *)
let new_local_env =
AssocDictionary.remove (CFIdentifier.as_string x) local_env
in
( RemoteMapGet (x, adr, m, ks, fetch),
( RemoteMapGet (x, adr, m, mutability, ks, fetch),
param_env,
field_env,
new_local_env,
Expand Down
241 changes: 149 additions & 92 deletions src/base/DeadCodeDetector.ml
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ module DeadCodeDetector (SR : Rep) (ER : Rep) = struct
else (
warn "Unused load statement to: " x ER.get_loc;
(lv, adts, ctrs))
| RemoteLoad (x, addr, m) ->
| RemoteLoad (x, addr, m, _mutability) ->
FieldsState.mark_field_read fs m;
(* m is a field, thus we don't track its liveness *)
if ERSet.mem lv x then
Expand Down Expand Up @@ -397,7 +397,7 @@ module DeadCodeDetector (SR : Rep) (ER : Rep) = struct
else (
warn "Unused map get statement to: " x ER.get_loc;
(lv, adts, ctrs))
| RemoteMapGet (x, addr, i, il, _) ->
| RemoteMapGet (x, addr, i, _mutability, il, _) ->
(* i is a field, thus we don't track its liveness *)
FieldsState.mark_field_read fs i;
if ERSet.mem lv x then
Expand Down Expand Up @@ -539,115 +539,171 @@ module DeadCodeDetector (SR : Rep) (ER : Rep) = struct
Map.merge m1 m2 ~f:(fun ~key:_ -> function
| `Both (s1, s2) -> Some (Set.union s1 s2) | `Left s | `Right s -> Some s)

(** Returns a list of fields with the contract address type from
[address_params] that are used in [s]. *)
let rec get_used_address_fields address_params (s, _annot) =
(** Returns maps of immutable and mutable fields with the contract address
type from [address_params] that are used in [s]. *)
let rec get_used_address_fields (s, _annot) =
match s with
| RemoteLoad (_, addr, field) | RemoteMapGet (_, addr, field, _, _) ->
Map.set emp_idsmap ~key:(get_id addr)
~data:(SCIdentifierSet.singleton (get_id field))
| RemoteLoad (_, addr, field, Immutable)
| RemoteMapGet (_, addr, field, Immutable, _, _) ->
( Map.set emp_idsmap ~key:(get_id addr)
~data:(SCIdentifierSet.singleton (get_id field)),
emp_idsmap )
| RemoteLoad (_, addr, field, Mutable)
| RemoteMapGet (_, addr, field, Mutable, _, _) ->
( emp_idsmap,
Map.set emp_idsmap ~key:(get_id addr)
~data:(SCIdentifierSet.singleton (get_id field)) )
| MatchStmt (_id, arms) ->
List.fold_left arms ~init:emp_idsmap ~f:(fun m (_pattern, stmts) ->
List.fold_left stmts ~init:emp_idsmap ~f:(fun m sa ->
get_used_address_fields address_params sa |> merge_id_maps m)
|> merge_id_maps m)
List.fold_left arms ~init:(emp_idsmap, emp_idsmap)
~f:(fun (immut_m, mut_m) (_pattern, stmts) ->
let immut_m', mut_m' =
List.fold_left stmts ~init:(emp_idsmap, emp_idsmap)
~f:(fun (immut_m', mut_m') sa ->
let immut_m'', mut_m'' = get_used_address_fields sa in
( merge_id_maps immut_m' immut_m'',
merge_id_maps mut_m' mut_m'' ))
in
(merge_id_maps immut_m immut_m', merge_id_maps mut_m mut_m'))
| Bind _ | Load _ | Store _ | MapUpdate _ | MapGet _ | ReadFromBC _
| TypeCast _ | AcceptPayment | Return _ | Iterate _ | SendMsgs _
| CreateEvnt _ | CallProc _ | Throw _ | GasStmt _ ->
emp_idsmap
(emp_idsmap, emp_idsmap)

(** Returns a set of field names of the contract address type. *)
let get_addr_fields addr =
List.fold_left (SType.IdLoc_Comp.Map.keys addr) ~init:emp_idset
let get_addr_fields fields =
List.fold_left (SType.IdLoc_Comp.Map.keys fields) ~init:emp_idset
~f:(fun s id -> SCIdentifierSet.add s (get_id id))

(** Updates a map of identifiers [m] iff [ty] has contract address type.
[m] has the following structure: [id |-> F] where [F] is a set of field
names used in the contract address type. *)
let update_contract_params_map m id ty =
(** Returns sets with names of immutable and mutable fields of the contract
address type [ty]. *)
let find_contract_type_fields ty =
match ty with
| SType.Address (ContrAddr addr) ->
let data = get_addr_fields addr in
Map.set m ~key:(SCIdentifier.get_id id) ~data
| _ -> m

(** Checks for unused fields in contract address types of [comp]'s
parameters.
Returns a set of ids of contract parameters used in this [comp]. *)
let check_contract_address_types_in_params used_contract_params
contract_params comp =
let address_params =
List.fold_left comp.comp_params ~init:contract_params
~f:(fun m (id, ty) -> update_contract_params_map m id ty)
| SType.Address (ContrAddr (immutable_fields, mutable_fields)) ->
Some (get_addr_fields immutable_fields, get_addr_fields mutable_fields)
| _ -> None

(** Takes the procedure/transition [comp] and looks for unused fields in its parameters.
Returns maps of immutable and mutable fields of the contract parameters used
in the body of [comp].
Arguments:
- [contr_immut_used] and [contr_mut_used] are parameters of the
contract that are known as used.
- [contr_immut_fields] and [contr_mut_fields] are all the fields of the
contract. *)
let check_addresses_in_params (comp : component) contr_immut_used
contr_mut_used contr_immut_fields contr_mut_fields =
(* Collect fields of contract address types from parameters of the component *)
let immut_address_params, mut_address_params =
List.fold_left comp.comp_params
~init:(contr_immut_fields, contr_mut_fields)
~f:(fun (immut_m, mut_m) (id, ty) ->
find_contract_type_fields ty
|> Option.value_map ~default:(immut_m, mut_m)
~f:(fun (immut_fields, mut_fields) ->
let update_map m data =
Map.set m ~key:(SCIdentifier.get_id id) ~data
in
(update_map immut_m immut_fields, update_map mut_m mut_fields)))
in
let used_addresses =
(* Collect fields of contract address types used in the body of the component *)
let immut_used_addresses, mut_used_addresses =
(* addr |-> set of used fields *)
List.fold_left comp.comp_body ~init:emp_idsmap ~f:(fun m s ->
get_used_address_fields address_params s |> merge_id_maps m)
List.fold_left comp.comp_body ~init:(emp_idsmap, emp_idsmap)
~f:(fun (immut_m, mut_m) s ->
let immut_m', mut_m' = get_used_address_fields s in
(merge_id_maps immut_m immut_m', merge_id_maps mut_m mut_m'))
in
(* Generate warnings for unused fields in component arguments. *)
(* Generate warnings for unused fields in component parameters *)
List.iter comp.comp_params ~f:(fun (id, ty) ->
let name = get_id id in
match (Map.find address_params name, Map.find used_addresses name) with
| Some fields, Some used_fields
when not @@ phys_equal (Set.length fields) (Set.length used_fields)
-> (
match ty with
| SType.Address (ContrAddr m) ->
List.iter (SType.IdLoc_Comp.Map.keys m) ~f:(fun id ->
let name = get_id id in
if Set.mem fields name && (not @@ Set.mem used_fields name)
then
warn1
("Unused field in contract address type: "
^ as_error_string id)
warning_level_dead_code
(SType.TIdentifier.get_rep id))
| _ -> ())
match ty with
| SType.Address (ContrAddr (ims, ms)) ->
let name = get_id id in
let find_unused address_fields params used_params warn_name =
match (Map.find params name, Map.find used_params name) with
| Some fields, Some used_fields
when not
@@ phys_equal (Set.length fields) (Set.length used_fields)
->
List.iter (SType.IdLoc_Comp.Map.keys address_fields)
~f:(fun id ->
let name = get_id id in
if Set.mem fields name && (not @@ Set.mem used_fields name)
then
warn1
("Unused " ^ warn_name ^ " in contract address type: "
^ as_error_string id)
warning_level_dead_code
(SType.TIdentifier.get_rep id))
| _ -> ()
in
(* Handle immutable fields *)
find_unused ims immut_address_params immut_used_addresses
"contract parameter";
(* Handle mutable fields *)
find_unused ms mut_address_params mut_used_addresses "field"
| _ -> ());
(* Collect fields of the [cmod] contract with contract address types used
(* Collect fields of the contract with contract address types used
in this component. *)
Map.keys used_addresses
|> List.fold_left ~init:used_contract_params ~f:(fun used_ids_map used_id ->
let used_fields = Map.find_exn used_addresses used_id in
match Map.find used_ids_map used_id with
| Some used_fields ->
let data = used_fields |> Set.union used_fields in
Map.set used_ids_map ~key:used_id ~data
| None -> Map.set used_ids_map ~key:used_id ~data:used_fields)
let collect contr_used comp_used =
Map.keys comp_used
|> List.fold_left ~init:contr_used ~f:(fun used_ids_map used_id ->
let used_fields = Map.find_exn comp_used used_id in
match Map.find used_ids_map used_id with
| Some used_fields ->
let data = used_fields |> Set.union used_fields in
Map.set used_ids_map ~key:used_id ~data
| None -> Map.set used_ids_map ~key:used_id ~data:used_fields)
in
( collect contr_immut_used immut_used_addresses,
collect contr_mut_used mut_used_addresses )

(** Checks for unused fields in contract address types occurred in contract
parameters and parameters of contract's components. *)
let check_param_contract_address_types cmod =
let contract_params =
List.fold_left cmod.contr.cparams ~init:emp_idsmap ~f:(fun m (id, ty) ->
update_contract_params_map m id ty)
(* Collect names of fields in address types of contract params *)
let contr_immut, contr_mut =
List.fold_left cmod.contr.cparams ~init:(emp_idsmap, emp_idsmap)
~f:(fun (immut_m, mut_m) (id, ty) ->
find_contract_type_fields ty
|> Option.value_map ~default:(immut_m, mut_m)
~f:(fun (immut_fields', mut_fields') ->
let update_map m data =
Map.set m ~key:(SCIdentifier.get_id id) ~data
in
(update_map immut_m immut_fields', update_map mut_m mut_fields')))
in
let used_contract_params =
List.fold_left cmod.contr.ccomps ~init:emp_idsmap ~f:(fun used c ->
check_contract_address_types_in_params used contract_params c)
let contr_immut_used, contr_mut_used =
List.fold_left cmod.contr.ccomps ~init:(emp_idsmap, emp_idsmap)
~f:(fun (immut_used, mut_used) comp ->
check_addresses_in_params comp immut_used mut_used contr_immut
contr_mut)
in
(* Report unused contract parameters with contract address types. *)
Map.keys contract_params
|> List.iter ~f:(fun param ->
match Map.find used_contract_params param with
| Some used_fields ->
let all_fields = Map.find_exn contract_params param in
let unused_fields = Set.diff all_fields used_fields in
if not @@ Set.is_empty unused_fields then
List.iter cmod.contr.cparams ~f:(fun (id, _ty) ->
if SCIdentifier.Name.equal param (SCIdentifier.get_id id)
then
Set.iter unused_fields ~f:(fun f ->
warn1
("Unused field in contract address type: "
^ SCIdentifier.Name.as_string f)
warning_level_dead_code
(ER.get_loc (SCIdentifier.get_rep id))))
| None ->
(* All the fields of [param] are unused, so we don't report it.
It is an unused contract parameter.*)
())
(* Report unused contract parameters with contract address types *)
let check fields used warn_name =
Map.keys fields
|> List.iter ~f:(fun param ->
match Map.find used param with
| Some used_fields ->
let all_fields = Map.find_exn fields param in
let unused_fields = Set.diff all_fields used_fields in
if not @@ Set.is_empty unused_fields then
List.iter cmod.contr.cparams ~f:(fun (id, _ty) ->
if SCIdentifier.Name.equal param (SCIdentifier.get_id id)
then
Set.iter unused_fields ~f:(fun f ->
warn1
("Unused " ^ warn_name
^ " in contract address type: "
^ SCIdentifier.Name.as_string f)
warning_level_dead_code
(ER.get_loc (SCIdentifier.get_rep id))))
| None ->
(* All the fields of [param] are unused, so we don't report it.
It is an unused contract parameter.*)
())
in
check contr_immut contr_immut_used "contract_parameter";
check contr_mut contr_mut_used "field"

type adts_ty =
( Name.t,
Expand Down Expand Up @@ -680,8 +736,8 @@ module DeadCodeDetector (SR : Rep) (ER : Rep) = struct
~init:(Map.empty (module Int))
~f:
(fun i m -> function
| SType.Address (ContrAddr addr) ->
Map.set m ~key:i ~data:(get_addr_fields addr)
| SType.Address (ContrAddr (_im_addr, m_addr)) ->
Map.set m ~key:i ~data:(get_addr_fields m_addr)
| _ -> m)
in
if Map.is_empty args_map then m
Expand Down Expand Up @@ -778,7 +834,8 @@ module DeadCodeDetector (SR : Rep) (ER : Rep) = struct
in
ignore @@ Stack.pop env_stack;
res))
| RemoteLoad (_, addr, field) | RemoteMapGet (_, addr, field, _, _) -> (
| RemoteLoad (_, addr, field, _) | RemoteMapGet (_, addr, field, _, _, _)
-> (
match env_find_bind (SCIdentifier.get_id addr) with
| Some (ctr_name, ctr_arg_pos) when Map.mem adt_ctrs ctr_name ->
let ctr_arg_pos_to_fields =
Expand Down
Loading