279 lines
12 KiB
OCaml
279 lines
12 KiB
OCaml
open Trace
|
|
open Test_helpers
|
|
|
|
let type_file f =
|
|
let%bind simplified = Ligo.Compile.Of_source.compile f (Syntax_name "pascaligo") in
|
|
let%bind typed,state = Ligo.Compile.Of_simplified.compile simplified in
|
|
ok @@ (typed,state)
|
|
|
|
let get_program =
|
|
let s = ref None in
|
|
fun () -> match !s with
|
|
| Some s -> ok s
|
|
| None -> (
|
|
let%bind program = type_file "./contracts/multisig-v2.ligo" in
|
|
s := Some program ;
|
|
ok program
|
|
)
|
|
|
|
let compile_main () =
|
|
let%bind simplified = Ligo.Compile.Of_source.compile "./contracts/multisig-v2.ligo" (Syntax_name "pascaligo") in
|
|
let%bind typed_prg,_ = Ligo.Compile.Of_simplified.compile simplified in
|
|
let%bind mini_c_prg = Ligo.Compile.Of_typed.compile typed_prg in
|
|
let%bind michelson_prg = Ligo.Compile.Of_mini_c.aggregate_and_compile_contract mini_c_prg "main" in
|
|
let%bind (_contract: Tezos_utils.Michelson.michelson) =
|
|
(* fails if the given entry point is not a valid contract *)
|
|
Ligo.Compile.Of_michelson.build_contract michelson_prg in
|
|
ok ()
|
|
|
|
open Ast_simplified
|
|
|
|
let empty_op_list =
|
|
(e_typed_list [] t_operation)
|
|
let empty_message = e_lambda (Var.of_name "arguments")
|
|
(Some t_bytes) (Some (t_list t_operation))
|
|
empty_op_list
|
|
let empty_message2 = e_lambda (Var.of_name "arguments")
|
|
(Some t_bytes) (Some (t_list t_operation))
|
|
( e_let_in ((Var.of_name "foo"),Some t_unit) false (e_unit ()) empty_op_list)
|
|
|
|
let send_param msg = e_constructor "Send" msg
|
|
let withdraw_param = e_constructor "Withdraw" empty_message
|
|
|
|
type st_type = {
|
|
state_hash : bytes ;
|
|
threshold:int ;
|
|
max_proposal:int ;
|
|
max_msg_size:int ;
|
|
id_counter_list: (int * int) list ;
|
|
msg_store_list: (expression * expression) list ;
|
|
}
|
|
let storage {state_hash ; threshold ; max_proposal ; max_msg_size ; id_counter_list ; msg_store_list} =
|
|
let auth_set,counter_store = List.fold_left
|
|
(fun (auth_set,counter_st) (id,ctr) ->
|
|
let addr_exp = e_address @@ addr id in
|
|
addr_exp::auth_set , (addr_exp, e_nat ctr)::counter_st)
|
|
([],[])
|
|
id_counter_list in
|
|
e_ez_record [
|
|
("state_hash" , e_bytes_ofbytes state_hash ) ;
|
|
("threshold" , e_nat threshold ) ;
|
|
("max_proposal" , e_nat max_proposal ) ;
|
|
("max_message_size" , e_nat max_msg_size ) ;
|
|
("authorized_addresses", e_typed_set auth_set t_address ) ;
|
|
("message_store" , e_typed_map msg_store_list t_bytes (t_set t_address) ) ;
|
|
("proposal_counters" , e_typed_map counter_store t_address t_nat ) ;
|
|
]
|
|
|
|
(* sender not stored in the authorized set *)
|
|
let wrong_addr () =
|
|
let%bind program,_ = get_program () in
|
|
let init_storage = storage {
|
|
threshold = 1 ; max_proposal = 1 ; max_msg_size = 1 ; state_hash = Bytes.empty ;
|
|
id_counter_list = [1,0 ; 2,0] ;
|
|
msg_store_list = []
|
|
} in
|
|
let source = contract 3 in
|
|
let options = Proto_alpha_utils.Memory_proto_alpha.make_options ~source () in
|
|
let%bind () =
|
|
let exp_failwith = "Unauthorized address" in
|
|
expect_string_failwith ~options program "main"
|
|
(e_pair (send_param empty_message) init_storage) exp_failwith in
|
|
ok ()
|
|
|
|
(* send a message which exceed the size limit *)
|
|
let message_size_exceeded () =
|
|
let%bind program,_ = get_program () in
|
|
let init_storage = storage {
|
|
threshold = 1 ; max_proposal = 1 ; max_msg_size = 1 ; state_hash = Bytes.empty ;
|
|
id_counter_list = [1,0] ;
|
|
msg_store_list = []
|
|
} in
|
|
let source = contract 1 in
|
|
let options = Proto_alpha_utils.Memory_proto_alpha.make_options ~source () in
|
|
let%bind () =
|
|
let exp_failwith = "Message size exceed maximum limit" in
|
|
expect_string_failwith ~options program "main"
|
|
(e_pair (send_param empty_message) init_storage) exp_failwith in
|
|
ok ()
|
|
|
|
(* sender has already has reached maximum number of proposal *)
|
|
let maximum_number_of_proposal () =
|
|
let%bind program,_ = get_program () in
|
|
let%bind packed_payload1 = pack_payload program (send_param empty_message) in
|
|
let bytes1 = e_bytes_ofbytes packed_payload1 in
|
|
let init_storage = storage {
|
|
threshold = 1 ; max_proposal = 1 ; max_msg_size = 15 ; state_hash = Bytes.empty ;
|
|
id_counter_list = [1,1] ;
|
|
msg_store_list = [(bytes1, e_set [e_address@@ addr 1])]
|
|
} in
|
|
let source = contract 1 in
|
|
let options = Proto_alpha_utils.Memory_proto_alpha.make_options ~source () in
|
|
let%bind () =
|
|
let exp_failwith = "Maximum number of proposal reached" in
|
|
expect_string_failwith ~options program "main"
|
|
(e_pair (send_param empty_message2) init_storage) exp_failwith in
|
|
ok ()
|
|
|
|
(* sender message is already stored in the message store *)
|
|
let send_already_accounted () =
|
|
let%bind program,_ = get_program () in
|
|
let%bind packed_payload = pack_payload program empty_message in
|
|
let bytes = e_bytes_ofbytes packed_payload in
|
|
let init_storage = storage {
|
|
threshold = 2 ; max_proposal = 1 ; max_msg_size = 15 ; state_hash = Bytes.empty ;
|
|
id_counter_list = [1,1 ; 2,0] ;
|
|
msg_store_list = [(bytes, e_set [e_address@@ addr 1])]
|
|
} in
|
|
let options =
|
|
let source = contract 1 in
|
|
Proto_alpha_utils.Memory_proto_alpha.make_options ~source () in
|
|
expect_eq ~options program "main"
|
|
(e_pair (send_param empty_message) init_storage) (e_pair empty_op_list init_storage)
|
|
|
|
(* sender message isn't stored in the message store *)
|
|
let send_never_accounted () =
|
|
let%bind program,_ = get_program () in
|
|
let%bind packed_payload = pack_payload program empty_message in
|
|
let bytes = e_bytes_ofbytes packed_payload in
|
|
let init_storage' = {
|
|
threshold = 2 ; max_proposal = 1 ; max_msg_size = 15 ; state_hash = Bytes.empty ;
|
|
id_counter_list = [1,0 ; 2,0] ;
|
|
msg_store_list = []
|
|
} in
|
|
let init_storage = storage init_storage' in
|
|
let final_storage = storage { init_storage' with
|
|
id_counter_list = [1,1 ; 2,0] ;
|
|
msg_store_list = [(bytes, e_set [e_address@@ addr 1])] ;
|
|
} in
|
|
let options =
|
|
let source = contract 1 in
|
|
Proto_alpha_utils.Memory_proto_alpha.make_options ~source () in
|
|
expect_eq ~options program "main"
|
|
(e_pair (send_param empty_message) init_storage) (e_pair empty_op_list final_storage)
|
|
|
|
(* sender withdraw message is already binded to one address in the message store *)
|
|
let withdraw_already_accounted_one () =
|
|
let%bind program,_ = get_program () in
|
|
let%bind packed_payload = pack_payload program empty_message in
|
|
let bytes = e_bytes_ofbytes packed_payload in
|
|
let param = withdraw_param in
|
|
let init_storage' = {
|
|
threshold = 2 ; max_proposal = 1 ; max_msg_size = 1 ; state_hash = Bytes.empty ;
|
|
id_counter_list = [1,1 ; 2,0] ;
|
|
msg_store_list = [(bytes, e_set [e_address@@ addr 1])] ;
|
|
} in
|
|
let init_storage = storage init_storage' in
|
|
let final_storage = storage { init_storage' with
|
|
id_counter_list = [1,0 ; 2,0] ;
|
|
msg_store_list = [] } in
|
|
let options =
|
|
let source = contract 1 in
|
|
Proto_alpha_utils.Memory_proto_alpha.make_options ~source () in
|
|
expect_eq ~options program "main"
|
|
(e_pair param init_storage) (e_pair empty_op_list final_storage)
|
|
|
|
(* sender withdraw message is already binded to two addresses in the message store *)
|
|
let withdraw_already_accounted_two () =
|
|
let%bind program,_ = get_program () in
|
|
let%bind packed_payload = pack_payload program empty_message in
|
|
let bytes = e_bytes_ofbytes packed_payload in
|
|
let param = withdraw_param in
|
|
let init_storage' = {
|
|
threshold = 2 ; max_proposal = 2 ; max_msg_size = 1 ; state_hash = Bytes.empty ;
|
|
id_counter_list = [1,1 ; 2,1] ;
|
|
msg_store_list = [(bytes, e_set [e_address@@ addr 1; e_address@@ addr 2])] ;
|
|
} in
|
|
let init_storage = storage init_storage' in
|
|
let final_storage = storage { init_storage' with
|
|
id_counter_list = [1,0 ; 2,1] ;
|
|
msg_store_list = [(bytes, e_set [e_address@@ addr 2])] } in
|
|
let options =
|
|
let source = contract 1 in
|
|
Proto_alpha_utils.Memory_proto_alpha.make_options ~source () in
|
|
expect_eq ~options program "main"
|
|
(e_pair param init_storage) (e_pair empty_op_list final_storage)
|
|
|
|
(* triggers the threshold and check that all the participants get their counters decremented *)
|
|
let counters_reset () =
|
|
let%bind program,_ = get_program () in
|
|
let%bind packed_payload = pack_payload program empty_message in
|
|
let bytes = e_bytes_ofbytes packed_payload in
|
|
let param = send_param empty_message in
|
|
let hash_after_msg = sha_256_hash (Bytes.concat Bytes.empty [Bytes.empty ; packed_payload]) in
|
|
let init_storage' = {
|
|
threshold = 3 ; max_proposal = 2 ; max_msg_size = 15 ; state_hash = Bytes.empty ;
|
|
id_counter_list = [1,1 ; 2,1 ; 3,0] ;
|
|
msg_store_list = [(bytes, e_set [e_address@@ addr 1; e_address@@ addr 2])] ;
|
|
} in
|
|
let init_storage = storage init_storage' in
|
|
let final_storage = storage { init_storage' with
|
|
state_hash = hash_after_msg ;
|
|
id_counter_list = [1,0 ; 2,0 ; 3,0] ;
|
|
msg_store_list = [] } in
|
|
let options =
|
|
let source = contract 3 in
|
|
Proto_alpha_utils.Memory_proto_alpha.make_options ~source () in
|
|
expect_eq ~options program "main"
|
|
(e_pair param init_storage) (e_pair empty_op_list final_storage)
|
|
|
|
(* sender withdraw message was never accounted *)
|
|
let withdraw_never_accounted () =
|
|
let%bind program,_ = get_program () in
|
|
let param = withdraw_param in
|
|
let init_storage = storage {
|
|
threshold = 2 ; max_proposal = 1 ; max_msg_size = 1 ; state_hash = Bytes.empty ;
|
|
id_counter_list = [1,0 ; 2,0] ;
|
|
msg_store_list = [] ;
|
|
} in
|
|
let options =
|
|
let source = contract 1 in
|
|
Proto_alpha_utils.Memory_proto_alpha.make_options ~source () in
|
|
expect_eq ~options program "main"
|
|
(e_pair param init_storage) (e_pair empty_op_list init_storage)
|
|
|
|
(* successful storing in the message store *)
|
|
let succeeded_storing () =
|
|
let%bind program,_ = get_program () in
|
|
let%bind packed_payload = pack_payload program empty_message in
|
|
let bytes = e_bytes_ofbytes packed_payload in
|
|
let init_storage th = {
|
|
threshold = th ; max_proposal = 1 ; max_msg_size = 15 ; state_hash = Bytes.empty ;
|
|
id_counter_list = [1,0 ; 2,0 ; 3,0] ;
|
|
msg_store_list = [(bytes, e_typed_set [] t_address)] ;
|
|
} in
|
|
let options =
|
|
let source = contract 1 in
|
|
Proto_alpha_utils.Memory_proto_alpha.make_options ~source () in
|
|
let%bind () = expect_eq_n_trace_aux ~options [1;2] program "main"
|
|
(fun th ->
|
|
let init_storage = storage (init_storage th) in
|
|
ok @@ e_pair (send_param empty_message) init_storage
|
|
)
|
|
(fun th ->
|
|
let hash_after_msg = sha_256_hash (Bytes.concat Bytes.empty [Bytes.empty ; packed_payload]) in
|
|
let final_id_counter, final_msg_store, ret, final_state_hash = match th with
|
|
| 1 -> [1,0 ; 2,0 ; 3,0] , [] , empty_op_list , hash_after_msg
|
|
| 2 -> [1,1 ; 2,0 ; 3,0] , [(bytes, e_set [e_address@@ addr 1])] , empty_op_list , (init_storage th).state_hash
|
|
| _ -> assert false in
|
|
let final_storage = storage { (init_storage th) with
|
|
state_hash = final_state_hash ;
|
|
msg_store_list = final_msg_store ;
|
|
id_counter_list = final_id_counter } in
|
|
ok @@ e_pair ret final_storage
|
|
) in
|
|
ok ()
|
|
|
|
let main = test_suite "Multisig v2" [
|
|
test "compile" compile_main ;
|
|
test "wrong_addr" wrong_addr ;
|
|
test "message_size_exceeded" message_size_exceeded ;
|
|
test "maximum_number_of_proposal" maximum_number_of_proposal ;
|
|
test "send_already_accounted" send_already_accounted ;
|
|
test "send_never_accounted" send_never_accounted ;
|
|
test "succeeded_storing" succeeded_storing ;
|
|
test "withdraw_already_accounted_one" withdraw_already_accounted_one ;
|
|
test "withdraw_already_accounted_two" withdraw_already_accounted_two ;
|
|
test "counters_reset" counters_reset ;
|
|
]
|