2019-09-05 17:21:01 +04:00
|
|
|
(*****************************************************************************)
|
|
|
|
(* *)
|
|
|
|
(* Open Source License *)
|
|
|
|
(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
|
|
|
(* *)
|
|
|
|
(* Permission is hereby granted, free of charge, to any person obtaining a *)
|
|
|
|
(* copy of this software and associated documentation files (the "Software"),*)
|
|
|
|
(* to deal in the Software without restriction, including without limitation *)
|
|
|
|
(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)
|
|
|
|
(* and/or sell copies of the Software, and to permit persons to whom the *)
|
|
|
|
(* Software is furnished to do so, subject to the following conditions: *)
|
|
|
|
(* *)
|
|
|
|
(* The above copyright notice and this permission notice shall be included *)
|
|
|
|
(* in all copies or substantial portions of the Software. *)
|
|
|
|
(* *)
|
|
|
|
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
|
|
|
|
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)
|
|
|
|
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)
|
|
|
|
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
|
|
|
|
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)
|
|
|
|
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)
|
|
|
|
(* DEALINGS IN THE SOFTWARE. *)
|
|
|
|
(* *)
|
|
|
|
(*****************************************************************************)
|
|
|
|
|
|
|
|
type error +=
|
2020-02-12 20:40:17 +04:00
|
|
|
| Balance_too_low of Contract_repr.contract * Tez_repr.t * Tez_repr.t
|
|
|
|
| (* `Temporary *)
|
|
|
|
Counter_in_the_past of Contract_repr.contract * Z.t * Z.t
|
|
|
|
| (* `Branch *)
|
|
|
|
Counter_in_the_future of Contract_repr.contract * Z.t * Z.t
|
|
|
|
| (* `Temporary *)
|
|
|
|
Unspendable_contract of Contract_repr.contract
|
|
|
|
| (* `Permanent *)
|
|
|
|
Non_existing_contract of Contract_repr.contract
|
|
|
|
| (* `Temporary *)
|
|
|
|
Empty_implicit_contract of Signature.Public_key_hash.t
|
|
|
|
| (* `Temporary *)
|
|
|
|
Empty_implicit_delegated_contract of
|
|
|
|
Signature.Public_key_hash.t
|
|
|
|
| (* `Temporary *)
|
|
|
|
Empty_transaction of Contract_repr.t (* `Temporary *)
|
|
|
|
| Inconsistent_hash of
|
|
|
|
Signature.Public_key.t
|
|
|
|
* Signature.Public_key_hash.t
|
|
|
|
* Signature.Public_key_hash.t
|
|
|
|
| (* `Permanent *)
|
|
|
|
Inconsistent_public_key of
|
|
|
|
Signature.Public_key.t * Signature.Public_key.t
|
|
|
|
| (* `Permanent *)
|
|
|
|
Failure of string (* `Permanent *)
|
2019-09-05 17:21:01 +04:00
|
|
|
| Previously_revealed_key of Contract_repr.t (* `Permanent *)
|
2020-02-12 20:40:17 +04:00
|
|
|
| Unrevealed_manager_key of Contract_repr.t
|
|
|
|
|
|
|
|
(* `Permanent *)
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let () =
|
|
|
|
register_error_kind
|
|
|
|
`Permanent
|
|
|
|
~id:"contract.unspendable_contract"
|
|
|
|
~title:"Unspendable contract"
|
2020-02-12 20:40:17 +04:00
|
|
|
~description:
|
|
|
|
"An operation tried to spend tokens from an unspendable contract"
|
2019-09-05 17:21:01 +04:00
|
|
|
~pp:(fun ppf c ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"The tokens of contract %a can only be spent by its script"
|
|
|
|
Contract_repr.pp
|
|
|
|
c)
|
2019-09-05 17:21:01 +04:00
|
|
|
Data_encoding.(obj1 (req "contract" Contract_repr.encoding))
|
2020-02-12 20:40:17 +04:00
|
|
|
(function Unspendable_contract c -> Some c | _ -> None)
|
2019-09-05 17:21:01 +04:00
|
|
|
(fun c -> Unspendable_contract c) ;
|
|
|
|
register_error_kind
|
|
|
|
`Temporary
|
|
|
|
~id:"contract.balance_too_low"
|
|
|
|
~title:"Balance too low"
|
2020-02-12 20:40:17 +04:00
|
|
|
~description:
|
|
|
|
"An operation tried to spend more tokens than the contract has"
|
2019-09-05 17:21:01 +04:00
|
|
|
~pp:(fun ppf (c, b, a) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"Balance of contract %a too low (%a) to spend %a"
|
|
|
|
Contract_repr.pp
|
|
|
|
c
|
|
|
|
Tez_repr.pp
|
|
|
|
b
|
|
|
|
Tez_repr.pp
|
|
|
|
a)
|
|
|
|
Data_encoding.(
|
|
|
|
obj3
|
|
|
|
(req "contract" Contract_repr.encoding)
|
|
|
|
(req "balance" Tez_repr.encoding)
|
|
|
|
(req "amount" Tez_repr.encoding))
|
|
|
|
(function Balance_too_low (c, b, a) -> Some (c, b, a) | _ -> None)
|
2019-09-05 17:21:01 +04:00
|
|
|
(fun (c, b, a) -> Balance_too_low (c, b, a)) ;
|
|
|
|
register_error_kind
|
|
|
|
`Temporary
|
|
|
|
~id:"contract.counter_in_the_future"
|
|
|
|
~title:"Invalid counter (not yet reached) in a manager operation"
|
|
|
|
~description:"An operation assumed a contract counter in the future"
|
|
|
|
~pp:(fun ppf (contract, exp, found) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"Counter %s not yet reached for contract %a (expected %s)"
|
|
|
|
(Z.to_string found)
|
|
|
|
Contract_repr.pp
|
|
|
|
contract
|
|
|
|
(Z.to_string exp))
|
|
|
|
Data_encoding.(
|
|
|
|
obj3
|
|
|
|
(req "contract" Contract_repr.encoding)
|
|
|
|
(req "expected" z)
|
|
|
|
(req "found" z))
|
2019-09-05 17:21:01 +04:00
|
|
|
(function Counter_in_the_future (c, x, y) -> Some (c, x, y) | _ -> None)
|
|
|
|
(fun (c, x, y) -> Counter_in_the_future (c, x, y)) ;
|
|
|
|
register_error_kind
|
|
|
|
`Branch
|
|
|
|
~id:"contract.counter_in_the_past"
|
|
|
|
~title:"Invalid counter (already used) in a manager operation"
|
|
|
|
~description:"An operation assumed a contract counter in the past"
|
|
|
|
~pp:(fun ppf (contract, exp, found) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"Counter %s already used for contract %a (expected %s)"
|
|
|
|
(Z.to_string found)
|
|
|
|
Contract_repr.pp
|
|
|
|
contract
|
|
|
|
(Z.to_string exp))
|
|
|
|
Data_encoding.(
|
|
|
|
obj3
|
|
|
|
(req "contract" Contract_repr.encoding)
|
|
|
|
(req "expected" z)
|
|
|
|
(req "found" z))
|
2019-09-05 17:21:01 +04:00
|
|
|
(function Counter_in_the_past (c, x, y) -> Some (c, x, y) | _ -> None)
|
|
|
|
(fun (c, x, y) -> Counter_in_the_past (c, x, y)) ;
|
|
|
|
register_error_kind
|
|
|
|
`Temporary
|
|
|
|
~id:"contract.non_existing_contract"
|
|
|
|
~title:"Non existing contract"
|
2020-02-12 20:40:17 +04:00
|
|
|
~description:
|
|
|
|
"A contract handle is not present in the context (either it never was \
|
|
|
|
or it has been destroyed)"
|
2019-09-05 17:21:01 +04:00
|
|
|
~pp:(fun ppf contract ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf ppf "Contract %a does not exist" Contract_repr.pp contract)
|
2019-09-05 17:21:01 +04:00
|
|
|
Data_encoding.(obj1 (req "contract" Contract_repr.encoding))
|
|
|
|
(function Non_existing_contract c -> Some c | _ -> None)
|
|
|
|
(fun c -> Non_existing_contract c) ;
|
|
|
|
register_error_kind
|
|
|
|
`Permanent
|
|
|
|
~id:"contract.manager.inconsistent_hash"
|
|
|
|
~title:"Inconsistent public key hash"
|
2020-02-12 20:40:17 +04:00
|
|
|
~description:
|
|
|
|
"A revealed manager public key is inconsistent with the announced hash"
|
2019-09-05 17:21:01 +04:00
|
|
|
~pp:(fun ppf (k, eh, ph) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"The hash of the manager public key %s is not %a as announced but %a"
|
|
|
|
(Signature.Public_key.to_b58check k)
|
|
|
|
Signature.Public_key_hash.pp
|
|
|
|
ph
|
|
|
|
Signature.Public_key_hash.pp
|
|
|
|
eh)
|
|
|
|
Data_encoding.(
|
|
|
|
obj3
|
|
|
|
(req "public_key" Signature.Public_key.encoding)
|
|
|
|
(req "expected_hash" Signature.Public_key_hash.encoding)
|
|
|
|
(req "provided_hash" Signature.Public_key_hash.encoding))
|
2019-09-05 17:21:01 +04:00
|
|
|
(function Inconsistent_hash (k, eh, ph) -> Some (k, eh, ph) | _ -> None)
|
|
|
|
(fun (k, eh, ph) -> Inconsistent_hash (k, eh, ph)) ;
|
|
|
|
register_error_kind
|
|
|
|
`Permanent
|
|
|
|
~id:"contract.manager.inconsistent_public_key"
|
|
|
|
~title:"Inconsistent public key"
|
2020-02-12 20:40:17 +04:00
|
|
|
~description:
|
|
|
|
"A provided manager public key is different with the public key stored \
|
|
|
|
in the contract"
|
2019-09-05 17:21:01 +04:00
|
|
|
~pp:(fun ppf (eh, ph) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"Expected manager public key %s but %s was provided"
|
|
|
|
(Signature.Public_key.to_b58check ph)
|
|
|
|
(Signature.Public_key.to_b58check eh))
|
|
|
|
Data_encoding.(
|
|
|
|
obj2
|
|
|
|
(req "public_key" Signature.Public_key.encoding)
|
|
|
|
(req "expected_public_key" Signature.Public_key.encoding))
|
2019-09-05 17:21:01 +04:00
|
|
|
(function Inconsistent_public_key (eh, ph) -> Some (eh, ph) | _ -> None)
|
|
|
|
(fun (eh, ph) -> Inconsistent_public_key (eh, ph)) ;
|
|
|
|
register_error_kind
|
|
|
|
`Permanent
|
|
|
|
~id:"contract.failure"
|
|
|
|
~title:"Contract storage failure"
|
|
|
|
~description:"Unexpected contract storage error"
|
|
|
|
~pp:(fun ppf s -> Format.fprintf ppf "Contract_storage.Failure %S" s)
|
|
|
|
Data_encoding.(obj1 (req "message" string))
|
|
|
|
(function Failure s -> Some s | _ -> None)
|
|
|
|
(fun s -> Failure s) ;
|
|
|
|
register_error_kind
|
|
|
|
`Branch
|
|
|
|
~id:"contract.unrevealed_key"
|
|
|
|
~title:"Manager operation precedes key revelation"
|
|
|
|
~description:
|
2020-02-12 20:40:17 +04:00
|
|
|
"One tried to apply a manager operation without revealing the manager \
|
|
|
|
public key"
|
2019-09-05 17:21:01 +04:00
|
|
|
~pp:(fun ppf s ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"Unrevealed manager key for contract %a."
|
|
|
|
Contract_repr.pp
|
|
|
|
s)
|
2019-09-05 17:21:01 +04:00
|
|
|
Data_encoding.(obj1 (req "contract" Contract_repr.encoding))
|
|
|
|
(function Unrevealed_manager_key s -> Some s | _ -> None)
|
|
|
|
(fun s -> Unrevealed_manager_key s) ;
|
|
|
|
register_error_kind
|
|
|
|
`Branch
|
|
|
|
~id:"contract.previously_revealed_key"
|
|
|
|
~title:"Manager operation already revealed"
|
2020-02-12 20:40:17 +04:00
|
|
|
~description:"One tried to revealed twice a manager public key"
|
2019-09-05 17:21:01 +04:00
|
|
|
~pp:(fun ppf s ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"Previously revealed manager key for contract %a."
|
|
|
|
Contract_repr.pp
|
|
|
|
s)
|
2019-09-05 17:21:01 +04:00
|
|
|
Data_encoding.(obj1 (req "contract" Contract_repr.encoding))
|
|
|
|
(function Previously_revealed_key s -> Some s | _ -> None)
|
|
|
|
(fun s -> Previously_revealed_key s) ;
|
|
|
|
register_error_kind
|
|
|
|
`Branch
|
|
|
|
~id:"implicit.empty_implicit_contract"
|
|
|
|
~title:"Empty implicit contract"
|
2020-02-12 20:40:17 +04:00
|
|
|
~description:
|
|
|
|
"No manager operations are allowed on an empty implicit contract."
|
2019-09-05 17:21:01 +04:00
|
|
|
~pp:(fun ppf implicit ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"Empty implicit contract (%a)"
|
|
|
|
Signature.Public_key_hash.pp
|
|
|
|
implicit)
|
2019-09-05 17:21:01 +04:00
|
|
|
Data_encoding.(obj1 (req "implicit" Signature.Public_key_hash.encoding))
|
|
|
|
(function Empty_implicit_contract c -> Some c | _ -> None)
|
|
|
|
(fun c -> Empty_implicit_contract c) ;
|
2020-02-12 20:40:17 +04:00
|
|
|
register_error_kind
|
|
|
|
`Branch
|
|
|
|
~id:"implicit.empty_implicit_delegated_contract"
|
|
|
|
~title:"Empty implicit delegated contract"
|
|
|
|
~description:"Emptying an implicit delegated account is not allowed."
|
|
|
|
~pp:(fun ppf implicit ->
|
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"Emptying implicit delegated contract (%a)"
|
|
|
|
Signature.Public_key_hash.pp
|
|
|
|
implicit)
|
|
|
|
Data_encoding.(obj1 (req "implicit" Signature.Public_key_hash.encoding))
|
|
|
|
(function Empty_implicit_delegated_contract c -> Some c | _ -> None)
|
|
|
|
(fun c -> Empty_implicit_delegated_contract c) ;
|
2019-09-05 17:21:01 +04:00
|
|
|
register_error_kind
|
|
|
|
`Branch
|
|
|
|
~id:"contract.empty_transaction"
|
|
|
|
~title:"Empty transaction"
|
|
|
|
~description:"Forbidden to credit 0ꜩ to a contract without code."
|
|
|
|
~pp:(fun ppf contract ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Format.fprintf
|
|
|
|
ppf
|
|
|
|
"Transaction of 0ꜩ towards a contract without code are forbidden \
|
|
|
|
(%a)."
|
|
|
|
Contract_repr.pp
|
|
|
|
contract)
|
2019-09-05 17:21:01 +04:00
|
|
|
Data_encoding.(obj1 (req "contract" Contract_repr.encoding))
|
|
|
|
(function Empty_transaction c -> Some c | _ -> None)
|
|
|
|
(fun c -> Empty_transaction c)
|
|
|
|
|
|
|
|
let failwith msg = fail (Failure msg)
|
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
type big_map_diff_item =
|
|
|
|
| Update of {
|
|
|
|
big_map : Z.t;
|
|
|
|
diff_key : Script_repr.expr;
|
|
|
|
diff_key_hash : Script_expr_hash.t;
|
|
|
|
diff_value : Script_repr.expr option;
|
|
|
|
}
|
|
|
|
| Clear of Z.t
|
|
|
|
| Copy of Z.t * Z.t
|
|
|
|
| Alloc of {
|
|
|
|
big_map : Z.t;
|
|
|
|
key_type : Script_repr.expr;
|
|
|
|
value_type : Script_repr.expr;
|
|
|
|
}
|
|
|
|
|
2019-09-05 17:21:01 +04:00
|
|
|
type big_map_diff = big_map_diff_item list
|
|
|
|
|
|
|
|
let big_map_diff_item_encoding =
|
|
|
|
let open Data_encoding in
|
2019-10-17 13:45:27 +04:00
|
|
|
union
|
2020-02-12 20:40:17 +04:00
|
|
|
[ case
|
|
|
|
(Tag 0)
|
|
|
|
~title:"update"
|
2019-10-17 13:45:27 +04:00
|
|
|
(obj5
|
|
|
|
(req "action" (constant "update"))
|
|
|
|
(req "big_map" z)
|
|
|
|
(req "key_hash" Script_expr_hash.encoding)
|
|
|
|
(req "key" Script_repr.expr_encoding)
|
|
|
|
(opt "value" Script_repr.expr_encoding))
|
|
|
|
(function
|
2020-02-12 20:40:17 +04:00
|
|
|
| Update {big_map; diff_key_hash; diff_key; diff_value} ->
|
2019-10-17 13:45:27 +04:00
|
|
|
Some ((), big_map, diff_key_hash, diff_key, diff_value)
|
2020-02-12 20:40:17 +04:00
|
|
|
| _ ->
|
|
|
|
None)
|
2019-10-17 13:45:27 +04:00
|
|
|
(fun ((), big_map, diff_key_hash, diff_key, diff_value) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Update {big_map; diff_key_hash; diff_key; diff_value});
|
|
|
|
case
|
|
|
|
(Tag 1)
|
|
|
|
~title:"remove"
|
|
|
|
(obj2 (req "action" (constant "remove")) (req "big_map" z))
|
|
|
|
(function Clear big_map -> Some ((), big_map) | _ -> None)
|
|
|
|
(fun ((), big_map) -> Clear big_map);
|
|
|
|
case
|
|
|
|
(Tag 2)
|
|
|
|
~title:"copy"
|
2019-10-17 13:45:27 +04:00
|
|
|
(obj3
|
|
|
|
(req "action" (constant "copy"))
|
|
|
|
(req "source_big_map" z)
|
|
|
|
(req "destination_big_map" z))
|
2020-02-12 20:40:17 +04:00
|
|
|
(function Copy (src, dst) -> Some ((), src, dst) | _ -> None)
|
|
|
|
(fun ((), src, dst) -> Copy (src, dst));
|
|
|
|
case
|
|
|
|
(Tag 3)
|
|
|
|
~title:"alloc"
|
2019-10-17 13:45:27 +04:00
|
|
|
(obj4
|
|
|
|
(req "action" (constant "alloc"))
|
|
|
|
(req "big_map" z)
|
|
|
|
(req "key_type" Script_repr.expr_encoding)
|
|
|
|
(req "value_type" Script_repr.expr_encoding))
|
|
|
|
(function
|
2020-02-12 20:40:17 +04:00
|
|
|
| Alloc {big_map; key_type; value_type} ->
|
2019-10-17 13:45:27 +04:00
|
|
|
Some ((), big_map, key_type, value_type)
|
2020-02-12 20:40:17 +04:00
|
|
|
| _ ->
|
|
|
|
None)
|
2019-10-17 13:45:27 +04:00
|
|
|
(fun ((), big_map, key_type, value_type) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Alloc {big_map; key_type; value_type}) ]
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let big_map_diff_encoding =
|
|
|
|
let open Data_encoding in
|
2020-02-12 20:40:17 +04:00
|
|
|
def "contract.big_map_diff" @@ list big_map_diff_item_encoding
|
2019-09-05 17:21:01 +04:00
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
let big_map_key_cost = 65
|
2020-02-12 20:40:17 +04:00
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
let big_map_cost = 33
|
|
|
|
|
|
|
|
let update_script_big_map c = function
|
2020-02-12 20:40:17 +04:00
|
|
|
| None ->
|
|
|
|
return (c, Z.zero)
|
2019-09-05 17:21:01 +04:00
|
|
|
| Some diff ->
|
2020-02-12 20:40:17 +04:00
|
|
|
fold_left_s
|
|
|
|
(fun (c, total) -> function Clear id ->
|
|
|
|
Storage.Big_map.Total_bytes.get c id
|
|
|
|
>>=? fun size ->
|
|
|
|
Storage.Big_map.remove_rec c id
|
|
|
|
>>= fun c ->
|
|
|
|
if Compare.Z.(id < Z.zero) then return (c, total)
|
|
|
|
else return (c, Z.sub (Z.sub total size) (Z.of_int big_map_cost))
|
2019-10-17 13:45:27 +04:00
|
|
|
| Copy (from, to_) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Big_map.copy c ~from ~to_
|
|
|
|
>>=? fun c ->
|
|
|
|
if Compare.Z.(to_ < Z.zero) then return (c, total)
|
2019-10-17 13:45:27 +04:00
|
|
|
else
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Big_map.Total_bytes.get c from
|
|
|
|
>>=? fun size ->
|
2019-10-17 13:45:27 +04:00
|
|
|
return (c, Z.add (Z.add total size) (Z.of_int big_map_cost))
|
2020-02-12 20:40:17 +04:00
|
|
|
| Alloc {big_map; key_type; value_type} ->
|
|
|
|
Storage.Big_map.Total_bytes.init c big_map Z.zero
|
|
|
|
>>=? fun c ->
|
2019-10-17 13:45:27 +04:00
|
|
|
(* Annotations are erased to allow sharing on
|
|
|
|
[Copy]. The types from the contract code are used,
|
|
|
|
these ones are only used to make sure they are
|
|
|
|
compatible during transmissions between contracts,
|
|
|
|
and only need to be compatible, annotations
|
|
|
|
nonwhistanding. *)
|
2020-02-12 20:40:17 +04:00
|
|
|
let key_type =
|
|
|
|
Micheline.strip_locations
|
|
|
|
(Script_repr.strip_annotations (Micheline.root key_type))
|
|
|
|
in
|
|
|
|
let value_type =
|
|
|
|
Micheline.strip_locations
|
|
|
|
(Script_repr.strip_annotations (Micheline.root value_type))
|
|
|
|
in
|
|
|
|
Storage.Big_map.Key_type.init c big_map key_type
|
|
|
|
>>=? fun c ->
|
|
|
|
Storage.Big_map.Value_type.init c big_map value_type
|
|
|
|
>>=? fun c ->
|
|
|
|
if Compare.Z.(big_map < Z.zero) then return (c, total)
|
|
|
|
else return (c, Z.add total (Z.of_int big_map_cost))
|
|
|
|
| Update {big_map; diff_key_hash; diff_value = None} ->
|
2019-10-17 13:45:27 +04:00
|
|
|
Storage.Big_map.Contents.remove (c, big_map) diff_key_hash
|
|
|
|
>>=? fun (c, freed, existed) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
let freed =
|
|
|
|
if existed then freed + big_map_key_cost else freed
|
|
|
|
in
|
|
|
|
Storage.Big_map.Total_bytes.get c big_map
|
|
|
|
>>=? fun size ->
|
|
|
|
Storage.Big_map.Total_bytes.set
|
|
|
|
c
|
|
|
|
big_map
|
|
|
|
(Z.sub size (Z.of_int freed))
|
|
|
|
>>=? fun c ->
|
|
|
|
if Compare.Z.(big_map < Z.zero) then return (c, total)
|
|
|
|
else return (c, Z.sub total (Z.of_int freed))
|
|
|
|
| Update {big_map; diff_key_hash; diff_value = Some v} ->
|
2019-10-17 13:45:27 +04:00
|
|
|
Storage.Big_map.Contents.init_set (c, big_map) diff_key_hash v
|
|
|
|
>>=? fun (c, size_diff, existed) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
let size_diff =
|
|
|
|
if existed then size_diff else size_diff + big_map_key_cost
|
|
|
|
in
|
|
|
|
Storage.Big_map.Total_bytes.get c big_map
|
|
|
|
>>=? fun size ->
|
|
|
|
Storage.Big_map.Total_bytes.set
|
|
|
|
c
|
|
|
|
big_map
|
|
|
|
(Z.add size (Z.of_int size_diff))
|
|
|
|
>>=? fun c ->
|
|
|
|
if Compare.Z.(big_map < Z.zero) then return (c, total)
|
|
|
|
else return (c, Z.add total (Z.of_int size_diff)))
|
|
|
|
(c, Z.zero)
|
|
|
|
diff
|
|
|
|
|
|
|
|
let create_base c ?(prepaid_bootstrap_storage = false)
|
|
|
|
(* Free space for bootstrap contracts *)
|
|
|
|
contract ~balance ~manager ~delegate ?script () =
|
|
|
|
( match Contract_repr.is_implicit contract with
|
|
|
|
| None ->
|
|
|
|
return c
|
|
|
|
| Some _ ->
|
|
|
|
Storage.Contract.Global_counter.get c
|
|
|
|
>>=? fun counter -> Storage.Contract.Counter.init c contract counter )
|
|
|
|
>>=? fun c ->
|
|
|
|
Storage.Contract.Balance.init c contract balance
|
|
|
|
>>=? fun c ->
|
|
|
|
( match manager with
|
|
|
|
| Some manager ->
|
|
|
|
Storage.Contract.Manager.init c contract (Manager_repr.Hash manager)
|
|
|
|
| None ->
|
|
|
|
return c )
|
|
|
|
>>=? fun c ->
|
|
|
|
( match delegate with
|
|
|
|
| None ->
|
|
|
|
return c
|
|
|
|
| Some delegate ->
|
|
|
|
Delegate_storage.init c contract delegate )
|
|
|
|
>>=? fun c ->
|
2019-10-17 13:45:27 +04:00
|
|
|
match script with
|
2020-02-12 20:40:17 +04:00
|
|
|
| Some ({Script_repr.code; storage}, big_map_diff) ->
|
|
|
|
Storage.Contract.Code.init c contract code
|
|
|
|
>>=? fun (c, code_size) ->
|
|
|
|
Storage.Contract.Storage.init c contract storage
|
|
|
|
>>=? fun (c, storage_size) ->
|
|
|
|
update_script_big_map c big_map_diff
|
|
|
|
>>=? fun (c, big_map_size) ->
|
|
|
|
let total_size =
|
|
|
|
Z.add (Z.add (Z.of_int code_size) (Z.of_int storage_size)) big_map_size
|
|
|
|
in
|
|
|
|
assert (Compare.Z.(total_size >= Z.zero)) ;
|
2019-10-17 13:45:27 +04:00
|
|
|
let prepaid_bootstrap_storage =
|
2020-02-12 20:40:17 +04:00
|
|
|
if prepaid_bootstrap_storage then total_size else Z.zero
|
2019-10-17 13:45:27 +04:00
|
|
|
in
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Paid_storage_space.init
|
|
|
|
c
|
|
|
|
contract
|
|
|
|
prepaid_bootstrap_storage
|
|
|
|
>>=? fun c ->
|
2019-10-17 13:45:27 +04:00
|
|
|
Storage.Contract.Used_storage_space.init c contract total_size
|
|
|
|
| None ->
|
|
|
|
return c
|
2019-09-05 17:21:01 +04:00
|
|
|
|
2020-02-12 20:40:17 +04:00
|
|
|
let originate c ?prepaid_bootstrap_storage contract ~balance ~script ~delegate
|
|
|
|
=
|
|
|
|
create_base
|
|
|
|
c
|
|
|
|
?prepaid_bootstrap_storage
|
|
|
|
contract
|
|
|
|
~balance
|
|
|
|
~manager:None
|
|
|
|
~delegate
|
|
|
|
~script
|
|
|
|
()
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let create_implicit c manager ~balance =
|
2020-02-12 20:40:17 +04:00
|
|
|
create_base
|
|
|
|
c
|
|
|
|
(Contract_repr.implicit_contract manager)
|
|
|
|
~balance
|
|
|
|
~manager:(Some manager)
|
|
|
|
?script:None
|
|
|
|
~delegate:None
|
|
|
|
()
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let delete c contract =
|
|
|
|
match Contract_repr.is_implicit contract with
|
|
|
|
| None ->
|
|
|
|
(* For non implicit contract Big_map should be cleared *)
|
|
|
|
failwith "Non implicit contracts cannot be removed"
|
|
|
|
| Some _ ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Delegate_storage.remove c contract
|
|
|
|
>>=? fun c ->
|
|
|
|
Storage.Contract.Balance.delete c contract
|
|
|
|
>>=? fun c ->
|
|
|
|
Storage.Contract.Manager.delete c contract
|
|
|
|
>>=? fun c ->
|
|
|
|
Storage.Contract.Counter.delete c contract
|
|
|
|
>>=? fun c ->
|
|
|
|
Storage.Contract.Code.remove c contract
|
|
|
|
>>=? fun (c, _, _) ->
|
|
|
|
Storage.Contract.Storage.remove c contract
|
|
|
|
>>=? fun (c, _, _) ->
|
|
|
|
Storage.Contract.Paid_storage_space.remove c contract
|
|
|
|
>>= fun c ->
|
|
|
|
Storage.Contract.Used_storage_space.remove c contract
|
|
|
|
>>= fun c -> return c
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let allocated c contract =
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Balance.get_option c contract
|
|
|
|
>>=? function None -> return_false | Some _ -> return_true
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let exists c contract =
|
|
|
|
match Contract_repr.is_implicit contract with
|
2020-02-12 20:40:17 +04:00
|
|
|
| Some _ ->
|
|
|
|
return_true
|
|
|
|
| None ->
|
|
|
|
allocated c contract
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let must_exist c contract =
|
2020-02-12 20:40:17 +04:00
|
|
|
exists c contract
|
|
|
|
>>=? function
|
|
|
|
| true -> return_unit | false -> fail (Non_existing_contract contract)
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let must_be_allocated c contract =
|
2020-02-12 20:40:17 +04:00
|
|
|
allocated c contract
|
|
|
|
>>=? function
|
|
|
|
| true ->
|
|
|
|
return_unit
|
|
|
|
| false -> (
|
|
|
|
match Contract_repr.is_implicit contract with
|
|
|
|
| Some pkh ->
|
|
|
|
fail (Empty_implicit_contract pkh)
|
|
|
|
| None ->
|
|
|
|
fail (Non_existing_contract contract) )
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let list c = Storage.Contract.list c
|
|
|
|
|
|
|
|
let fresh_contract_from_current_nonce c =
|
2020-02-12 20:40:17 +04:00
|
|
|
Lwt.return (Raw_context.increment_origination_nonce c)
|
|
|
|
>>=? fun (c, nonce) -> return (c, Contract_repr.originated_contract nonce)
|
|
|
|
|
|
|
|
let originated_from_current_nonce ~since:ctxt_since ~until:ctxt_until =
|
|
|
|
Lwt.return (Raw_context.origination_nonce ctxt_since)
|
|
|
|
>>=? fun since ->
|
|
|
|
Lwt.return (Raw_context.origination_nonce ctxt_until)
|
|
|
|
>>=? fun until ->
|
2019-09-05 17:21:01 +04:00
|
|
|
filter_map_s
|
2020-02-12 20:40:17 +04:00
|
|
|
(fun contract ->
|
|
|
|
exists ctxt_until contract
|
|
|
|
>>=? function true -> return_some contract | false -> return_none)
|
2019-09-05 17:21:01 +04:00
|
|
|
(Contract_repr.originated_contracts ~since ~until)
|
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
let check_counter_increment c manager counter =
|
|
|
|
let contract = Contract_repr.implicit_contract manager in
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Counter.get c contract
|
|
|
|
>>=? fun contract_counter ->
|
2019-09-05 17:21:01 +04:00
|
|
|
let expected = Z.succ contract_counter in
|
2020-02-12 20:40:17 +04:00
|
|
|
if Compare.Z.(expected = counter) then return_unit
|
2019-09-05 17:21:01 +04:00
|
|
|
else if Compare.Z.(expected > counter) then
|
|
|
|
fail (Counter_in_the_past (contract, expected, counter))
|
2020-02-12 20:40:17 +04:00
|
|
|
else fail (Counter_in_the_future (contract, expected, counter))
|
2019-09-05 17:21:01 +04:00
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
let increment_counter c manager =
|
|
|
|
let contract = Contract_repr.implicit_contract manager in
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Global_counter.get c
|
|
|
|
>>=? fun global_counter ->
|
|
|
|
Storage.Contract.Global_counter.set c (Z.succ global_counter)
|
|
|
|
>>=? fun c ->
|
|
|
|
Storage.Contract.Counter.get c contract
|
|
|
|
>>=? fun contract_counter ->
|
2019-09-05 17:21:01 +04:00
|
|
|
Storage.Contract.Counter.set c contract (Z.succ contract_counter)
|
|
|
|
|
2020-02-12 20:40:17 +04:00
|
|
|
let get_script_code c contract = Storage.Contract.Code.get_option c contract
|
2019-10-17 13:45:27 +04:00
|
|
|
|
2019-09-05 17:21:01 +04:00
|
|
|
let get_script c contract =
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Code.get_option c contract
|
|
|
|
>>=? fun (c, code) ->
|
|
|
|
Storage.Contract.Storage.get_option c contract
|
|
|
|
>>=? fun (c, storage) ->
|
|
|
|
match (code, storage) with
|
|
|
|
| (None, None) ->
|
|
|
|
return (c, None)
|
|
|
|
| (Some code, Some storage) ->
|
|
|
|
return (c, Some {Script_repr.code; storage})
|
|
|
|
| (None, Some _) | (Some _, None) ->
|
|
|
|
failwith "get_script"
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let get_storage ctxt contract =
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Storage.get_option ctxt contract
|
|
|
|
>>=? function
|
|
|
|
| (ctxt, None) ->
|
|
|
|
return (ctxt, None)
|
2019-09-05 17:21:01 +04:00
|
|
|
| (ctxt, Some storage) ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Lwt.return (Script_repr.force_decode storage)
|
|
|
|
>>=? fun (storage, cost) ->
|
|
|
|
Lwt.return (Raw_context.consume_gas ctxt cost)
|
|
|
|
>>=? fun ctxt -> return (ctxt, Some storage)
|
2019-09-05 17:21:01 +04:00
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
let get_counter c manager =
|
|
|
|
let contract = Contract_repr.implicit_contract manager in
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Counter.get_option c contract
|
|
|
|
>>=? function
|
|
|
|
| None -> (
|
|
|
|
match Contract_repr.is_implicit contract with
|
|
|
|
| Some _ ->
|
|
|
|
Storage.Contract.Global_counter.get c
|
|
|
|
| None ->
|
|
|
|
failwith "get_counter" )
|
|
|
|
| Some v ->
|
|
|
|
return v
|
2019-09-05 17:21:01 +04:00
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
let get_manager_key c manager =
|
|
|
|
let contract = Contract_repr.implicit_contract manager in
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Manager.get_option c contract
|
|
|
|
>>=? function
|
|
|
|
| None ->
|
|
|
|
failwith "get_manager_key"
|
|
|
|
| Some (Manager_repr.Hash _) ->
|
|
|
|
fail (Unrevealed_manager_key contract)
|
|
|
|
| Some (Manager_repr.Public_key v) ->
|
|
|
|
return v
|
2019-09-05 17:21:01 +04:00
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
let is_manager_key_revealed c manager =
|
|
|
|
let contract = Contract_repr.implicit_contract manager in
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Manager.get_option c contract
|
|
|
|
>>=? function
|
|
|
|
| None ->
|
|
|
|
return_false
|
|
|
|
| Some (Manager_repr.Hash _) ->
|
|
|
|
return_false
|
|
|
|
| Some (Manager_repr.Public_key _) ->
|
|
|
|
return_true
|
2019-09-05 17:21:01 +04:00
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
let reveal_manager_key c manager public_key =
|
|
|
|
let contract = Contract_repr.implicit_contract manager in
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Manager.get c contract
|
|
|
|
>>=? function
|
|
|
|
| Public_key _ ->
|
|
|
|
fail (Previously_revealed_key contract)
|
2019-09-05 17:21:01 +04:00
|
|
|
| Hash v ->
|
|
|
|
let actual_hash = Signature.Public_key.hash public_key in
|
2020-02-12 20:40:17 +04:00
|
|
|
if Signature.Public_key_hash.equal actual_hash v then
|
|
|
|
let v = Manager_repr.Public_key public_key in
|
|
|
|
Storage.Contract.Manager.set c contract v >>=? fun c -> return c
|
|
|
|
else fail (Inconsistent_hash (public_key, v, actual_hash))
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let get_balance c contract =
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Balance.get_option c contract
|
|
|
|
>>=? function
|
|
|
|
| None -> (
|
|
|
|
match Contract_repr.is_implicit contract with
|
|
|
|
| Some _ ->
|
|
|
|
return Tez_repr.zero
|
|
|
|
| None ->
|
|
|
|
failwith "get_balance" )
|
|
|
|
| Some v ->
|
|
|
|
return v
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let update_script_storage c contract storage big_map_diff =
|
|
|
|
let storage = Script_repr.lazy_expr storage in
|
2020-02-12 20:40:17 +04:00
|
|
|
update_script_big_map c big_map_diff
|
|
|
|
>>=? fun (c, big_map_size_diff) ->
|
|
|
|
Storage.Contract.Storage.set c contract storage
|
|
|
|
>>=? fun (c, size_diff) ->
|
|
|
|
Storage.Contract.Used_storage_space.get c contract
|
|
|
|
>>=? fun previous_size ->
|
|
|
|
let new_size =
|
|
|
|
Z.add previous_size (Z.add big_map_size_diff (Z.of_int size_diff))
|
|
|
|
in
|
2019-09-05 17:21:01 +04:00
|
|
|
Storage.Contract.Used_storage_space.set c contract new_size
|
|
|
|
|
2019-10-17 13:45:27 +04:00
|
|
|
let spend c contract amount =
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Balance.get c contract
|
|
|
|
>>=? fun balance ->
|
2019-09-05 17:21:01 +04:00
|
|
|
match Tez_repr.(balance -? amount) with
|
|
|
|
| Error _ ->
|
|
|
|
fail (Balance_too_low (contract, balance, amount))
|
2020-02-12 20:40:17 +04:00
|
|
|
| Ok new_balance -> (
|
|
|
|
Storage.Contract.Balance.set c contract new_balance
|
|
|
|
>>=? fun c ->
|
|
|
|
Roll_storage.Contract.remove_amount c contract amount
|
|
|
|
>>=? fun c ->
|
|
|
|
if Tez_repr.(new_balance > Tez_repr.zero) then return c
|
|
|
|
else
|
|
|
|
match Contract_repr.is_implicit contract with
|
|
|
|
| None ->
|
|
|
|
return c (* Never delete originated contracts *)
|
|
|
|
| Some pkh -> (
|
|
|
|
Delegate_storage.get c contract
|
|
|
|
>>=? function
|
2019-09-05 17:21:01 +04:00
|
|
|
| Some pkh' ->
|
2020-02-12 20:40:17 +04:00
|
|
|
if Signature.Public_key_hash.equal pkh pkh' then return c
|
|
|
|
else
|
|
|
|
(* Delegated implicit accounts cannot be emptied *)
|
|
|
|
fail (Empty_implicit_delegated_contract pkh)
|
2019-09-05 17:21:01 +04:00
|
|
|
| None ->
|
|
|
|
(* Delete empty implicit contract *)
|
2020-02-12 20:40:17 +04:00
|
|
|
delete c contract ) )
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let credit c contract amount =
|
2020-02-12 20:40:17 +04:00
|
|
|
( if Tez_repr.(amount <> Tez_repr.zero) then return c
|
|
|
|
else
|
|
|
|
Storage.Contract.Code.mem c contract
|
|
|
|
>>=? fun (c, target_has_code) ->
|
|
|
|
fail_unless target_has_code (Empty_transaction contract)
|
|
|
|
>>=? fun () -> return c )
|
|
|
|
>>=? fun c ->
|
|
|
|
Storage.Contract.Balance.get_option c contract
|
|
|
|
>>=? function
|
|
|
|
| None -> (
|
|
|
|
match Contract_repr.is_implicit contract with
|
|
|
|
| None ->
|
|
|
|
fail (Non_existing_contract contract)
|
|
|
|
| Some manager ->
|
|
|
|
create_implicit c manager ~balance:amount )
|
2019-09-05 17:21:01 +04:00
|
|
|
| Some balance ->
|
2020-02-12 20:40:17 +04:00
|
|
|
Lwt.return Tez_repr.(amount +? balance)
|
|
|
|
>>=? fun balance ->
|
|
|
|
Storage.Contract.Balance.set c contract balance
|
|
|
|
>>=? fun c -> Roll_storage.Contract.add_amount c contract amount
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let init c =
|
|
|
|
Storage.Contract.Global_counter.init c Z.zero
|
2020-02-12 20:40:17 +04:00
|
|
|
>>=? fun c -> Storage.Big_map.Next.init c
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let used_storage_space c contract =
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Used_storage_space.get_option c contract
|
|
|
|
>>=? function None -> return Z.zero | Some fees -> return fees
|
2019-09-05 17:21:01 +04:00
|
|
|
|
|
|
|
let paid_storage_space c contract =
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Paid_storage_space.get_option c contract
|
|
|
|
>>=? function None -> return Z.zero | Some paid_space -> return paid_space
|
|
|
|
|
|
|
|
let set_paid_storage_space_and_return_fees_to_pay c contract new_storage_space
|
|
|
|
=
|
|
|
|
Storage.Contract.Paid_storage_space.get c contract
|
|
|
|
>>=? fun already_paid_space ->
|
|
|
|
if Compare.Z.(already_paid_space >= new_storage_space) then return (Z.zero, c)
|
2019-09-05 17:21:01 +04:00
|
|
|
else
|
|
|
|
let to_pay = Z.sub new_storage_space already_paid_space in
|
2020-02-12 20:40:17 +04:00
|
|
|
Storage.Contract.Paid_storage_space.set c contract new_storage_space
|
|
|
|
>>=? fun c -> return (to_pay, c)
|