Alpha: rename "default contract" into "implicit contract"
This commit is contained in:
parent
16758a5c74
commit
c78dd51f3d
@ -112,7 +112,7 @@ module Account = struct
|
||||
| Some keys -> keys
|
||||
| None -> let _, pk, sk = Ed25519.generate_key () in sk, pk in
|
||||
let pkh = Ed25519.Public_key.hash pk in
|
||||
let contract = Contract.default_contract pkh in
|
||||
let contract = Contract.implicit_contract pkh in
|
||||
{ alias ; contract ; pkh ; pk ; sk }
|
||||
|
||||
type destination = {
|
||||
@ -163,7 +163,7 @@ module Account = struct
|
||||
let alias = Printf.sprintf "bootstrap%d" !cpt in
|
||||
let pk = Ed25519.Secret_key.to_public_key sk in
|
||||
let pkh = Ed25519.Public_key.hash pk in
|
||||
{ alias ; contract = Contract.default_contract pkh; pkh ; pk ; sk }
|
||||
{ alias ; contract = Contract.implicit_contract pkh; pkh ; pk ; sk }
|
||||
end [ bootstrap1_sk; bootstrap2_sk; bootstrap3_sk;
|
||||
bootstrap4_sk; bootstrap5_sk; ]
|
||||
with
|
||||
|
@ -146,7 +146,7 @@ let list_contract_labels (cctxt : #Proto_alpha.full) block =
|
||||
Alpha_services.Contract.list
|
||||
cctxt block >>=? fun contracts ->
|
||||
map_s (fun h ->
|
||||
begin match Contract.is_default h with
|
||||
begin match Contract.is_implicit h with
|
||||
| Some m -> begin
|
||||
Public_key_hash.rev_find cctxt m >>=? function
|
||||
| None -> return ""
|
||||
@ -161,8 +161,8 @@ let list_contract_labels (cctxt : #Proto_alpha.full) block =
|
||||
| Some nm -> return (" (known as " ^ nm ^ ")")
|
||||
end
|
||||
end >>=? fun nm ->
|
||||
let kind = match Contract.is_default h with
|
||||
| Some _ -> " (default)"
|
||||
let kind = match Contract.is_implicit h with
|
||||
| Some _ -> " (implicit)"
|
||||
| None -> "" in
|
||||
let h_b58 = Contract.to_b58check h in
|
||||
return (nm, h_b58, kind))
|
||||
|
@ -33,16 +33,16 @@ module ContractAlias = struct
|
||||
| None ->
|
||||
Client_keys.Public_key_hash.find_opt cctxt s >>=? function
|
||||
| Some v ->
|
||||
return (s, Contract.default_contract v)
|
||||
return (s, Contract.implicit_contract v)
|
||||
| None ->
|
||||
failwith "no contract or key named %s" s
|
||||
|
||||
let find_key cctxt name =
|
||||
Client_keys.Public_key_hash.find cctxt name >>=? fun v ->
|
||||
return (name, Contract.default_contract v)
|
||||
return (name, Contract.implicit_contract v)
|
||||
|
||||
let rev_find cctxt c =
|
||||
match Contract.is_default c with
|
||||
match Contract.is_implicit c with
|
||||
| Some hash -> begin
|
||||
Client_keys.Public_key_hash.rev_find cctxt hash >>=? function
|
||||
| Some name -> return (Some ("key:" ^ name))
|
||||
@ -91,7 +91,7 @@ module ContractAlias = struct
|
||||
find cctxt alias
|
||||
| [ "key" ; text ] ->
|
||||
Client_keys.Public_key_hash.find cctxt text >>=? fun v ->
|
||||
return (s, Contract.default_contract v)
|
||||
return (s, Contract.implicit_contract v)
|
||||
| _ ->
|
||||
find cctxt s >>= function
|
||||
| Ok v -> return v
|
||||
@ -120,22 +120,22 @@ let list_contracts cctxt =
|
||||
(fun (n, v) -> Lwt.return ("", n, v))
|
||||
raw_contracts >>= fun contracts ->
|
||||
Client_keys.Public_key_hash.load cctxt >>=? fun keys ->
|
||||
(* List accounts (default contracts of identities) *)
|
||||
(* List accounts (implicit contracts of identities) *)
|
||||
map_s (fun (n, v) ->
|
||||
RawContractAlias.mem cctxt n >>=? fun mem ->
|
||||
let p = if mem then "key:" else "" in
|
||||
let v' = Contract.default_contract v in
|
||||
let v' = Contract.implicit_contract v in
|
||||
return (p, n, v'))
|
||||
keys >>=? fun accounts ->
|
||||
return (contracts @ accounts)
|
||||
|
||||
let get_manager cctxt block source =
|
||||
match Contract.is_default source with
|
||||
match Contract.is_implicit source with
|
||||
| Some hash -> return hash
|
||||
| None -> Alpha_services.Contract.manager cctxt block source
|
||||
|
||||
let get_delegate cctxt block source =
|
||||
match Contract.is_default source with
|
||||
match Contract.is_implicit source with
|
||||
| Some hash -> return hash
|
||||
| None ->
|
||||
Alpha_services.Contract.delegate_opt cctxt
|
||||
|
@ -400,8 +400,8 @@ module Contract : sig
|
||||
val to_b58check: contract -> string
|
||||
val of_b58check: string -> contract tzresult
|
||||
|
||||
val default_contract: public_key_hash -> contract
|
||||
val is_default: contract -> public_key_hash option
|
||||
val implicit_contract: public_key_hash -> contract
|
||||
val is_implicit: contract -> public_key_hash option
|
||||
|
||||
val exists: context -> contract -> bool tzresult Lwt.t
|
||||
val must_exist: context -> contract -> unit tzresult Lwt.t
|
||||
|
@ -129,12 +129,12 @@ let pay_baking_bond c { Block_header.priority ; _ } id =
|
||||
if Compare.Int.(priority >= Constants.first_free_baking_slot c)
|
||||
then return c
|
||||
else
|
||||
Contract.spend c (Contract.default_contract id) Constants.baking_bond_cost
|
||||
Contract.spend c (Contract.implicit_contract id) Constants.baking_bond_cost
|
||||
|> trace Cannot_pay_baking_bond
|
||||
|
||||
let pay_endorsement_bond c id =
|
||||
let bond = Constants.endorsement_bond_cost in
|
||||
Contract.spend c (Contract.default_contract id) bond
|
||||
Contract.spend c (Contract.implicit_contract id) bond
|
||||
|> trace Cannot_pay_endorsement_bond >>=? fun c ->
|
||||
return (c, bond)
|
||||
|
||||
|
@ -16,7 +16,7 @@ let init_account ctxt account =
|
||||
Storage.Public_key.init ctxt account.public_key_hash account.public_key >>=? fun ctxt ->
|
||||
Contract_storage.credit
|
||||
ctxt
|
||||
(Contract_repr.default_contract account.public_key_hash)
|
||||
(Contract_repr.implicit_contract account.public_key_hash)
|
||||
Constants_repr.bootstrap_wealth >>=? fun ctxt ->
|
||||
return ctxt
|
||||
|
||||
|
@ -8,19 +8,19 @@
|
||||
(**************************************************************************)
|
||||
|
||||
type t =
|
||||
| Default of Ed25519.Public_key_hash.t
|
||||
| Implicit of Ed25519.Public_key_hash.t
|
||||
| Originated of Contract_hash.t
|
||||
|
||||
include Compare.Make(struct
|
||||
type nonrec t = t
|
||||
let compare l1 l2 =
|
||||
match l1, l2 with
|
||||
| Default pkh1, Default pkh2 ->
|
||||
| Implicit pkh1, Implicit pkh2 ->
|
||||
Ed25519.Public_key_hash.compare pkh1 pkh2
|
||||
| Originated h1, Originated h2 ->
|
||||
Contract_hash.compare h1 h2
|
||||
| Default _, Originated _ -> -1
|
||||
| Originated _, Default _ -> 1
|
||||
| Implicit _, Originated _ -> -1
|
||||
| Originated _, Implicit _ -> 1
|
||||
end)
|
||||
|
||||
type contract = t
|
||||
@ -28,21 +28,21 @@ type contract = t
|
||||
type error += Invalid_contract_notation of string (* `Permanent *)
|
||||
|
||||
let to_b58check = function
|
||||
| Default pbk -> Ed25519.Public_key_hash.to_b58check pbk
|
||||
| Implicit pbk -> Ed25519.Public_key_hash.to_b58check pbk
|
||||
| Originated h -> Contract_hash.to_b58check h
|
||||
|
||||
let of_b58check s =
|
||||
match Base58.decode s with
|
||||
| Some (Ed25519.Public_key_hash.Hash h) -> ok (Default h)
|
||||
| Some (Ed25519.Public_key_hash.Hash h) -> ok (Implicit h)
|
||||
| Some (Contract_hash.Hash h) -> ok (Originated h)
|
||||
| _ -> error (Invalid_contract_notation s)
|
||||
|
||||
let pp ppf = function
|
||||
| Default pbk -> Ed25519.Public_key_hash.pp ppf pbk
|
||||
| Implicit pbk -> Ed25519.Public_key_hash.pp ppf pbk
|
||||
| Originated h -> Contract_hash.pp ppf h
|
||||
|
||||
let pp_short ppf = function
|
||||
| Default pbk -> Ed25519.Public_key_hash.pp_short ppf pbk
|
||||
| Implicit pbk -> Ed25519.Public_key_hash.pp_short ppf pbk
|
||||
| Originated h -> Contract_hash.pp_short ppf h
|
||||
|
||||
let encoding =
|
||||
@ -52,14 +52,14 @@ let encoding =
|
||||
"A contract handle"
|
||||
~description:
|
||||
"A contract notation as given to an RPC or inside scripts. \
|
||||
Can be a base58 public key hash, representing the default contract \
|
||||
Can be a base58 public key hash, representing the implicit contract \
|
||||
of this identity, or a base58 originated contract hash." @@
|
||||
splitted
|
||||
~binary:
|
||||
(union ~tag_size:`Uint8 [
|
||||
case (Tag 0) Ed25519.Public_key_hash.encoding
|
||||
(function Default k -> Some k | _ -> None)
|
||||
(fun k -> Default k) ;
|
||||
(function Implicit k -> Some k | _ -> None)
|
||||
(fun k -> Implicit k) ;
|
||||
case (Tag 1) Contract_hash.encoding
|
||||
(function Originated k -> Some k | _ -> None)
|
||||
(fun k -> Originated k) ;
|
||||
@ -86,10 +86,10 @@ let () =
|
||||
(function Invalid_contract_notation loc -> Some loc | _ -> None)
|
||||
(fun loc -> Invalid_contract_notation loc)
|
||||
|
||||
let default_contract id = Default id
|
||||
let implicit_contract id = Implicit id
|
||||
|
||||
let is_default = function
|
||||
| Default m -> Some m
|
||||
let is_implicit = function
|
||||
| Implicit m -> Some m
|
||||
| Originated _ -> None
|
||||
|
||||
type origination_nonce =
|
||||
@ -151,15 +151,15 @@ module Index = struct
|
||||
Ed25519.Public_key_hash.path_length + 1
|
||||
let to_path c l =
|
||||
match c with
|
||||
| Default k ->
|
||||
"pubkey" :: Ed25519.Public_key_hash.to_path k l
|
||||
| Implicit k ->
|
||||
"implicit" :: Ed25519.Public_key_hash.to_path k l
|
||||
| Originated h ->
|
||||
"originated" :: Contract_hash.to_path h l
|
||||
let of_path = function
|
||||
| "pubkey" :: key -> begin
|
||||
| "implicit" :: key -> begin
|
||||
match Ed25519.Public_key_hash.of_path key with
|
||||
| None -> None
|
||||
| Some h -> Some (Default h)
|
||||
| Some h -> Some (Implicit h)
|
||||
end
|
||||
| "originated" :: key -> begin
|
||||
match Contract_hash.of_path key with
|
||||
|
@ -8,17 +8,17 @@
|
||||
(**************************************************************************)
|
||||
|
||||
type t = private
|
||||
| Default of Ed25519.Public_key_hash.t
|
||||
| Implicit of Ed25519.Public_key_hash.t
|
||||
| Originated of Contract_hash.t
|
||||
type contract = t
|
||||
|
||||
include Compare.S with type t := contract
|
||||
|
||||
(** {2 Default contracts} *****************************************************)
|
||||
(** {2 Implicit contracts} *****************************************************)
|
||||
|
||||
val default_contract : Ed25519.Public_key_hash.t -> contract
|
||||
val implicit_contract : Ed25519.Public_key_hash.t -> contract
|
||||
|
||||
val is_default : contract -> Ed25519.Public_key_hash.t option
|
||||
val is_implicit : contract -> Ed25519.Public_key_hash.t option
|
||||
|
||||
(** {2 Originated contracts} **************************************************)
|
||||
|
||||
|
@ -81,7 +81,7 @@ let () =
|
||||
`Temporary
|
||||
~id:"contract.non_existing_contract"
|
||||
~title:"Non existing contract"
|
||||
~description:"A non default contract handle is not present in the context \
|
||||
~description:"A contract handle is not present in the context \
|
||||
(either it never was or it has been destroyed)"
|
||||
~pp:(fun ppf contract ->
|
||||
Format.fprintf ppf "Contract %a does not exist"
|
||||
@ -93,7 +93,7 @@ let () =
|
||||
`Permanent
|
||||
~id:"contract.undelagatable_contract"
|
||||
~title:"Non delegatable contract"
|
||||
~description:"Tried to delegate a default contract \
|
||||
~description:"Tried to delegate a implicit contract \
|
||||
or a non delegatable originated contract"
|
||||
~pp:(fun ppf contract ->
|
||||
Format.fprintf ppf "Contract %a is not delegatable"
|
||||
@ -156,7 +156,7 @@ let failwith msg = fail (Failure msg)
|
||||
|
||||
let create_base c contract
|
||||
~balance ~manager ~delegate ?script ~spendable ~delegatable =
|
||||
(match Contract_repr.is_default contract with
|
||||
(match Contract_repr.is_implicit contract with
|
||||
| None -> return 0l
|
||||
| Some _ -> Storage.Contract.Global_counter.get c) >>=? fun counter ->
|
||||
Storage.Contract.Balance.init c contract balance >>=? fun c ->
|
||||
@ -187,8 +187,8 @@ let originate c nonce ~balance ~manager ?script ~delegate ~spendable ~delegatabl
|
||||
create_base c contract ~balance ~manager ~delegate ?script ~spendable ~delegatable >>=? fun (ctxt, contract) ->
|
||||
return (ctxt, contract, Contract_repr.incr_origination_nonce nonce)
|
||||
|
||||
let create_default c manager ~balance =
|
||||
create_base c (Contract_repr.default_contract manager)
|
||||
let create_implicit c manager ~balance =
|
||||
create_base c (Contract_repr.implicit_contract manager)
|
||||
~balance ~manager ~delegate:(Some manager)
|
||||
?script:None
|
||||
~spendable:true ~delegatable:false
|
||||
@ -211,7 +211,7 @@ let delete c contract =
|
||||
return c
|
||||
|
||||
let exists c contract =
|
||||
match Contract_repr.is_default contract with
|
||||
match Contract_repr.is_implicit contract with
|
||||
| Some _ -> return true
|
||||
| None ->
|
||||
Storage.Contract.Counter.get_option c contract >>=? function
|
||||
@ -254,7 +254,7 @@ let get_storage = Storage.Contract.Storage.get_option
|
||||
let get_counter c contract =
|
||||
Storage.Contract.Counter.get_option c contract >>=? function
|
||||
| None -> begin
|
||||
match Contract_repr.is_default contract with
|
||||
match Contract_repr.is_implicit contract with
|
||||
| Some _ -> Storage.Contract.Global_counter.get c
|
||||
| None -> failwith "get_counter"
|
||||
end
|
||||
@ -263,7 +263,7 @@ let get_counter c contract =
|
||||
let get_manager c contract =
|
||||
Storage.Contract.Manager.get_option c contract >>=? function
|
||||
| None -> begin
|
||||
match Contract_repr.is_default contract with
|
||||
match Contract_repr.is_implicit contract with
|
||||
| Some manager -> return manager
|
||||
| None -> failwith "get_manager"
|
||||
end
|
||||
@ -295,7 +295,7 @@ let get_delegate_opt = Roll_storage.get_contract_delegate
|
||||
let get_balance c contract =
|
||||
Storage.Contract.Balance.get_option c contract >>=? function
|
||||
| None -> begin
|
||||
match Contract_repr.is_default contract with
|
||||
match Contract_repr.is_implicit contract with
|
||||
| Some _ -> return Tez_repr.zero
|
||||
| None -> failwith "get_balance"
|
||||
end
|
||||
@ -304,7 +304,7 @@ let get_balance c contract =
|
||||
let is_delegatable c contract =
|
||||
Storage.Contract.Delegatable.get_option c contract >>=? function
|
||||
| None -> begin
|
||||
match Contract_repr.is_default contract with
|
||||
match Contract_repr.is_implicit contract with
|
||||
| Some _ -> return false
|
||||
| None -> failwith "is_delegatable"
|
||||
end
|
||||
@ -313,7 +313,7 @@ let is_delegatable c contract =
|
||||
let is_spendable c contract =
|
||||
Storage.Contract.Spendable.get_option c contract >>=? function
|
||||
| None -> begin
|
||||
match Contract_repr.is_default contract with
|
||||
match Contract_repr.is_implicit contract with
|
||||
| Some _ -> return true
|
||||
| None -> failwith "is_spendable"
|
||||
end
|
||||
@ -374,17 +374,17 @@ let spend_from_script c contract amount =
|
||||
Storage.Contract.Balance.set c contract new_balance >>=? fun c ->
|
||||
Roll_storage.Contract.remove_amount c contract amount
|
||||
else
|
||||
match Contract_repr.is_default contract with
|
||||
match Contract_repr.is_implicit contract with
|
||||
| Some _ -> delete c contract
|
||||
| None -> return c
|
||||
|
||||
let credit c contract amount =
|
||||
Storage.Contract.Balance.get_option c contract >>=? function
|
||||
| None -> begin
|
||||
match Contract_repr.is_default contract with
|
||||
match Contract_repr.is_implicit contract with
|
||||
| None -> fail (Non_existing_contract contract)
|
||||
| Some manager ->
|
||||
create_default c manager ~balance:amount >>=? fun (c, _) ->
|
||||
create_implicit c manager ~balance:amount >>=? fun (c, _) ->
|
||||
return c
|
||||
end
|
||||
| Some balance ->
|
||||
|
@ -257,7 +257,7 @@ module Cost_of = struct
|
||||
let transfer = step_cost 50
|
||||
let create_account = step_cost 20
|
||||
let create_contract = step_cost 70
|
||||
let default_account = step_cost 10
|
||||
let implicit_account = step_cost 10
|
||||
let balance = step_cost 5
|
||||
let now = step_cost 3
|
||||
let check_signature = step_cost 3
|
||||
|
@ -84,7 +84,7 @@ module Cost_of : sig
|
||||
val transfer : cost
|
||||
val create_account : cost
|
||||
val create_contract : cost
|
||||
val default_account : cost
|
||||
val implicit_account : cost
|
||||
val balance : cost
|
||||
val now : cost
|
||||
val check_signature : cost
|
||||
|
@ -135,7 +135,7 @@ module I = struct
|
||||
let operation = { hash ; shell ; contents ; signature } in
|
||||
let level = Alpha_context.Level.current ctxt in
|
||||
Baking.baking_priorities ctxt level >>=? fun (Misc.LCons (baker_pkh, _)) ->
|
||||
let baker_contract = Contract.default_contract baker_pkh in
|
||||
let baker_contract = Contract.implicit_contract baker_pkh in
|
||||
let block_prio = 0 in
|
||||
Apply.apply_operation
|
||||
ctxt (Some baker_contract) pred_block block_prio operation
|
||||
@ -149,7 +149,7 @@ module I = struct
|
||||
match contract with
|
||||
| Some contract -> contract
|
||||
| None ->
|
||||
Contract.default_contract
|
||||
Contract.implicit_contract
|
||||
(List.hd (Bootstrap.accounts ctxt)).Bootstrap.public_key_hash in
|
||||
let max_gas =
|
||||
Constants.max_gas ctxt in
|
||||
|
@ -107,7 +107,7 @@ let apply_operation ({ mode ; ctxt ; op_count } as data) operation =
|
||||
| Full_construction { predecessor ; protocol_data ; baker } ->
|
||||
predecessor,
|
||||
protocol_data.priority,
|
||||
Some (Alpha_context.Contract.default_contract baker) in
|
||||
Some (Alpha_context.Contract.implicit_contract baker) in
|
||||
Apply.apply_operation
|
||||
ctxt baker_contract pred_block block_prio operation
|
||||
>>=? fun (ctxt, _contracts, _ignored_script_error) ->
|
||||
|
@ -48,7 +48,7 @@ let pay_rewards_for_cycle c cycle =
|
||||
| Error _ -> Lwt.return c
|
||||
| Ok c ->
|
||||
Contract_storage.credit c
|
||||
(Contract_repr.default_contract delegate)
|
||||
(Contract_repr.implicit_contract delegate)
|
||||
amount) >>=? fun c ->
|
||||
Storage.Rewards.Amount.clear (c, cycle) >>= fun c ->
|
||||
return c
|
||||
|
@ -14,12 +14,12 @@ type error +=
|
||||
| No_roll_snapshot_for_cycle of Cycle_repr.t
|
||||
|
||||
let get_contract_delegate c contract =
|
||||
match Contract_repr.is_default contract with
|
||||
match Contract_repr.is_implicit contract with
|
||||
| Some manager -> return (Some manager)
|
||||
| None -> Storage.Contract.Delegate.get_option c contract
|
||||
|
||||
let get_contract_delegate_at_cycle c cycle contract =
|
||||
match Contract_repr.is_default contract with
|
||||
match Contract_repr.is_implicit contract with
|
||||
| Some manager -> return (Some manager)
|
||||
| None -> Storage.Contract.Delegate.Snapshot.get_option c (cycle, contract)
|
||||
|
||||
|
@ -730,9 +730,9 @@ let rec interp
|
||||
Fees.origination_burn ctxt ~source contract >>=? fun ctxt ->
|
||||
logged_return ~origination (Item ((Unit_t, Unit_t, contract), rest), gas, ctxt)
|
||||
| Default_account, Item (key, rest) ->
|
||||
let gas = Gas.consume gas Gas.Cost_of.default_account in
|
||||
let gas = Gas.consume gas Gas.Cost_of.implicit_account in
|
||||
Gas.check gas >>=? fun () ->
|
||||
let contract = Contract.default_contract key in
|
||||
let contract = Contract.implicit_contract key in
|
||||
logged_return (Item ((Unit_t, Unit_t, contract), rest), gas, ctxt)
|
||||
| Create_contract (storage_type, param_type, return_type),
|
||||
Item (manager, Item
|
||||
|
@ -373,7 +373,7 @@ let () =
|
||||
Contract.Indexed_context.resolve ctxt p >|= fun l ->
|
||||
List.map
|
||||
(function
|
||||
| Contract_repr.Default _ -> assert false
|
||||
| Contract_repr.Implicit _ -> assert false
|
||||
| Contract_repr.Originated s -> s)
|
||||
l) ;
|
||||
Raw_context.register_resolvers
|
||||
@ -383,6 +383,6 @@ let () =
|
||||
Contract.Indexed_context.resolve ctxt p >|= fun l ->
|
||||
List.map
|
||||
(function
|
||||
| Contract_repr.Default s -> s
|
||||
| Contract_repr.Implicit s -> s
|
||||
| Contract_repr.Originated _ -> assert false)
|
||||
l)
|
||||
|
@ -47,13 +47,13 @@ let bootstrap_accounts =
|
||||
pub ;
|
||||
ppk ;
|
||||
hpub ;
|
||||
contract = Contract.default_contract hpub
|
||||
contract = Contract.implicit_contract hpub
|
||||
}
|
||||
in List.map aux keys
|
||||
|
||||
let new_account () : account =
|
||||
let (hpub, pub, ppk) = Ed25519.generate_key () in
|
||||
let contract = Contract.default_contract hpub in
|
||||
let contract = Contract.implicit_contract hpub in
|
||||
{hpub ; pub ; ppk ; contract}
|
||||
|
||||
let init_amount = 10000
|
||||
|
@ -55,7 +55,7 @@ let test_endorsement_payment () =
|
||||
let contract_p =
|
||||
Misc.find_account bootstrap_accounts
|
||||
@@ List.nth endorsers endorser_slot in
|
||||
Contract.get_balance tc (Contract.default_contract contract_p.hpub) >>=? fun init_balance ->
|
||||
Contract.get_balance tc (Contract.implicit_contract contract_p.hpub) >>=? fun init_balance ->
|
||||
|
||||
(* After one block, endorsement bond cost should be paid *)
|
||||
Block.endorsement
|
||||
|
Loading…
Reference in New Issue
Block a user