236 lines
10 KiB
OCaml
236 lines
10 KiB
OCaml
|
(*****************************************************************************)
|
||
|
(* *)
|
||
|
(* 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. *)
|
||
|
(* *)
|
||
|
(*****************************************************************************)
|
||
|
|
||
|
open Protocol
|
||
|
open Test_utils
|
||
|
open Test_tez
|
||
|
|
||
|
let ten_tez = Tez.of_int 10
|
||
|
|
||
|
(** [register_origination fee credit spendable delegatable] takes four
|
||
|
optional parameter: fee for the fee need to be paid if set to
|
||
|
create an originated contract; credit is the amount of tez that
|
||
|
send to this originated contract; spendable default is set to true
|
||
|
meaning that this contract is spendable; delegatable default is
|
||
|
set to true meaning that this contract is able to delegate. *)
|
||
|
let register_origination ?(fee=Tez.zero) ?(credit=Tez.zero) () =
|
||
|
Context.init 1 >>=? fun (b, contracts) ->
|
||
|
let source = List.hd contracts in
|
||
|
Context.Contract.balance (B b) source >>=? fun source_balance ->
|
||
|
Op.origination (B b) source ~fee ~credit ~script:Op.dummy_script
|
||
|
>>=? fun (operation, originated) ->
|
||
|
Block.bake ~operation b >>=? fun b ->
|
||
|
(* fee + credit + block security deposit were debited from source *)
|
||
|
Context.get_constants (B b) >>=? fun {parametric = { origination_size ;
|
||
|
cost_per_byte ;
|
||
|
block_security_deposit ; _ }; _ } ->
|
||
|
Tez.(cost_per_byte *? Int64.of_int origination_size) >>?= fun origination_burn ->
|
||
|
Lwt.return (
|
||
|
Tez.(+?) credit block_security_deposit >>?
|
||
|
Tez.(+?) fee >>?
|
||
|
Tez.(+?) origination_burn >>?
|
||
|
Tez.(+?) Op.dummy_script_cost ) >>=? fun total_fee ->
|
||
|
Assert.balance_was_debited ~loc:__LOC__ (B b) source source_balance total_fee >>=? fun () ->
|
||
|
(* originated contract has been credited *)
|
||
|
Assert.balance_was_credited ~loc:__LOC__ (B b) originated Tez.zero credit >>=? fun () ->
|
||
|
(* TODO spendable or not and delegatable or not if relevant for some
|
||
|
test. Not the case at the moment, cf. uses of
|
||
|
register_origination *)
|
||
|
return (b, source, originated)
|
||
|
|
||
|
|
||
|
(* [test_origination_balances fee credit spendable delegatable]
|
||
|
takes four optional parameter: fee is the fee that pay if require to create
|
||
|
an originated contract; credit is the amount of tez that will send to this
|
||
|
contract; delegatable default is set to true meaning that this contract is
|
||
|
able to delegate.
|
||
|
This function will create a contract, get the balance of this contract, call
|
||
|
the origination operation to create a new originated contract from this
|
||
|
contract with all the possible fees; and check the balance before/after
|
||
|
originated operation valid.
|
||
|
- the source contract has payed all the fees
|
||
|
- the originated has been credited correctly *)
|
||
|
let test_origination_balances ~loc:_ ?(fee=Tez.zero) ?(credit=Tez.zero) () =
|
||
|
Context.init 1 >>=? fun (b, contracts) ->
|
||
|
let contract = List.hd contracts in
|
||
|
Context.Contract.balance (B b) contract >>=? fun balance ->
|
||
|
Op.origination (B b) contract ~fee ~credit ~script:Op.dummy_script
|
||
|
>>=? fun (operation, new_contract) ->
|
||
|
(* The possible fees are: a given credit, an origination burn fee
|
||
|
(constants_repr.default.origination_burn = 257 mtez),
|
||
|
a fee that is paid when creating an originate contract.
|
||
|
|
||
|
We also take into account a block security deposit. Note that it
|
||
|
is not related to origination but to the baking done in the
|
||
|
tests.*)
|
||
|
Context.get_constants (B b) >>=? fun
|
||
|
{ parametric =
|
||
|
{ origination_size ;
|
||
|
cost_per_byte ;
|
||
|
block_security_deposit
|
||
|
; _ }
|
||
|
; _ } ->
|
||
|
Tez.(cost_per_byte *? Int64.of_int origination_size) >>?= fun origination_burn ->
|
||
|
Lwt.return (
|
||
|
Tez.(+?) credit block_security_deposit >>?
|
||
|
Tez.(+?) fee >>?
|
||
|
Tez.(+?) origination_burn >>?
|
||
|
Tez.(+?) Op.dummy_script_cost ) >>=? fun total_fee ->
|
||
|
Block.bake ~operation b >>=? fun b ->
|
||
|
(* check that after the block has been baked the source contract
|
||
|
was debited all the fees *)
|
||
|
Assert.balance_was_debited ~loc:__LOC__ (B b) contract balance total_fee
|
||
|
>>=? fun _ ->
|
||
|
(* check the balance of the originate contract is equal to credit *)
|
||
|
Assert.balance_is ~loc:__LOC__ (B b) new_contract credit
|
||
|
|
||
|
(******************************************************)
|
||
|
(** Tests *)
|
||
|
(******************************************************)
|
||
|
|
||
|
(** compute half of the balance and divided it by nth times *)
|
||
|
|
||
|
let two_nth_of_balance incr contract nth =
|
||
|
Context.Contract.balance (I incr) contract >>=? fun balance ->
|
||
|
Tez.(/?) balance nth >>?= fun res ->
|
||
|
Tez.( *?) res 2L >>?= fun balance ->
|
||
|
return balance
|
||
|
|
||
|
(*******************)
|
||
|
(** Basic test *)
|
||
|
(*******************)
|
||
|
|
||
|
let balances_simple () = test_origination_balances ~loc:__LOC__ ()
|
||
|
|
||
|
let balances_credit () =
|
||
|
test_origination_balances ~loc:__LOC__ ~credit:ten_tez ()
|
||
|
|
||
|
let balances_credit_fee () =
|
||
|
test_origination_balances ~loc:__LOC__ ~credit:(Tez.of_int 2) ~fee:ten_tez ()
|
||
|
|
||
|
let balances_undelegatable () =
|
||
|
test_origination_balances ~loc:__LOC__ ()
|
||
|
|
||
|
(*******************)
|
||
|
(** ask source contract to pay a fee when originating a contract *)
|
||
|
(*******************)
|
||
|
|
||
|
let pay_fee () =
|
||
|
register_origination ~credit:(Tez.of_int 2) ~fee:ten_tez () >>=? fun (_b, _contract, _new_contract) ->
|
||
|
return_unit
|
||
|
|
||
|
(******************************************************)
|
||
|
(** Errors *)
|
||
|
(******************************************************)
|
||
|
|
||
|
(*******************)
|
||
|
(** create an originate contract where the contract
|
||
|
does not have enough tez to pay for the fee *)
|
||
|
(*******************)
|
||
|
|
||
|
let not_tez_in_contract_to_pay_fee () =
|
||
|
Context.init 2 >>=? fun (b, contracts) ->
|
||
|
let contract_1 = List.nth contracts 0 in
|
||
|
let contract_2 = List.nth contracts 1 in
|
||
|
Incremental.begin_construction b >>=? fun inc ->
|
||
|
(* transfer everything but one tez from 1 to 2 and check balance of 1 *)
|
||
|
Context.Contract.balance (I inc) contract_1 >>=? fun balance ->
|
||
|
Lwt.return @@ Tez.(-?) balance Tez.one >>=? fun amount ->
|
||
|
Op.transaction (I inc) contract_1 contract_2 amount >>=? fun operation ->
|
||
|
Incremental.add_operation inc operation >>=? fun inc ->
|
||
|
Assert.balance_was_debited ~loc:__LOC__ (I inc) contract_1 balance amount
|
||
|
>>=? fun _ ->
|
||
|
(* use this source contract to create an originate contract where it requires
|
||
|
to pay a fee and add an amount of credit into this new contract *)
|
||
|
Op.origination (I inc) ~fee:ten_tez ~credit:Tez.one contract_1 ~script:Op.dummy_script >>=? fun (op, _) ->
|
||
|
Incremental.add_operation inc op >>= fun inc ->
|
||
|
Assert.proto_error ~loc:__LOC__ inc begin function
|
||
|
| Contract_storage.Balance_too_low _ -> true
|
||
|
| _ -> false
|
||
|
end
|
||
|
|
||
|
(***************************************************)
|
||
|
(* set the endorser of the block as manager/delegate of the originated
|
||
|
account *)
|
||
|
(***************************************************)
|
||
|
|
||
|
let register_contract_get_endorser () =
|
||
|
Context.init 1 >>=? fun (b, contracts) ->
|
||
|
let contract = List.hd contracts in
|
||
|
Incremental.begin_construction b >>=? fun inc ->
|
||
|
Context.get_endorser (I inc) >>=? fun (account_endorser, _slots) ->
|
||
|
return (inc, contract, account_endorser)
|
||
|
|
||
|
(*******************)
|
||
|
(** create multiple originated contracts and
|
||
|
ask contract to pay the fee *)
|
||
|
(*******************)
|
||
|
|
||
|
let n_originations n ?credit ?fee () =
|
||
|
fold_left_s (fun new_contracts _ ->
|
||
|
register_origination ?fee ?credit () >>=? fun (_b, _source, new_contract) ->
|
||
|
|
||
|
let contracts = new_contract :: new_contracts in
|
||
|
return contracts
|
||
|
) [] (1 -- n)
|
||
|
|
||
|
let multiple_originations () =
|
||
|
n_originations 100 ~credit:(Tez.of_int 2) ~fee:ten_tez () >>=? fun contracts ->
|
||
|
Assert.equal_int ~loc:__LOC__ (List.length contracts) 100
|
||
|
|
||
|
(*******************)
|
||
|
(** cannot originate two contracts with the same context's counter *)
|
||
|
(*******************)
|
||
|
|
||
|
let counter () =
|
||
|
Context.init 1 >>=? fun (b, contracts) ->
|
||
|
let contract = List.hd contracts in
|
||
|
Incremental.begin_construction b >>=? fun inc ->
|
||
|
Op.origination (I inc) ~credit:Tez.one contract ~script:Op.dummy_script >>=? fun (op1, _) ->
|
||
|
Op.origination (I inc) ~credit:Tez.one contract ~script:Op.dummy_script >>=? fun (op2, _) ->
|
||
|
Incremental.add_operation inc op1 >>=? fun inc ->
|
||
|
Incremental.add_operation inc op2 >>= fun res ->
|
||
|
Assert.proto_error ~loc:__LOC__ res begin function
|
||
|
| Contract_storage.Counter_in_the_past _ -> true
|
||
|
| _ -> false
|
||
|
end
|
||
|
|
||
|
(******************************************************)
|
||
|
|
||
|
let tests = [
|
||
|
Test.tztest "balances_simple" `Quick balances_simple ;
|
||
|
Test.tztest "balances_credit" `Quick balances_credit ;
|
||
|
Test.tztest "balances_credit_fee" `Quick balances_credit_fee ;
|
||
|
Test.tztest "balances_undelegatable" `Quick balances_undelegatable ;
|
||
|
|
||
|
Test.tztest "pay_fee" `Quick pay_fee;
|
||
|
|
||
|
Test.tztest "not enough tez in contract to pay fee" `Quick not_tez_in_contract_to_pay_fee;
|
||
|
|
||
|
Test.tztest "multiple originations" `Quick multiple_originations;
|
||
|
|
||
|
Test.tztest "counter" `Quick counter;
|
||
|
]
|