From 1ce8984d7a67099468426fc85fd4986aaac3156c Mon Sep 17 00:00:00 2001 From: bsall Date: Fri, 11 Feb 2022 22:30:50 +0100 Subject: [PATCH 01/31] Proto: introduce a function to access contract's intrinsic stake Accesses to a contract's stake are redirected to a function in Contract_storage. So that when we include frozen bonds in the stake, the change is done at one location. --- .../lib_protocol/contract_delegate_storage.ml | 28 +++++++++---------- .../contract_delegate_storage.mli | 22 +++++++++------ .../lib_protocol/contract_storage.ml | 5 +++- .../lib_protocol/contract_storage.mli | 4 +++ .../lib_protocol/delegate_storage.ml | 11 +++++--- 5 files changed, 42 insertions(+), 28 deletions(-) diff --git a/src/proto_alpha/lib_protocol/contract_delegate_storage.ml b/src/proto_alpha/lib_protocol/contract_delegate_storage.ml index ca295af19167..757e862c4da9 100644 --- a/src/proto_alpha/lib_protocol/contract_delegate_storage.ml +++ b/src/proto_alpha/lib_protocol/contract_delegate_storage.ml @@ -43,40 +43,38 @@ let registered c delegate = Signature.Public_key_hash.equal delegate current_delegate | None -> false -let link c contract delegate = - Storage.Contract.Balance.get c contract >>=? fun balance -> - Stake_storage.add_stake c delegate balance >>=? fun c -> +let link c contract stake delegate = + Stake_storage.add_stake c delegate stake >>=? fun c -> Storage.Contract.Delegated.add (c, Contract_repr.implicit_contract delegate) contract >|= ok -let unlink c contract = +let unlink c contract stake = Storage.Contract.Delegate.find c contract >>=? function | None -> return c | Some delegate -> - Storage.Contract.Balance.get c contract >>=? fun balance -> - (* Removes the balance of the contract from the delegate *) - Stake_storage.remove_stake c delegate balance >>=? fun c -> + (* Removes the stake of the contract from the delegate *) + Stake_storage.remove_stake c delegate stake >>=? fun c -> Storage.Contract.Delegated.remove (c, Contract_repr.implicit_contract delegate) contract >|= ok -let init ctxt contract delegate = +let init ctxt contract stake delegate = Storage.Contract.Delegate.init ctxt contract delegate >>=? fun ctxt -> - link ctxt contract delegate + link ctxt contract stake delegate -let delete ctxt contract = - unlink ctxt contract >>=? fun ctxt -> +let delete ctxt contract stake = + unlink ctxt contract stake >>=? fun ctxt -> Storage.Contract.Delegate.remove ctxt contract >|= ok -let remove ctxt contract = unlink ctxt contract +let remove ctxt contract stake = unlink ctxt contract stake -let set ctxt contract delegate = - unlink ctxt contract >>=? fun ctxt -> +let set ctxt contract stake delegate = + unlink ctxt contract stake >>=? fun ctxt -> Storage.Contract.Delegate.add ctxt contract delegate >>= fun ctxt -> - link ctxt contract delegate + link ctxt contract stake delegate let delegated_contracts ctxt delegate = let contract = Contract_repr.implicit_contract delegate in diff --git a/src/proto_alpha/lib_protocol/contract_delegate_storage.mli b/src/proto_alpha/lib_protocol/contract_delegate_storage.mli index 1a62d96b6ade..10bdb30ef881 100644 --- a/src/proto_alpha/lib_protocol/contract_delegate_storage.mli +++ b/src/proto_alpha/lib_protocol/contract_delegate_storage.mli @@ -42,31 +42,37 @@ val registered : val init : Raw_context.t -> Contract_repr.t -> + Tez_repr.t -> Signature.Public_key_hash.t -> Raw_context.t tzresult Lwt.t -(** [remove ctxt contract] removes contract from the list of contracts that +(** [remove ctxt contract stake] removes contract from the list of contracts that delegated to [find ctxt contract], i.e. the output of [delegated_contracts]. This function does not affect the value of the expression - [find ctxt contract]. + [find ctxt contract]. [stake] is the total stake of [contract] This function is undefined if [contract] is not allocated. *) -val remove : Raw_context.t -> Contract_repr.t -> Raw_context.t tzresult Lwt.t +val remove : + Raw_context.t -> Contract_repr.t -> Tez_repr.t -> Raw_context.t tzresult Lwt.t -(** [delete ctxt contract] behaves as [remove ctxt contract], but in addition - removes the association of the [contract] to its current delegate, leaving - the former with no delegate. +(** [delete ctxt contract stake] behaves as [remove ctxt contract stake], but + in addition removes the association of the [contract] to its current + delegate, leaving the former with no delegate. [stake] is the total stake of + [contract]. This function is undefined if [contract] is not allocated. *) -val delete : Raw_context.t -> Contract_repr.t -> Raw_context.t tzresult Lwt.t +val delete : + Raw_context.t -> Contract_repr.t -> Tez_repr.t -> Raw_context.t tzresult Lwt.t -(** [set ctxt contract delegate] updates the [delegate] associated to [contract]. +(** [set ctxt contract stake delegate] updates the [delegate] associated to + [contract], where [stake] is the total stake of [contract]. This function is undefined if [contract] is not allocated, or if [contract] does not have a delegate. *) val set : Raw_context.t -> Contract_repr.t -> + Tez_repr.t -> Signature.Public_key_hash.t -> Raw_context.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/contract_storage.ml b/src/proto_alpha/lib_protocol/contract_storage.ml index 5bce09cebc50..a2df06fc0fca 100644 --- a/src/proto_alpha/lib_protocol/contract_storage.ml +++ b/src/proto_alpha/lib_protocol/contract_storage.ml @@ -436,13 +436,16 @@ let create_implicit c manager ~balance = ?script:None () +let stake = Storage.Contract.Balance.get + 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 _ -> - Contract_delegate_storage.remove c contract >>=? fun c -> + stake c contract >>=? fun stake -> + Contract_delegate_storage.remove c contract stake >>=? fun c -> Storage.Contract.Balance.remove_existing c contract >>=? fun c -> Contract_manager_storage.remove_existing c contract >>=? fun c -> Storage.Contract.Counter.remove_existing c contract >>=? fun c -> diff --git a/src/proto_alpha/lib_protocol/contract_storage.mli b/src/proto_alpha/lib_protocol/contract_storage.mli index ed8a89f02d09..98c2cb54d9e8 100644 --- a/src/proto_alpha/lib_protocol/contract_storage.mli +++ b/src/proto_alpha/lib_protocol/contract_storage.mli @@ -172,3 +172,7 @@ val increase_balance_only_call_from_token : break important invariants. Consider calling [spend] instead. *) val decrease_balance_only_call_from_token : Raw_context.t -> Contract_repr.t -> Tez_repr.t -> Raw_context.t tzresult Lwt.t + +(** [stake ctxt contract] returns the stake of [contract]. + This function fails if [contract] is not allocated. *) +val stake : Raw_context.t -> Contract_repr.t -> Tez_repr.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/delegate_storage.ml b/src/proto_alpha/lib_protocol/delegate_storage.ml index 2677d68150c9..1274f2e173ab 100644 --- a/src/proto_alpha/lib_protocol/delegate_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_storage.ml @@ -199,18 +199,20 @@ let init ctxt contract delegate = error_unless known_delegate (Unregistered_delegate delegate) >>?= fun () -> Contract_delegate_storage.registered ctxt delegate >>=? fun is_registered -> error_unless is_registered (Unregistered_delegate delegate) >>?= fun () -> - Contract_delegate_storage.init ctxt contract delegate + Contract_storage.stake ctxt contract >>=? fun stake -> + Contract_delegate_storage.init ctxt contract stake delegate let set c contract delegate = match delegate with | None -> ( + Contract_storage.stake c contract >>=? fun stake -> match Contract_repr.is_implicit contract with | Some pkh -> (* check if contract is a registered delegate *) Contract_delegate_storage.registered c pkh >>=? fun is_registered -> if is_registered then fail (No_deletion pkh) - else Contract_delegate_storage.delete c contract - | None -> Contract_delegate_storage.delete c contract) + else Contract_delegate_storage.delete c contract stake + | None -> Contract_delegate_storage.delete c contract stake) | Some delegate -> Contract_manager_storage.is_manager_key_revealed c delegate >>=? fun known_delegate -> @@ -249,7 +251,8 @@ let set c contract delegate = (self_delegation && not exists) (Empty_delegate_account delegate) >>?= fun () -> - Contract_delegate_storage.set c contract delegate >>=? fun c -> + Contract_storage.stake c contract >>=? fun stake -> + Contract_delegate_storage.set c contract stake delegate >>=? fun c -> if self_delegation then Storage.Delegates.add c delegate >>= fun c -> set_active c delegate else return c -- GitLab From 3e00bfb5c7b53a6f3f9eefdc4e81d2551937ddaf Mon Sep 17 00:00:00 2001 From: bsall Date: Sun, 13 Feb 2022 21:51:11 +0100 Subject: [PATCH 02/31] Proto: access a contract's stake through an explicit function Replace 'balance' by 'stake', even though at this point those are the same for implicit contracts that are not delegates. This is necessary so that when the stake includes rollup bonds, it is automatically take into account in the calculation of baking rights. Here we have to pass a function as a parameter, to avoid the circular dependency that would result from calling directly 'Contract_storage.stake'. --- src/proto_alpha/lib_protocol/delegate_storage.ml | 6 +++++- src/proto_alpha/lib_protocol/init_storage.ml | 5 ++++- src/proto_alpha/lib_protocol/stake_storage.ml | 13 ++++++------- src/proto_alpha/lib_protocol/stake_storage.mli | 3 +++ 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/proto_alpha/lib_protocol/delegate_storage.ml b/src/proto_alpha/lib_protocol/delegate_storage.ml index 1274f2e173ab..3198917c3a50 100644 --- a/src/proto_alpha/lib_protocol/delegate_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_storage.ml @@ -522,7 +522,11 @@ let freeze_deposits_do_not_call_except_for_migration = let cycle_end ctxt last_cycle unrevealed_nonces = let new_cycle = Cycle_repr.add last_cycle 1 in - Stake_storage.select_new_distribution_at_cycle_end ctxt ~new_cycle pubkey + Stake_storage.select_new_distribution_at_cycle_end + ctxt + ~new_cycle + pubkey + Contract_storage.stake >>=? fun ctxt -> clear_outdated_slashed_deposits ctxt ~new_cycle >>= fun ctxt -> distribute_endorsing_rewards ctxt last_cycle unrevealed_nonces diff --git a/src/proto_alpha/lib_protocol/init_storage.ml b/src/proto_alpha/lib_protocol/init_storage.ml index 300345ec8d3d..93b9515666df 100644 --- a/src/proto_alpha/lib_protocol/init_storage.ml +++ b/src/proto_alpha/lib_protocol/init_storage.ml @@ -89,7 +89,10 @@ let prepare_first_block ctxt ~typecheck ~level ~timestamp = param.bootstrap_accounts param.bootstrap_contracts >>=? fun (ctxt, bootstrap_balance_updates) -> - Stake_storage.init_first_cycles ctxt Delegate_storage.pubkey + Stake_storage.init_first_cycles + ctxt + Delegate_storage.pubkey + Contract_storage.stake >>=? fun ctxt -> let cycle = (Raw_context.current_level ctxt).cycle in Delegate_storage.freeze_deposits_do_not_call_except_for_migration diff --git a/src/proto_alpha/lib_protocol/stake_storage.ml b/src/proto_alpha/lib_protocol/stake_storage.ml index 34d68b4538f8..9adde0c03bd3 100644 --- a/src/proto_alpha/lib_protocol/stake_storage.ml +++ b/src/proto_alpha/lib_protocol/stake_storage.ml @@ -170,7 +170,7 @@ let snapshot ctxt = Storage.Stake.Staking_balance.snapshot ctxt index >>=? fun ctxt -> Storage.Stake.Active_delegate_with_one_roll.snapshot ctxt index -let select_distribution_for_cycle ctxt cycle pubkey = +let select_distribution_for_cycle ctxt cycle pubkey undeposited_stake = Storage.Stake.Last_snapshot.get ctxt >>=? fun max_index -> Storage.Seed.For_cycle.get ctxt cycle >>=? fun seed -> let rd = Seed_repr.initialize_new seed [Bytes.of_string "stake_snapshot"] in @@ -192,8 +192,7 @@ let select_distribution_for_cycle ctxt cycle pubkey = let delegate_contract = Contract_repr.implicit_contract delegate in Storage.Contract.Frozen_deposits_limit.find ctxt delegate_contract >>=? fun frozen_deposits_limit -> - Storage.Contract.Balance.get ctxt delegate_contract - >>=? fun balance -> + undeposited_stake ctxt delegate_contract >>=? fun balance -> Frozen_deposits_storage.get ctxt delegate_contract >>=? fun frozen_deposits -> Tez_repr.(balance +? frozen_deposits.current_amount) @@ -261,7 +260,7 @@ let clear_cycle ctxt cycle = Delegate_sampler_state.remove_existing ctxt cycle >>=? fun ctxt -> Storage.Seed.For_cycle.remove_existing ctxt cycle -let init_first_cycles ctxt pubkey = +let init_first_cycles ctxt pubkey undeposited_stake = let preserved = Constants_storage.preserved_cycles ctxt in List.fold_left_es (fun ctxt c -> @@ -269,7 +268,7 @@ let init_first_cycles ctxt pubkey = snapshot ctxt >>=? fun ctxt -> (* NB: we need to take several snapshots because select_distribution_for_cycle deletes the snapshots *) - select_distribution_for_cycle ctxt cycle pubkey) + select_distribution_for_cycle ctxt cycle pubkey undeposited_stake) ctxt (0 --> preserved) @@ -283,10 +282,10 @@ let fold ctxt ~f ~order init = get_staking_balance ctxt delegate >>=? fun stake -> f (delegate, stake) acc) -let select_new_distribution_at_cycle_end ctxt ~new_cycle = +let select_new_distribution_at_cycle_end ctxt ~new_cycle undeposited_stake = let preserved = Constants_storage.preserved_cycles ctxt in let for_cycle = Cycle_repr.add new_cycle preserved in - select_distribution_for_cycle ctxt for_cycle + select_distribution_for_cycle ctxt for_cycle undeposited_stake let clear_at_cycle_end ctxt ~new_cycle = let max_slashing_period = Constants_storage.max_slashing_period ctxt in diff --git a/src/proto_alpha/lib_protocol/stake_storage.mli b/src/proto_alpha/lib_protocol/stake_storage.mli index 66984a63211e..281fe093f727 100644 --- a/src/proto_alpha/lib_protocol/stake_storage.mli +++ b/src/proto_alpha/lib_protocol/stake_storage.mli @@ -68,6 +68,7 @@ val select_distribution_for_cycle_do_not_call_except_for_migration : (Raw_context.t -> Signature.Public_key_hash.t -> Signature.Public_key.t tzresult Lwt.t) -> + (Raw_context.t -> Contract_repr.t -> Tez_repr.t tzresult Lwt.t) -> Raw_context.t tzresult Lwt.t val clear_cycle : Raw_context.t -> Cycle_repr.t -> Raw_context.t tzresult Lwt.t @@ -77,6 +78,7 @@ val init_first_cycles : (Raw_context.t -> Signature.Public_key_hash.t -> Signature.Public_key.t tzresult Lwt.t) -> + (Raw_context.t -> Contract_repr.t -> Tez_repr.t tzresult Lwt.t) -> Raw_context.t tzresult Lwt.t val fold : @@ -92,6 +94,7 @@ val select_new_distribution_at_cycle_end : (Raw_context.t -> Signature.Public_key_hash.t -> Signature.Public_key.t tzresult Lwt.t) -> + (Raw_context.t -> Contract_repr.t -> Tez_repr.t tzresult Lwt.t) -> Raw_context.t tzresult Lwt.t val clear_at_cycle_end : -- GitLab From 33731b22796746c31680aacf2242c354b9e53a95 Mon Sep 17 00:00:00 2001 From: bsall Date: Wed, 9 Feb 2022 17:00:17 +0100 Subject: [PATCH 03/31] Proto: deleting stakeless implicit contracts in Token --- .../lib_protocol/contract_storage.ml | 10 +++--- .../lib_protocol/contract_storage.mli | 3 ++ src/proto_alpha/lib_protocol/token.ml | 35 ++++++++++++++++++- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/proto_alpha/lib_protocol/contract_storage.ml b/src/proto_alpha/lib_protocol/contract_storage.ml index a2df06fc0fca..19654c0954ae 100644 --- a/src/proto_alpha/lib_protocol/contract_storage.ml +++ b/src/proto_alpha/lib_protocol/contract_storage.ml @@ -438,7 +438,7 @@ let create_implicit c manager ~balance = let stake = Storage.Contract.Balance.get -let delete c contract = +let delete_only_call_from_token c contract = match Contract_repr.is_implicit contract with | None -> (* For non implicit contract Big_map should be cleared *) @@ -572,8 +572,10 @@ let spend_only_call_from_token c contract amount = >>=? fun c -> if Tez_repr.(new_balance > Tez_repr.zero) then return c else + (* Ensure that empty implicit contracts that delegate to other contracts + remain non empty. *) match Contract_repr.is_implicit contract with - | None -> return c (* Never delete originated contracts *) + | None -> return c | Some pkh -> ( Contract_delegate_storage.find c contract >>=? function | Some pkh' -> @@ -581,9 +583,7 @@ let spend_only_call_from_token c contract amount = else (* Delegated implicit accounts cannot be emptied *) fail (Empty_implicit_delegated_contract pkh) - | None -> - (* Delete empty implicit contract *) - delete c contract)) + | None -> return c)) (* [Tez_repr.(amount <> zero)] is a precondition of this function. It ensures that no entry associating a null balance to an implicit contract exists in the map diff --git a/src/proto_alpha/lib_protocol/contract_storage.mli b/src/proto_alpha/lib_protocol/contract_storage.mli index 98c2cb54d9e8..64eab5434ca6 100644 --- a/src/proto_alpha/lib_protocol/contract_storage.mli +++ b/src/proto_alpha/lib_protocol/contract_storage.mli @@ -122,6 +122,9 @@ val update_script_storage : Lazy_storage_diff.diffs option -> Raw_context.t tzresult Lwt.t +val delete_only_call_from_token : + Raw_context.t -> Contract_repr.t -> Raw_context.t tzresult Lwt.t + val credit_only_call_from_token : Raw_context.t -> Contract_repr.t -> Tez_repr.t -> Raw_context.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/token.ml b/src/proto_alpha/lib_protocol/token.ml index beefc1a06382..cd49a6c8549d 100644 --- a/src/proto_alpha/lib_protocol/token.ml +++ b/src/proto_alpha/lib_protocol/token.ml @@ -153,6 +153,24 @@ let spend ctxt src amount origin = >>?= fun ctxt -> return (ctxt, Block_fees)) >|=? fun (ctxt, balance) -> (ctxt, (balance, Debited amount, origin)) +let deallocate_stakeless_implicit_contracts ctxt contract = + match Contract_repr.is_implicit contract with + | None -> return ctxt (* Never delete originated contracts *) + | Some _ -> + Contract_storage.stake ctxt contract >>=? fun stake -> + if Tez_repr.(stake = Tez_repr.zero) then + (* Delete empty implicit contract. *) + Contract_delegate_storage.find ctxt contract >>=? function + | Some _ -> + (* Here, we know that the contract delegates to iself. Indeed, it + does not delegate to a different one, because the balance of + such contracts cannot be zero (see [spend_only_call_from_token] + in module [Contract_storage]), hence the stake of such contracts + cannot be zero either. *) + return ctxt + | None -> Contract_storage.delete_only_call_from_token ctxt contract + else return ctxt + let transfer_n ?(origin = Receipt_repr.Block_application) ctxt src dest = let sources = List.filter (fun (_, am) -> Tez_repr.(am <> zero)) src in match sources with @@ -168,7 +186,22 @@ let transfer_n ?(origin = Receipt_repr.Block_application) ctxt src dest = (ctxt, Tez_repr.zero, []) sources >>=? fun (ctxt, amount, debit_logs) -> - credit ctxt dest amount origin >|=? fun (ctxt, credit_log) -> + credit ctxt dest amount origin >>=? fun (ctxt, credit_log) -> + (* Deallocate implicit contracts with no stake. *) + List.fold_left_es + (fun ctxt (source, _amount) -> + match source with + | `Contract contract -> + (* If [contract] is in [sources] more than once, we must avoid + deallocating twice. *) + Contract_storage.allocated ctxt contract >>=? fun allocated -> + if allocated then + deallocate_stakeless_implicit_contracts ctxt contract + else return ctxt + | #source -> return ctxt) + ctxt + sources + >|=? fun ctxt -> (* Make sure the order of balance updates is : debit logs in the order of of the parameter [src], and then the credit log. *) let balance_updates = List.rev (credit_log :: debit_logs) in -- GitLab From 16f0200b0fd8fe6bcd8652781387302da50495a8 Mon Sep 17 00:00:00 2001 From: bsall Date: Wed, 9 Feb 2022 17:00:17 +0100 Subject: [PATCH 04/31] Proto: introduce frozen bonds for tx-rollups --- .../lib_client/operation_result.ml | 7 ++ src/proto_alpha/lib_protocol/TEZOS_PROTOCOL | 2 + src/proto_alpha/lib_protocol/alpha_context.ml | 1 + .../lib_protocol/alpha_context.mli | 72 +++++++------ src/proto_alpha/lib_protocol/dune.inc | 10 ++ .../frozen_rollup_bonds_storage.ml | 100 ++++++++++++++++++ .../frozen_rollup_bonds_storage.mli | 82 ++++++++++++++ src/proto_alpha/lib_protocol/receipt_repr.ml | 15 +++ src/proto_alpha/lib_protocol/receipt_repr.mli | 1 + .../lib_protocol/rollup_bond_id_repr.ml | 88 +++++++++++++++ .../lib_protocol/rollup_bond_id_repr.mli | 36 +++++++ src/proto_alpha/lib_protocol/storage.ml | 22 ++++ src/proto_alpha/lib_protocol/storage.mli | 12 +++ .../test/integration/test_token.ml | 52 ++++++++- .../lib_protocol/test/unit/test_receipt.ml | 9 +- src/proto_alpha/lib_protocol/token.ml | 30 +++++- src/proto_alpha/lib_protocol/token.mli | 3 +- 17 files changed, 501 insertions(+), 41 deletions(-) create mode 100644 src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.ml create mode 100644 src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli create mode 100644 src/proto_alpha/lib_protocol/rollup_bond_id_repr.ml create mode 100644 src/proto_alpha/lib_protocol/rollup_bond_id_repr.mli diff --git a/src/proto_alpha/lib_client/operation_result.ml b/src/proto_alpha/lib_client/operation_result.ml index be74cd41935f..96387adb8ba2 100644 --- a/src/proto_alpha/lib_client/operation_result.ml +++ b/src/proto_alpha/lib_client/operation_result.ml @@ -276,6 +276,13 @@ let pp_balance_updates ppf = function | Invoice -> "invoices" | Initial_commitments -> "initial commitments" | Minted -> "minted" + | Rollup_bonds (contract, bond_id) -> + Format.asprintf + "Rollup_bonds(%a,%a)" + Contract.pp + contract + Rollup_bond_id.pp + bond_id in let balance = match origin with diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index cd98654f903e..847684b29538 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -48,6 +48,7 @@ "Tx_rollup_message_repr", "Tx_rollup_inbox_repr", "Tx_rollup_commitments_repr", + "Rollup_bond_id_repr", "Vote_repr", "Block_header_repr", "Entrypoint_repr", @@ -83,6 +84,7 @@ "Lazy_storage_diff", "Contract_storage", "Commitment_storage", + "Frozen_rollup_bonds_storage", "Token", "Delegate_storage", "Bootstrap_storage", diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index d0987bfc0ac0..9f48bbc47073 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -349,6 +349,7 @@ module Sapling = struct type alloc = Sapling_state.alloc = {memo_size : Sapling_repr.Memo_size.t} end +module Rollup_bond_id = Rollup_bond_id_repr module Receipt = Receipt_repr module Delegate = struct diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 8251e23c73d2..4d48cde97a44 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -1487,6 +1487,43 @@ module Contract : sig end end +(** This module re-exports definitions from {!Tx_rollup_repr} and + {!Tx_rollup_storage}. *) +module Tx_rollup : sig + include BASIC_DATA + + type tx_rollup = t + + val rpc_arg : tx_rollup RPC_arg.arg + + val to_b58check : tx_rollup -> string + + val of_b58check : string -> tx_rollup tzresult + + val of_b58check_opt : string -> tx_rollup option + + val pp : Format.formatter -> tx_rollup -> unit + + val encoding : tx_rollup Data_encoding.t + + val originate : context -> (context * tx_rollup) tzresult Lwt.t + + val update_tx_rollups_at_block_finalization : + context -> context tzresult Lwt.t + + module Internal_for_tests : sig + (** see [tx_rollup_repr.originated_tx_rollup] for documentation *) + val originated_tx_rollup : + Origination_nonce.Internal_for_tests.t -> tx_rollup + end +end + +module Rollup_bond_id : sig + type t = Tx_rollup_bond_id of Tx_rollup.t + + val pp : Format.formatter -> t -> unit +end + module Receipt : sig type balance = | Contract of Contract.t @@ -1507,6 +1544,7 @@ module Receipt : sig | Invoice | Initial_commitments | Minted + | Rollup_bonds of Contract.t * Rollup_bond_id.t val compare_balance : balance -> balance -> int @@ -1942,37 +1980,6 @@ module Destination : sig type error += Invalid_destination_b58check of string end -(** This module re-exports definitions from {!Tx_rollup_repr} and - {!Tx_rollup_storage}. *) -module Tx_rollup : sig - include BASIC_DATA - - type tx_rollup = t - - val rpc_arg : tx_rollup RPC_arg.arg - - val to_b58check : tx_rollup -> string - - val of_b58check : string -> tx_rollup tzresult - - val of_b58check_opt : string -> tx_rollup option - - val pp : Format.formatter -> tx_rollup -> unit - - val encoding : tx_rollup Data_encoding.t - - val originate : context -> (context * tx_rollup) tzresult Lwt.t - - val update_tx_rollups_at_block_finalization : - context -> context tzresult Lwt.t - - module Internal_for_tests : sig - (** see [tx_rollup_repr.originated_tx_rollup] for documentation *) - val originated_tx_rollup : - Origination_nonce.Internal_for_tests.t -> tx_rollup - end -end - (** This module re-exports definitions from {!Tx_rollup_state_repr} and {!Tx_rollup_state_storage}. *) module Tx_rollup_state : sig @@ -2718,7 +2725,8 @@ module Token : sig | `Collected_commitments of Blinded_public_key_hash.t | `Delegate_balance of Signature.Public_key_hash.t | `Frozen_deposits of Signature.Public_key_hash.t - | `Block_fees ] + | `Block_fees + | `Frozen_rollup_bonds of Contract.t * Rollup_bond_id.t ] type source = [ `Invoice diff --git a/src/proto_alpha/lib_protocol/dune.inc b/src/proto_alpha/lib_protocol/dune.inc index 76eeb3bbf8c6..db667c88347b 100644 --- a/src/proto_alpha/lib_protocol/dune.inc +++ b/src/proto_alpha/lib_protocol/dune.inc @@ -73,6 +73,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end tx_rollup_message_repr.mli tx_rollup_message_repr.ml tx_rollup_inbox_repr.mli tx_rollup_inbox_repr.ml tx_rollup_commitments_repr.mli tx_rollup_commitments_repr.ml + rollup_bond_id_repr.mli rollup_bond_id_repr.ml vote_repr.mli vote_repr.ml block_header_repr.mli block_header_repr.ml entrypoint_repr.mli entrypoint_repr.ml @@ -106,6 +107,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end lazy_storage_diff.mli lazy_storage_diff.ml contract_storage.mli contract_storage.ml commitment_storage.mli commitment_storage.ml + frozen_rollup_bonds_storage.mli frozen_rollup_bonds_storage.ml token.mli token.ml delegate_storage.mli delegate_storage.ml bootstrap_storage.mli bootstrap_storage.ml @@ -228,6 +230,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end tx_rollup_message_repr.mli tx_rollup_message_repr.ml tx_rollup_inbox_repr.mli tx_rollup_inbox_repr.ml tx_rollup_commitments_repr.mli tx_rollup_commitments_repr.ml + rollup_bond_id_repr.mli rollup_bond_id_repr.ml vote_repr.mli vote_repr.ml block_header_repr.mli block_header_repr.ml entrypoint_repr.mli entrypoint_repr.ml @@ -261,6 +264,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end lazy_storage_diff.mli lazy_storage_diff.ml contract_storage.mli contract_storage.ml commitment_storage.mli commitment_storage.ml + frozen_rollup_bonds_storage.mli frozen_rollup_bonds_storage.ml token.mli token.ml delegate_storage.mli delegate_storage.ml bootstrap_storage.mli bootstrap_storage.ml @@ -383,6 +387,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end tx_rollup_message_repr.mli tx_rollup_message_repr.ml tx_rollup_inbox_repr.mli tx_rollup_inbox_repr.ml tx_rollup_commitments_repr.mli tx_rollup_commitments_repr.ml + rollup_bond_id_repr.mli rollup_bond_id_repr.ml vote_repr.mli vote_repr.ml block_header_repr.mli block_header_repr.ml entrypoint_repr.mli entrypoint_repr.ml @@ -416,6 +421,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end lazy_storage_diff.mli lazy_storage_diff.ml contract_storage.mli contract_storage.ml commitment_storage.mli commitment_storage.ml + frozen_rollup_bonds_storage.mli frozen_rollup_bonds_storage.ml token.mli token.ml delegate_storage.mli delegate_storage.ml bootstrap_storage.mli bootstrap_storage.ml @@ -560,6 +566,7 @@ include Tezos_raw_protocol_alpha.Main Tx_rollup_message_repr Tx_rollup_inbox_repr Tx_rollup_commitments_repr + Rollup_bond_id_repr Vote_repr Block_header_repr Entrypoint_repr @@ -593,6 +600,7 @@ include Tezos_raw_protocol_alpha.Main Lazy_storage_diff Contract_storage Commitment_storage + Frozen_rollup_bonds_storage Token Delegate_storage Bootstrap_storage @@ -756,6 +764,7 @@ include Tezos_raw_protocol_alpha.Main tx_rollup_message_repr.mli tx_rollup_message_repr.ml tx_rollup_inbox_repr.mli tx_rollup_inbox_repr.ml tx_rollup_commitments_repr.mli tx_rollup_commitments_repr.ml + rollup_bond_id_repr.mli rollup_bond_id_repr.ml vote_repr.mli vote_repr.ml block_header_repr.mli block_header_repr.ml entrypoint_repr.mli entrypoint_repr.ml @@ -789,6 +798,7 @@ include Tezos_raw_protocol_alpha.Main lazy_storage_diff.mli lazy_storage_diff.ml contract_storage.mli contract_storage.ml commitment_storage.mli commitment_storage.ml + frozen_rollup_bonds_storage.mli frozen_rollup_bonds_storage.ml token.mli token.ml delegate_storage.mli delegate_storage.ml bootstrap_storage.mli bootstrap_storage.ml diff --git a/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.ml b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.ml new file mode 100644 index 000000000000..35de33c96e2c --- /dev/null +++ b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.ml @@ -0,0 +1,100 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** This module encapsulates the following storage maps: + - [Storage.Contract.Frozen_rollup_bonds] + - [Storage.Contract.Total_rollup_bonds] + + This module enforces the following invariants: + - [ (Frozen_rollup_bonds.mem x) <-> (Total_rollup_bonds.mem x) ] + - [ Total_rollup_bonds.find x ] = sum of all bond values in + [ Frozen_rollup_bonds.bindings x ]. *) + +open Storage.Contract + +type error += + | Frozen_rollup_bonds_must_be_spent_at_once of + Contract_repr.t * Rollup_bond_id_repr.t + +let () = + register_error_kind + `Permanent + ~id:"frozen_rollup_bonds.must_be_spent_at_once" + ~title:"Partial spending of rollup bonds" + ~description:"Frozen rollup bonds must be spent at once." + ~pp:(fun ppf (contract, bond_id) -> + Format.fprintf + ppf + "The frozen funds for contract (%a) and rollup bond (%a) are not \ + allowed to be partially withdrawn. The amount withdrawn must be equal \ + to the entire deposit for the said bond." + Contract_repr.pp + contract + Rollup_bond_id_repr.pp + bond_id) + Data_encoding.( + obj2 + (req "contract" Contract_repr.encoding) + (req "bond_id" Rollup_bond_id_repr.encoding)) + (function + | Frozen_rollup_bonds_must_be_spent_at_once (c, b) -> Some (c, b) + | _ -> None) + (fun (c, b) -> Frozen_rollup_bonds_must_be_spent_at_once (c, b)) + +let has_frozen_bonds ctxt contract = Total_rollup_bonds.mem ctxt contract >|= ok + +let allocated ctxt contract bond_id = + Frozen_rollup_bonds.mem (ctxt, contract) bond_id >|= ok + +let find ctxt contract bond_id = + Frozen_rollup_bonds.find (ctxt, contract) bond_id + +(** PRE : amount > 0, fullfilled by unique caller [Token.transfer]. *) +let spend_only_call_from_token ctxt contract bond_id amount = + Frozen_rollup_bonds.get (ctxt, contract) bond_id >>=? fun frozen_bonds -> + error_when + Tez_repr.(frozen_bonds <> amount) + (Frozen_rollup_bonds_must_be_spent_at_once (contract, bond_id)) + >>?= fun () -> + Frozen_rollup_bonds.remove_existing (ctxt, contract) bond_id >>=? fun ctxt -> + Total_rollup_bonds.get ctxt contract >>=? fun total -> + Tez_repr.(total -? amount) >>?= fun new_total -> + if Tez_repr.(new_total = zero) then + Total_rollup_bonds.remove_existing ctxt contract + else Total_rollup_bonds.update ctxt contract new_total + +(** PRE : [amount > 0], fullfilled by unique caller [Token.transfer].*) +let credit_only_call_from_token ctxt contract bond_id amount = + (Frozen_rollup_bonds.find (ctxt, contract) bond_id >>=? function + | None -> Frozen_rollup_bonds.init (ctxt, contract) bond_id amount + | Some frozen_bonds -> + Tez_repr.(frozen_bonds +? amount) >>?= fun new_amount -> + Frozen_rollup_bonds.update (ctxt, contract) bond_id new_amount) + >>=? fun ctxt -> + Total_rollup_bonds.find ctxt contract >>=? function + | None -> Total_rollup_bonds.init ctxt contract amount + | Some total -> + Tez_repr.(total +? amount) >>?= fun new_total -> + Total_rollup_bonds.update ctxt contract new_total diff --git a/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli new file mode 100644 index 000000000000..9c97f267a2dd --- /dev/null +++ b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli @@ -0,0 +1,82 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** This module manages frozen rollups deposits (here called bonds). *) + +(** This error is raised when [spend_only_call_from_token] is called with an + amount that is less than the deposit associated to the given contract and + rollup bond id.*) +type error += + | (* `Permanent *) + Frozen_rollup_bonds_must_be_spent_at_once of + Contract_repr.t * Rollup_bond_id_repr.t + +(** [has_frozen_bonds ctxt contract] returns true if there are frozen bonds + associated to [contract], and returns false otherwise. *) +val has_frozen_bonds : Raw_context.t -> Contract_repr.t -> bool tzresult Lwt.t + +(** [allocated ctxt contract bond_id] returns [true] if there is a bond + associated to [contract] and [bond_id], and returns false otherwise. *) +val allocated : + Raw_context.t -> + Contract_repr.t -> + Rollup_bond_id_repr.t -> + bool tzresult Lwt.t + +(** [find ctxt contract bond_id] returns the bond associated to + [contract] and [bond_id] if there is one, and returns [None] otherwise. *) +val find : + Raw_context.t -> + Contract_repr.t -> + Rollup_bond_id_repr.t -> + Tez_repr.t option tzresult Lwt.t + +(** [spend ctxt contract bond_id amount] withdraws the given [amount] from + the value of the bond associated to [contract] and [bond_id]. + + Fails when there is no bond for [contract] and [bond_id]. + + @raise a [Frozen_rollup_bonds_must_be_spent_at_once (contract, bond_id)] + error when the amount is different from the bond associated to [contract] + and [bond_id]. + *) +val spend_only_call_from_token : + Raw_context.t -> + Contract_repr.t -> + Rollup_bond_id_repr.t -> + Tez_repr.t -> + Raw_context.t tzresult Lwt.t + +(** [credit ctxt contract bond_id amount] adds the given [amount] to the bond + associated to [contract] and [bond_id]. If no bond exists, one whose value + is [amount] is created. + + Fails when [(find ctxt contract bond_id) + amount > Int64.max_int]. *) +val credit_only_call_from_token : + Raw_context.t -> + Contract_repr.t -> + Rollup_bond_id_repr.t -> + Tez_repr.t -> + Raw_context.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/receipt_repr.ml b/src/proto_alpha/lib_protocol/receipt_repr.ml index d9e1cd6fe9a8..ac1380e4b2f6 100644 --- a/src/proto_alpha/lib_protocol/receipt_repr.ml +++ b/src/proto_alpha/lib_protocol/receipt_repr.ml @@ -43,6 +43,7 @@ type balance = | Invoice | Initial_commitments | Minted + | Rollup_bonds of Contract_repr.t * Rollup_bond_id_repr.t let balance_encoding = let open Data_encoding in @@ -201,6 +202,16 @@ let balance_encoding = (req "category" (constant "minted"))) (function Minted -> Some ((), ()) | _ -> None) (fun ((), ()) -> Minted); + case + (Tag 21) + ~title:"Frozen_rollup_bonds" + (obj4 + (req "kind" (constant "freezer")) + (req "category" (constant "tx_rollup_bonds")) + (req "contract" Contract_repr.encoding) + (req "bond_id" Rollup_bond_id_repr.encoding)) + (function Rollup_bonds (c, r) -> Some ((), (), c, r) | _ -> None) + (fun ((), (), c, r) -> Rollup_bonds (c, r)); ] let is_not_zero c = not (Compare.Int.equal c 0) @@ -219,6 +230,9 @@ let compare_balance ba bb = if is_not_zero c then c else Compare.Bool.compare ra rb | (Commitments bpkha, Commitments bpkhb) -> Blinded_public_key_hash.compare bpkha bpkhb + | (Rollup_bonds (ca, ra), Rollup_bonds (cb, rb)) -> + let c = Contract_repr.compare ca cb in + if is_not_zero c then c else Rollup_bond_id_repr.compare ra rb | (_, _) -> let index b = match b with @@ -240,6 +254,7 @@ let compare_balance ba bb = | Invoice -> 15 | Initial_commitments -> 16 | Minted -> 17 + | Rollup_bonds _ -> 18 (* don't forget to add parameterized cases in the first part of the function *) in Compare.Int.compare (index ba) (index bb) diff --git a/src/proto_alpha/lib_protocol/receipt_repr.mli b/src/proto_alpha/lib_protocol/receipt_repr.mli index 42817c0b9ebe..58a69d20821c 100644 --- a/src/proto_alpha/lib_protocol/receipt_repr.mli +++ b/src/proto_alpha/lib_protocol/receipt_repr.mli @@ -44,6 +44,7 @@ type balance = | Invoice | Initial_commitments | Minted + | Rollup_bonds of Contract_repr.t * Rollup_bond_id_repr.t (** Compares two balances. *) val compare_balance : balance -> balance -> int diff --git a/src/proto_alpha/lib_protocol/rollup_bond_id_repr.ml b/src/proto_alpha/lib_protocol/rollup_bond_id_repr.ml new file mode 100644 index 000000000000..700033046423 --- /dev/null +++ b/src/proto_alpha/lib_protocol/rollup_bond_id_repr.ml @@ -0,0 +1,88 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs *) +(* *) +(* 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 t = Tx_rollup_bond_id of Tx_rollup_repr.t + +include Compare.Make (struct + type nonrec t = t + + let compare id1 id2 = + match (id1, id2) with + | (Tx_rollup_bond_id id1, Tx_rollup_bond_id id2) -> + Tx_rollup_repr.compare id1 id2 +end) + +let encoding = + let open Data_encoding in + def "tx_rollup_bond_id" + @@ union + [ + case + (Tag 0) + ~title:"Tx_rollup_bond_id" + (obj1 (req "tx_rollup" Tx_rollup_repr.encoding)) + (function Tx_rollup_bond_id id -> Some id) + (fun id -> Tx_rollup_bond_id id); + ] + +let pp ppf (Tx_rollup_bond_id id) = Tx_rollup_repr.pp ppf id + +let rpc_arg = + let construct (Tx_rollup_bond_id id) = Tx_rollup_repr.to_b58check id in + let destruct id = + Result.map_error + (fun _ -> "Cannot parse tx rollup id") + (Tx_rollup_repr.of_b58check id >>? fun id -> ok (Tx_rollup_bond_id id)) + in + RPC_arg.make + ~descr:"A rollup bond identifier." + ~name:"rollup_bond_id" + ~construct + ~destruct + () + +module Index = struct + type nonrec t = t + + let path_length = 1 + + let to_path c l = + let raw_key = Data_encoding.Binary.to_bytes_exn encoding c in + let (`Hex key) = Hex.of_bytes raw_key in + key :: l + + let of_path = function + | [key] -> + Option.bind + (Hex.to_bytes (`Hex key)) + (Data_encoding.Binary.of_bytes_opt encoding) + | _ -> None + + let rpc_arg = rpc_arg + + let encoding = encoding + + let compare = compare +end diff --git a/src/proto_alpha/lib_protocol/rollup_bond_id_repr.mli b/src/proto_alpha/lib_protocol/rollup_bond_id_repr.mli new file mode 100644 index 000000000000..ff37a6cdff50 --- /dev/null +++ b/src/proto_alpha/lib_protocol/rollup_bond_id_repr.mli @@ -0,0 +1,36 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** This module defines identifiers for rollup bonds. *) + +type t = Tx_rollup_bond_id of Tx_rollup_repr.t + +val pp : Format.formatter -> t -> unit + +val encoding : t Data_encoding.t + +include Compare.S with type t := t + +module Index : Storage_description.INDEX with type t = t diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index 6eccb3d03f3b..e88866fe458f 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -348,6 +348,28 @@ module Contract = struct let name = ["frozen_deposits_limit"] end) (Tez_repr) + + module Rollup_bond_id_index = + Make_indexed_subcontext + (Make_subcontext (Ghost) (Indexed_context.Raw_context) + (struct + let name = ["rollup_bond_id_index"] + end)) + (Make_index (Rollup_bond_id_repr.Index)) + + module Frozen_rollup_bonds = + Rollup_bond_id_index.Make_map + (struct + let name = ["rollup_bonds"] + end) + (Tez_repr) + + module Total_rollup_bonds = + Indexed_context.Make_map + (struct + let name = ["total_rollup_bonds"] + end) + (Tez_repr) end module type NEXT = sig diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index 8e94c44f8921..6c3da12abfd0 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -179,6 +179,18 @@ module Contract : sig with type key = Contract_repr.t and type value = Z.t and type t := Raw_context.t + + module Frozen_rollup_bonds : + Indexed_data_storage + with type key = Rollup_bond_id_repr.t + and type value = Tez_repr.t + and type t := Raw_context.t * Contract_repr.t + + module Total_rollup_bonds : + Indexed_data_storage + with type key = Contract_repr.t + and type value = Tez_repr.t + and type t := Raw_context.t end module Big_map : sig diff --git a/src/proto_alpha/lib_protocol/test/integration/test_token.ml b/src/proto_alpha/lib_protocol/test/integration/test_token.ml index add025766523..8b7d0f5d96cd 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_token.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_token.ml @@ -52,6 +52,10 @@ let random_amount () = | None -> assert false | Some x -> x +let nonce = Origination_nonce.Internal_for_tests.initial Operation_hash.zero + +let mk_rollup () = Tx_rollup.Internal_for_tests.originated_tx_rollup nonce + (** Check balances for a simple transfer from [bootstrap] to new [Implicit]. *) let test_simple_balances () = Random.init 0 ; @@ -133,7 +137,12 @@ let test_allocated () = let dest = `Frozen_deposits pkh in test_allocated_and_still_allocated_when_empty ctxt dest false >>=? fun _ -> let dest = `Block_fees in - test_allocated_and_still_allocated_when_empty ctxt dest true + test_allocated_and_still_allocated_when_empty ctxt dest true >>=? fun _ -> + let dest = + let bond_id = Rollup_bond_id.Tx_rollup_bond_id (mk_rollup ()) in + `Frozen_rollup_bonds (Contract.implicit_contract pkh, bond_id) + in + test_allocated_and_deallocated_when_empty ctxt dest let check_sink_balances ctxt ctxt' dest amount = wrap (Token.balance ctxt dest) >>=? fun bal_dest -> @@ -253,6 +262,18 @@ let test_transferring_to_burned ctxt = ]) true +let test_transferring_to_frozen_tx_rollup_bonds ctxt = + let (pkh, _pk, _sk) = Signature.generate_key () in + let contract = Contract.implicit_contract pkh in + let tx_rollup = mk_rollup () in + let bond_id = Rollup_bond_id.Tx_rollup_bond_id tx_rollup in + let amount = random_amount () in + test_transferring_to_sink + ctxt + (`Frozen_rollup_bonds (contract, bond_id)) + amount + [(Rollup_bonds (contract, bond_id), Credited amount, Block_application)] + let test_transferring_to_sink () = Random.init 0 ; create_context () >>=? fun (ctxt, _) -> @@ -261,7 +282,8 @@ let test_transferring_to_sink () = test_transferring_to_delegate_balance ctxt >>=? fun _ -> test_transferring_to_frozen_deposits ctxt >>=? fun _ -> test_transferring_to_collected_fees ctxt >>=? fun _ -> - test_transferring_to_burned ctxt + test_transferring_to_burned ctxt >>=? fun _ -> + test_transferring_to_frozen_tx_rollup_bonds ctxt let check_src_balances ctxt ctxt' src amount = wrap (Token.balance ctxt src) >>=? fun bal_src -> @@ -351,6 +373,18 @@ let test_transferring_from_collected_fees ctxt = amount [(Block_fees, Debited amount, Block_application)] +let test_transferring_from_frozen_tx_rollup_bonds ctxt = + let (pkh, _pk, _sk) = Signature.generate_key () in + let contract = Contract.implicit_contract pkh in + let tx_rollup = mk_rollup () in + let bond_id = Rollup_bond_id.Tx_rollup_bond_id tx_rollup in + let amount = random_amount () in + test_transferring_from_bounded_source + ctxt + (`Frozen_rollup_bonds (contract, bond_id)) + amount + [(Rollup_bonds (contract, bond_id), Debited amount, Block_application)] + let test_transferring_from_source () = Random.init 0 ; create_context () >>=? fun (ctxt, _) -> @@ -393,7 +427,8 @@ let test_transferring_from_source () = test_transferring_from_collected_commitments ctxt >>=? fun _ -> test_transferring_from_delegate_balance ctxt >>=? fun _ -> test_transferring_from_frozen_deposits ctxt >>=? fun _ -> - test_transferring_from_collected_fees ctxt + test_transferring_from_collected_fees ctxt >>=? fun _ -> + test_transferring_from_frozen_tx_rollup_bonds ctxt let cast_to_container_type x = match x with @@ -404,6 +439,7 @@ let cast_to_container_type x = | `Collected_commitments _ as x -> Some x | `Delegate_balance _ as x -> Some x | `Block_fees as x -> Some x + | `Frozen_rollup_bonds _ as x -> Some x (** Generates all combinations of constructors. *) let build_test_cases () = @@ -437,6 +473,12 @@ let build_test_cases () = >>=? fun ctxt -> wrap (Delegate.set ctxt (Contract.implicit_contract user1) (Some baker2)) >>=? fun ctxt -> + let tx_rollup1 = mk_rollup () in + let bond_id1 = Rollup_bond_id.Tx_rollup_bond_id tx_rollup1 in + let tx_rollup2 = mk_rollup () in + let bond_id2 = Rollup_bond_id.Tx_rollup_bond_id tx_rollup2 in + let user1ic = Contract.implicit_contract user1 in + let baker2ic = Contract.implicit_contract baker2 in let src_list = [ (`Invoice, random_amount ()); @@ -452,6 +494,8 @@ let build_test_cases () = (user2c, random_amount ()); (baker1c, random_amount ()); (baker2c, random_amount ()); + (`Frozen_rollup_bonds (user1ic, bond_id1), random_amount ()); + (`Frozen_rollup_bonds (baker2ic, bond_id2), random_amount ()); ] in let dest_list = @@ -464,6 +508,8 @@ let build_test_cases () = user2c; baker1c; baker2c; + `Frozen_rollup_bonds (user1ic, bond_id1); + `Frozen_rollup_bonds (baker2ic, bond_id2); `Burned; ] in diff --git a/src/proto_alpha/lib_protocol/test/unit/test_receipt.ml b/src/proto_alpha/lib_protocol/test/unit/test_receipt.ml index d7c290974366..5ece588a0ad5 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_receipt.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_receipt.ml @@ -86,6 +86,13 @@ let test_encodings () = test_encodings (Commitments Blinded_public_key_hash.zero) >>=? fun () -> test_encodings Bootstrap >>=? fun () -> test_encodings Invoice >>=? fun () -> - test_encodings Initial_commitments >>=? fun () -> test_encodings Minted + test_encodings Initial_commitments >>=? fun () -> + test_encodings Minted >>=? fun () -> + let nonce = + Origination_nonce.Internal_for_tests.initial Operation_hash.zero + in + let tx_rollup = Tx_rollup.Internal_for_tests.originated_tx_rollup nonce in + let bond_id = Rollup_bond_id.Tx_rollup_bond_id tx_rollup in + test_encodings (Rollup_bonds (Contract.implicit_contract pkh, bond_id)) let tests = Tztest.[tztest "receipt - encoding" `Quick test_encodings] diff --git a/src/proto_alpha/lib_protocol/token.ml b/src/proto_alpha/lib_protocol/token.ml index cd49a6c8549d..723985b0065e 100644 --- a/src/proto_alpha/lib_protocol/token.ml +++ b/src/proto_alpha/lib_protocol/token.ml @@ -28,7 +28,8 @@ type container = | `Collected_commitments of Blinded_public_key_hash.t | `Delegate_balance of Signature.Public_key_hash.t | `Frozen_deposits of Signature.Public_key_hash.t - | `Block_fees ] + | `Block_fees + | `Frozen_rollup_bonds of Contract_repr.t * Rollup_bond_id_repr.t ] type source = [ `Invoice @@ -61,6 +62,8 @@ let allocated ctxt stored = let contract = Contract_repr.implicit_contract delegate in Frozen_deposits_storage.allocated ctxt contract >|= ok | `Block_fees -> return_true + | `Frozen_rollup_bonds (contract, bond_id) -> + Frozen_rollup_bonds_storage.allocated ctxt contract bond_id let balance ctxt stored = match stored with @@ -76,6 +79,9 @@ let balance ctxt stored = | None -> Tez_repr.zero | Some frozen_deposits -> frozen_deposits.current_amount) | `Block_fees -> return (Raw_context.get_collected_fees ctxt) + | `Frozen_rollup_bonds (contract, bond_id) -> + Frozen_rollup_bonds_storage.find ctxt contract bond_id + >|=? Option.value ~default:Tez_repr.zero let credit ctxt dest amount origin = let open Receipt_repr in @@ -110,7 +116,14 @@ let credit ctxt dest amount origin = >|=? fun ctxt -> (ctxt, Deposits delegate) | `Block_fees -> Raw_context.credit_collected_fees_only_call_from_token ctxt amount - >>?= fun ctxt -> return (ctxt, Block_fees)) + >>?= fun ctxt -> return (ctxt, Block_fees) + | `Frozen_rollup_bonds (contract, bond_id) -> + Frozen_rollup_bonds_storage.credit_only_call_from_token + ctxt + contract + bond_id + amount + >>=? fun ctxt -> return (ctxt, Rollup_bonds (contract, bond_id))) >|=? fun (ctxt, balance) -> (ctxt, (balance, Credited amount, origin)) let spend ctxt src amount origin = @@ -150,7 +163,14 @@ let spend ctxt src amount origin = >>=? fun ctxt -> return (ctxt, Deposits delegate) | `Block_fees -> Raw_context.spend_collected_fees_only_call_from_token ctxt amount - >>?= fun ctxt -> return (ctxt, Block_fees)) + >>?= fun ctxt -> return (ctxt, Block_fees) + | `Frozen_rollup_bonds (contract, bond_id) -> + Frozen_rollup_bonds_storage.spend_only_call_from_token + ctxt + contract + bond_id + amount + >>=? fun ctxt -> return (ctxt, Rollup_bonds (contract, bond_id))) >|=? fun (ctxt, balance) -> (ctxt, (balance, Debited amount, origin)) let deallocate_stakeless_implicit_contracts ctxt contract = @@ -178,6 +198,7 @@ let transfer_n ?(origin = Receipt_repr.Block_application) ctxt src dest = (* Avoid accessing context data when there is nothing to transfer. *) return (ctxt, []) | _ :: _ -> + (* Withdraw from sources. *) List.fold_left_es (fun (ctxt, total, debit_logs) (source, amount) -> spend ctxt source amount origin >>=? fun (ctxt, debit_log) -> @@ -186,12 +207,13 @@ let transfer_n ?(origin = Receipt_repr.Block_application) ctxt src dest = (ctxt, Tez_repr.zero, []) sources >>=? fun (ctxt, amount, debit_logs) -> + (* Credit the destination. *) credit ctxt dest amount origin >>=? fun (ctxt, credit_log) -> (* Deallocate implicit contracts with no stake. *) List.fold_left_es (fun ctxt (source, _amount) -> match source with - | `Contract contract -> + | `Contract contract | `Frozen_rollup_bonds (contract, _) -> (* If [contract] is in [sources] more than once, we must avoid deallocating twice. *) Contract_storage.allocated ctxt contract >>=? fun allocated -> diff --git a/src/proto_alpha/lib_protocol/token.mli b/src/proto_alpha/lib_protocol/token.mli index e872b872c348..53f98eeed0c7 100644 --- a/src/proto_alpha/lib_protocol/token.mli +++ b/src/proto_alpha/lib_protocol/token.mli @@ -46,7 +46,8 @@ type container = | `Collected_commitments of Blinded_public_key_hash.t | `Delegate_balance of Signature.Public_key_hash.t | `Frozen_deposits of Signature.Public_key_hash.t - | `Block_fees ] + | `Block_fees + | `Frozen_rollup_bonds of Contract_repr.t * Rollup_bond_id_repr.t ] (** [source] is the type of token providers. Token providers that are not containers are considered to have infinite capacity. *) -- GitLab From 2fae353f4a34de3642417305924450612c022336 Mon Sep 17 00:00:00 2001 From: bsall Date: Thu, 10 Feb 2022 14:00:49 +0100 Subject: [PATCH 05/31] Proto: make rollup bonds part of the stake --- src/proto_alpha/lib_protocol/TEZOS_PROTOCOL | 2 +- src/proto_alpha/lib_protocol/contract_storage.ml | 6 +++++- src/proto_alpha/lib_protocol/dune.inc | 10 +++++----- .../lib_protocol/frozen_rollup_bonds_storage.ml | 7 +++++++ .../lib_protocol/frozen_rollup_bonds_storage.mli | 7 ++++++- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index 847684b29538..7dc82c9159ed 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -82,9 +82,9 @@ "Contract_delegate_storage", "Sapling_storage", "Lazy_storage_diff", + "Frozen_rollup_bonds_storage", "Contract_storage", "Commitment_storage", - "Frozen_rollup_bonds_storage", "Token", "Delegate_storage", "Bootstrap_storage", diff --git a/src/proto_alpha/lib_protocol/contract_storage.ml b/src/proto_alpha/lib_protocol/contract_storage.ml index 19654c0954ae..389e9e23fa32 100644 --- a/src/proto_alpha/lib_protocol/contract_storage.ml +++ b/src/proto_alpha/lib_protocol/contract_storage.ml @@ -436,7 +436,11 @@ let create_implicit c manager ~balance = ?script:None () -let stake = Storage.Contract.Balance.get +let stake ctxt contract = + let open Storage.Contract in + Balance.get ctxt contract >>=? fun balance -> + Frozen_rollup_bonds_storage.total ctxt contract >>=? fun rollup_bonds -> + Lwt.return Tez_repr.(balance +? rollup_bonds) let delete_only_call_from_token c contract = match Contract_repr.is_implicit contract with diff --git a/src/proto_alpha/lib_protocol/dune.inc b/src/proto_alpha/lib_protocol/dune.inc index db667c88347b..2e7eabee26fc 100644 --- a/src/proto_alpha/lib_protocol/dune.inc +++ b/src/proto_alpha/lib_protocol/dune.inc @@ -105,9 +105,9 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end contract_delegate_storage.mli contract_delegate_storage.ml sapling_storage.ml lazy_storage_diff.mli lazy_storage_diff.ml + frozen_rollup_bonds_storage.mli frozen_rollup_bonds_storage.ml contract_storage.mli contract_storage.ml commitment_storage.mli commitment_storage.ml - frozen_rollup_bonds_storage.mli frozen_rollup_bonds_storage.ml token.mli token.ml delegate_storage.mli delegate_storage.ml bootstrap_storage.mli bootstrap_storage.ml @@ -262,9 +262,9 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end contract_delegate_storage.mli contract_delegate_storage.ml sapling_storage.ml lazy_storage_diff.mli lazy_storage_diff.ml + frozen_rollup_bonds_storage.mli frozen_rollup_bonds_storage.ml contract_storage.mli contract_storage.ml commitment_storage.mli commitment_storage.ml - frozen_rollup_bonds_storage.mli frozen_rollup_bonds_storage.ml token.mli token.ml delegate_storage.mli delegate_storage.ml bootstrap_storage.mli bootstrap_storage.ml @@ -419,9 +419,9 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end contract_delegate_storage.mli contract_delegate_storage.ml sapling_storage.ml lazy_storage_diff.mli lazy_storage_diff.ml + frozen_rollup_bonds_storage.mli frozen_rollup_bonds_storage.ml contract_storage.mli contract_storage.ml commitment_storage.mli commitment_storage.ml - frozen_rollup_bonds_storage.mli frozen_rollup_bonds_storage.ml token.mli token.ml delegate_storage.mli delegate_storage.ml bootstrap_storage.mli bootstrap_storage.ml @@ -598,9 +598,9 @@ include Tezos_raw_protocol_alpha.Main Contract_delegate_storage Sapling_storage Lazy_storage_diff + Frozen_rollup_bonds_storage Contract_storage Commitment_storage - Frozen_rollup_bonds_storage Token Delegate_storage Bootstrap_storage @@ -796,9 +796,9 @@ include Tezos_raw_protocol_alpha.Main contract_delegate_storage.mli contract_delegate_storage.ml sapling_storage.ml lazy_storage_diff.mli lazy_storage_diff.ml + frozen_rollup_bonds_storage.mli frozen_rollup_bonds_storage.ml contract_storage.mli contract_storage.ml commitment_storage.mli commitment_storage.ml - frozen_rollup_bonds_storage.mli frozen_rollup_bonds_storage.ml token.mli token.ml delegate_storage.mli delegate_storage.ml bootstrap_storage.mli bootstrap_storage.ml diff --git a/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.ml b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.ml index 35de33c96e2c..d1236058d483 100644 --- a/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.ml +++ b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.ml @@ -73,6 +73,8 @@ let find ctxt contract bond_id = (** PRE : amount > 0, fullfilled by unique caller [Token.transfer]. *) let spend_only_call_from_token ctxt contract bond_id amount = + Contract_delegate_storage.remove_contract_stake ctxt contract amount + >>=? fun ctxt -> Frozen_rollup_bonds.get (ctxt, contract) bond_id >>=? fun frozen_bonds -> error_when Tez_repr.(frozen_bonds <> amount) @@ -87,6 +89,8 @@ let spend_only_call_from_token ctxt contract bond_id amount = (** PRE : [amount > 0], fullfilled by unique caller [Token.transfer].*) let credit_only_call_from_token ctxt contract bond_id amount = + Contract_delegate_storage.add_contract_stake ctxt contract amount + >>=? fun ctxt -> (Frozen_rollup_bonds.find (ctxt, contract) bond_id >>=? function | None -> Frozen_rollup_bonds.init (ctxt, contract) bond_id amount | Some frozen_bonds -> @@ -98,3 +102,6 @@ let credit_only_call_from_token ctxt contract bond_id amount = | Some total -> Tez_repr.(total +? amount) >>?= fun new_total -> Total_rollup_bonds.update ctxt contract new_total + +let total ctxt contract = + Total_rollup_bonds.find ctxt contract >|=? Option.value ~default:Tez_repr.zero diff --git a/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli index 9c97f267a2dd..85b259515d44 100644 --- a/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli +++ b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli @@ -23,7 +23,8 @@ (* *) (*****************************************************************************) -(** This module manages frozen rollups deposits (here called bonds). *) +(** This module manages frozen rollups deposits (here called bonds). These + bonds are part of the stake of the contract making the deposit. *) (** This error is raised when [spend_only_call_from_token] is called with an amount that is less than the deposit associated to the given contract and @@ -80,3 +81,7 @@ val credit_only_call_from_token : Rollup_bond_id_repr.t -> Tez_repr.t -> Raw_context.t tzresult Lwt.t + +(** [total ctxt contract] returns the total amount of bonds associated to + [contract]. *) +val total : Raw_context.t -> Contract_repr.t -> Tez_repr.t tzresult Lwt.t -- GitLab From 0e2c53e89c1cf1150b72a29fc98ae0d01aa508ac Mon Sep 17 00:00:00 2001 From: bsall Date: Wed, 9 Feb 2022 17:00:17 +0100 Subject: [PATCH 06/31] Proto: test frozen tx-rollup bonds --- .../lib_protocol/alpha_context.mli | 2 + .../lib_protocol/test/integration/main.ml | 1 + .../test/integration/test_rollup_deposits.ml | 313 ++++++++++++++++++ 3 files changed, 316 insertions(+) create mode 100644 src/proto_alpha/lib_protocol/test/integration/test_rollup_deposits.ml diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 4d48cde97a44..da89f9baee6a 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -1439,6 +1439,8 @@ module Contract : sig val originated_from_current_nonce : since:context -> until:context -> contract list tzresult Lwt.t + val stake : context -> contract -> Tez.t tzresult Lwt.t + module Legacy_big_map_diff : sig type item = private | Update of { diff --git a/src/proto_alpha/lib_protocol/test/integration/main.ml b/src/proto_alpha/lib_protocol/test/integration/main.ml index ccb4fa8d5bec..30434853a27a 100644 --- a/src/proto_alpha/lib_protocol/test/integration/main.ml +++ b/src/proto_alpha/lib_protocol/test/integration/main.ml @@ -39,5 +39,6 @@ let () = ("storage description", Test_storage.tests); ("storage tests", Test_storage_functions.tests); ("token movements", Test_token.tests); + ("rollup deposits", Test_rollup_deposits.tests); ] |> Lwt_main.run diff --git a/src/proto_alpha/lib_protocol/test/integration/test_rollup_deposits.ml b/src/proto_alpha/lib_protocol/test/integration/test_rollup_deposits.ml new file mode 100644 index 000000000000..33e17811859b --- /dev/null +++ b/src/proto_alpha/lib_protocol/test/integration/test_rollup_deposits.ml @@ -0,0 +1,313 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (token) + Invocation: dune exec \ + src/proto_alpha/lib_protocol/test/integration/main.exe \ + -- test "^rollup deposits" + Subject: Frozen rollup deposits. +*) + +open Protocol +open Alpha_context +open Test_tez + +let ( >>>=? ) x f = x >|= Environment.wrap_tzresult >>=? f + +let big_random_amount () = + match Tez.of_mutez (Int64.add 1L (Random.int64 10_000L)) with + | None -> assert false + | Some x -> x + +let small_random_amount () = + match Tez.of_mutez (Int64.add 1L (Random.int64 1_000L)) with + | None -> assert false + | Some x -> x + +let very_small_random_amount () = + match Tez.of_mutez (Int64.add 1L (Random.int64 100L)) with + | None -> assert false + | Some x -> x + +let nonce_zero = + Origination_nonce.Internal_for_tests.initial Operation_hash.zero + +let mk_tx_rollup ?(nonce = nonce_zero) () = + ( Tx_rollup.Internal_for_tests.originated_tx_rollup nonce, + Origination_nonce.Internal_for_tests.incr nonce ) + +(** Creates a context with a single account. Returns the context and the public + key hash of the account. *) +let create_context () = + let accounts = Account.generate_accounts 1 in + Block.alpha_context accounts >>=? fun ctxt -> + match accounts with + | [({pkh; _}, _)] -> return (ctxt, pkh) + | _ -> (* Exactly one account has been generated. *) assert false + +(** Creates a context, a user contract, and a delegate. + Returns the context, the user contract, the user account, and the + delegate's pkh. *) +let init_test ~user_is_delegate = + create_context () >>=? fun (ctxt, _) -> + let (delegate, delegate_pk, _) = Signature.generate_key () in + let delegate_contract = Contract.implicit_contract delegate in + let delegate_account = `Contract (Contract.implicit_contract delegate) in + let user_contract = + if user_is_delegate then delegate_contract + else + let (user, _, _) = Signature.generate_key () in + Contract.implicit_contract user + in + let user_account = `Contract user_contract in + (* Allocate contracts for user and delegate. *) + let user_balance = big_random_amount () in + Token.transfer ctxt `Minted user_account user_balance >>>=? fun (ctxt, _) -> + let delegate_balance = big_random_amount () in + Token.transfer ctxt `Minted delegate_account delegate_balance + >>>=? fun (ctxt, _) -> + (* Configure delegate, as a delegate by self-delegation, for which + revealing its manager key is a prerequisite. *) + Contract.reveal_manager_key ctxt delegate delegate_pk >>>=? fun ctxt -> + Delegate.set ctxt delegate_contract (Some delegate) >>>=? fun ctxt -> + return (ctxt, user_contract, user_account, delegate) + +(** Tested scenario : + 1. user contract delegates to 'delegate', + 2. freeze a rollup deposit, + 3. check that staking balance of delegate has not changed, + 4. remove delegation, + 5. check staking balance decreased accordingly, + 6. unfreeze part of the rollup deposit, + 7. check that staking balance is unchanged, + 8. check that user's balance decreased accordingly. *) +let test_delegate_then_freeze_tx_rollup_deposit () = + init_test ~user_is_delegate:false + >>=? fun (ctxt, user_contract, user_account, delegate) -> + (* Fetch user's initial balance before freeze. *) + Token.balance ctxt user_account >>>=? fun user_balance -> + (* Let user delegate to "delegate". *) + Delegate.set ctxt user_contract (Some delegate) >>>=? fun ctxt -> + (* Fetch staking balance after delegation and before freeze. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance -> + (* Freeze a tx-rollup deposit. *) + let (tx_rollup, _) = mk_tx_rollup () in + let bond_id = Rollup_bond_id.Tx_rollup_bond_id tx_rollup in + let deposit_amount = small_random_amount () in + let deposit_account = `Frozen_rollup_bonds (user_contract, bond_id) in + Token.transfer ctxt user_account deposit_account deposit_amount + >>>=? fun (ctxt, _) -> + (* Fetch staking balance after freeze. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance' -> + (* Ensure staking balance did not change. *) + Assert.equal_tez ~loc:__LOC__ staking_balance' staking_balance >>=? fun () -> + (* Remove delegation. *) + Delegate.set ctxt user_contract None >>>=? fun ctxt -> + (* Fetch staking balance after delegation removal. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance'' -> + (* Ensure staking balance decreased by user's initial balance. *) + Assert.equal_tez + ~loc:__LOC__ + staking_balance'' + (staking_balance' -! user_balance) + >>=? fun () -> + (* Unfreeze the deposit. *) + Token.transfer ctxt deposit_account user_account deposit_amount + >>>=? fun (ctxt, _) -> + (* Fetch staking balance of delegate. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance''' -> + (* Ensure that staking balance is unchanged. *) + Assert.equal_tez ~loc:__LOC__ staking_balance''' staking_balance'' + >>=? fun () -> + (* Fetch user's balance again. *) + Token.balance ctxt user_account >>>=? fun user_balance' -> + (* Ensure user's balance decreased. *) + Assert.equal_tez ~loc:__LOC__ user_balance' user_balance + +(** Tested scenario: + 1. freeze a rollup deposit, + 2. user contract delegate to 'delegate', + 3. check that staking balance of delegate has increased as expected, + 4. unfreeze part of the rollup deposit, + 5. check that staking balance has not changed, + 6. remove delegation, + 7. check that staking balance has decreased as expected, + 8. check the the user's balance decreased accordingly. *) +let test_freeze_tx_rollup_deposit_then_delegate () = + init_test ~user_is_delegate:false + >>=? fun (ctxt, user_contract, user_account, delegate) -> + (* Fetch user's initial balance before freeze. *) + Token.balance ctxt user_account >>>=? fun user_balance -> + (* Freeze a tx-rollup deposit. *) + let (tx_rollup, _) = mk_tx_rollup () in + let bond_id = Rollup_bond_id.Tx_rollup_bond_id tx_rollup in + let deposit_amount = small_random_amount () in + let deposit_account = `Frozen_rollup_bonds (user_contract, bond_id) in + Token.transfer ctxt user_account deposit_account deposit_amount + >>>=? fun (ctxt, _) -> + (* Here, user balance has decreased. + Now, fetch staking balance before delegation and after freeze. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance -> + (* Let user delegate to "delegate". *) + Delegate.set ctxt user_contract (Some delegate) >>>=? fun ctxt -> + (* Fetch staking balance after delegation. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance' -> + (* ensure staking balance increased by the user's balance. *) + Assert.equal_tez + ~loc:__LOC__ + staking_balance' + (user_balance +! staking_balance) + >>=? fun () -> + (* Unfreeze the deposit. *) + Token.transfer ctxt deposit_account user_account deposit_amount + >>>=? fun (ctxt, _) -> + (* Fetch staking balance after unfreeze. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance'' -> + (* Ensure that staking balance is unchanged. *) + Assert.equal_tez ~loc:__LOC__ staking_balance'' staking_balance' + >>=? fun () -> + (* Remove delegation. *) + Delegate.set ctxt user_contract None >>>=? fun ctxt -> + (* Fetch staking balance. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance''' -> + (* Check that staking balance has decreased by the user's initial balance. *) + Assert.equal_tez + ~loc:__LOC__ + staking_balance''' + (staking_balance'' -! user_balance) + >>=? fun () -> + (* Fetch user's balance. *) + Token.balance ctxt user_account >>>=? fun user_balance' -> + (* Ensure user's balance decreased. *) + Assert.equal_tez ~loc:__LOC__ user_balance' user_balance + +(** Tested scenario: + 1. freeze a rollup deposit (with deposit amount = balance), + 2. check that the user contract is still allocated, + 3. punish the user contract, + 4. check that the user contract is unallocated, except if it's a delegate. *) +let test_allocated_when_frozen_deposits_exists ~user_is_delegate () = + init_test ~user_is_delegate + >>=? fun (ctxt, user_contract, user_account, _delegate) -> + (* Fetch user's initial balance before freeze. *) + Token.balance ctxt user_account >>>=? fun user_balance -> + Assert.equal_bool ~loc:__LOC__ Tez.(user_balance > zero) true >>=? fun () -> + (* Freeze a tx-rollup deposit. *) + let (tx_rollup, _) = mk_tx_rollup () in + let bond_id = Rollup_bond_id.Tx_rollup_bond_id tx_rollup in + let deposit_amount = user_balance in + let deposit_account = `Frozen_rollup_bonds (user_contract, bond_id) in + Token.transfer ctxt user_account deposit_account deposit_amount + >>>=? fun (ctxt, _) -> + (* Check that user contract is still allocated, despite a null balance. *) + Token.balance ctxt user_account >>>=? fun balance -> + Assert.equal_tez ~loc:__LOC__ balance Tez.zero >>=? fun () -> + Token.allocated ctxt user_account >>>=? fun user_allocated -> + Token.allocated ctxt deposit_account >>>=? fun dep_allocated -> + Assert.equal_bool ~loc:__LOC__ (user_allocated && dep_allocated) true + >>=? fun () -> + (* Punish the user contract. *) + Token.transfer ctxt deposit_account `Burned deposit_amount + >>>=? fun (ctxt, _) -> + (* Check that user and deposit accounts have been unallocated. *) + Token.allocated ctxt user_account >>>=? fun user_allocated -> + Token.allocated ctxt deposit_account >>>=? fun dep_allocated -> + if user_is_delegate then + Assert.equal_bool ~loc:__LOC__ (user_allocated && not dep_allocated) true + else Assert.equal_bool ~loc:__LOC__ (user_allocated || dep_allocated) false + +(** Tested scenario: + 1. freeze two rollup deposits for the user contract, + 2. check that the stake of the user contract is balance + two deposits, + 3. punish for one of the deposits, + 4. check that the stake of the user contract balance + deposit, + 5. punish for the other deposit, + 6. check that the stake of the user contract is equal to balance. *) +let test_total_stake ~user_is_delegate () = + init_test ~user_is_delegate + >>=? fun (ctxt, user_contract, user_account, _delegate) -> + (* Fetch user's initial balance before freeze. *) + Token.balance ctxt user_account >>>=? fun user_balance -> + Assert.equal_bool ~loc:__LOC__ Tez.(user_balance > zero) true >>=? fun () -> + (* Freeze 2 tx-rollup deposits. *) + let (tx_rollup, nonce) = mk_tx_rollup () in + let bond_id1 = Rollup_bond_id.Tx_rollup_bond_id tx_rollup in + let (tx_rollup, _) = mk_tx_rollup ~nonce () in + let bond_id2 = Rollup_bond_id.Tx_rollup_bond_id tx_rollup in + let deposit_amount = small_random_amount () in + let deposit_account1 = `Frozen_rollup_bonds (user_contract, bond_id1) in + Token.transfer ctxt user_account deposit_account1 deposit_amount + >>>=? fun (ctxt, _) -> + let deposit_account2 = `Frozen_rollup_bonds (user_contract, bond_id2) in + Token.transfer ctxt user_account deposit_account2 deposit_amount + >>>=? fun (ctxt, _) -> + (* Check that the stake of user contract is balance + two deposits. *) + Contract.stake ctxt user_contract >>>=? fun stake -> + Token.balance ctxt user_account >>>=? fun balance -> + Assert.equal_tez ~loc:__LOC__ (stake -! balance) (deposit_amount *! 2L) + >>=? fun () -> + (* Punish for one deposit. *) + Token.transfer ctxt deposit_account2 `Burned deposit_amount + >>>=? fun (ctxt, _) -> + (* Check that stake of contract is balance + deposit. *) + Contract.stake ctxt user_contract >>>=? fun stake -> + Assert.equal_tez ~loc:__LOC__ (stake -! balance) deposit_amount >>=? fun () -> + (* Punish for the other deposit. *) + Token.transfer ctxt deposit_account1 `Burned deposit_amount + >>>=? fun (ctxt, _) -> + (* Check that stake of contract is equal to balance. *) + Contract.stake ctxt user_contract >>>=? fun stake -> + Assert.equal_tez ~loc:__LOC__ stake balance + +let tests = + Tztest. + [ + tztest + "rollup deposits - delegate then freeze" + `Quick + test_delegate_then_freeze_tx_rollup_deposit; + tztest + "rollup deposits - freeze then delegate" + `Quick + test_freeze_tx_rollup_deposit_then_delegate; + tztest + "rollup deposits - contract remains allocated, user is not a delegate" + `Quick + (test_allocated_when_frozen_deposits_exists ~user_is_delegate:false); + tztest + "rollup deposits - contract remains allocated, user is a delegate" + `Quick + (test_allocated_when_frozen_deposits_exists ~user_is_delegate:true); + tztest + "rollup deposits - total stake, user is not a delegate" + `Quick + (test_total_stake ~user_is_delegate:false); + tztest + "rollup deposits - total stake, user is a delegate" + `Quick + (test_total_stake ~user_is_delegate:true); + ] -- GitLab From c72e78b20950f86cc077a9a94ad2d9efd33fc189 Mon Sep 17 00:00:00 2001 From: bsall Date: Fri, 11 Feb 2022 18:52:12 +0100 Subject: [PATCH 07/31] Proto: simplify the testing of empty transfers --- .../test/integration/test_token.ml | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/integration/test_token.ml b/src/proto_alpha/lib_protocol/test/integration/test_token.ml index 8b7d0f5d96cd..41b89982cdc8 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_token.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_token.ml @@ -151,15 +151,9 @@ let check_sink_balances ctxt ctxt' dest amount = Assert.equal_tez ~loc:__LOC__ bal_dest' add_bal_dest_amount let test_transferring_to_sink ctxt sink amount expected_bupds = - (* Transferring zero must not return balance updates. *) - (match sink with - | `Contract _ | `Delegate_balance _ -> - return_unit (* Transaction of 0tz is forbidden. *) - | _ -> - wrap (Token.transfer ctxt `Minted sink Tez.zero) - >>=? fun (ctxt', bupds) -> - check_sink_balances ctxt ctxt' sink Tez.zero >>=? fun _ -> - Assert.equal_bool ~loc:__LOC__ (bupds = []) true) + (* Transferring zero must be a noop, and must not return balance updates. *) + wrap (Token.transfer ctxt `Minted sink Tez.zero) >>=? fun (ctxt', bupds) -> + Assert.equal_bool ~loc:__LOC__ (ctxt == ctxt' && bupds = []) true >>=? fun _ -> (* Test transferring a non null amount. *) wrap (Token.transfer ctxt `Minted sink amount) >>=? fun (ctxt', bupds) -> @@ -306,14 +300,9 @@ let test_transferring_from_unbounded_source ctxt src expected_bupds = return_unit let test_transferring_from_bounded_source ctxt src amount expected_bupds = - (* Transferring zero must not return balance updates. *) - (match src with - | `Contract _ | `Delegate_balance _ -> - return_unit (* Transaction of 0tz is forbidden. *) - | _ -> - wrap (Token.transfer ctxt src `Burned Tez.zero) >>=? fun (ctxt', bupds) -> - check_src_balances ctxt ctxt' src Tez.zero >>=? fun _ -> - Assert.equal_bool ~loc:__LOC__ (bupds = []) true) + (* Transferring zero must be a noop, and must not return balance updates. *) + wrap (Token.transfer ctxt src `Burned Tez.zero) >>=? fun (ctxt', bupds) -> + Assert.equal_bool ~loc:__LOC__ (ctxt == ctxt' && bupds = []) true >>=? fun _ -> (* Test transferring a non null amount. *) wrap (Token.transfer ctxt `Minted src amount) >>=? fun (ctxt, _) -> -- GitLab From 9291497f5af7fcddfcf861d5a7b82f76559d9168 Mon Sep 17 00:00:00 2001 From: bsall Date: Fri, 11 Feb 2022 19:44:44 +0100 Subject: [PATCH 08/31] Proto: simplify the allocation of contracts prior to test --- .../test/integration/test_token.ml | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/integration/test_token.ml b/src/proto_alpha/lib_protocol/test/integration/test_token.ml index 41b89982cdc8..daccf44cd010 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_token.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_token.ml @@ -150,11 +150,23 @@ let check_sink_balances ctxt ctxt' dest amount = bal_dest +? amount >>?= fun add_bal_dest_amount -> Assert.equal_tez ~loc:__LOC__ bal_dest' add_bal_dest_amount +(* Accounts of the form (`DelegateBalance pkh) are not allocated when they + receive funds for the first time. To force allocation, we transfer to + (`Contract pkh) instead. *) +let force_allocation_if_need_be ctxt account = + match account with + | `Delegate_balance pkh -> + let account = `Contract (Contract.implicit_contract pkh) in + wrap (Token.transfer ctxt `Minted account Tez.one_mutez) >|=? fst + | _ -> return ctxt + let test_transferring_to_sink ctxt sink amount expected_bupds = (* Transferring zero must be a noop, and must not return balance updates. *) wrap (Token.transfer ctxt `Minted sink Tez.zero) >>=? fun (ctxt', bupds) -> Assert.equal_bool ~loc:__LOC__ (ctxt == ctxt' && bupds = []) true >>=? fun _ -> + (* Force the allocation of [dest] if need be. *) + force_allocation_if_need_be ctxt sink >>=? fun ctxt -> (* Test transferring a non null amount. *) wrap (Token.transfer ctxt `Minted sink amount) >>=? fun (ctxt', bupds) -> check_sink_balances ctxt ctxt' sink amount >>=? fun _ -> @@ -187,11 +199,6 @@ let test_transferring_to_collected_commitments ctxt = let test_transferring_to_delegate_balance ctxt = let (pkh, _pk, _sk) = Signature.generate_key () in let dest = Contract.implicit_contract pkh in - (* First we need to force the allocation of [dest]. *) - wrap (Token.transfer ctxt `Minted (`Contract dest) Tez.one) - >>=? fun (ctxt, _) -> - wrap (Token.allocated ctxt (`Delegate_balance pkh)) >>=? fun allocated -> - Assert.equal_bool ~loc:__LOC__ allocated true >>=? fun () -> let amount = random_amount () in test_transferring_to_sink ctxt @@ -304,6 +311,8 @@ let test_transferring_from_bounded_source ctxt src amount expected_bupds = wrap (Token.transfer ctxt src `Burned Tez.zero) >>=? fun (ctxt', bupds) -> Assert.equal_bool ~loc:__LOC__ (ctxt == ctxt' && bupds = []) true >>=? fun _ -> + (* Force the allocation of [dest] if need be. *) + force_allocation_if_need_be ctxt src >>=? fun ctxt -> (* Test transferring a non null amount. *) wrap (Token.transfer ctxt `Minted src amount) >>=? fun (ctxt, _) -> wrap (Token.transfer ctxt src `Burned amount) >>=? fun (ctxt', bupds) -> @@ -336,9 +345,6 @@ let test_transferring_from_delegate_balance ctxt = let (pkh, _pk, _sk) = Signature.generate_key () in let amount = random_amount () in let src = Contract.implicit_contract pkh in - (* First we need to force the allocation of [dest]. *) - wrap (Token.transfer ctxt `Minted (`Contract src) Tez.one) - >>=? fun (ctxt, _) -> test_transferring_from_bounded_source ctxt (`Delegate_balance pkh) -- GitLab From 9c5c171bdc99c87515cb16e36541450619968c87 Mon Sep 17 00:00:00 2001 From: bsall Date: Fri, 11 Feb 2022 12:17:35 +0100 Subject: [PATCH 09/31] Proto: test that withdrawing or crediting too much fails --- .../test/integration/test_token.ml | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/integration/test_token.ml b/src/proto_alpha/lib_protocol/test/integration/test_token.ml index daccf44cd010..8e388d2f7eda 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_token.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_token.ml @@ -175,7 +175,12 @@ let test_transferring_to_sink ctxt sink amount expected_bupds = in Alcotest.( check bool "Balance updates do not match." (bupds = expected_bupds) true) ; - return_unit + (* Test transferring to go beyond capacity. *) + wrap (Token.balance ctxt' sink) >>=? fun bal -> + let amount = Tez.of_mutez_exn Int64.max_int -! bal +! Tez.one_mutez in + wrap (Token.transfer ctxt' `Minted sink amount) >>= function + | Error _ -> return_unit + | Ok _ -> failwith "Transferring (Int64.max - balance + 1) should fail." let test_transferring_to_contract ctxt = let (pkh, _pk, _sk) = Signature.generate_key () in @@ -306,21 +311,52 @@ let test_transferring_from_unbounded_source ctxt src expected_bupds = Assert.equal_bool ~loc:__LOC__ (bupds = expected_bupds) true >>=? fun () -> return_unit +(* Returns the balance of [account] if [account] is allocated, and returns + [Tez.zero] otherwise. *) +let balance_no_fail ctxt account = + wrap (Token.allocated ctxt account) >>=? fun allocated -> + if allocated then wrap (Token.balance ctxt account) else return Tez.zero + let test_transferring_from_bounded_source ctxt src amount expected_bupds = + balance_no_fail ctxt src >>=? fun balance -> + Assert.equal_tez ~loc:__LOC__ balance Tez.zero >>=? fun () -> + (* Test transferring from an empty account. *) + (wrap (Token.transfer ctxt src `Burned Tez.one) >>= function + | Error _ -> return_unit + | Ok _ -> failwith "Transferring from an empty account should fail.") + >>=? fun () -> (* Transferring zero must be a noop, and must not return balance updates. *) wrap (Token.transfer ctxt src `Burned Tez.zero) >>=? fun (ctxt', bupds) -> Assert.equal_bool ~loc:__LOC__ (ctxt == ctxt' && bupds = []) true >>=? fun _ -> (* Force the allocation of [dest] if need be. *) force_allocation_if_need_be ctxt src >>=? fun ctxt -> - (* Test transferring a non null amount. *) + (* Test transferring everything. *) wrap (Token.transfer ctxt `Minted src amount) >>=? fun (ctxt, _) -> wrap (Token.transfer ctxt src `Burned amount) >>=? fun (ctxt', bupds) -> check_src_balances ctxt ctxt' src amount >>=? fun _ -> let expected_bupds = expected_bupds @ Receipt.[(Burned, Credited amount, Block_application)] in - Assert.equal_bool ~loc:__LOC__ (bupds = expected_bupds) true + Assert.equal_bool ~loc:__LOC__ (bupds = expected_bupds) true >>=? fun () -> + (* Test transferring a smaller amount. *) + wrap (Token.transfer ctxt `Minted src amount) >>=? fun (ctxt, _) -> + (match src with + | `Frozen_rollup_bonds _ -> ( + wrap (Token.transfer ctxt src `Burned amount) >>= function + | Ok _ -> + failwith "Partial withdrawals are forbidden for frozen rollup bonds." + | Error _ -> return_unit) + | _ -> + wrap (Token.transfer ctxt src `Burned amount) >>=? fun (ctxt', bupds) -> + check_src_balances ctxt ctxt' src amount >>=? fun _ -> + Assert.equal_bool ~loc:__LOC__ (bupds = expected_bupds) true) + >>=? fun () -> + (* Test transferring more than available. *) + wrap (Token.balance ctxt src) >>=? fun balance -> + wrap (Token.transfer ctxt src `Burned (balance +! Tez.one)) >>= function + | Error _ -> return_unit + | Ok _ -> failwith "Transferring more than available should fail." let test_transferring_from_contract ctxt = let (pkh, _pk, _sk) = Signature.generate_key () in -- GitLab From 826d7dc5284994098fd6ff06dcce3bf75d9bfb53 Mon Sep 17 00:00:00 2001 From: bsall Date: Tue, 15 Feb 2022 18:46:50 +0100 Subject: [PATCH 10/31] Proto: make storage 'carbonated' --- .../lib_protocol/contract_storage.ml | 6 ++++ .../lib_protocol/contract_storage.mli | 4 +++ .../frozen_rollup_bonds_storage.ml | 31 +++++++++++-------- .../frozen_rollup_bonds_storage.mli | 18 ++++++----- src/proto_alpha/lib_protocol/storage.ml | 4 +-- src/proto_alpha/lib_protocol/storage.mli | 2 +- src/proto_alpha/lib_protocol/token.ml | 25 ++++++++++----- src/proto_alpha/lib_protocol/token.mli | 18 ++++++++++- 8 files changed, 76 insertions(+), 32 deletions(-) diff --git a/src/proto_alpha/lib_protocol/contract_storage.ml b/src/proto_alpha/lib_protocol/contract_storage.ml index 389e9e23fa32..7d50eff8c8e8 100644 --- a/src/proto_alpha/lib_protocol/contract_storage.ml +++ b/src/proto_alpha/lib_protocol/contract_storage.ml @@ -436,6 +436,12 @@ let create_implicit c manager ~balance = ?script:None () +let has_stake ctxt contract = + let open Storage.Contract in + Balance.get ctxt contract >>=? fun balance -> + if Tez_repr.(balance > Tez_repr.zero) then return true + else Frozen_rollup_bonds_storage.has_frozen_bonds ctxt contract + let stake ctxt contract = let open Storage.Contract in Balance.get ctxt contract >>=? fun balance -> diff --git a/src/proto_alpha/lib_protocol/contract_storage.mli b/src/proto_alpha/lib_protocol/contract_storage.mli index 64eab5434ca6..60de8205999d 100644 --- a/src/proto_alpha/lib_protocol/contract_storage.mli +++ b/src/proto_alpha/lib_protocol/contract_storage.mli @@ -176,6 +176,10 @@ val increase_balance_only_call_from_token : val decrease_balance_only_call_from_token : Raw_context.t -> Contract_repr.t -> Tez_repr.t -> Raw_context.t tzresult Lwt.t +(** [stake ctxt contract] returns true iff [contract] has a positive stake. *) +val has_stake : Raw_context.t -> Contract_repr.t -> bool tzresult Lwt.t + (** [stake ctxt contract] returns the stake of [contract]. + This function fails if [contract] is not allocated. *) val stake : Raw_context.t -> Contract_repr.t -> Tez_repr.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.ml b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.ml index d1236058d483..391c62f0d8b7 100644 --- a/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.ml +++ b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.ml @@ -23,14 +23,14 @@ (* *) (*****************************************************************************) -(** This module encapsulates the following storage maps: +(** This module encapsulates the following (carbonated) storage maps: - [Storage.Contract.Frozen_rollup_bonds] - [Storage.Contract.Total_rollup_bonds] This module enforces the following invariants: - [ (Frozen_rollup_bonds.mem x) <-> (Total_rollup_bonds.mem x) ] - - [ Total_rollup_bonds.find x ] = sum of all bond values in - [ Frozen_rollup_bonds.bindings x ]. *) + - [ Total_rollup_bonds.find (ctxt, contract) ] = sum of all bond values in + [ Frozen_rollup_bonds] that are associated to contract. *) open Storage.Contract @@ -66,7 +66,7 @@ let () = let has_frozen_bonds ctxt contract = Total_rollup_bonds.mem ctxt contract >|= ok let allocated ctxt contract bond_id = - Frozen_rollup_bonds.mem (ctxt, contract) bond_id >|= ok + Frozen_rollup_bonds.mem (ctxt, contract) bond_id let find ctxt contract bond_id = Frozen_rollup_bonds.find (ctxt, contract) bond_id @@ -75,12 +75,14 @@ let find ctxt contract bond_id = let spend_only_call_from_token ctxt contract bond_id amount = Contract_delegate_storage.remove_contract_stake ctxt contract amount >>=? fun ctxt -> - Frozen_rollup_bonds.get (ctxt, contract) bond_id >>=? fun frozen_bonds -> + Frozen_rollup_bonds.get (ctxt, contract) bond_id + >>=? fun (ctxt, frozen_bonds) -> error_when Tez_repr.(frozen_bonds <> amount) (Frozen_rollup_bonds_must_be_spent_at_once (contract, bond_id)) >>?= fun () -> - Frozen_rollup_bonds.remove_existing (ctxt, contract) bond_id >>=? fun ctxt -> + Frozen_rollup_bonds.remove_existing (ctxt, contract) bond_id + >>=? fun (ctxt, _) -> Total_rollup_bonds.get ctxt contract >>=? fun total -> Tez_repr.(total -? amount) >>?= fun new_total -> if Tez_repr.(new_total = zero) then @@ -91,13 +93,16 @@ let spend_only_call_from_token ctxt contract bond_id amount = let credit_only_call_from_token ctxt contract bond_id amount = Contract_delegate_storage.add_contract_stake ctxt contract amount >>=? fun ctxt -> - (Frozen_rollup_bonds.find (ctxt, contract) bond_id >>=? function - | None -> Frozen_rollup_bonds.init (ctxt, contract) bond_id amount - | Some frozen_bonds -> - Tez_repr.(frozen_bonds +? amount) >>?= fun new_amount -> - Frozen_rollup_bonds.update (ctxt, contract) bond_id new_amount) - >>=? fun ctxt -> - Total_rollup_bonds.find ctxt contract >>=? function + ( Frozen_rollup_bonds.find (ctxt, contract) bond_id + >>=? fun (ctxt, frozen_bonds_opt) -> + match frozen_bonds_opt with + | None -> Frozen_rollup_bonds.init (ctxt, contract) bond_id amount + | Some frozen_bonds -> + Tez_repr.(frozen_bonds +? amount) >>?= fun new_amount -> + Frozen_rollup_bonds.update (ctxt, contract) bond_id new_amount ) + >>=? fun (ctxt, _consumed1) -> + Total_rollup_bonds.find ctxt contract >>=? fun total_opt -> + match total_opt with | None -> Total_rollup_bonds.init ctxt contract amount | Some total -> Tez_repr.(total +? amount) >>?= fun new_total -> diff --git a/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli index 85b259515d44..31aa20cd8c98 100644 --- a/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli +++ b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli @@ -34,25 +34,27 @@ type error += Frozen_rollup_bonds_must_be_spent_at_once of Contract_repr.t * Rollup_bond_id_repr.t -(** [has_frozen_bonds ctxt contract] returns true if there are frozen bonds - associated to [contract], and returns false otherwise. *) +(** [has_frozen_bonds ctxt contract] returns true iff there are frozen bonds + associated to [contract]. *) val has_frozen_bonds : Raw_context.t -> Contract_repr.t -> bool tzresult Lwt.t -(** [allocated ctxt contract bond_id] returns [true] if there is a bond - associated to [contract] and [bond_id], and returns false otherwise. *) +(** [allocated ctxt contract bond_id] returns a new context because of an access + to carbonated data, and a boolean that is [true] iff there is a bond + associated to [contract] and [bond_id]. *) val allocated : Raw_context.t -> Contract_repr.t -> Rollup_bond_id_repr.t -> - bool tzresult Lwt.t + (Raw_context.t * bool) tzresult Lwt.t -(** [find ctxt contract bond_id] returns the bond associated to - [contract] and [bond_id] if there is one, and returns [None] otherwise. *) +(** [find ctxt contract bond_id] returns a new context because of an access + to carbonated data, and the bond associated to [contract] and [bond_id] if + there is one, or [None] if there is none. *) val find : Raw_context.t -> Contract_repr.t -> Rollup_bond_id_repr.t -> - Tez_repr.t option tzresult Lwt.t + (Raw_context.t * Tez_repr.t option) tzresult Lwt.t (** [spend ctxt contract bond_id amount] withdraws the given [amount] from the value of the bond associated to [contract] and [bond_id]. diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index e88866fe458f..ff48a79440d6 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -351,14 +351,14 @@ module Contract = struct module Rollup_bond_id_index = Make_indexed_subcontext - (Make_subcontext (Ghost) (Indexed_context.Raw_context) + (Make_subcontext (Registered) (Indexed_context.Raw_context) (struct let name = ["rollup_bond_id_index"] end)) (Make_index (Rollup_bond_id_repr.Index)) module Frozen_rollup_bonds = - Rollup_bond_id_index.Make_map + Rollup_bond_id_index.Make_carbonated_map (struct let name = ["rollup_bonds"] end) diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index 6c3da12abfd0..2cc8d9569f9b 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -181,7 +181,7 @@ module Contract : sig and type t := Raw_context.t module Frozen_rollup_bonds : - Indexed_data_storage + Non_iterable_indexed_carbonated_data_storage with type key = Rollup_bond_id_repr.t and type value = Tez_repr.t and type t := Raw_context.t * Contract_repr.t diff --git a/src/proto_alpha/lib_protocol/token.ml b/src/proto_alpha/lib_protocol/token.ml index 723985b0065e..3029c7186e13 100644 --- a/src/proto_alpha/lib_protocol/token.ml +++ b/src/proto_alpha/lib_protocol/token.ml @@ -23,13 +23,16 @@ (* *) (*****************************************************************************) +type carb_container = + [`Frozen_rollup_bonds of Contract_repr.t * Rollup_bond_id_repr.t] + type container = [ `Contract of Contract_repr.t | `Collected_commitments of Blinded_public_key_hash.t | `Delegate_balance of Signature.Public_key_hash.t | `Frozen_deposits of Signature.Public_key_hash.t | `Block_fees - | `Frozen_rollup_bonds of Contract_repr.t * Rollup_bond_id_repr.t ] + | carb_container ] type source = [ `Invoice @@ -51,6 +54,11 @@ type sink = | `Burned | container ] +let carb_allocated ctxt stored = + match stored with + | `Frozen_rollup_bonds (contract, bond_id) -> + Frozen_rollup_bonds_storage.allocated ctxt contract bond_id + let allocated ctxt stored = match stored with | `Contract contract -> Contract_storage.allocated ctxt contract @@ -62,8 +70,13 @@ let allocated ctxt stored = let contract = Contract_repr.implicit_contract delegate in Frozen_deposits_storage.allocated ctxt contract >|= ok | `Block_fees -> return_true + | `Frozen_rollup_bonds _ as account -> carb_allocated ctxt account >|=? snd + +let carb_balance ctxt stored = + match stored with | `Frozen_rollup_bonds (contract, bond_id) -> - Frozen_rollup_bonds_storage.allocated ctxt contract bond_id + Frozen_rollup_bonds_storage.find ctxt contract bond_id + >|=? fun (ctxt, value) -> (ctxt, Option.value ~default:Tez_repr.zero value) let balance ctxt stored = match stored with @@ -79,9 +92,7 @@ let balance ctxt stored = | None -> Tez_repr.zero | Some frozen_deposits -> frozen_deposits.current_amount) | `Block_fees -> return (Raw_context.get_collected_fees ctxt) - | `Frozen_rollup_bonds (contract, bond_id) -> - Frozen_rollup_bonds_storage.find ctxt contract bond_id - >|=? Option.value ~default:Tez_repr.zero + | `Frozen_rollup_bonds _ as stored -> carb_balance ctxt stored >|=? snd let credit ctxt dest amount origin = let open Receipt_repr in @@ -177,8 +188,8 @@ let deallocate_stakeless_implicit_contracts ctxt contract = match Contract_repr.is_implicit contract with | None -> return ctxt (* Never delete originated contracts *) | Some _ -> - Contract_storage.stake ctxt contract >>=? fun stake -> - if Tez_repr.(stake = Tez_repr.zero) then + Contract_storage.has_stake ctxt contract >>=? fun has_stake -> + if not has_stake then (* Delete empty implicit contract. *) Contract_delegate_storage.find ctxt contract >>=? function | Some _ -> diff --git a/src/proto_alpha/lib_protocol/token.mli b/src/proto_alpha/lib_protocol/token.mli index 53f98eeed0c7..c652ceb47f55 100644 --- a/src/proto_alpha/lib_protocol/token.mli +++ b/src/proto_alpha/lib_protocol/token.mli @@ -41,13 +41,16 @@ to/from [`Delegate_balance d] will not update [d]'s stake, while transferring to/from [`Contract (Contract_repr.implicit_contract d)] will update [d]'s stake. *) +type carb_container = + [`Frozen_rollup_bonds of Contract_repr.t * Rollup_bond_id_repr.t] + type container = [ `Contract of Contract_repr.t | `Collected_commitments of Blinded_public_key_hash.t | `Delegate_balance of Signature.Public_key_hash.t | `Frozen_deposits of Signature.Public_key_hash.t | `Block_fees - | `Frozen_rollup_bonds of Contract_repr.t * Rollup_bond_id_repr.t ] + | carb_container ] (** [source] is the type of token providers. Token providers that are not containers are considered to have infinite capacity. *) @@ -73,11 +76,24 @@ type sink = | `Burned | container ] +(** [carb_allocated ctxt container] returns a new context because of an access + to carbonated data, and a boolean that is true when [balance ctxt container] + is guaranteed not to fail, and false when [balance ctxt container] may fail. +*) +val carb_allocated : + Raw_context.t -> carb_container -> (Raw_context.t * bool) tzresult Lwt.t + (** [allocated ctxt container] returns true if [balance ctxt container] is guaranteed not to fail, and returns false when [balance ctxt container] may fail. *) val allocated : Raw_context.t -> container -> bool tzresult Lwt.t +(** [carb_balance ctxt container] returns a new context because of an access + to carbonated data, and the balance associated to [container], or + [Tez_rep.zero] if there is no balance associated to [container]. *) +val carb_balance : + Raw_context.t -> carb_container -> (Raw_context.t * Tez_repr.t) tzresult Lwt.t + (** [balance ctxt container] returns the balance associated to the token holder, may fail if [allocated ctxt container] returns [false]. Returns an error with the message "get_balance" if [container] refers to an -- GitLab From 889f550a448d6f244cc285cee457781d32d37b21 Mon Sep 17 00:00:00 2001 From: bsall Date: Tue, 15 Feb 2022 18:51:47 +0100 Subject: [PATCH 11/31] Proto: fixup-01 --- src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli | 4 ++-- src/proto_alpha/lib_protocol/token.ml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli index 31aa20cd8c98..a7371bc0b613 100644 --- a/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli +++ b/src/proto_alpha/lib_protocol/frozen_rollup_bonds_storage.mli @@ -27,8 +27,8 @@ bonds are part of the stake of the contract making the deposit. *) (** This error is raised when [spend_only_call_from_token] is called with an - amount that is less than the deposit associated to the given contract and - rollup bond id.*) + amount that is not equal to the deposit associated to the given contract and + rollup bond id. *) type error += | (* `Permanent *) Frozen_rollup_bonds_must_be_spent_at_once of diff --git a/src/proto_alpha/lib_protocol/token.ml b/src/proto_alpha/lib_protocol/token.ml index 3029c7186e13..6221c498c592 100644 --- a/src/proto_alpha/lib_protocol/token.ml +++ b/src/proto_alpha/lib_protocol/token.ml @@ -193,7 +193,7 @@ let deallocate_stakeless_implicit_contracts ctxt contract = (* Delete empty implicit contract. *) Contract_delegate_storage.find ctxt contract >>=? function | Some _ -> - (* Here, we know that the contract delegates to iself. Indeed, it + (* Here, we know that the contract delegates to itself. Indeed, it does not delegate to a different one, because the balance of such contracts cannot be zero (see [spend_only_call_from_token] in module [Contract_storage]), hence the stake of such contracts -- GitLab From 6eedcdf8d9b60757ea6af19ccfdefbf97a0515d9 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 24 Jan 2022 11:04:08 -0500 Subject: [PATCH 12/31] Proto, Tx_rollup: Collect commitment bonds Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- src/proto_alpha/lib_client/mockup.ml | 25 +++++++++++++--- .../lib_parameters/default_parameters.ml | 1 + .../lib_protocol/alpha_context.mli | 9 ++++++ src/proto_alpha/lib_protocol/apply.ml | 15 ++++++++-- .../lib_protocol/constants_repr.ml | 13 +++++--- .../lib_protocol/constants_repr.mli | 2 ++ .../lib_protocol/constants_storage.ml | 4 +++ .../lib_protocol/constants_storage.mli | 2 ++ src/proto_alpha/lib_protocol/raw_context.ml | 1 + src/proto_alpha/lib_protocol/storage.ml | 25 ++++++++++++++-- src/proto_alpha/lib_protocol/storage.mli | 10 +++++++ .../integration/operations/test_tx_rollup.ml | 13 +++++++- .../tx_rollup_commitments_storage.ml | 30 +++++++++++++++++-- .../tx_rollup_commitments_storage.mli | 9 ++++++ tests_python/tests_alpha/test_mockup.py | 1 + tezt/_regressions/rpc/alpha.client.others.out | 3 +- tezt/_regressions/rpc/alpha.light.others.out | 3 +- tezt/_regressions/rpc/alpha.proxy.others.out | 3 +- .../rpc/alpha.proxy_server.others.out | 3 +- 19 files changed, 151 insertions(+), 21 deletions(-) diff --git a/src/proto_alpha/lib_client/mockup.ml b/src/proto_alpha/lib_client/mockup.ml index 7c9d4eb1126b..556c9ba13bd3 100644 --- a/src/proto_alpha/lib_client/mockup.ml +++ b/src/proto_alpha/lib_client/mockup.ml @@ -75,6 +75,7 @@ module Protocol_constants_overrides = struct tx_rollup_origination_size : int option; tx_rollup_hard_size_limit_per_inbox : int option; tx_rollup_hard_size_limit_per_message : int option; + tx_rollup_commitment_bond : Tez.t option; sc_rollup_enable : bool option; sc_rollup_origination_size : int option; (* Additional, "bastard" parameters (they are not protocol constants but partially treated the same way). *) @@ -129,7 +130,8 @@ module Protocol_constants_overrides = struct ( ( c.tx_rollup_enable, c.tx_rollup_origination_size, c.tx_rollup_hard_size_limit_per_inbox, - c.tx_rollup_hard_size_limit_per_message ), + c.tx_rollup_hard_size_limit_per_message, + c.tx_rollup_commitment_bond ), (c.sc_rollup_enable, c.sc_rollup_origination_size) ) ) ) ) ) )) (fun ( ( preserved_cycles, @@ -173,7 +175,8 @@ module Protocol_constants_overrides = struct ( ( tx_rollup_enable, tx_rollup_origination_size, tx_rollup_hard_size_limit_per_inbox, - tx_rollup_hard_size_limit_per_message ), + tx_rollup_hard_size_limit_per_message, + tx_rollup_commitment_bond ), (sc_rollup_enable, sc_rollup_origination_size) ) ) ) ) ) ) -> { @@ -216,6 +219,7 @@ module Protocol_constants_overrides = struct tx_rollup_origination_size; tx_rollup_hard_size_limit_per_inbox; tx_rollup_hard_size_limit_per_message; + tx_rollup_commitment_bond; sc_rollup_enable; sc_rollup_origination_size; chain_id; @@ -275,11 +279,12 @@ module Protocol_constants_overrides = struct (opt "cache_stake_distribution_cycles" int8) (opt "cache_sampler_state_cycles" int8)) (merge_objs - (obj4 + (obj5 (opt "tx_rollup_enable" Data_encoding.bool) (opt "tx_rollup_origination_size" int31) (opt "tx_rollup_hard_size_limit_per_inbox" int31) - (opt "tx_rollup_hard_size_limit_per_message" int31)) + (opt "tx_rollup_hard_size_limit_per_message" int31) + (opt "tx_rollup_commitment_bond" Tez.encoding)) (obj2 (opt "sc_rollup_enable" bool) (opt "sc_rollup_origination_size" int31)))))))) @@ -351,6 +356,7 @@ module Protocol_constants_overrides = struct Some parametric.tx_rollup_hard_size_limit_per_inbox; tx_rollup_hard_size_limit_per_message = Some parametric.tx_rollup_hard_size_limit_per_message; + tx_rollup_commitment_bond = Some parametric.tx_rollup_commitment_bond; sc_rollup_enable = Some parametric.sc_rollup_enable; sc_rollup_origination_size = Some parametric.sc_rollup_origination_size; (* Bastard additional parameters. *) @@ -402,6 +408,7 @@ module Protocol_constants_overrides = struct tx_rollup_origination_size = None; tx_rollup_hard_size_limit_per_inbox = None; tx_rollup_hard_size_limit_per_message = None; + tx_rollup_commitment_bond = None; sc_rollup_enable = None; sc_rollup_origination_size = None; chain_id = None; @@ -660,6 +667,12 @@ module Protocol_constants_overrides = struct override_value = o.tx_rollup_hard_size_limit_per_message; pp = pp_print_int; }; + O + { + name = "tx_rollup_commitment_bond"; + override_value = o.tx_rollup_commitment_bond; + pp = Tez.pp; + }; ] in let fields_with_override = @@ -804,6 +817,10 @@ module Protocol_constants_overrides = struct Option.value ~default:c.tx_rollup_hard_size_limit_per_message o.tx_rollup_hard_size_limit_per_message; + tx_rollup_commitment_bond = + Option.value + ~default:c.tx_rollup_commitment_bond + o.tx_rollup_commitment_bond; sc_rollup_enable = Option.value ~default:c.sc_rollup_enable o.sc_rollup_enable; sc_rollup_origination_size = diff --git a/src/proto_alpha/lib_parameters/default_parameters.ml b/src/proto_alpha/lib_parameters/default_parameters.ml index bcff5ea4b2a8..6f3dcae59c12 100644 --- a/src/proto_alpha/lib_parameters/default_parameters.ml +++ b/src/proto_alpha/lib_parameters/default_parameters.ml @@ -104,6 +104,7 @@ let constants_mainnet = (* Transaction rollup’s size limits are expressed in number of bytes *) tx_rollup_hard_size_limit_per_inbox = 100_000; tx_rollup_hard_size_limit_per_message = 5_000; + tx_rollup_commitment_bond = Tez.of_mutez_exn 10_000_000_000L; sc_rollup_enable = false; (* The following value is chosen to prevent spam. *) sc_rollup_origination_size = 6_314; diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index da89f9baee6a..f70d930233d8 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -781,6 +781,7 @@ module Constants : sig tx_rollup_origination_size : int; tx_rollup_hard_size_limit_per_inbox : int; tx_rollup_hard_size_limit_per_message : int; + tx_rollup_commitment_bond : Tez.t; sc_rollup_enable : bool; sc_rollup_origination_size : int; } @@ -872,6 +873,8 @@ module Constants : sig val tx_rollup_hard_size_limit_per_message : context -> int + val tx_rollup_commitment_bond : context -> Tez.t + val sc_rollup_enable : context -> bool val sc_rollup_origination_size : context -> int @@ -2160,6 +2163,12 @@ module Tx_rollup_commitments : sig val get_commitments : context -> Tx_rollup.t -> Raw_level.t -> (context * t) tzresult Lwt.t + + val pending_bonded_commitments : + context -> + Tx_rollup.t -> + Signature.public_key_hash -> + (context * int) tzresult Lwt.t end module Kind : sig diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 1553cd61fe6b..d0e4d924672a 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -1202,19 +1202,30 @@ let apply_manager_operation_content : in return (ctxt, result, []) | Tx_rollup_commit {tx_rollup; commitment} -> ( - (* TODO: bonds https://gitlab.com/tezos/tezos/-/issues/2459 *) match Contract.is_implicit source with | None -> fail Tx_rollup_commit_with_non_implicit_contract (* This is only called with implicit contracts *) | Some key -> + ( Tx_rollup_commitments.pending_bonded_commitments ctxt tx_rollup key + >>=? fun (ctxt, pending) -> + let bond_id = Rollup_bond_id.Tx_rollup_bond_id tx_rollup in + match pending with + | 0 -> + Token.transfer + ctxt + (`Contract source) + (`Frozen_rollup_bonds (source, bond_id)) + (Constants.tx_rollup_commitment_bond ctxt) + | _ -> return (ctxt, []) ) + >>=? fun (ctxt, balance_updates) -> Tx_rollup_commitments.add_commitment ctxt tx_rollup key commitment >>=? fun ctxt -> let result = Tx_rollup_commit_result { consumed_gas = Gas.consumed ~since:before_operation ~until:ctxt; - balance_updates = []; + balance_updates; } in return (ctxt, result, [])) diff --git a/src/proto_alpha/lib_protocol/constants_repr.ml b/src/proto_alpha/lib_protocol/constants_repr.ml index bc9112cff620..9f862cba6484 100644 --- a/src/proto_alpha/lib_protocol/constants_repr.ml +++ b/src/proto_alpha/lib_protocol/constants_repr.ml @@ -162,6 +162,7 @@ type parametric = { tx_rollup_origination_size : int; tx_rollup_hard_size_limit_per_inbox : int; tx_rollup_hard_size_limit_per_message : int; + tx_rollup_commitment_bond : Tez_repr.t; sc_rollup_enable : bool; sc_rollup_origination_size : int; } @@ -209,7 +210,8 @@ let parametric_encoding = ( ( c.tx_rollup_enable, c.tx_rollup_origination_size, c.tx_rollup_hard_size_limit_per_inbox, - c.tx_rollup_hard_size_limit_per_message ), + c.tx_rollup_hard_size_limit_per_message, + c.tx_rollup_commitment_bond ), (c.sc_rollup_enable, c.sc_rollup_origination_size) ) ) ) ) ) )) (fun ( ( preserved_cycles, @@ -251,7 +253,8 @@ let parametric_encoding = ( ( tx_rollup_enable, tx_rollup_origination_size, tx_rollup_hard_size_limit_per_inbox, - tx_rollup_hard_size_limit_per_message ), + tx_rollup_hard_size_limit_per_message, + tx_rollup_commitment_bond ), (sc_rollup_enable, sc_rollup_origination_size) ) ) ) ) ) ) -> { preserved_cycles; @@ -294,6 +297,7 @@ let parametric_encoding = tx_rollup_origination_size; tx_rollup_hard_size_limit_per_inbox; tx_rollup_hard_size_limit_per_message; + tx_rollup_commitment_bond; sc_rollup_enable; sc_rollup_origination_size; }) @@ -350,11 +354,12 @@ let parametric_encoding = (req "cache_stake_distribution_cycles" int8) (req "cache_sampler_state_cycles" int8)) (merge_objs - (obj4 + (obj5 (req "tx_rollup_enable" bool) (req "tx_rollup_origination_size" int31) (req "tx_rollup_hard_size_limit_per_inbox" int31) - (req "tx_rollup_hard_size_limit_per_message" int31)) + (req "tx_rollup_hard_size_limit_per_message" int31) + (req "tx_rollup_commitment_bond" Tez_repr.encoding)) (obj2 (req "sc_rollup_enable" bool) (req "sc_rollup_origination_size" int31)))))))) diff --git a/src/proto_alpha/lib_protocol/constants_repr.mli b/src/proto_alpha/lib_protocol/constants_repr.mli index 062306c4a7d3..85821046a5de 100644 --- a/src/proto_alpha/lib_protocol/constants_repr.mli +++ b/src/proto_alpha/lib_protocol/constants_repr.mli @@ -127,6 +127,8 @@ type parametric = { tx_rollup_hard_size_limit_per_inbox : int; (* the maximum amount of bytes one batch can allocate in an inbox *) tx_rollup_hard_size_limit_per_message : int; + (* the amount of tez to bond a tx rollup commitment *) + tx_rollup_commitment_bond : Tez_repr.t; sc_rollup_enable : bool; sc_rollup_origination_size : int; } diff --git a/src/proto_alpha/lib_protocol/constants_storage.ml b/src/proto_alpha/lib_protocol/constants_storage.ml index 50a01c127def..7c5dd10e8cac 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.ml +++ b/src/proto_alpha/lib_protocol/constants_storage.ml @@ -161,6 +161,10 @@ let tx_rollup_hard_size_limit_per_message c = let constants = Raw_context.constants c in constants.tx_rollup_hard_size_limit_per_message +let tx_rollup_commitment_bond c = + let constants = Raw_context.constants c in + constants.tx_rollup_commitment_bond + let ratio_of_frozen_deposits_slashed_per_double_endorsement c = let constants = Raw_context.constants c in constants.ratio_of_frozen_deposits_slashed_per_double_endorsement diff --git a/src/proto_alpha/lib_protocol/constants_storage.mli b/src/proto_alpha/lib_protocol/constants_storage.mli index 7772926806c6..87e53d43353f 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.mli +++ b/src/proto_alpha/lib_protocol/constants_storage.mli @@ -91,6 +91,8 @@ val tx_rollup_hard_size_limit_per_inbox : Raw_context.t -> int val tx_rollup_hard_size_limit_per_message : Raw_context.t -> int +val tx_rollup_commitment_bond : Raw_context.t -> Tez_repr.t + val ratio_of_frozen_deposits_slashed_per_double_endorsement : Raw_context.t -> Constants_repr.ratio diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index edeca90b1bce..42dc176f816c 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -881,6 +881,7 @@ let prepare_first_block ~level ~timestamp ctxt = tx_rollup_origination_size = 60_000; tx_rollup_hard_size_limit_per_inbox = 100_000; tx_rollup_hard_size_limit_per_message = 5_000; + tx_rollup_commitment_bond = Tez_repr.of_mutez_exn 10_000_000_000L; sc_rollup_enable = false; (* The following value is chosen to prevent spam. *) sc_rollup_origination_size = 6_314; diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index ff48a79440d6..2d72f1f5bccd 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -862,15 +862,15 @@ module Public_key_hash = struct match key with | Ed25519 h -> ( match Path_Ed25519.to_path h l with - | [s] -> ["ed25519"; s] + | s :: t -> "ed25519" :: s :: t | _ -> assert false) | Secp256k1 h -> ( match Path_Secp256k1.to_path h l with - | [s] -> ["secp256k1"; s] + | s :: t -> "secp256k1" :: s :: t | _ -> assert false) | P256 h -> ( match Path_P256.to_path h l with - | [s] -> ["p256"; s] + | s :: t -> "p256" :: s :: t | _ -> assert false) let of_path : _ -> public_key_hash option = function @@ -1451,12 +1451,31 @@ module Tx_rollup = struct (Raw_level_repr.Index)) (Make_index (Tx_rollup_repr.Index))) + module Bond_indexed_context = + Make_indexed_subcontext + (Make_subcontext (Registered) (Raw_context) + (struct + let name = ["tx_rollup_bond"] + end)) + (Pair (Make_index (Tx_rollup_repr.Index)) (Public_key_hash_index)) + module Commitment_list = Level_indexed_context.Make_carbonated_map (struct let name = ["commitment_list"] end) (Tx_rollup_commitments_repr) + + module Commitment_bond = + Bond_indexed_context.Make_carbonated_map + (struct + let name = ["commitment_bond"] + end) + (struct + type t = int + + let encoding = Data_encoding.int31 + end) end module Sc_rollup = struct diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index 2cc8d9569f9b..3a88700a4e49 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -647,6 +647,16 @@ module Tx_rollup : sig with type key = Raw_level_repr.t * Tx_rollup_repr.t and type value = Tx_rollup_commitments_repr.t and type t := Raw_context.t + + (* This stores information about which contracts have bonds + for each rollup, and how many commitments those bonds + stake. *) + module Commitment_bond : + Non_iterable_indexed_carbonated_data_storage + with type key = Tx_rollup_repr.t * Signature.public_key_hash + (* The value here is the number of unfinalized commitments *) + and type value = int + and type t := Raw_context.t end module Sc_rollup : sig diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index 20efc0bc54ad..cd77f0b21dc6 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -3,6 +3,7 @@ (* Open Source License *) (* Copyright (c) 2021 Marigold *) (* Copyright (c) 2021 Nomadic Labs *) +(* Copyright (c) 2022 Oxhead Alpha *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -170,6 +171,13 @@ let public_key_hash_exn contract = | None -> assert false | Some public_key_hash -> public_key_hash +let check_bond ctxt tx_rollup contract count = + wrap + (Tx_rollup_commitments.pending_bonded_commitments ctxt tx_rollup contract) + >>=? fun (_, pending) -> + Alcotest.(check int "Pending commitment count correct" count pending) ; + return () + (** ---- TESTS -------------------------------------------------------------- *) (** [test_origination] originates a transaction rollup and checks that @@ -583,6 +591,7 @@ let test_commitment_duplication () = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 1 in let pkh1 = public_key_hash_exn contract1 in + let pkh2 = public_key_hash_exn contract2 in originate b contract1 >>=? fun (b, tx_rollup) -> Context.Contract.balance (B b) contract1 >>=? fun balance -> Context.Contract.balance (B b) contract2 >>=? fun balance2 -> @@ -660,7 +669,7 @@ let test_commitment_duplication () = >>=? fun () -> let ctxt = Incremental.alpha_ctxt i in wrap (Tx_rollup_commitments.get_commitments ctxt tx_rollup level) - >>=? fun (_, commitments) -> + >>=? fun (ctxt, commitments) -> (Alcotest.(check int "Expected one commitment" 1 (List.length commitments)) ; let expected_hash = Tx_rollup_commitments.Commitment.hash commitment in match List.nth commitments 0 with @@ -675,6 +684,8 @@ let test_commitment_duplication () = check raw_level_testable "Submitted" submitted_level submitted_at) ; return ()) >>=? fun () -> + check_bond ctxt tx_rollup pkh1 1 >>=? fun () -> + check_bond ctxt tx_rollup pkh2 0 >>=? fun () -> ignore i ; return () diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml index 550d8d19ed7f..8e1a4bce9fac 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml @@ -45,6 +45,20 @@ let get_prev_level ctxt tx_rollup level = Tx_rollup_inbox_storage.get_adjacent_levels ctxt level tx_rollup >|=? fun (ctxt, predecessor_level, _) -> (ctxt, predecessor_level) +(* This indicates a programming error. *) +type error += (*`Temporary*) Commitment_bond_negative of int + +let adjust_commitment_bond ctxt tx_rollup pkh delta = + let bond_key = (tx_rollup, pkh) in + Storage.Tx_rollup.Commitment_bond.find ctxt bond_key + >>=? fun (ctxt, commitment) -> + let count = + match commitment with Some count -> count + delta | None -> delta + in + fail_when Compare.Int.(count < 0) (Commitment_bond_negative count) + >>=? fun () -> + Storage.Tx_rollup.Commitment_bond.add ctxt bond_key count >|=? just_ctxt + let check_commitment_predecessor_hash ctxt tx_rollup (commitment : Commitment.t) = let level = commitment.level in @@ -64,7 +78,7 @@ let check_commitment_predecessor_hash ctxt tx_rollup (commitment : Commitment.t) Missing_commitment_predecessor >>=? fun () -> return ctxt -let add_commitment ctxt tx_rollup contract (commitment : Commitment.t) = +let add_commitment ctxt tx_rollup pkh (commitment : Commitment.t) = let key = (commitment.level, tx_rollup) in get_or_empty_commitments ctxt key >>=? fun (ctxt, pending) -> Tx_rollup_inbox_storage.get ctxt ~level:(`Level commitment.level) tx_rollup @@ -76,11 +90,12 @@ let add_commitment ctxt tx_rollup contract (commitment : Commitment.t) = check_commitment_predecessor_hash ctxt tx_rollup commitment >>=? fun ctxt -> Tx_rollup_commitments_repr.append pending - contract + pkh commitment (Raw_context.current_level ctxt).level >>?= fun new_pending -> - Storage.Tx_rollup.Commitment_list.add ctxt key new_pending >|=? just_ctxt + Storage.Tx_rollup.Commitment_list.add ctxt key new_pending + >>=? fun (ctxt, _, _) -> adjust_commitment_bond ctxt tx_rollup pkh 1 let get_commitments : Raw_context.t -> @@ -92,3 +107,12 @@ let get_commitments : match state with | None -> fail @@ Tx_rollup_state_storage.Tx_rollup_does_not_exist tx_rollup | Some _ -> get_or_empty_commitments ctxt (level, tx_rollup) + +let pending_bonded_commitments : + Raw_context.t -> + Tx_rollup_repr.t -> + Signature.public_key_hash -> + (Raw_context.t * int) tzresult Lwt.t = + fun ctxt tx_rollup pkh -> + Storage.Tx_rollup.Commitment_bond.find ctxt (tx_rollup, pkh) + >|=? fun (ctxt, pending) -> (ctxt, Option.value ~default:0 pending) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli index a135ed1cae61..c7ea72d12b6a 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli @@ -49,3 +49,12 @@ val get_commitments : Tx_rollup_repr.t -> Raw_level_repr.t -> (Raw_context.t * Tx_rollup_commitments_repr.t) tzresult Lwt.t + +(** [pending bonded_commitments ctxt tx_rollup contract] returns the + number of commitments that [contract] has made that are still + pending (that is, still subject to rejection) *) +val pending_bonded_commitments : + Raw_context.t -> + Tx_rollup_repr.t -> + Signature.public_key_hash -> + (Raw_context.t * int) tzresult Lwt.t diff --git a/tests_python/tests_alpha/test_mockup.py b/tests_python/tests_alpha/test_mockup.py index 988b7ebf5e71..688cf2bd9404 100644 --- a/tests_python/tests_alpha/test_mockup.py +++ b/tests_python/tests_alpha/test_mockup.py @@ -659,6 +659,7 @@ def _test_create_mockup_init_show_roundtrip( "tx_rollup_origination_size": 30_000, "tx_rollup_hard_size_limit_per_inbox": 75_000, "tx_rollup_hard_size_limit_per_message": 9_999, + "tx_rollup_commitment_bond": "10000000000", "sc_rollup_enable": False, "sc_rollup_origination_size": 6_314, } diff --git a/tezt/_regressions/rpc/alpha.client.others.out b/tezt/_regressions/rpc/alpha.client.others.out index e945ddd84cbc..52ab8b42f94c 100644 --- a/tezt/_regressions/rpc/alpha.client.others.out +++ b/tezt/_regressions/rpc/alpha.client.others.out @@ -31,7 +31,8 @@ tezt/_regressions/rpc/alpha.client.others.out "cache_stake_distribution_cycles": 8, "cache_sampler_state_cycles": 8, "tx_rollup_enable": false, "tx_rollup_origination_size": 60000, "tx_rollup_hard_size_limit_per_inbox": 100000, - "tx_rollup_hard_size_limit_per_message": 5000, "sc_rollup_enable": false, + "tx_rollup_hard_size_limit_per_message": 5000, + "tx_rollup_commitment_bond": "10000000000", "sc_rollup_enable": false, "sc_rollup_origination_size": 6314 } ./tezos-client rpc get /chains/main/blocks/head/helpers/baking_rights diff --git a/tezt/_regressions/rpc/alpha.light.others.out b/tezt/_regressions/rpc/alpha.light.others.out index b9f4dcb1d138..5462a3a58b1e 100644 --- a/tezt/_regressions/rpc/alpha.light.others.out +++ b/tezt/_regressions/rpc/alpha.light.others.out @@ -32,7 +32,8 @@ protocol of light mode unspecified, using the node's protocol: ProtoGenesisGenes "cache_stake_distribution_cycles": 8, "cache_sampler_state_cycles": 8, "tx_rollup_enable": false, "tx_rollup_origination_size": 60000, "tx_rollup_hard_size_limit_per_inbox": 100000, - "tx_rollup_hard_size_limit_per_message": 5000, "sc_rollup_enable": false, + "tx_rollup_hard_size_limit_per_message": 5000, + "tx_rollup_commitment_bond": "10000000000", "sc_rollup_enable": false, "sc_rollup_origination_size": 6314 } ./tezos-client --mode light rpc get /chains/main/blocks/head/helpers/baking_rights diff --git a/tezt/_regressions/rpc/alpha.proxy.others.out b/tezt/_regressions/rpc/alpha.proxy.others.out index 760067d3046d..65e3efa2f3f6 100644 --- a/tezt/_regressions/rpc/alpha.proxy.others.out +++ b/tezt/_regressions/rpc/alpha.proxy.others.out @@ -32,7 +32,8 @@ protocol of proxy unspecified, using the node's protocol: ProtoGenesisGenesisGen "cache_stake_distribution_cycles": 8, "cache_sampler_state_cycles": 8, "tx_rollup_enable": false, "tx_rollup_origination_size": 60000, "tx_rollup_hard_size_limit_per_inbox": 100000, - "tx_rollup_hard_size_limit_per_message": 5000, "sc_rollup_enable": false, + "tx_rollup_hard_size_limit_per_message": 5000, + "tx_rollup_commitment_bond": "10000000000", "sc_rollup_enable": false, "sc_rollup_origination_size": 6314 } ./tezos-client --mode proxy rpc get /chains/main/blocks/head/helpers/baking_rights diff --git a/tezt/_regressions/rpc/alpha.proxy_server.others.out b/tezt/_regressions/rpc/alpha.proxy_server.others.out index 6ec3dc57ad95..70f5d0b24b36 100644 --- a/tezt/_regressions/rpc/alpha.proxy_server.others.out +++ b/tezt/_regressions/rpc/alpha.proxy_server.others.out @@ -31,7 +31,8 @@ tezt/_regressions/rpc/alpha.proxy_server.others.out "cache_stake_distribution_cycles": 8, "cache_sampler_state_cycles": 8, "tx_rollup_enable": false, "tx_rollup_origination_size": 60000, "tx_rollup_hard_size_limit_per_inbox": 100000, - "tx_rollup_hard_size_limit_per_message": 5000, "sc_rollup_enable": false, + "tx_rollup_hard_size_limit_per_message": 5000, + "tx_rollup_commitment_bond": "10000000000", "sc_rollup_enable": false, "sc_rollup_origination_size": 6314 } ./tezos-client rpc get /chains/main/blocks/head/helpers/baking_rights -- GitLab From 0a7412c4d23856cf15fda779450d468f682b953f Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 24 Jan 2022 11:04:08 -0500 Subject: [PATCH 13/31] Proto,Tx_rollup: Add levels to Commitment_Too_Early Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- src/proto_alpha/lib_protocol/alpha_context.mli | 2 +- src/proto_alpha/lib_protocol/apply.ml | 3 ++- .../lib_protocol/tx_rollup_commitments_repr.ml | 15 +++++++++++---- .../lib_protocol/tx_rollup_commitments_repr.mli | 3 ++- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index f70d930233d8..87e49c4a1ae9 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2152,7 +2152,7 @@ module Tx_rollup_commitments : sig type error += Wrong_batch_count - type error += Commitment_too_early + type error += Commitment_too_early of Raw_level.t * Raw_level.t val add_commitment : context -> diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index d0e4d924672a..f20d1404ab38 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -1380,7 +1380,8 @@ let precheck_manager_contents (type kind) ctxt (op : kind Kind.manager contents) let current_level = (Level.current ctxt).level in fail_when Raw_level.(current_level <= Raw_level.succ commitment.level) - Tx_rollup_commitments.Commitment_too_early + (Tx_rollup_commitments.Commitment_too_early + (commitment.level, current_level)) >|=? fun () -> ctxt | Sc_rollup_originate _ | Sc_rollup_add_messages _ -> assert_sc_rollup_feature_enabled ctxt >|=? fun () -> ctxt) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml index a5ed1c1d5e0f..53609a3a7dfb 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml @@ -35,7 +35,8 @@ type error += (* `Temporary *) Missing_commitment_predecessor type error += (* `Branch *) Wrong_batch_count -type error += (* `Temporary *) Commitment_too_early +type error += + | (* `Temporary *) Commitment_too_early of Raw_level_repr.t * Raw_level_repr.t let () = let open Data_encoding in @@ -93,9 +94,15 @@ let () = ~id:"tx_rollup_commitment_too_early" ~title:"This commitment is for a level that hasn't finished yet" ~description:"This commitment is for a level that hasn't finished yet" - unit - (function Commitment_too_early -> Some () | _ -> None) - (fun () -> Commitment_too_early) + (obj2 + (req "commitment_level" Raw_level_repr.encoding) + (req "submit_level" Raw_level_repr.encoding)) + (function + | Commitment_too_early (commitment_level, submit_level) -> + Some (commitment_level, submit_level) + | _ -> None) + (fun (commitment_level, submit_level) -> + Commitment_too_early (commitment_level, submit_level)) let compare_or cmp c1 c2 f = match cmp c1 c2 with 0 -> f () | diff -> diff diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli index 876019cd65ad..1b8ff7348051 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli @@ -35,7 +35,8 @@ type error += (* `Temporary *) Missing_commitment_predecessor type error += (* `Branch *) Wrong_batch_count -type error += (* `Temporary *) Commitment_too_early +type error += + | (* `Temporary *) Commitment_too_early of Raw_level_repr.t * Raw_level_repr.t (** A specialized Blake2B implementation for hashing commitments with "toc1" as a base58 prefix *) -- GitLab From d6d90dd59afd9810e490c0422a90df912143d407 Mon Sep 17 00:00:00 2001 From: David Turner Date: Fri, 11 Feb 2022 15:13:47 -0500 Subject: [PATCH 14/31] Proto, Tx_rollup: Make check_bond helper take a contract Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- .../integration/operations/test_tx_rollup.ml | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index cd77f0b21dc6..a7eae6154435 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -172,12 +172,24 @@ let public_key_hash_exn contract = | Some public_key_hash -> public_key_hash let check_bond ctxt tx_rollup contract count = - wrap - (Tx_rollup_commitments.pending_bonded_commitments ctxt tx_rollup contract) + let pkh = public_key_hash_exn contract in + wrap (Tx_rollup_commitments.pending_bonded_commitments ctxt tx_rollup pkh) >>=? fun (_, pending) -> Alcotest.(check int "Pending commitment count correct" count pending) ; return () +let rec bake_until i top = + let level = Incremental.level i in + if level >= top then return i + else + Incremental.finalize_block i >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> bake_until i top + +let assert_retired retired = + match retired with + | `Retired -> return_unit + | _ -> failwith "Expected retired" + (** ---- TESTS -------------------------------------------------------------- *) (** [test_origination] originates a transaction rollup and checks that @@ -591,7 +603,6 @@ let test_commitment_duplication () = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 1 in let pkh1 = public_key_hash_exn contract1 in - let pkh2 = public_key_hash_exn contract2 in originate b contract1 >>=? fun (b, tx_rollup) -> Context.Contract.balance (B b) contract1 >>=? fun balance -> Context.Contract.balance (B b) contract2 >>=? fun balance2 -> @@ -684,8 +695,8 @@ let test_commitment_duplication () = check raw_level_testable "Submitted" submitted_level submitted_at) ; return ()) >>=? fun () -> - check_bond ctxt tx_rollup pkh1 1 >>=? fun () -> - check_bond ctxt tx_rollup pkh2 0 >>=? fun () -> + check_bond ctxt tx_rollup contract1 1 >>=? fun () -> + check_bond ctxt tx_rollup contract2 0 >>=? fun () -> ignore i ; return () -- GitLab From a311d596bf95818606e845c8e018309ed1f2ab6a Mon Sep 17 00:00:00 2001 From: David Turner Date: Fri, 3 Dec 2021 16:26:27 -0500 Subject: [PATCH 15/31] Proto,Tx_rollup: Commitment bond and finalization functions Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- src/proto_alpha/lib_protocol/alpha_context.ml | 5 + .../lib_protocol/alpha_context.mli | 9 + .../integration/operations/test_tx_rollup.ml | 234 ++++++++++++++++++ .../tx_rollup_commitments_repr.ml | 16 +- .../tx_rollup_commitments_repr.mli | 3 + .../tx_rollup_commitments_storage.ml | 83 +++++++ .../tx_rollup_commitments_storage.mli | 12 + 7 files changed, 360 insertions(+), 2 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index 9f48bbc47073..18c99e8f7258 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -273,6 +273,11 @@ end module Tx_rollup_commitments = struct include Tx_rollup_commitments_repr include Tx_rollup_commitments_storage + + module Internal_for_tests = struct + include Tx_rollup_commitments_repr + include Tx_rollup_commitments_storage + end end module Global_constants_storage = Global_constants_storage diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 87e49c4a1ae9..893c5164fc5f 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2154,6 +2154,8 @@ module Tx_rollup_commitments : sig type error += Commitment_too_early of Raw_level.t * Raw_level.t + type error += Retire_uncommitted_level of Raw_level.t + val add_commitment : context -> Tx_rollup.t -> @@ -2169,6 +2171,13 @@ module Tx_rollup_commitments : sig Tx_rollup.t -> Signature.public_key_hash -> (context * int) tzresult Lwt.t + + module Internal_for_tests : sig + (** See [Tx_rollup_commitments_storage.retire_rollup_level] + for documentation *) + val retire_rollup_level : + context -> Tx_rollup.t -> Raw_level.t -> context tzresult Lwt.t + end end module Kind : sig diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index a7eae6154435..a840e710c4fb 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -793,6 +793,228 @@ let test_commitment_predecessor () = ignore i ; return () +(** [test_commitment_retire_simple] tests commitment retirement simple cases. + Note that it manually retires commitments rather than waiting for them to + age out. *) +let test_commitment_retire_simple () = + context_init 1 >>=? fun (b, contracts) -> + let contract1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + originate b contract1 >>=? fun (b, tx_rollup) -> + (* In order to have a permissible commitment, we need a transaction. *) + let contents = "batch" in + Op.tx_rollup_submit_batch (B b) contract1 tx_rollup contents + >>=? fun operation -> + Block.bake ~operation b >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + let level = raw_level 2l in + Incremental.finalize_block i >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + (* Test retirement with no commitment *) + wrap + (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level + (Incremental.alpha_ctxt i) + tx_rollup + level) + >>= fun res -> + Assert.proto_error ~loc:__LOC__ res (fun e -> + e = Tx_rollup_commitments.Retire_uncommitted_level level) + >>=? fun () -> + (* Now, make a commitment *) + let batches : Tx_rollup_commitments.Commitment.batch_commitment list = + [{root = Bytes.make 20 '0'}] + in + let commitment : Tx_rollup_commitments.Commitment.t = + {level; batches; predecessor = None} + in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + check_bond (Incremental.alpha_ctxt i) tx_rollup contract1 1 >>=? fun () -> + (* We can retire this level *) + wrap + (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level + (Incremental.alpha_ctxt i) + tx_rollup + level) + >>=? fun ctxt -> + check_bond ctxt tx_rollup contract1 0 >>=? fun () -> + ignore i ; + return () + +(** [test_commitment_retire_complex] tests a complicated commitment + retirement scenario: + + We have inboxes at 2, 3, and 6. + + - A: Contract 1 commits to 2. + - B: Contract 2 commits to 2 (after A; this commitment is + necessarily bogus, but we will assume that nobody notices) + - C: Contract 2 commits to 3 (atop A). + - D: Contract 1 commits to 3 (atop bogus commit B) + - E: Contract 2 commits to 6 (atop D). + - F: Contract 1 commits to 6 (atop C). + + So now we retire 2. We want nobody to get a bond back, but D and + E are gone. Then we retire 3, which will enable 2 to get its bond + back. Then we retire 6, which lets Contract 1 get its bond back. +*) +let test_commitment_retire_complex () = + context_init 2 >>=? fun (b, contracts) -> + let contract1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + let contract2 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 1 + in + originate b contract1 >>=? fun (b, tx_rollup) -> + (* Transactions in blocks 2, 3, 6 *) + make_transactions_in tx_rollup contract1 [2; 3; 6] b >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + let batches : Tx_rollup_commitments.Commitment.batch_commitment list = + [{root = Bytes.make 20 '0'}] + in + let batches2 : Tx_rollup_commitments.Commitment.batch_commitment list = + [{root = Bytes.make 20 '1'}] + in + let commitment_a : Tx_rollup_commitments.Commitment.t = + {level = raw_level 2l; batches; predecessor = None} + in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment_a >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + let commitment_b : Tx_rollup_commitments.Commitment.t = + {level = raw_level 2l; batches = batches2; predecessor = None} + in + Op.tx_rollup_commit (I i) contract2 tx_rollup commitment_b >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + let predecessor = Tx_rollup_commitments.Commitment.hash commitment_a in + let commitment_c : Tx_rollup_commitments.Commitment.t = + {level = raw_level 3l; batches; predecessor = Some predecessor} + in + Op.tx_rollup_commit (I i) contract2 tx_rollup commitment_c >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + let predecessor = Tx_rollup_commitments.Commitment.hash commitment_b in + + let commitment_d : Tx_rollup_commitments.Commitment.t = + {level = raw_level 3l; batches; predecessor = Some predecessor} + in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment_d >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + (* Need to bake to avoid running out of gas *) + Incremental.finalize_block i >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + let predecessor = Tx_rollup_commitments.Commitment.hash commitment_d in + + let commitment_e : Tx_rollup_commitments.Commitment.t = + {level = raw_level 6l; batches; predecessor = Some predecessor} + in + Op.tx_rollup_commit (I i) contract2 tx_rollup commitment_e >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + let predecessor = Tx_rollup_commitments.Commitment.hash commitment_c in + let commitment_f : Tx_rollup_commitments.Commitment.t = + {level = raw_level 6l; batches; predecessor = Some predecessor} + in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment_f >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + wrap + (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level + (Incremental.alpha_ctxt i) + tx_rollup + (raw_level 2l)) + >>=? fun ctxt -> + check_bond ctxt tx_rollup contract1 1 >>=? fun () -> + check_bond ctxt tx_rollup contract2 1 >>=? fun () -> + wrap + (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level + ctxt + tx_rollup + (raw_level 3l)) + >>=? fun ctxt -> + check_bond ctxt tx_rollup contract1 1 >>=? fun () -> + check_bond ctxt tx_rollup contract2 0 >>=? fun () -> + wrap + (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level + ctxt + tx_rollup + (raw_level 6l)) + >>=? fun ctxt -> + check_bond ctxt tx_rollup contract1 0 >>=? fun () -> + check_bond ctxt tx_rollup contract2 0 >>=? fun () -> + ignore ctxt ; + ignore i ; + return () + +(** [test_commitment_acceptance] tests a case where there are multiple + nonrejected commitments at finalization time. +- A: Contract 1 commits to 2 (this will be accepted) +- B: Contract 2 commits to 2 (this will removed but not rejected) +- C: Contract 2 commits to 3 (atop A). +- D: Contract 3 commits to 3 (atop B, to be removed) +*) +let test_commitment_acceptance () = + context_init 3 >>=? fun (b, contracts) -> + let contract1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + let contract2 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 1 + in + let contract3 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 2 + in + originate b contract1 >>=? fun (b, tx_rollup) -> + make_transactions_in tx_rollup contract1 [2; 3] b >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + (* Need an extra block here to ensure finality *) + Incremental.finalize_block i >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + let batches1 : Tx_rollup_commitments.Commitment.batch_commitment list = + [{root = Bytes.make 20 '0'}] + in + let batches2 : Tx_rollup_commitments.Commitment.batch_commitment list = + [{root = Bytes.make 20 '1'}] + in + let commitment_a : Tx_rollup_commitments.Commitment.t = + {level = raw_level 2l; batches = batches1; predecessor = None} + in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment_a >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + let commitment_b : Tx_rollup_commitments.Commitment.t = + {level = raw_level 2l; batches = batches2; predecessor = None} + in + Op.tx_rollup_commit (I i) contract2 tx_rollup commitment_b >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + let predecessor = Tx_rollup_commitments.Commitment.hash commitment_a in + let commitment_c : Tx_rollup_commitments.Commitment.t = + {level = raw_level 3l; batches = batches1; predecessor = Some predecessor} + in + Op.tx_rollup_commit (I i) contract2 tx_rollup commitment_c >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + let predecessor = Tx_rollup_commitments.Commitment.hash commitment_b in + let commitment_d : Tx_rollup_commitments.Commitment.t = + {level = raw_level 3l; batches = batches2; predecessor = Some predecessor} + in + Op.tx_rollup_commit (I i) contract3 tx_rollup commitment_d >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + wrap + (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level + (Incremental.alpha_ctxt i) + tx_rollup + (raw_level 2l)) + >>=? fun ctxt -> + wrap + (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level + ctxt + tx_rollup + (raw_level 3l)) + >>=? fun ctxt -> + check_bond ctxt tx_rollup contract1 0 >>=? fun () -> + check_bond ctxt tx_rollup contract2 0 >>=? fun () -> + check_bond ctxt tx_rollup contract3 0 >>=? fun () -> + ignore ctxt ; + ignore i ; + return () + let tests = [ Tztest.tztest @@ -826,4 +1048,16 @@ let tests = "Test commitment predecessor edge cases" `Quick test_commitment_predecessor; + Tztest.tztest + "Test commitment retirement" + `Quick + test_commitment_retire_simple; + Tztest.tztest + "Test complex commitment retirement" + `Quick + test_commitment_retire_complex; + Tztest.tztest + "Test multiple nonrejected commitment" + `Quick + test_commitment_acceptance; ] diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml index 53609a3a7dfb..56f9bd8751ac 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml @@ -38,6 +38,8 @@ type error += (* `Branch *) Wrong_batch_count type error += | (* `Temporary *) Commitment_too_early of Raw_level_repr.t * Raw_level_repr.t +type error += (* `Temporary *) Retire_uncommitted_level of Raw_level_repr.t + let () = let open Data_encoding in (* Commitment_hash_already_submitted *) @@ -102,7 +104,17 @@ let () = Some (commitment_level, submit_level) | _ -> None) (fun (commitment_level, submit_level) -> - Commitment_too_early (commitment_level, submit_level)) + Commitment_too_early (commitment_level, submit_level)) ; + (* Retire_uncommitted_level *) + register_error_kind + `Permanent + ~id:"tx_rollup_retire_uncommitted_level" + ~title:"Tried to retire a rollup level with no commitments" + ~description: + "An attempt was made to retire a rollup level with no commitments" + (obj1 (req "level" Raw_level_repr.encoding)) + (function Retire_uncommitted_level level -> Some level | _ -> None) + (fun level -> Retire_uncommitted_level level) let compare_or cmp c1 c2 f = match cmp c1 c2 with 0 -> f () | diff -> diff @@ -145,7 +157,7 @@ end module Commitment = struct type batch_commitment = { (* TODO: add effects and replace bytes with Irmin: - https://gitlab.com/tezos/tezos/-/issues/2444 + https://gitlab.com/tezos/tezos/-/issues/2444 *) root : bytes; } diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli index 1b8ff7348051..23666b5c1fee 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli @@ -38,6 +38,9 @@ type error += (* `Branch *) Wrong_batch_count type error += | (* `Temporary *) Commitment_too_early of Raw_level_repr.t * Raw_level_repr.t +type error += (* `Branch *) + Retire_uncommitted_level of Raw_level_repr.t + (** A specialized Blake2B implementation for hashing commitments with "toc1" as a base58 prefix *) module Commitment_hash : sig diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml index 8e1a4bce9fac..1239f05874d3 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml @@ -41,6 +41,10 @@ let get_or_empty_commitments : ~none:(ctxt, Tx_rollup_commitments_repr.empty) ~some:(fun l -> (ctxt, List.rev l)) +let get_next_level ctxt tx_rollup level = + Tx_rollup_inbox_storage.get_adjacent_levels ctxt level tx_rollup + >|=? fun (ctxt, _, next_level) -> (ctxt, next_level) + let get_prev_level ctxt tx_rollup level = Tx_rollup_inbox_storage.get_adjacent_levels ctxt level tx_rollup >|=? fun (ctxt, predecessor_level, _) -> (ctxt, predecessor_level) @@ -97,6 +101,85 @@ let add_commitment ctxt tx_rollup pkh (commitment : Commitment.t) = Storage.Tx_rollup.Commitment_list.add ctxt key new_pending >>=? fun (ctxt, _, _) -> adjust_commitment_bond ctxt tx_rollup pkh 1 +module Commitment_set = Set.Make (Commitment_hash) + +let rec remove_successors : + Raw_context.t -> + Tx_rollup_repr.t -> + Raw_level_repr.t -> + Raw_level_repr.t -> + Commitment_set.t -> + Raw_context.t tzresult Lwt.t = + fun ctxt tx_rollup level top commitments -> + if Raw_level_repr.(level > top) then return ctxt + else + let key = (level, tx_rollup) in + get_next_level ctxt tx_rollup level >>=? fun (ctxt, next_level) -> + Storage.Tx_rollup.Commitment_list.find ctxt key + >>=? fun (ctxt, commitment_list) -> + match commitment_list with + | None -> ( + match next_level with + | None -> return ctxt + | Some next_level -> + remove_successors ctxt tx_rollup next_level top commitments) + | Some pending -> + let pending = List.rev pending in + let next_commitments = + List.fold_left + (fun next_commitments {commitment; hash; _} -> + if + Option.fold + ~none:false + ~some:(fun predecessor -> + Commitment_set.mem predecessor commitments) + commitment.predecessor + then Commitment_set.add hash next_commitments + else next_commitments) + commitments + pending + in + if not @@ Commitment_set.is_empty commitments then + let (to_remove, new_pending) = + List.partition + (fun {hash; _} -> Commitment_set.mem hash next_commitments) + pending + in + List.fold_left_es + (fun ctxt {committer; _} -> + adjust_commitment_bond ctxt tx_rollup committer (-1)) + ctxt + to_remove + >>=? fun ctxt -> + Storage.Tx_rollup.Commitment_list.add ctxt key new_pending + >>=? fun (ctxt, _, _) -> + match next_level with + | None -> return ctxt + | Some next_level -> + remove_successors ctxt tx_rollup next_level top next_commitments + else return ctxt + +let retire_rollup_level : + Raw_context.t -> + Tx_rollup_repr.t -> + Raw_level_repr.t -> + Raw_context.t tzresult Lwt.t = + fun ctxt tx_rollup level -> + let top = (Raw_context.current_level ctxt).level in + let key = (level, tx_rollup) in + get_or_empty_commitments ctxt key >>=? fun (ctxt, commitments) -> + match commitments with + | [] -> fail (Retire_uncommitted_level level) + | accepted :: rejected -> + let to_obviate = + Commitment_set.of_seq + (Seq.map (fun {hash; _} -> hash) (List.to_seq rejected)) + in + remove_successors ctxt tx_rollup level top to_obviate >>=? fun ctxt -> + adjust_commitment_bond ctxt tx_rollup accepted.committer (-1) + >>=? fun ctxt -> + Storage.Tx_rollup.Commitment_list.add ctxt key [accepted] >|=? just_ctxt + let get_commitments : Raw_context.t -> Tx_rollup_repr.t -> diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli index c7ea72d12b6a..57a5e7ef32a8 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli @@ -41,6 +41,18 @@ val add_commitment : Tx_rollup_commitments_repr.Commitment.t -> Raw_context.t tzresult Lwt.t +(** [retire_rollup_level context tx_rollup level] removes all data + associated with a level. It decrements the bonded commitment count + for any contracts whose commitments have been either accepted or + obviated (that is, neither accepted nor rejected). This is normally + used in finalization (during a Commitment operation) and is only + public for testing. *) +val retire_rollup_level : + Raw_context.t -> + Tx_rollup_repr.t -> + Raw_level_repr.t -> + Raw_context.t tzresult Lwt.t + (** [get_commitments context tx_rollup level] returns the list of non-rejected commitments for a rollup at a level, first-submitted first. *) -- GitLab From 31c08c491cbc794cc13dbc9a1214647ef7f58eba Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 24 Jan 2022 11:04:08 -0500 Subject: [PATCH 16/31] Proto,tx_rollup: Finality period constant Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- src/proto_alpha/lib_client/mockup.ml | 19 +++++++++++++++---- .../lib_parameters/default_parameters.ml | 1 + .../lib_protocol/alpha_context.mli | 3 +++ .../lib_protocol/constants_repr.ml | 13 +++++++++---- .../lib_protocol/constants_repr.mli | 3 ++- .../lib_protocol/constants_storage.ml | 4 ++++ .../lib_protocol/constants_storage.mli | 2 ++ src/proto_alpha/lib_protocol/raw_context.ml | 1 + tests_python/tests_alpha/test_mockup.py | 1 + tezt/_regressions/rpc/alpha.client.others.out | 3 ++- tezt/_regressions/rpc/alpha.light.others.out | 3 ++- tezt/_regressions/rpc/alpha.proxy.others.out | 3 ++- .../rpc/alpha.proxy_server.others.out | 3 ++- 13 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/proto_alpha/lib_client/mockup.ml b/src/proto_alpha/lib_client/mockup.ml index 556c9ba13bd3..fe91a6a3cad2 100644 --- a/src/proto_alpha/lib_client/mockup.ml +++ b/src/proto_alpha/lib_client/mockup.ml @@ -76,6 +76,7 @@ module Protocol_constants_overrides = struct tx_rollup_hard_size_limit_per_inbox : int option; tx_rollup_hard_size_limit_per_message : int option; tx_rollup_commitment_bond : Tez.t option; + tx_rollup_finality_period : int option; sc_rollup_enable : bool option; sc_rollup_origination_size : int option; (* Additional, "bastard" parameters (they are not protocol constants but partially treated the same way). *) @@ -131,7 +132,8 @@ module Protocol_constants_overrides = struct c.tx_rollup_origination_size, c.tx_rollup_hard_size_limit_per_inbox, c.tx_rollup_hard_size_limit_per_message, - c.tx_rollup_commitment_bond ), + c.tx_rollup_commitment_bond, + c.tx_rollup_finality_period ), (c.sc_rollup_enable, c.sc_rollup_origination_size) ) ) ) ) ) )) (fun ( ( preserved_cycles, @@ -176,7 +178,8 @@ module Protocol_constants_overrides = struct tx_rollup_origination_size, tx_rollup_hard_size_limit_per_inbox, tx_rollup_hard_size_limit_per_message, - tx_rollup_commitment_bond ), + tx_rollup_commitment_bond, + tx_rollup_finality_period ), (sc_rollup_enable, sc_rollup_origination_size) ) ) ) ) ) ) -> { @@ -220,6 +223,7 @@ module Protocol_constants_overrides = struct tx_rollup_hard_size_limit_per_inbox; tx_rollup_hard_size_limit_per_message; tx_rollup_commitment_bond; + tx_rollup_finality_period; sc_rollup_enable; sc_rollup_origination_size; chain_id; @@ -279,12 +283,13 @@ module Protocol_constants_overrides = struct (opt "cache_stake_distribution_cycles" int8) (opt "cache_sampler_state_cycles" int8)) (merge_objs - (obj5 + (obj6 (opt "tx_rollup_enable" Data_encoding.bool) (opt "tx_rollup_origination_size" int31) (opt "tx_rollup_hard_size_limit_per_inbox" int31) (opt "tx_rollup_hard_size_limit_per_message" int31) - (opt "tx_rollup_commitment_bond" Tez.encoding)) + (opt "tx_rollup_commitment_bond" Tez.encoding) + (opt "tx_rollup_finality_period" int31)) (obj2 (opt "sc_rollup_enable" bool) (opt "sc_rollup_origination_size" int31)))))))) @@ -357,6 +362,7 @@ module Protocol_constants_overrides = struct tx_rollup_hard_size_limit_per_message = Some parametric.tx_rollup_hard_size_limit_per_message; tx_rollup_commitment_bond = Some parametric.tx_rollup_commitment_bond; + tx_rollup_finality_period = Some parametric.tx_rollup_finality_period; sc_rollup_enable = Some parametric.sc_rollup_enable; sc_rollup_origination_size = Some parametric.sc_rollup_origination_size; (* Bastard additional parameters. *) @@ -409,6 +415,7 @@ module Protocol_constants_overrides = struct tx_rollup_hard_size_limit_per_inbox = None; tx_rollup_hard_size_limit_per_message = None; tx_rollup_commitment_bond = None; + tx_rollup_finality_period = None; sc_rollup_enable = None; sc_rollup_origination_size = None; chain_id = None; @@ -821,6 +828,10 @@ module Protocol_constants_overrides = struct Option.value ~default:c.tx_rollup_commitment_bond o.tx_rollup_commitment_bond; + tx_rollup_finality_period = + Option.value + ~default:c.tx_rollup_finality_period + o.tx_rollup_finality_period; sc_rollup_enable = Option.value ~default:c.sc_rollup_enable o.sc_rollup_enable; sc_rollup_origination_size = diff --git a/src/proto_alpha/lib_parameters/default_parameters.ml b/src/proto_alpha/lib_parameters/default_parameters.ml index 6f3dcae59c12..2d07f76bd307 100644 --- a/src/proto_alpha/lib_parameters/default_parameters.ml +++ b/src/proto_alpha/lib_parameters/default_parameters.ml @@ -105,6 +105,7 @@ let constants_mainnet = tx_rollup_hard_size_limit_per_inbox = 100_000; tx_rollup_hard_size_limit_per_message = 5_000; tx_rollup_commitment_bond = Tez.of_mutez_exn 10_000_000_000L; + tx_rollup_finality_period = 2_000; sc_rollup_enable = false; (* The following value is chosen to prevent spam. *) sc_rollup_origination_size = 6_314; diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 893c5164fc5f..86157914e5a1 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -782,6 +782,7 @@ module Constants : sig tx_rollup_hard_size_limit_per_inbox : int; tx_rollup_hard_size_limit_per_message : int; tx_rollup_commitment_bond : Tez.t; + tx_rollup_finality_period : int; sc_rollup_enable : bool; sc_rollup_origination_size : int; } @@ -875,6 +876,8 @@ module Constants : sig val tx_rollup_commitment_bond : context -> Tez.t + val tx_rollup_finality_period : context -> int + val sc_rollup_enable : context -> bool val sc_rollup_origination_size : context -> int diff --git a/src/proto_alpha/lib_protocol/constants_repr.ml b/src/proto_alpha/lib_protocol/constants_repr.ml index 9f862cba6484..c379b47a9e66 100644 --- a/src/proto_alpha/lib_protocol/constants_repr.ml +++ b/src/proto_alpha/lib_protocol/constants_repr.ml @@ -163,6 +163,7 @@ type parametric = { tx_rollup_hard_size_limit_per_inbox : int; tx_rollup_hard_size_limit_per_message : int; tx_rollup_commitment_bond : Tez_repr.t; + tx_rollup_finality_period : int; sc_rollup_enable : bool; sc_rollup_origination_size : int; } @@ -211,7 +212,8 @@ let parametric_encoding = c.tx_rollup_origination_size, c.tx_rollup_hard_size_limit_per_inbox, c.tx_rollup_hard_size_limit_per_message, - c.tx_rollup_commitment_bond ), + c.tx_rollup_commitment_bond, + c.tx_rollup_finality_period ), (c.sc_rollup_enable, c.sc_rollup_origination_size) ) ) ) ) ) )) (fun ( ( preserved_cycles, @@ -254,7 +256,8 @@ let parametric_encoding = tx_rollup_origination_size, tx_rollup_hard_size_limit_per_inbox, tx_rollup_hard_size_limit_per_message, - tx_rollup_commitment_bond ), + tx_rollup_commitment_bond, + tx_rollup_finality_period ), (sc_rollup_enable, sc_rollup_origination_size) ) ) ) ) ) ) -> { preserved_cycles; @@ -298,6 +301,7 @@ let parametric_encoding = tx_rollup_hard_size_limit_per_inbox; tx_rollup_hard_size_limit_per_message; tx_rollup_commitment_bond; + tx_rollup_finality_period; sc_rollup_enable; sc_rollup_origination_size; }) @@ -354,12 +358,13 @@ let parametric_encoding = (req "cache_stake_distribution_cycles" int8) (req "cache_sampler_state_cycles" int8)) (merge_objs - (obj5 + (obj6 (req "tx_rollup_enable" bool) (req "tx_rollup_origination_size" int31) (req "tx_rollup_hard_size_limit_per_inbox" int31) (req "tx_rollup_hard_size_limit_per_message" int31) - (req "tx_rollup_commitment_bond" Tez_repr.encoding)) + (req "tx_rollup_commitment_bond" Tez_repr.encoding) + (req "tx_rollup_finality_period" int31)) (obj2 (req "sc_rollup_enable" bool) (req "sc_rollup_origination_size" int31)))))))) diff --git a/src/proto_alpha/lib_protocol/constants_repr.mli b/src/proto_alpha/lib_protocol/constants_repr.mli index 85821046a5de..4b29bea2f580 100644 --- a/src/proto_alpha/lib_protocol/constants_repr.mli +++ b/src/proto_alpha/lib_protocol/constants_repr.mli @@ -129,6 +129,7 @@ type parametric = { tx_rollup_hard_size_limit_per_message : int; (* the amount of tez to bond a tx rollup commitment *) tx_rollup_commitment_bond : Tez_repr.t; + tx_rollup_finality_period : int; sc_rollup_enable : bool; sc_rollup_origination_size : int; } @@ -209,7 +210,7 @@ end subcache, a parametric constant can be used to change the limit (see {parametric}). - The number of subcaches and the limits for all those subcaches form + The number of subcaches and the limits for all those subcaches form together what is called the [cache_layout]. *) val cache_layout_size : int diff --git a/src/proto_alpha/lib_protocol/constants_storage.ml b/src/proto_alpha/lib_protocol/constants_storage.ml index 7c5dd10e8cac..eab227a83f3e 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.ml +++ b/src/proto_alpha/lib_protocol/constants_storage.ml @@ -165,6 +165,10 @@ let tx_rollup_commitment_bond c = let constants = Raw_context.constants c in constants.tx_rollup_commitment_bond +let tx_rollup_finality_period c = + let constants = Raw_context.constants c in + constants.tx_rollup_finality_period + let ratio_of_frozen_deposits_slashed_per_double_endorsement c = let constants = Raw_context.constants c in constants.ratio_of_frozen_deposits_slashed_per_double_endorsement diff --git a/src/proto_alpha/lib_protocol/constants_storage.mli b/src/proto_alpha/lib_protocol/constants_storage.mli index 87e53d43353f..466577634dfa 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.mli +++ b/src/proto_alpha/lib_protocol/constants_storage.mli @@ -93,6 +93,8 @@ val tx_rollup_hard_size_limit_per_message : Raw_context.t -> int val tx_rollup_commitment_bond : Raw_context.t -> Tez_repr.t +val tx_rollup_finality_period : Raw_context.t -> int + val ratio_of_frozen_deposits_slashed_per_double_endorsement : Raw_context.t -> Constants_repr.ratio diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index 42dc176f816c..e69fd450ce87 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -882,6 +882,7 @@ let prepare_first_block ~level ~timestamp ctxt = tx_rollup_hard_size_limit_per_inbox = 100_000; tx_rollup_hard_size_limit_per_message = 5_000; tx_rollup_commitment_bond = Tez_repr.of_mutez_exn 10_000_000_000L; + tx_rollup_finality_period = 2_000; sc_rollup_enable = false; (* The following value is chosen to prevent spam. *) sc_rollup_origination_size = 6_314; diff --git a/tests_python/tests_alpha/test_mockup.py b/tests_python/tests_alpha/test_mockup.py index 688cf2bd9404..1bb91250e2e4 100644 --- a/tests_python/tests_alpha/test_mockup.py +++ b/tests_python/tests_alpha/test_mockup.py @@ -660,6 +660,7 @@ def _test_create_mockup_init_show_roundtrip( "tx_rollup_hard_size_limit_per_inbox": 75_000, "tx_rollup_hard_size_limit_per_message": 9_999, "tx_rollup_commitment_bond": "10000000000", + "tx_rollup_finality_period": 2000, "sc_rollup_enable": False, "sc_rollup_origination_size": 6_314, } diff --git a/tezt/_regressions/rpc/alpha.client.others.out b/tezt/_regressions/rpc/alpha.client.others.out index 52ab8b42f94c..5092389d9005 100644 --- a/tezt/_regressions/rpc/alpha.client.others.out +++ b/tezt/_regressions/rpc/alpha.client.others.out @@ -32,7 +32,8 @@ tezt/_regressions/rpc/alpha.client.others.out "tx_rollup_enable": false, "tx_rollup_origination_size": 60000, "tx_rollup_hard_size_limit_per_inbox": 100000, "tx_rollup_hard_size_limit_per_message": 5000, - "tx_rollup_commitment_bond": "10000000000", "sc_rollup_enable": false, + "tx_rollup_commitment_bond": "10000000000", + "tx_rollup_finality_period": 2000, "sc_rollup_enable": false, "sc_rollup_origination_size": 6314 } ./tezos-client rpc get /chains/main/blocks/head/helpers/baking_rights diff --git a/tezt/_regressions/rpc/alpha.light.others.out b/tezt/_regressions/rpc/alpha.light.others.out index 5462a3a58b1e..231a443e94fa 100644 --- a/tezt/_regressions/rpc/alpha.light.others.out +++ b/tezt/_regressions/rpc/alpha.light.others.out @@ -33,7 +33,8 @@ protocol of light mode unspecified, using the node's protocol: ProtoGenesisGenes "tx_rollup_enable": false, "tx_rollup_origination_size": 60000, "tx_rollup_hard_size_limit_per_inbox": 100000, "tx_rollup_hard_size_limit_per_message": 5000, - "tx_rollup_commitment_bond": "10000000000", "sc_rollup_enable": false, + "tx_rollup_commitment_bond": "10000000000", + "tx_rollup_finality_period": 2000, "sc_rollup_enable": false, "sc_rollup_origination_size": 6314 } ./tezos-client --mode light rpc get /chains/main/blocks/head/helpers/baking_rights diff --git a/tezt/_regressions/rpc/alpha.proxy.others.out b/tezt/_regressions/rpc/alpha.proxy.others.out index 65e3efa2f3f6..a6f8251ece3a 100644 --- a/tezt/_regressions/rpc/alpha.proxy.others.out +++ b/tezt/_regressions/rpc/alpha.proxy.others.out @@ -33,7 +33,8 @@ protocol of proxy unspecified, using the node's protocol: ProtoGenesisGenesisGen "tx_rollup_enable": false, "tx_rollup_origination_size": 60000, "tx_rollup_hard_size_limit_per_inbox": 100000, "tx_rollup_hard_size_limit_per_message": 5000, - "tx_rollup_commitment_bond": "10000000000", "sc_rollup_enable": false, + "tx_rollup_commitment_bond": "10000000000", + "tx_rollup_finality_period": 2000, "sc_rollup_enable": false, "sc_rollup_origination_size": 6314 } ./tezos-client --mode proxy rpc get /chains/main/blocks/head/helpers/baking_rights diff --git a/tezt/_regressions/rpc/alpha.proxy_server.others.out b/tezt/_regressions/rpc/alpha.proxy_server.others.out index 70f5d0b24b36..f24ff71a7f96 100644 --- a/tezt/_regressions/rpc/alpha.proxy_server.others.out +++ b/tezt/_regressions/rpc/alpha.proxy_server.others.out @@ -32,7 +32,8 @@ tezt/_regressions/rpc/alpha.proxy_server.others.out "tx_rollup_enable": false, "tx_rollup_origination_size": 60000, "tx_rollup_hard_size_limit_per_inbox": 100000, "tx_rollup_hard_size_limit_per_message": 5000, - "tx_rollup_commitment_bond": "10000000000", "sc_rollup_enable": false, + "tx_rollup_commitment_bond": "10000000000", + "tx_rollup_finality_period": 2000, "sc_rollup_enable": false, "sc_rollup_origination_size": 6314 } ./tezos-client rpc get /chains/main/blocks/head/helpers/baking_rights -- GitLab From cca2cbffb308089721c47f9b45f42e39cbd67a66 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 3 Jan 2022 16:13:22 -0500 Subject: [PATCH 17/31] Proto,Tx_rollup: Unfinalized inbox limit constant Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- src/proto_alpha/lib_client/mockup.ml | 20 +++++++++++++++---- .../lib_parameters/default_parameters.ml | 1 + .../lib_protocol/alpha_context.mli | 3 +++ .../lib_protocol/constants_repr.ml | 13 ++++++++---- .../lib_protocol/constants_repr.mli | 1 + .../lib_protocol/constants_storage.ml | 4 ++++ .../lib_protocol/constants_storage.mli | 2 ++ src/proto_alpha/lib_protocol/raw_context.ml | 1 + tests_python/tests_alpha/test_mockup.py | 1 + 9 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/proto_alpha/lib_client/mockup.ml b/src/proto_alpha/lib_client/mockup.ml index fe91a6a3cad2..1e627d02e128 100644 --- a/src/proto_alpha/lib_client/mockup.ml +++ b/src/proto_alpha/lib_client/mockup.ml @@ -77,6 +77,7 @@ module Protocol_constants_overrides = struct tx_rollup_hard_size_limit_per_message : int option; tx_rollup_commitment_bond : Tez.t option; tx_rollup_finality_period : int option; + tx_rollup_max_unfinalized_levels : int option; sc_rollup_enable : bool option; sc_rollup_origination_size : int option; (* Additional, "bastard" parameters (they are not protocol constants but partially treated the same way). *) @@ -133,7 +134,8 @@ module Protocol_constants_overrides = struct c.tx_rollup_hard_size_limit_per_inbox, c.tx_rollup_hard_size_limit_per_message, c.tx_rollup_commitment_bond, - c.tx_rollup_finality_period ), + c.tx_rollup_finality_period, + c.tx_rollup_max_unfinalized_levels ), (c.sc_rollup_enable, c.sc_rollup_origination_size) ) ) ) ) ) )) (fun ( ( preserved_cycles, @@ -179,7 +181,8 @@ module Protocol_constants_overrides = struct tx_rollup_hard_size_limit_per_inbox, tx_rollup_hard_size_limit_per_message, tx_rollup_commitment_bond, - tx_rollup_finality_period ), + tx_rollup_finality_period, + tx_rollup_max_unfinalized_levels ), (sc_rollup_enable, sc_rollup_origination_size) ) ) ) ) ) ) -> { @@ -224,6 +227,7 @@ module Protocol_constants_overrides = struct tx_rollup_hard_size_limit_per_message; tx_rollup_commitment_bond; tx_rollup_finality_period; + tx_rollup_max_unfinalized_levels; sc_rollup_enable; sc_rollup_origination_size; chain_id; @@ -283,13 +287,14 @@ module Protocol_constants_overrides = struct (opt "cache_stake_distribution_cycles" int8) (opt "cache_sampler_state_cycles" int8)) (merge_objs - (obj6 + (obj7 (opt "tx_rollup_enable" Data_encoding.bool) (opt "tx_rollup_origination_size" int31) (opt "tx_rollup_hard_size_limit_per_inbox" int31) (opt "tx_rollup_hard_size_limit_per_message" int31) (opt "tx_rollup_commitment_bond" Tez.encoding) - (opt "tx_rollup_finality_period" int31)) + (opt "tx_rollup_finality_period" int31) + (opt "tx_rollup_max_unfinalized_levels" int31)) (obj2 (opt "sc_rollup_enable" bool) (opt "sc_rollup_origination_size" int31)))))))) @@ -363,6 +368,8 @@ module Protocol_constants_overrides = struct Some parametric.tx_rollup_hard_size_limit_per_message; tx_rollup_commitment_bond = Some parametric.tx_rollup_commitment_bond; tx_rollup_finality_period = Some parametric.tx_rollup_finality_period; + tx_rollup_max_unfinalized_levels = + Some parametric.tx_rollup_max_unfinalized_levels; sc_rollup_enable = Some parametric.sc_rollup_enable; sc_rollup_origination_size = Some parametric.sc_rollup_origination_size; (* Bastard additional parameters. *) @@ -416,6 +423,7 @@ module Protocol_constants_overrides = struct tx_rollup_hard_size_limit_per_message = None; tx_rollup_commitment_bond = None; tx_rollup_finality_period = None; + tx_rollup_max_unfinalized_levels = None; sc_rollup_enable = None; sc_rollup_origination_size = None; chain_id = None; @@ -832,6 +840,10 @@ module Protocol_constants_overrides = struct Option.value ~default:c.tx_rollup_finality_period o.tx_rollup_finality_period; + tx_rollup_max_unfinalized_levels = + Option.value + ~default:c.tx_rollup_max_unfinalized_levels + o.tx_rollup_max_unfinalized_levels; sc_rollup_enable = Option.value ~default:c.sc_rollup_enable o.sc_rollup_enable; sc_rollup_origination_size = diff --git a/src/proto_alpha/lib_parameters/default_parameters.ml b/src/proto_alpha/lib_parameters/default_parameters.ml index 2d07f76bd307..e740c80a3530 100644 --- a/src/proto_alpha/lib_parameters/default_parameters.ml +++ b/src/proto_alpha/lib_parameters/default_parameters.ml @@ -106,6 +106,7 @@ let constants_mainnet = tx_rollup_hard_size_limit_per_message = 5_000; tx_rollup_commitment_bond = Tez.of_mutez_exn 10_000_000_000L; tx_rollup_finality_period = 2_000; + tx_rollup_max_unfinalized_levels = 2_100; sc_rollup_enable = false; (* The following value is chosen to prevent spam. *) sc_rollup_origination_size = 6_314; diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 86157914e5a1..613b1b8f6c8b 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -783,6 +783,7 @@ module Constants : sig tx_rollup_hard_size_limit_per_message : int; tx_rollup_commitment_bond : Tez.t; tx_rollup_finality_period : int; + tx_rollup_max_unfinalized_levels : int; sc_rollup_enable : bool; sc_rollup_origination_size : int; } @@ -878,6 +879,8 @@ module Constants : sig val tx_rollup_finality_period : context -> int + val tx_rollup_max_unfinalized_levels : context -> int + val sc_rollup_enable : context -> bool val sc_rollup_origination_size : context -> int diff --git a/src/proto_alpha/lib_protocol/constants_repr.ml b/src/proto_alpha/lib_protocol/constants_repr.ml index c379b47a9e66..68a8db63b88f 100644 --- a/src/proto_alpha/lib_protocol/constants_repr.ml +++ b/src/proto_alpha/lib_protocol/constants_repr.ml @@ -164,6 +164,7 @@ type parametric = { tx_rollup_hard_size_limit_per_message : int; tx_rollup_commitment_bond : Tez_repr.t; tx_rollup_finality_period : int; + tx_rollup_max_unfinalized_levels : int; sc_rollup_enable : bool; sc_rollup_origination_size : int; } @@ -213,7 +214,8 @@ let parametric_encoding = c.tx_rollup_hard_size_limit_per_inbox, c.tx_rollup_hard_size_limit_per_message, c.tx_rollup_commitment_bond, - c.tx_rollup_finality_period ), + c.tx_rollup_finality_period, + c.tx_rollup_max_unfinalized_levels ), (c.sc_rollup_enable, c.sc_rollup_origination_size) ) ) ) ) ) )) (fun ( ( preserved_cycles, @@ -257,7 +259,8 @@ let parametric_encoding = tx_rollup_hard_size_limit_per_inbox, tx_rollup_hard_size_limit_per_message, tx_rollup_commitment_bond, - tx_rollup_finality_period ), + tx_rollup_finality_period, + tx_rollup_max_unfinalized_levels ), (sc_rollup_enable, sc_rollup_origination_size) ) ) ) ) ) ) -> { preserved_cycles; @@ -302,6 +305,7 @@ let parametric_encoding = tx_rollup_hard_size_limit_per_message; tx_rollup_commitment_bond; tx_rollup_finality_period; + tx_rollup_max_unfinalized_levels; sc_rollup_enable; sc_rollup_origination_size; }) @@ -358,13 +362,14 @@ let parametric_encoding = (req "cache_stake_distribution_cycles" int8) (req "cache_sampler_state_cycles" int8)) (merge_objs - (obj6 + (obj7 (req "tx_rollup_enable" bool) (req "tx_rollup_origination_size" int31) (req "tx_rollup_hard_size_limit_per_inbox" int31) (req "tx_rollup_hard_size_limit_per_message" int31) (req "tx_rollup_commitment_bond" Tez_repr.encoding) - (req "tx_rollup_finality_period" int31)) + (req "tx_rollup_finality_period" int31) + (req "tx_rollup_max_unfinalized_levels" int31)) (obj2 (req "sc_rollup_enable" bool) (req "sc_rollup_origination_size" int31)))))))) diff --git a/src/proto_alpha/lib_protocol/constants_repr.mli b/src/proto_alpha/lib_protocol/constants_repr.mli index 4b29bea2f580..4b1757c614b2 100644 --- a/src/proto_alpha/lib_protocol/constants_repr.mli +++ b/src/proto_alpha/lib_protocol/constants_repr.mli @@ -130,6 +130,7 @@ type parametric = { (* the amount of tez to bond a tx rollup commitment *) tx_rollup_commitment_bond : Tez_repr.t; tx_rollup_finality_period : int; + tx_rollup_max_unfinalized_levels : int; sc_rollup_enable : bool; sc_rollup_origination_size : int; } diff --git a/src/proto_alpha/lib_protocol/constants_storage.ml b/src/proto_alpha/lib_protocol/constants_storage.ml index eab227a83f3e..5ec3646f6d79 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.ml +++ b/src/proto_alpha/lib_protocol/constants_storage.ml @@ -169,6 +169,10 @@ let tx_rollup_finality_period c = let constants = Raw_context.constants c in constants.tx_rollup_finality_period +let tx_rollup_max_unfinalized_levels c = + let constants = Raw_context.constants c in + constants.tx_rollup_max_unfinalized_levels + let ratio_of_frozen_deposits_slashed_per_double_endorsement c = let constants = Raw_context.constants c in constants.ratio_of_frozen_deposits_slashed_per_double_endorsement diff --git a/src/proto_alpha/lib_protocol/constants_storage.mli b/src/proto_alpha/lib_protocol/constants_storage.mli index 466577634dfa..0b8fe1a63cb3 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.mli +++ b/src/proto_alpha/lib_protocol/constants_storage.mli @@ -95,6 +95,8 @@ val tx_rollup_commitment_bond : Raw_context.t -> Tez_repr.t val tx_rollup_finality_period : Raw_context.t -> int +val tx_rollup_max_unfinalized_levels : Raw_context.t -> int + val ratio_of_frozen_deposits_slashed_per_double_endorsement : Raw_context.t -> Constants_repr.ratio diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index e69fd450ce87..c93f69b63494 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -883,6 +883,7 @@ let prepare_first_block ~level ~timestamp ctxt = tx_rollup_hard_size_limit_per_message = 5_000; tx_rollup_commitment_bond = Tez_repr.of_mutez_exn 10_000_000_000L; tx_rollup_finality_period = 2_000; + tx_rollup_max_unfinalized_levels = 2_100; sc_rollup_enable = false; (* The following value is chosen to prevent spam. *) sc_rollup_origination_size = 6_314; diff --git a/tests_python/tests_alpha/test_mockup.py b/tests_python/tests_alpha/test_mockup.py index 1bb91250e2e4..db0d2d42573f 100644 --- a/tests_python/tests_alpha/test_mockup.py +++ b/tests_python/tests_alpha/test_mockup.py @@ -661,6 +661,7 @@ def _test_create_mockup_init_show_roundtrip( "tx_rollup_hard_size_limit_per_message": 9_999, "tx_rollup_commitment_bond": "10000000000", "tx_rollup_finality_period": 2000, + "tx_rollup_max_unfinalized_levels": 2100, "sc_rollup_enable": False, "sc_rollup_origination_size": 6_314, } -- GitLab From 4ce60de43d459f2ed70101d3448d141e5663e438 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 24 Jan 2022 11:04:08 -0500 Subject: [PATCH 18/31] Proto,tx_rollup: Finalize old commitments during commitment apply Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- .../lib_protocol/alpha_context.mli | 19 +++- src/proto_alpha/lib_protocol/apply.ml | 39 +++++--- .../integration/operations/test_tx_rollup.ml | 52 +++++++---- .../tx_rollup_commitments_repr.ml | 42 +++++++-- .../tx_rollup_commitments_repr.mli | 8 +- .../tx_rollup_commitments_storage.ml | 67 +++++++++++--- .../tx_rollup_commitments_storage.mli | 38 ++++++-- .../lib_protocol/tx_rollup_inbox_storage.ml | 8 ++ .../lib_protocol/tx_rollup_state_repr.ml | 91 ++++++++++++++++--- .../lib_protocol/tx_rollup_state_repr.mli | 14 +++ .../lib_protocol/tx_rollup_state_storage.ml | 8 ++ .../lib_protocol/tx_rollup_state_storage.mli | 8 ++ .../tx_rollup_simple_use_case.out | 15 +-- 13 files changed, 331 insertions(+), 78 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 613b1b8f6c8b..0fb6dc6958e4 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2012,6 +2012,9 @@ module Tx_rollup_state : sig val last_inbox_level : t -> Raw_level.t option + val first_unfinalized_level : + context -> Tx_rollup.t -> (context * Raw_level.t option) tzresult Lwt.t + type error += | Tx_rollup_already_exists of Tx_rollup.t | Tx_rollup_does_not_exist of Tx_rollup.t @@ -2160,7 +2163,11 @@ module Tx_rollup_commitments : sig type error += Commitment_too_early of Raw_level.t * Raw_level.t - type error += Retire_uncommitted_level of Raw_level.t + type error += Bond_does_not_exist of Signature.public_key_hash + + type error += Bond_in_use of Signature.public_key_hash + + type error += Too_many_unfinalized_levels val add_commitment : context -> @@ -2178,11 +2185,19 @@ module Tx_rollup_commitments : sig Signature.public_key_hash -> (context * int) tzresult Lwt.t + val finalize_pending_commitments : + context -> Tx_rollup.t -> Raw_level.t -> context tzresult Lwt.t + module Internal_for_tests : sig (** See [Tx_rollup_commitments_storage.retire_rollup_level] for documentation *) val retire_rollup_level : - context -> Tx_rollup.t -> Raw_level.t -> context tzresult Lwt.t + context -> + Tx_rollup.t -> + Raw_level.t -> + Raw_level.t -> + (context * [> `No_commitment | `Commitment_too_late | `Retired]) tzresult + Lwt.t end end diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index f20d1404ab38..3f90d5a9a15d 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -1207,17 +1207,34 @@ let apply_manager_operation_content : fail Tx_rollup_commit_with_non_implicit_contract (* This is only called with implicit contracts *) | Some key -> - ( Tx_rollup_commitments.pending_bonded_commitments ctxt tx_rollup key - >>=? fun (ctxt, pending) -> - let bond_id = Rollup_bond_id.Tx_rollup_bond_id tx_rollup in - match pending with - | 0 -> - Token.transfer - ctxt - (`Contract source) - (`Frozen_rollup_bonds (source, bond_id)) - (Constants.tx_rollup_commitment_bond ctxt) - | _ -> return (ctxt, []) ) + (let current_level = (Level.current ctxt).level in + let finality_period = + Int32.of_int @@ Constants.tx_rollup_finality_period ctxt + in + (if + Compare.Int32.(Raw_level.to_int32 current_level > finality_period) + then + Lwt.return + @@ Raw_level.of_int32 + (Int32.sub (Raw_level.to_int32 current_level) finality_period) + >>=? fun last_level_to_finalize -> + Tx_rollup_commitments.finalize_pending_commitments + ctxt + tx_rollup + last_level_to_finalize + else return ctxt) + >>=? fun ctxt -> + Tx_rollup_commitments.pending_bonded_commitments ctxt tx_rollup key + >>=? fun (ctxt, pending) -> + let bond_id = Rollup_bond_id.Tx_rollup_bond_id tx_rollup in + match pending with + | 0 -> + Token.transfer + ctxt + (`Contract source) + (`Frozen_rollup_bonds (source, bond_id)) + (Constants.tx_rollup_commitment_bond ctxt) + | _ -> return (ctxt, [])) >>=? fun (ctxt, balance_updates) -> Tx_rollup_commitments.add_commitment ctxt tx_rollup key commitment >>=? fun ctxt -> diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index a840e710c4fb..166b1b328372 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -816,10 +816,12 @@ let test_commitment_retire_simple () = (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level (Incremental.alpha_ctxt i) tx_rollup - level) - >>= fun res -> - Assert.proto_error ~loc:__LOC__ res (fun e -> - e = Tx_rollup_commitments.Retire_uncommitted_level level) + level + (raw_level @@ Incremental.level i)) + >>=? fun (_ctxt, retired) -> + (match retired with + | `No_commitment -> return_unit + | _ -> failwith "Expected no commitment") >>=? fun () -> (* Now, make a commitment *) let batches : Tx_rollup_commitments.Commitment.batch_commitment list = @@ -830,14 +832,19 @@ let test_commitment_retire_simple () = in Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> Incremental.add_operation i op >>=? fun i -> + let commitment_submit_level = + (Level.current (Incremental.alpha_ctxt i)).level + in check_bond (Incremental.alpha_ctxt i) tx_rollup contract1 1 >>=? fun () -> (* We can retire this level *) wrap (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level (Incremental.alpha_ctxt i) tx_rollup - level) - >>=? fun ctxt -> + level + commitment_submit_level) + >>=? fun (ctxt, retired) -> + assert_retired retired >>=? fun () -> check_bond ctxt tx_rollup contract1 0 >>=? fun () -> ignore i ; return () @@ -920,24 +927,30 @@ let test_commitment_retire_complex () = (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level (Incremental.alpha_ctxt i) tx_rollup - (raw_level 2l)) - >>=? fun ctxt -> + (raw_level 2l) + (raw_level 10l)) + >>=? fun (ctxt, retired) -> + assert_retired retired >>=? fun () -> check_bond ctxt tx_rollup contract1 1 >>=? fun () -> check_bond ctxt tx_rollup contract2 1 >>=? fun () -> wrap (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level ctxt tx_rollup - (raw_level 3l)) - >>=? fun ctxt -> + (raw_level 3l) + (raw_level 10l)) + >>=? fun (ctxt, retired) -> + assert_retired retired >>=? fun () -> check_bond ctxt tx_rollup contract1 1 >>=? fun () -> check_bond ctxt tx_rollup contract2 0 >>=? fun () -> wrap (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level ctxt tx_rollup - (raw_level 6l)) - >>=? fun ctxt -> + (raw_level 6l) + (raw_level 10l)) + >>=? fun (ctxt, retired) -> + assert_retired retired >>=? fun () -> check_bond ctxt tx_rollup contract1 0 >>=? fun () -> check_bond ctxt tx_rollup contract2 0 >>=? fun () -> ignore ctxt ; @@ -996,18 +1009,25 @@ let test_commitment_acceptance () = in Op.tx_rollup_commit (I i) contract3 tx_rollup commitment_d >>=? fun op -> Incremental.add_operation i op >>=? fun i -> + let commitment_submit_level = + (Level.current (Incremental.alpha_ctxt i)).level + in wrap (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level (Incremental.alpha_ctxt i) tx_rollup - (raw_level 2l)) - >>=? fun ctxt -> + (raw_level 2l) + commitment_submit_level) + >>=? fun (ctxt, retired) -> + assert_retired retired >>=? fun () -> wrap (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level ctxt tx_rollup - (raw_level 3l)) - >>=? fun ctxt -> + (raw_level 3l) + commitment_submit_level) + >>=? fun (ctxt, retired) -> + assert_retired retired >>=? fun () -> check_bond ctxt tx_rollup contract1 0 >>=? fun () -> check_bond ctxt tx_rollup contract2 0 >>=? fun () -> check_bond ctxt tx_rollup contract3 0 >>=? fun () -> diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml index 56f9bd8751ac..59697140573f 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml @@ -38,7 +38,12 @@ type error += (* `Branch *) Wrong_batch_count type error += | (* `Temporary *) Commitment_too_early of Raw_level_repr.t * Raw_level_repr.t -type error += (* `Temporary *) Retire_uncommitted_level of Raw_level_repr.t +type error += (* `Temporary *) + Bond_does_not_exist of Signature.public_key_hash + +type error += (* `Temporary *) Bond_in_use of Signature.public_key_hash + +type error += (* `Temporary *) Too_many_unfinalized_levels let () = let open Data_encoding in @@ -105,16 +110,35 @@ let () = | _ -> None) (fun (commitment_level, submit_level) -> Commitment_too_early (commitment_level, submit_level)) ; - (* Retire_uncommitted_level *) + (* Bond_does_not_exist *) + register_error_kind + `Temporary + ~id:"tx_rollup_bond_does_not_exist" + ~title:"This account does not have a bond for this rollup" + ~description:"This account does not have a bond for this rollup" + (obj1 (req "contract" Signature.Public_key_hash.encoding)) + (function Bond_does_not_exist contract -> Some contract | _ -> None) + (fun contract -> Bond_does_not_exist contract) ; + (* Bond_in_use *) register_error_kind - `Permanent - ~id:"tx_rollup_retire_uncommitted_level" - ~title:"Tried to retire a rollup level with no commitments" + `Temporary + ~id:"tx_rollup_bond_in_use" + ~title:"This account's bond is in use for one or more commitments" + ~description:"This account's bond is in use for one or more commitments" + (obj1 (req "contract" Signature.Public_key_hash.encoding)) + (function Bond_in_use contract -> Some contract | _ -> None) + (fun contract -> Bond_in_use contract) ; + (* Too_many_unfinalized_levels *) + register_error_kind + `Temporary + ~id:"tx_rollup_too_many_unfinalized_levels" + ~title:"This rollup hasn't had a commitment in too long" ~description: - "An attempt was made to retire a rollup level with no commitments" - (obj1 (req "level" Raw_level_repr.encoding)) - (function Retire_uncommitted_level level -> Some level | _ -> None) - (fun level -> Retire_uncommitted_level level) + "This rollup hasn't a commitment in too long. We don't allow new \ + messages to keep commitment gas reasonable." + empty + (function Too_many_unfinalized_levels -> Some () | _ -> None) + (fun () -> Too_many_unfinalized_levels) let compare_or cmp c1 c2 f = match cmp c1 c2 with 0 -> f () | diff -> diff diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli index 23666b5c1fee..9528c8789772 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli @@ -38,8 +38,12 @@ type error += (* `Branch *) Wrong_batch_count type error += | (* `Temporary *) Commitment_too_early of Raw_level_repr.t * Raw_level_repr.t -type error += (* `Branch *) - Retire_uncommitted_level of Raw_level_repr.t +type error += (* `Temporary *) + Bond_does_not_exist of Signature.public_key_hash + +type error += (* `Temporary *) Bond_in_use of Signature.public_key_hash + +type error += (* `Temporary *) Too_many_unfinalized_levels (** A specialized Blake2B implementation for hashing commitments with "toc1" as a base58 prefix *) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml index 1239f05874d3..d48ac426bc42 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml @@ -163,22 +163,29 @@ let retire_rollup_level : Raw_context.t -> Tx_rollup_repr.t -> Raw_level_repr.t -> - Raw_context.t tzresult Lwt.t = - fun ctxt tx_rollup level -> + Raw_level_repr.t -> + (Raw_context.t * [> `No_commitment | `Commitment_too_late | `Retired]) + tzresult + Lwt.t = + fun ctxt tx_rollup level last_level_to_finalize -> let top = (Raw_context.current_level ctxt).level in let key = (level, tx_rollup) in get_or_empty_commitments ctxt key >>=? fun (ctxt, commitments) -> match commitments with - | [] -> fail (Retire_uncommitted_level level) + | [] -> return (ctxt, `No_commitment) | accepted :: rejected -> - let to_obviate = - Commitment_set.of_seq - (Seq.map (fun {hash; _} -> hash) (List.to_seq rejected)) - in - remove_successors ctxt tx_rollup level top to_obviate >>=? fun ctxt -> - adjust_commitment_bond ctxt tx_rollup accepted.committer (-1) - >>=? fun ctxt -> - Storage.Tx_rollup.Commitment_list.add ctxt key [accepted] >|=? just_ctxt + if Raw_level_repr.(accepted.submitted_at > last_level_to_finalize) then + return (ctxt, `Commitment_too_late) + else + let to_obviate = + Commitment_set.of_seq + (Seq.map (fun {hash; _} -> hash) (List.to_seq rejected)) + in + remove_successors ctxt tx_rollup level top to_obviate >>=? fun ctxt -> + adjust_commitment_bond ctxt tx_rollup accepted.committer (-1) + >>=? fun ctxt -> + Storage.Tx_rollup.Commitment_list.add ctxt key [accepted] + >>=? fun (ctxt, _, _) -> return (ctxt, `Retired) let get_commitments : Raw_context.t -> @@ -199,3 +206,41 @@ let pending_bonded_commitments : fun ctxt tx_rollup pkh -> Storage.Tx_rollup.Commitment_bond.find ctxt (tx_rollup, pkh) >|=? fun (ctxt, pending) -> (ctxt, Option.value ~default:0 pending) + +let finalize_pending_commitments ctxt tx_rollup last_level_to_finalize = + Tx_rollup_state_storage.get ctxt tx_rollup >>=? fun (ctxt, state) -> + let first_unfinalized_level = + Tx_rollup_state_repr.first_unfinalized_level state + in + match first_unfinalized_level with + | None -> return ctxt + | Some first_unfinalized_level -> + let rec finalize_level ctxt level top finalized_count = + if Raw_level_repr.(level > top) then + return (ctxt, finalized_count, Some level) + else + retire_rollup_level ctxt tx_rollup level last_level_to_finalize + >>=? fun (ctxt, finalized) -> + match finalized with + | `Retired -> ( + get_next_level ctxt tx_rollup level >>=? fun (ctxt, next_level) -> + match next_level with + | None -> return (ctxt, 0, None) + | Some next_level -> + (finalize_level [@tailcall]) + ctxt + next_level + top + (finalized_count + 1)) + | _ -> return (ctxt, finalized_count, Some level) + in + finalize_level ctxt first_unfinalized_level last_level_to_finalize 0 + >>=? fun (ctxt, finalized_count, first_unfinalized_level) -> + let new_state = + Tx_rollup_state_repr.update_after_finalize + state + first_unfinalized_level + finalized_count + in + Storage.Tx_rollup.State.add ctxt tx_rollup new_state + >>=? fun (ctxt, _, _) -> return ctxt diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli index 57a5e7ef32a8..a97fffd17168 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli @@ -42,16 +42,19 @@ val add_commitment : Raw_context.t tzresult Lwt.t (** [retire_rollup_level context tx_rollup level] removes all data - associated with a level. It decrements the bonded commitment count - for any contracts whose commitments have been either accepted or - obviated (that is, neither accepted nor rejected). This is normally - used in finalization (during a Commitment operation) and is only - public for testing. *) + associated with a level. It decrements the bonded commitment count + for any contracts whose commitments have been either accepted or + obviated (that is, neither accepted nor rejected). This is normally + used in finalization(during a Commitment operation) and is only and + is only public for testing. *) val retire_rollup_level : Raw_context.t -> Tx_rollup_repr.t -> Raw_level_repr.t -> - Raw_context.t tzresult Lwt.t + Raw_level_repr.t -> + (Raw_context.t * [> `Commitment_too_late | `No_commitment | `Retired]) + tzresult + Lwt.t (** [get_commitments context tx_rollup level] returns the list of non-rejected commitments for a rollup at a level, first-submitted @@ -62,11 +65,30 @@ val get_commitments : Raw_level_repr.t -> (Raw_context.t * Tx_rollup_commitments_repr.t) tzresult Lwt.t -(** [pending bonded_commitments ctxt tx_rollup contract] returns the - number of commitments that [contract] has made that are still +(** [pending bonded_commitments ctxt tx_rollup pkh] returns the + number of commitments that [pkh] has made that are still pending (that is, still subject to rejection) *) val pending_bonded_commitments : Raw_context.t -> Tx_rollup_repr.t -> Signature.public_key_hash -> (Raw_context.t * int) tzresult Lwt.t + +(** [finalize_pending_commitments ctxt tx_rollup last_level_to_finalize] + finalizes all pending commitments that are old enough. For each + unfinalized level up to and including last_level_to_finalize, the + oldest non-rejected commitment is chosen. Any other commitments are + deleted, and their transitive successors are also deleted. Because + these commitments have not been rejected, their bonds are not + slashed, but we still must maintain the count of bonded commitments. + + In the event that some level does not yet have any nonrejected + commitments, the level traversal stops. + + The state is adjusted as well, tracking which levels have been + finalized, and which are left to be finalized. *) +val finalize_pending_commitments : + Raw_context.t -> + Tx_rollup_repr.t -> + Raw_level_repr.t -> + Raw_context.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml index f3d49fc15e0b..1a42fced1622 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml @@ -43,6 +43,13 @@ let prepare_metadata : tzresult Lwt.t = fun ctxt rollup state level -> + (* First, check if there are too many unfinalized levels. *) + fail_when + Compare.Int.( + Tx_rollup_state_repr.unfinalized_level_count state + > Constants_storage.tx_rollup_max_unfinalized_levels ctxt) + Tx_rollup_commitments_repr.Too_many_unfinalized_levels + >>=? fun () -> Storage.Tx_rollup.Inbox_metadata.find (ctxt, level) rollup >>=? fun (ctxt, metadata) -> match metadata with @@ -52,6 +59,7 @@ let prepare_metadata : inbox count *) let predecessor = Tx_rollup_state_repr.last_inbox_level state in let new_state = Tx_rollup_state_repr.append_inbox state level in + Tx_rollup_state_storage.update ctxt rollup new_state >>=? fun ctxt -> (match predecessor with | None -> return ctxt | Some predecessor_level -> diff --git a/src/proto_alpha/lib_protocol/tx_rollup_state_repr.ml b/src/proto_alpha/lib_protocol/tx_rollup_state_repr.ml index 012412d254ce..fde3b173aa51 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_state_repr.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_state_repr.ml @@ -42,30 +42,71 @@ spurious spikes of [fees_per_byte]. *) type t = { + first_unfinalized_level : Raw_level_repr.t option; + unfinalized_level_count : int; fees_per_byte : Tez_repr.t; inbox_ema : int; last_inbox_level : Raw_level_repr.t option; } let initial_state = - {fees_per_byte = Tez_repr.zero; inbox_ema = 0; last_inbox_level = None} + { + first_unfinalized_level = None; + unfinalized_level_count = 0; + fees_per_byte = Tez_repr.zero; + inbox_ema = 0; + last_inbox_level = None; + } let encoding : t Data_encoding.t = let open Data_encoding in conv - (fun {last_inbox_level; fees_per_byte; inbox_ema} -> - (last_inbox_level, fees_per_byte, inbox_ema)) - (fun (last_inbox_level, fees_per_byte, inbox_ema) -> - {last_inbox_level; fees_per_byte; inbox_ema}) - (obj3 - (req "last_inbox_level" (option Raw_level_repr.encoding)) + (fun { + first_unfinalized_level; + unfinalized_level_count; + fees_per_byte; + inbox_ema; + last_inbox_level; + } -> + ( first_unfinalized_level, + unfinalized_level_count, + fees_per_byte, + inbox_ema, + last_inbox_level )) + (fun ( first_unfinalized_level, + unfinalized_level_count, + fees_per_byte, + inbox_ema, + last_inbox_level ) -> + { + first_unfinalized_level; + unfinalized_level_count; + fees_per_byte; + inbox_ema; + last_inbox_level; + }) + (obj5 + (req "first_unfinalized_level" (option Raw_level_repr.encoding)) + (req "unfinalized_level_count" int16) (req "fees_per_byte" Tez_repr.encoding) - (req "inbox_ema" int31)) + (req "inbox_ema" int31) + (req "last_inbox_level" (option Raw_level_repr.encoding))) -let pp fmt {fees_per_byte; last_inbox_level; inbox_ema} = +let pp fmt + { + first_unfinalized_level; + unfinalized_level_count; + fees_per_byte; + inbox_ema; + last_inbox_level; + } = Format.fprintf fmt - "Tx_rollup: fees_per_byte = %a; inbox_ema %d; last_inbox_level = %a" + "first_unfinalized_level: %a unfinalized_level_count: %d cost_per_byte: %a \ + inbox_ema: %d newest inbox: %a" + (Format.pp_print_option Raw_level_repr.pp) + first_unfinalized_level + unfinalized_level_count Tez_repr.pp fees_per_byte inbox_ema @@ -125,7 +166,27 @@ let fees {fees_per_byte; _} size = Tez_repr.(fees_per_byte *? Int64.of_int size) let last_inbox_level {last_inbox_level; _} = last_inbox_level -let append_inbox t level = {t with last_inbox_level = Some level} +let append_inbox t level = + { + t with + last_inbox_level = Some level; + first_unfinalized_level = + Some (Option.value ~default:level t.first_unfinalized_level); + unfinalized_level_count = t.unfinalized_level_count + 1; + } + +let unfinalized_level_count {unfinalized_level_count; _} = + unfinalized_level_count + +let first_unfinalized_level {first_unfinalized_level; _} = + first_unfinalized_level + +let update_after_finalize state level count = + { + state with + first_unfinalized_level = level; + unfinalized_level_count = state.unfinalized_level_count - count; + } module Internal_for_tests = struct let make : @@ -134,7 +195,13 @@ module Internal_for_tests = struct last_inbox_level:Raw_level_repr.t option -> t = fun ~fees_per_byte ~inbox_ema ~last_inbox_level -> - {fees_per_byte; inbox_ema; last_inbox_level} + { + fees_per_byte; + inbox_ema; + last_inbox_level; + first_unfinalized_level = None; + unfinalized_level_count = 0; + } let get_inbox_ema : t -> int = fun {inbox_ema; _} -> inbox_ema end diff --git a/src/proto_alpha/lib_protocol/tx_rollup_state_repr.mli b/src/proto_alpha/lib_protocol/tx_rollup_state_repr.mli index 28a1ef3b687b..977ab4a28656 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_state_repr.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_state_repr.mli @@ -63,6 +63,20 @@ val last_inbox_level : t -> Raw_level_repr.t option [state] when messages have been added at a level. *) val append_inbox : t -> Raw_level_repr.t -> t +(** [unfinalized_level_count state] returns the number of unfinalized + levels of the rollup. If this is too high, we stop appending + messages until commitments catch up. *) +val unfinalized_level_count : t -> int + +(** [first_unfinalized_level state] returns the first unfinalized + level of the rollup. Note that this level might be empty.*) +val first_unfinalized_level : t -> Raw_level_repr.t option + +(* [update_after_finalize state level count] updates a state + after some levels have been finalized. [count] is the number of + finalized levels *) +val update_after_finalize : t -> Raw_level_repr.t option -> int -> t + module Internal_for_tests : sig (** [make] returns a state for tests *) val make : diff --git a/src/proto_alpha/lib_protocol/tx_rollup_state_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_state_storage.ml index ff9921d52efd..9f8ed228492f 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_state_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_state_storage.ml @@ -107,3 +107,11 @@ let () = (obj1 (req "rollup_address" Tx_rollup_repr.encoding)) (function Tx_rollup_does_not_exist rollup -> Some rollup | _ -> None) (fun rollup -> Tx_rollup_does_not_exist rollup) + +let first_unfinalized_level : + Raw_context.t -> + Tx_rollup_repr.t -> + (Raw_context.t * Raw_level_repr.t option) tzresult Lwt.t = + fun ctxt tx_rollup -> + Storage.Tx_rollup.State.get ctxt tx_rollup >>=? fun (ctxt, state) -> + return (ctxt, Tx_rollup_state_repr.first_unfinalized_level state) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_state_storage.mli b/src/proto_alpha/lib_protocol/tx_rollup_state_storage.mli index aa313fcad784..ff6a981f2e89 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_state_storage.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_state_storage.mli @@ -80,3 +80,11 @@ val update : transaction rollup address. *) val assert_exist : Raw_context.t -> Tx_rollup_repr.t -> Raw_context.t tzresult Lwt.t + +(** [first_unfinalized_level] returns the first unfinalized level + of [tx_rollup]. If None, then there are no unfinalized levels + with inboxes. *) +val first_unfinalized_level : + Raw_context.t -> + Tx_rollup_repr.t -> + (Raw_context.t * Raw_level_repr.t option) tzresult Lwt.t diff --git a/tezt/_regressions/tx_rollup_simple_use_case.out b/tezt/_regressions/tx_rollup_simple_use_case.out index 2d1c52bee453..fd6421644c43 100644 --- a/tezt/_regressions/tx_rollup_simple_use_case.out +++ b/tezt/_regressions/tx_rollup_simple_use_case.out @@ -2,11 +2,12 @@ tezt/_regressions/tx_rollup_simple_use_case.out tru1EL3YqhLS3kwni3ikbqMrui61fA5k7StHz ./tezos-client rpc get /chains/main/blocks/head/context/tx_rollup/tru1EL3YqhLS3kwni3ikbqMrui61fA5k7StHz/state -{ "last_inbox_level": null, "fees_per_byte": "0", "inbox_ema": 0 } +{ "first_unfinalized_level": null, "unfinalized_level_count": 0, + "fees_per_byte": "0", "inbox_ema": 0, "last_inbox_level": null } ./tezos-client --wait none submit tx rollup batch 74657a6f73 to tru1EL3YqhLS3kwni3ikbqMrui61fA5k7StHz from '[PUBLIC_KEY_HASH]' Node is bootstrapped. -Estimated gas: 2440.220 units (will add 100 for safety) +Estimated gas: 2640.322 units (will add 100 for safety) Estimated storage: no bytes added Operation successfully injected in the node. Operation hash is '[OPERATION_HASH]' @@ -17,18 +18,18 @@ and/or an external block explorer to make sure that it has been included. This sequence of operations was run: Manager signed operations: From: [PUBLIC_KEY_HASH] - Fee to the baker: ꜩ0.000508 + Fee to the baker: ꜩ0.000528 Expected counter: 2 - Gas limit: 2541 + Gas limit: 2741 Storage limit: 0 bytes Balance updates: - [PUBLIC_KEY_HASH] ... -ꜩ0.000508 - payload fees(the block proposer) ....... +ꜩ0.000508 + [PUBLIC_KEY_HASH] ... -ꜩ0.000528 + payload fees(the block proposer) ....... +ꜩ0.000528 Tx rollup transaction:tru1EL3YqhLS3kwni3ikbqMrui61fA5k7StHz, 5 bytes, From: [PUBLIC_KEY_HASH] This tx rollup submit operation was successfully applied Balance updates: - Consumed gas: 2440.220 + Consumed gas: 2640.322 ./tezos-client rpc get /chains/main/blocks/head/context/tx_rollup/tru1EL3YqhLS3kwni3ikbqMrui61fA5k7StHz/inbox -- GitLab From 789946c23d1325484c3d8dfe3e23a9e545635472 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 3 Jan 2022 16:13:22 -0500 Subject: [PATCH 19/31] Proto,Tx_rollup: Retire commitments during commitment apply, and return bonds Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- src/proto_alpha/lib_client/injection.ml | 4 + .../lib_client/operation_result.ml | 35 ++++++++- .../lib_protocol/alpha_context.mli | 18 +++++ src/proto_alpha/lib_protocol/apply.ml | 24 ++++++ src/proto_alpha/lib_protocol/apply_results.ml | 75 +++++++++++++++++++ .../lib_protocol/apply_results.mli | 5 ++ .../lib_protocol/operation_repr.ml | 33 ++++++++ .../lib_protocol/operation_repr.mli | 11 +++ .../lib_protocol/test/helpers/block.ml | 5 +- .../lib_protocol/test/helpers/op.ml | 14 ++++ .../lib_protocol/test/helpers/op.mli | 11 +++ .../integration/operations/test_tx_rollup.ml | 57 ++++++++++++++ .../lib_protocol/ticket_operations_diff.ml | 1 + .../tx_rollup_commitments_storage.ml | 14 ++++ .../tx_rollup_commitments_storage.mli | 9 +++ 15 files changed, 313 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/lib_client/injection.ml b/src/proto_alpha/lib_client/injection.ml index ecf5fb52bbd8..70391c618356 100644 --- a/src/proto_alpha/lib_client/injection.ml +++ b/src/proto_alpha/lib_client/injection.ml @@ -326,6 +326,8 @@ let estimated_gas_single (type kind) | Applied (Tx_rollup_submit_batch_result {consumed_gas; _}) -> Ok consumed_gas | Applied (Tx_rollup_commit_result {consumed_gas; _}) -> Ok consumed_gas + | Applied (Tx_rollup_return_bond_result {consumed_gas; _}) -> + Ok consumed_gas | Applied (Sc_rollup_originate_result {consumed_gas; _}) -> Ok consumed_gas | Applied (Sc_rollup_add_messages_result {consumed_gas; _}) -> Ok consumed_gas @@ -369,6 +371,7 @@ let estimated_storage_single (type kind) ~tx_rollup_origination_size Michelson’s big map). *) Ok Z.zero | Applied (Tx_rollup_commit_result _) -> Ok Z.zero + | Applied (Tx_rollup_return_bond_result _) -> Ok Z.zero | Applied (Sc_rollup_originate_result {size; _}) -> Ok size | Applied (Sc_rollup_add_messages_result _) -> Ok Z.zero | Skipped _ -> assert false @@ -422,6 +425,7 @@ let originated_contracts_single (type kind) | Applied (Tx_rollup_origination_result _) -> Ok [] | Applied (Tx_rollup_submit_batch_result _) -> Ok [] | Applied (Tx_rollup_commit_result _) -> Ok [] + | Applied (Tx_rollup_return_bond_result _) -> Ok [] | Applied (Sc_rollup_originate_result _) -> Ok [] | Applied (Sc_rollup_add_messages_result _) -> Ok [] | Skipped _ -> assert false diff --git a/src/proto_alpha/lib_client/operation_result.ml b/src/proto_alpha/lib_client/operation_result.ml index 96387adb8ba2..075c7a677b40 100644 --- a/src/proto_alpha/lib_client/operation_result.ml +++ b/src/proto_alpha/lib_client/operation_result.ml @@ -201,6 +201,18 @@ let pp_manager_operation_content (type kind) source internal pp_result ppf source pp_result result + | Tx_rollup_return_bond {tx_rollup} -> + Format.fprintf + ppf + "@[%s:%a @,From: %a%a@]" + (if internal then "Internal tx rollup return commitment bond" + else "Tx rollup return commitment bond") + Tx_rollup.pp + tx_rollup + Contract.pp + source + pp_result + result | Sc_rollup_originate {kind; boot_sector} -> let (module R : Sc_rollups.PVM.S) = Sc_rollups.of_kind kind in Format.fprintf @@ -465,6 +477,15 @@ let pp_manager_operation_contents_and_result ppf balance_updates ; Format.fprintf ppf "@,Consumed gas: %a" Gas.Arith.pp consumed_gas in + let pp_tx_rollup_return_bond_result + (Tx_rollup_return_bond_result {balance_updates; consumed_gas}) = + Format.fprintf + ppf + "@,Balance updates:@, %a" + pp_balance_updates + balance_updates ; + Format.fprintf ppf "@,Consumed gas: %a" Gas.Arith.pp consumed_gas + in let pp_sc_rollup_originate_result (Sc_rollup_originate_result {address; consumed_gas; size; balance_updates}) = @@ -570,9 +591,21 @@ let pp_manager_operation_contents_and_result ppf | Backtracked ((Tx_rollup_commit_result _ as op), _err) -> Format.fprintf ppf - "@[This tx rollup commit rollup operation was BACKTRACKED, its \ + "@[This tx rollup commit operation was BACKTRACKED, its \ expected effects (as follow) were NOT applied.@]" ; pp_tx_rollup_commit_result op + | Applied (Tx_rollup_return_bond_result _ as op) -> + Format.fprintf + ppf + "This tx rollup return commitment bond operation was successfully \ + applied" ; + pp_tx_rollup_return_bond_result op + | Backtracked ((Tx_rollup_return_bond_result _ as op), _err) -> + Format.fprintf + ppf + "@[This tx rollup return commitment bond operation was \ + BACKTRACKED, its expected effects (as follow) were NOT applied.@]" ; + pp_tx_rollup_return_bond_result op | Applied (Sc_rollup_originate_result _ as op) -> Format.fprintf ppf diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 0fb6dc6958e4..95efe05aa877 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2188,6 +2188,12 @@ module Tx_rollup_commitments : sig val finalize_pending_commitments : context -> Tx_rollup.t -> Raw_level.t -> context tzresult Lwt.t + val remove_bond : + context -> + Tx_rollup.t -> + Signature.public_key_hash -> + context tzresult Lwt.t + module Internal_for_tests : sig (** See [Tx_rollup_commitments_storage.retire_rollup_level] for documentation *) @@ -2253,6 +2259,8 @@ module Kind : sig type tx_rollup_commit = Tx_rollup_commit_kind + type tx_rollup_return_bond = Tx_rollup_return_bond_kind + type sc_rollup_originate = Sc_rollup_originate_kind type sc_rollup_add_messages = Sc_rollup_add_messages_kind @@ -2267,6 +2275,7 @@ module Kind : sig | Tx_rollup_origination_manager_kind : tx_rollup_origination manager | Tx_rollup_submit_batch_manager_kind : tx_rollup_submit_batch manager | Tx_rollup_commit_manager_kind : tx_rollup_commit manager + | Tx_rollup_return_bond_manager_kind : tx_rollup_return_bond manager | Sc_rollup_originate_manager_kind : sc_rollup_originate manager | Sc_rollup_add_messages_manager_kind : sc_rollup_add_messages manager end @@ -2397,6 +2406,10 @@ and _ manager_operation = commitment : Tx_rollup_commitments.Commitment.t; } -> Kind.tx_rollup_commit manager_operation + | Tx_rollup_return_bond : { + tx_rollup : Tx_rollup.t; + } + -> Kind.tx_rollup_return_bond manager_operation | Sc_rollup_originate : { kind : Sc_rollup.Kind.t; boot_sector : Sc_rollup.PVM.boot_sector; @@ -2552,6 +2565,9 @@ module Operation : sig val tx_rollup_commit_case : Kind.tx_rollup_commit Kind.manager case + val tx_rollup_return_bond_case : + Kind.tx_rollup_return_bond Kind.manager case + val register_global_constant_case : Kind.register_global_constant Kind.manager case @@ -2592,6 +2608,8 @@ module Operation : sig val tx_rollup_commit_case : Kind.tx_rollup_commit case + val tx_rollup_return_bond_case : Kind.tx_rollup_return_bond case + val sc_rollup_originate_case : Kind.sc_rollup_originate case val sc_rollup_add_messages_case : Kind.sc_rollup_add_messages case diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 3f90d5a9a15d..fde7aead7484 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -1246,6 +1246,26 @@ let apply_manager_operation_content : } in return (ctxt, result, [])) + | Tx_rollup_return_bond {tx_rollup} -> + (match Contract.is_implicit source with + | None -> fail Tx_rollup_commit_with_non_implicit_contract + | Some key -> + let bond_id = Rollup_bond_id.Tx_rollup_bond_id tx_rollup in + Tx_rollup_commitments.remove_bond ctxt tx_rollup key >>=? fun ctxt -> + Token.transfer + ctxt + (`Frozen_rollup_bonds (source, bond_id)) + (`Contract source) + (Constants.tx_rollup_commitment_bond ctxt)) + >>=? fun (ctxt, balance_updates) -> + let result = + Tx_rollup_return_bond_result + { + consumed_gas = Gas.consumed ~since:before_operation ~until:ctxt; + balance_updates; + } + in + return (ctxt, result, []) | Sc_rollup_originate {kind; boot_sector} -> Sc_rollup_operations.originate ctxt ~kind ~boot_sector >>=? fun ({address; size}, ctxt) -> @@ -1400,6 +1420,8 @@ let precheck_manager_contents (type kind) ctxt (op : kind Kind.manager contents) (Tx_rollup_commitments.Commitment_too_early (commitment.level, current_level)) >|=? fun () -> ctxt + | Tx_rollup_return_bond _ -> + assert_tx_rollup_feature_enabled ctxt >|=? fun () -> ctxt | Sc_rollup_originate _ | Sc_rollup_add_messages _ -> assert_sc_rollup_feature_enabled ctxt >|=? fun () -> ctxt) >>=? fun ctxt -> @@ -1515,6 +1537,8 @@ let burn_storage_fees : consumed_gas = (_ : Gas.Arith.fp); } -> return (ctxt, storage_limit, smopr) + | Tx_rollup_return_bond_result payload -> + return (ctxt, storage_limit, Tx_rollup_return_bond_result payload) | Sc_rollup_originate_result payload -> let payer = `Contract payer in Fees.burn_sc_rollup_origination_fees diff --git a/src/proto_alpha/lib_protocol/apply_results.ml b/src/proto_alpha/lib_protocol/apply_results.ml index ab9b01cbb3ad..eb500f2fe480 100644 --- a/src/proto_alpha/lib_protocol/apply_results.ml +++ b/src/proto_alpha/lib_protocol/apply_results.ml @@ -106,6 +106,11 @@ type _ successful_manager_operation_result = consumed_gas : Gas.Arith.fp; } -> Kind.tx_rollup_commit successful_manager_operation_result + | Tx_rollup_return_bond_result : { + balance_updates : Receipt.balance_updates; + consumed_gas : Gas.Arith.fp; + } + -> Kind.tx_rollup_return_bond successful_manager_operation_result | Sc_rollup_originate_result : { balance_updates : Receipt.balance_updates; address : Sc_rollup.Address.t; @@ -576,6 +581,33 @@ module Manager_result = struct Tx_rollup_commit_result {balance_updates; consumed_gas = consumed_milligas}) + let[@coq_axiom_with_reason "gadt"] tx_rollup_return_bond_case = + make + ~op_case:Operation.Encoding.Manager_operations.tx_rollup_return_bond_case + ~encoding: + Data_encoding.( + obj3 + (req "balance_updates" Receipt.balance_updates_encoding) + (dft "consumed_gas" Gas.Arith.n_integral_encoding Gas.Arith.zero) + (dft "consumed_milligas" Gas.Arith.n_fp_encoding Gas.Arith.zero)) + ~iselect:(function + | Internal_operation_result + (({operation = Tx_rollup_return_bond _; _} as op), res) -> + Some (op, res) + | _ -> None) + ~select:(function + | Successful_manager_result (Tx_rollup_return_bond_result _ as op) -> + Some op + | _ -> None) + ~kind:Kind.Tx_rollup_return_bond_manager_kind + ~proj:(function + | Tx_rollup_return_bond_result {balance_updates; consumed_gas} -> + (balance_updates, Gas.Arith.ceil consumed_gas, consumed_gas)) + ~inj:(fun (balance_updates, consumed_gas, consumed_milligas) -> + assert (Gas.Arith.(equal (ceil consumed_milligas) consumed_gas)) ; + Tx_rollup_return_bond_result + {balance_updates; consumed_gas = consumed_milligas}) + let[@coq_axiom_with_reason "gadt"] sc_rollup_originate_case = make ~op_case:Operation.Encoding.Manager_operations.sc_rollup_originate_case @@ -783,6 +815,10 @@ let equal_manager_kind : | (Kind.Tx_rollup_commit_manager_kind, Kind.Tx_rollup_commit_manager_kind) -> Some Eq | (Kind.Tx_rollup_commit_manager_kind, _) -> None + | ( Kind.Tx_rollup_return_bond_manager_kind, + Kind.Tx_rollup_return_bond_manager_kind ) -> + Some Eq + | (Kind.Tx_rollup_return_bond_manager_kind, _) -> None | ( Kind.Sc_rollup_originate_manager_kind, Kind.Sc_rollup_originate_manager_kind ) -> Some Eq @@ -1175,6 +1211,17 @@ module Encoding = struct Some (op, res) | _ -> None) + let[@coq_axiom_with_reason "gadt"] tx_rollup_return_bond_case = + make_manager_case + Operation.Encoding.tx_rollup_return_bond_case + Manager_result.tx_rollup_return_bond_case + (function + | Contents_and_result + ( (Manager_operation {operation = Tx_rollup_return_bond _; _} as op), + res ) -> + Some (op, res) + | _ -> None) + let[@coq_axiom_with_reason "gadt"] sc_rollup_originate_case = make_manager_case Operation.Encoding.sc_rollup_originate_case @@ -1235,6 +1282,7 @@ let contents_result_encoding = make tx_rollup_origination_case; make tx_rollup_submit_batch_case; make tx_rollup_commit_case; + make tx_rollup_return_bond_case; make sc_rollup_originate_case; make sc_rollup_add_messages_case; ] @@ -1281,6 +1329,7 @@ let contents_and_result_encoding = make tx_rollup_origination_case; make tx_rollup_submit_batch_case; make tx_rollup_commit_case; + make tx_rollup_return_bond_case; make sc_rollup_originate_case; make sc_rollup_add_messages_case; ] @@ -1637,6 +1686,32 @@ let kind_equal : } ) -> Some Eq | (Manager_operation {operation = Tx_rollup_commit _; _}, _) -> None + | ( Manager_operation {operation = Tx_rollup_return_bond _; _}, + Manager_operation_result + {operation_result = Applied (Tx_rollup_return_bond_result _); _} ) -> + Some Eq + | ( Manager_operation {operation = Tx_rollup_return_bond _; _}, + Manager_operation_result + {operation_result = Backtracked (Tx_rollup_return_bond_result _, _); _} + ) -> + Some Eq + | ( Manager_operation {operation = Tx_rollup_return_bond _; _}, + Manager_operation_result + { + operation_result = + Failed (Alpha_context.Kind.Tx_rollup_return_bond_manager_kind, _); + _; + } ) -> + Some Eq + | ( Manager_operation {operation = Tx_rollup_return_bond _; _}, + Manager_operation_result + { + operation_result = + Skipped Alpha_context.Kind.Tx_rollup_return_bond_manager_kind; + _; + } ) -> + Some Eq + | (Manager_operation {operation = Tx_rollup_return_bond _; _}, _) -> None | ( Manager_operation {operation = Sc_rollup_originate _; _}, Manager_operation_result {operation_result = Applied (Sc_rollup_originate_result _); _} ) -> diff --git a/src/proto_alpha/lib_protocol/apply_results.mli b/src/proto_alpha/lib_protocol/apply_results.mli index 7fcdc6979d04..287c9e03f04f 100644 --- a/src/proto_alpha/lib_protocol/apply_results.mli +++ b/src/proto_alpha/lib_protocol/apply_results.mli @@ -179,6 +179,11 @@ and _ successful_manager_operation_result = consumed_gas : Gas.Arith.fp; } -> Kind.tx_rollup_commit successful_manager_operation_result + | Tx_rollup_return_bond_result : { + balance_updates : Receipt.balance_updates; + consumed_gas : Gas.Arith.fp; + } + -> Kind.tx_rollup_return_bond successful_manager_operation_result | Sc_rollup_originate_result : { balance_updates : Receipt.balance_updates; address : Sc_rollup.Address.t; diff --git a/src/proto_alpha/lib_protocol/operation_repr.ml b/src/proto_alpha/lib_protocol/operation_repr.ml index baa7930748c1..3bbe2b75040f 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.ml +++ b/src/proto_alpha/lib_protocol/operation_repr.ml @@ -77,6 +77,8 @@ module Kind = struct type tx_rollup_commit = Tx_rollup_commit_kind + type tx_rollup_return_bond = Tx_rollup_return_bond_kind + type sc_rollup_originate = Sc_rollup_originate_kind type sc_rollup_add_messages = Sc_rollup_add_messages_kind @@ -91,6 +93,7 @@ module Kind = struct | Tx_rollup_origination_manager_kind : tx_rollup_origination manager | Tx_rollup_submit_batch_manager_kind : tx_rollup_submit_batch manager | Tx_rollup_commit_manager_kind : tx_rollup_commit manager + | Tx_rollup_return_bond_manager_kind : tx_rollup_return_bond manager | Sc_rollup_originate_manager_kind : sc_rollup_originate manager | Sc_rollup_add_messages_manager_kind : sc_rollup_add_messages manager end @@ -281,6 +284,10 @@ and _ manager_operation = commitment : Tx_rollup_commitments_repr.Commitment.t; } -> Kind.tx_rollup_commit manager_operation + | Tx_rollup_return_bond : { + tx_rollup : Tx_rollup_repr.t; + } + -> Kind.tx_rollup_return_bond manager_operation | Sc_rollup_originate : { kind : Sc_rollup_repr.Kind.t; boot_sector : Sc_rollup_repr.PVM.boot_sector; @@ -305,6 +312,7 @@ let manager_kind : type kind. kind manager_operation -> kind Kind.manager = | Tx_rollup_origination -> Kind.Tx_rollup_origination_manager_kind | Tx_rollup_submit_batch _ -> Kind.Tx_rollup_submit_batch_manager_kind | Tx_rollup_commit _ -> Kind.Tx_rollup_commit_manager_kind + | Tx_rollup_return_bond _ -> Kind.Tx_rollup_return_bond_manager_kind | Sc_rollup_originate _ -> Kind.Sc_rollup_originate_manager_kind | Sc_rollup_add_messages _ -> Kind.Sc_rollup_add_messages_manager_kind @@ -574,6 +582,19 @@ module Encoding = struct Tx_rollup_commit {tx_rollup; commitment}); } + let[@coq_axiom_with_reason "gadt"] tx_rollup_return_bond_case = + MCase + { + tag = tx_rollup_operation_tag_offset + 3; + name = "tx_rollup_return_bond"; + encoding = obj1 (req "rollup" Tx_rollup_repr.encoding); + select = + (function + | Manager (Tx_rollup_return_bond _ as op) -> Some op | _ -> None); + proj = (function Tx_rollup_return_bond {tx_rollup} -> tx_rollup); + inj = (fun tx_rollup -> Tx_rollup_return_bond {tx_rollup}); + } + let[@coq_axiom_with_reason "gadt"] sc_rollup_originate_case = MCase { @@ -635,6 +656,7 @@ module Encoding = struct make tx_rollup_origination_case; make tx_rollup_submit_batch_case; make tx_rollup_commit_case; + make tx_rollup_return_bond_case; make sc_rollup_originate_case; make sc_rollup_add_messages_case; ] @@ -950,6 +972,11 @@ module Encoding = struct tx_rollup_operation_commit_tag Manager_operations.tx_rollup_commit_case + let tx_rollup_return_bond_case = + make_manager_case + (tx_rollup_operation_tag_offset + 3) + Manager_operations.tx_rollup_return_bond_case + let sc_rollup_originate_case = make_manager_case sc_rollup_operation_origination_tag @@ -991,6 +1018,7 @@ module Encoding = struct make tx_rollup_origination_case; make tx_rollup_submit_batch_case; make tx_rollup_commit_case; + make tx_rollup_return_bond_case; make sc_rollup_originate_case; make sc_rollup_add_messages_case; ] @@ -1198,6 +1226,8 @@ let equal_manager_operation_kind : | (Tx_rollup_submit_batch _, _) -> None | (Tx_rollup_commit _, Tx_rollup_commit _) -> Some Eq | (Tx_rollup_commit _, _) -> None + | (Tx_rollup_return_bond _, Tx_rollup_return_bond _) -> Some Eq + | (Tx_rollup_return_bond _, _) -> None | (Sc_rollup_originate _, Sc_rollup_originate _) -> Some Eq | (Sc_rollup_originate _, _) -> None | (Sc_rollup_add_messages _, Sc_rollup_add_messages _) -> Some Eq @@ -1313,6 +1343,9 @@ let internal_manager_operation_size (type a) (op : a manager_operation) = | Tx_rollup_commit _ -> (* Tx_rollup_commit operation can’t occur as internal operations *) assert false + | Tx_rollup_return_bond _ -> + (* Tx_rollup_return_bond operation can’t occur as internal operations *) + assert false let packed_internal_operation_in_memory_size : packed_internal_operation -> nodes_and_size = function diff --git a/src/proto_alpha/lib_protocol/operation_repr.mli b/src/proto_alpha/lib_protocol/operation_repr.mli index df21d962d1e0..0f5f31fa380a 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.mli +++ b/src/proto_alpha/lib_protocol/operation_repr.mli @@ -103,6 +103,8 @@ module Kind : sig type tx_rollup_commit = Tx_rollup_commit_kind + type tx_rollup_return_bond = Tx_rollup_return_bond_kind + type sc_rollup_originate = Sc_rollup_originate_kind type sc_rollup_add_messages = Sc_rollup_add_messages_kind @@ -117,6 +119,7 @@ module Kind : sig | Tx_rollup_origination_manager_kind : tx_rollup_origination manager | Tx_rollup_submit_batch_manager_kind : tx_rollup_submit_batch manager | Tx_rollup_commit_manager_kind : tx_rollup_commit manager + | Tx_rollup_return_bond_manager_kind : tx_rollup_return_bond manager | Sc_rollup_originate_manager_kind : sc_rollup_originate manager | Sc_rollup_add_messages_manager_kind : sc_rollup_add_messages manager end @@ -260,6 +263,10 @@ and _ manager_operation = commitment : Tx_rollup_commitments_repr.Commitment.t; } -> Kind.tx_rollup_commit manager_operation + | Tx_rollup_return_bond : { + tx_rollup : Tx_rollup_repr.t; + } + -> Kind.tx_rollup_return_bond manager_operation | Sc_rollup_originate : { kind : Sc_rollup_repr.Kind.t; boot_sector : Sc_rollup_repr.PVM.boot_sector; @@ -396,6 +403,8 @@ module Encoding : sig val tx_rollup_commit_case : Kind.tx_rollup_commit Kind.manager case + val tx_rollup_return_bond_case : Kind.tx_rollup_return_bond Kind.manager case + val sc_rollup_originate_case : Kind.sc_rollup_originate Kind.manager case val sc_rollup_add_messages_case : @@ -431,6 +440,8 @@ module Encoding : sig val tx_rollup_commit_case : Kind.tx_rollup_commit case + val tx_rollup_return_bond_case : Kind.tx_rollup_return_bond case + val sc_rollup_originate_case : Kind.sc_rollup_originate case val sc_rollup_add_messages_case : Kind.sc_rollup_add_messages case diff --git a/src/proto_alpha/lib_protocol/test/helpers/block.ml b/src/proto_alpha/lib_protocol/test/helpers/block.ml index 6e31efeb6925..eb19a648cea6 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/block.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/block.ml @@ -700,8 +700,8 @@ let bake_n_with_all_balance_updates ?(baking_mode = Application) ?policy | Reveal_result _ | Delegation_result _ | Set_deposits_limit_result _ | Tx_rollup_origination_result _ | Tx_rollup_submit_batch_result _ | Tx_rollup_commit_result _ - | Sc_rollup_originate_result _ | Sc_rollup_add_messages_result _ - -> + | Tx_rollup_return_bond_result _ | Sc_rollup_originate_result _ + | Sc_rollup_add_messages_result _ -> balance_updates_rev | Transaction_result (Transaction_to_contract_result {balance_updates; _}) @@ -733,6 +733,7 @@ let bake_n_with_origination_results ?(baking_mode = Application) ?policy n b = | Successful_manager_result (Tx_rollup_origination_result _) | Successful_manager_result (Tx_rollup_submit_batch_result _) | Successful_manager_result (Tx_rollup_commit_result _) + | Successful_manager_result (Tx_rollup_return_bond_result _) | Successful_manager_result (Sc_rollup_originate_result _) | Successful_manager_result (Sc_rollup_add_messages_result _) -> origination_results_rev diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index c01cb68c8b85..2e6350f7de07 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -553,3 +553,17 @@ let tx_rollup_commit ?counter ?fee ?gas_limit ?storage_limit ctxt >>=? fun to_sign_op -> Context.Contract.manager ctxt source >|=? fun account -> sign account.sk ctxt to_sign_op + +let tx_rollup_return_bond ?counter ?fee ?gas_limit ?storage_limit ctxt + (source : Contract.t) (tx_rollup : Tx_rollup.t) = + manager_operation + ?counter + ?fee + ?gas_limit + ?storage_limit + ~source + ctxt + (Tx_rollup_return_bond {tx_rollup}) + >>=? fun to_sign_op -> + Context.Contract.manager ctxt source >|=? fun account -> + sign account.sk ctxt to_sign_op diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index 6902adbea622..2caed6377d09 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -243,3 +243,14 @@ val tx_rollup_commit : Tx_rollup.t -> Tx_rollup_commitments.Commitment.t -> Operation.packed tzresult Lwt.t + +(** [tx_rollup_return_bond ctxt source tx_rollup] returns a commitment bond. *) +val tx_rollup_return_bond : + ?counter:Z.t -> + ?fee:Tez.tez -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:Z.t -> + Context.t -> + Contract.t -> + Tx_rollup.t -> + Operation.packed tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index 166b1b328372..71dcf0968e04 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -1035,6 +1035,62 @@ let test_commitment_acceptance () = ignore i ; return () +(** [test_bond_finalization] tests that commitment operations + in fact finalize bonds. *) +let test_bond_finalization () = + context_init 2 >>=? fun (b, contracts) -> + let contract1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + let pkh1 = public_key_hash_exn contract1 in + originate b contract1 >>=? fun (b, tx_rollup) -> + (* Transactions in block 2, 3, 4 *) + make_transactions_in tx_rollup contract1 [2; 3; 4] b >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + Incremental.finalize_block i >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + Op.tx_rollup_return_bond (I i) contract1 tx_rollup >>=? fun op -> + Incremental.add_operation i op ~expect_failure:(function + | Environment.Ecoproto_error + (Tx_rollup_commitments.Bond_does_not_exist a_pkh1 as e) + :: _ + when a_pkh1 = pkh1 -> + Assert.test_error_encodings e ; + return_unit + | _ -> failwith "Commitment bond should not exist yet") + >>=? fun i -> + let batches : Tx_rollup_commitments.Commitment.batch_commitment list = + [{root = Bytes.make 20 '0'}] + in + let commitment_a : Tx_rollup_commitments.Commitment.t = + {level = raw_level 2l; batches; predecessor = None} + in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment_a >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + Op.tx_rollup_return_bond (I i) contract1 tx_rollup >>=? fun op -> + Incremental.add_operation i op ~expect_failure:(function + | Environment.Ecoproto_error + (Tx_rollup_commitments.Bond_in_use a_pkh1 as e) + :: _ + when a_pkh1 = pkh1 -> + Assert.test_error_encodings e ; + return_unit + | _ -> failwith "Need to check that bond is in-use ") + >>=? fun i -> + wrap + (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level + (Incremental.alpha_ctxt i) + tx_rollup + (raw_level 2l) + (raw_level 30l)) + >>=? fun (ctxt, retired) -> + assert_retired retired >>=? fun () -> + let i = Incremental.set_alpha_ctxt i ctxt in + Op.tx_rollup_return_bond (I i) contract1 tx_rollup >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + ignore i ; + return () + let tests = [ Tztest.tztest @@ -1080,4 +1136,5 @@ let tests = "Test multiple nonrejected commitment" `Quick test_commitment_acceptance; + Tztest.tztest "Test bond finalization" `Quick test_bond_finalization; ] diff --git a/src/proto_alpha/lib_protocol/ticket_operations_diff.ml b/src/proto_alpha/lib_protocol/ticket_operations_diff.ml index 555951a41882..ff019e24bafa 100644 --- a/src/proto_alpha/lib_protocol/ticket_operations_diff.ml +++ b/src/proto_alpha/lib_protocol/ticket_operations_diff.ml @@ -251,6 +251,7 @@ let tickets_of_operation ctxt | Tx_rollup_origination -> return (None, ctxt) | Tx_rollup_submit_batch _ -> return (None, ctxt) | Tx_rollup_commit _ -> return (None, ctxt) + | Tx_rollup_return_bond _ -> return (None, ctxt) | Sc_rollup_originate {kind = _; boot_sector = _} -> return (None, ctxt) | Sc_rollup_add_messages {rollup = _; messages = _} -> return (None, ctxt) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml index d48ac426bc42..4f7906eed1f0 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml @@ -63,6 +63,20 @@ let adjust_commitment_bond ctxt tx_rollup pkh delta = >>=? fun () -> Storage.Tx_rollup.Commitment_bond.add ctxt bond_key count >|=? just_ctxt +let remove_bond : + Raw_context.t -> + Tx_rollup_repr.t -> + Signature.public_key_hash -> + Raw_context.t tzresult Lwt.t = + fun ctxt tx_rollup contract -> + let bond_key = (tx_rollup, contract) in + Storage.Tx_rollup.Commitment_bond.find ctxt bond_key >>=? fun (ctxt, bond) -> + match bond with + | None -> fail (Bond_does_not_exist contract) + | Some 0 -> + Storage.Tx_rollup.Commitment_bond.remove ctxt bond_key >|=? just_ctxt + | Some _ -> fail (Bond_in_use contract) + let check_commitment_predecessor_hash ctxt tx_rollup (commitment : Commitment.t) = let level = commitment.level in diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli index a97fffd17168..88f102b0aff3 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli @@ -41,6 +41,15 @@ val add_commitment : Tx_rollup_commitments_repr.Commitment.t -> Raw_context.t tzresult Lwt.t +(** [remove_bond context tx_rollup contract] removes the bond for an + implicit contract. This will fail if either the bond does not exist, + or the bond is currently in-use. *) +val remove_bond : + Raw_context.t -> + Tx_rollup_repr.t -> + Signature.public_key_hash -> + Raw_context.t tzresult Lwt.t + (** [retire_rollup_level context tx_rollup level] removes all data associated with a level. It decrements the bonded commitment count for any contracts whose commitments have been either accepted or -- GitLab From 84fe4f7938f7ca917a8c6fb5c1b13a76ba9ca260 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 3 Jan 2022 16:13:22 -0500 Subject: [PATCH 20/31] Proto,Tx_rollup: Pending bonded commitments RPC Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- .../lib_protocol/tx_rollup_services.ml | 18 ++++++++++++- tezt/lib_tezos/RPC.ml | 26 +++++++++++++++++++ tezt/lib_tezos/RPC.mli | 11 ++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_services.ml b/src/proto_alpha/lib_protocol/tx_rollup_services.ml index 436f948f8c7b..bf965888dbe1 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_services.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_services.ml @@ -50,6 +50,16 @@ module S = struct ~query:RPC_query.empty ~output:Tx_rollup_commitments.encoding RPC_path.(custom_root /: Tx_rollup.rpc_arg / "commitments") + + let pending_bonded_commitments = + RPC_service.get_service + ~description: + "Get the number of pending bonded commitments for a pkh on a rollup" + ~query:RPC_query.empty + ~output:Data_encoding.int32 + RPC_path.( + custom_root /: Tx_rollup.rpc_arg / "pending_bonded_commitments" + /: Signature.Public_key_hash.rpc_arg) end let register () = @@ -60,7 +70,13 @@ let register () = Tx_rollup_inbox.find ctxt tx_rollup ~level:`Current >|=? snd) ; register1 ~chunked:false S.commitments (fun ctxt tx_rollup () () -> let level = (Level.current ctxt).level in - Tx_rollup_commitments.get_commitments ctxt tx_rollup level >|=? snd) + Tx_rollup_commitments.get_commitments ctxt tx_rollup level >|=? snd) ; + register2 + ~chunked:false + S.pending_bonded_commitments + (fun ctxt tx_rollup pkh () () -> + Tx_rollup_commitments.pending_bonded_commitments ctxt tx_rollup pkh + >|=? fun (_, count) -> Int32.of_int count) let state ctxt block tx_rollup = RPC_context.make_call1 S.state ctxt block tx_rollup () () diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index 46070d9232ca..43c659ec0e27 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -645,6 +645,32 @@ module Tx_rollup = struct ~tx_rollup client = let path = sub_path ~chain ~block ~tx_rollup "commitments" in Client.rpc ?endpoint ?hooks GET path client + + let sub_pkh_path ?(chain = "main") ?(block = "head") ~tx_rollup + ~public_key_hash sub = + [ + "chains"; + chain; + "blocks"; + block; + "context"; + "tx_rollup"; + tx_rollup; + sub; + public_key_hash; + ] + + let get_pending_bonded_commitments ?endpoint ?hooks ?(chain = "main") + ?(block = "head") ~tx_rollup ~public_key_hash client = + let path = + sub_pkh_path + ~chain + ~block + ~tx_rollup + ~public_key_hash + "pending_bonded_commitments" + in + Client.rpc ?endpoint ?hooks GET path client end module Sc_rollup = struct diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index 0ca2f70cc4df..320d3347b6dd 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -1016,6 +1016,17 @@ module Tx_rollup : sig tx_rollup:string -> Client.t -> JSON.t Lwt.t + + (** Call RPC /chain/[chain]/blocks/[block]/context/[rollup_hash]/pending_bonded_commitments *) + val get_pending_bonded_commitments : + ?endpoint:Client.endpoint -> + ?hooks:Process.hooks -> + ?chain:string -> + ?block:string -> + tx_rollup:string -> + public_key_hash:string -> + Client.t -> + JSON.t Lwt.t end module Sc_rollup : sig -- GitLab From d39ed42763ab9bb0328057437e43ee82db5f67e5 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 3 Jan 2022 16:13:22 -0500 Subject: [PATCH 21/31] Proto,Tx_rollup: Full inbox test Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- .../integration/operations/test_tx_rollup.ml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index 71dcf0968e04..d8dc9d85b570 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -1091,6 +1091,42 @@ let test_bond_finalization () = ignore i ; return () +let test_full_inbox () = + let constants = + { + Tezos_protocol_alpha_parameters.Default_parameters.constants_test with + consensus_threshold = 0; + endorsing_reward_per_slot = Tez.zero; + baking_reward_bonus_per_slot = Tez.zero; + baking_reward_fixed_portion = Tez.zero; + tx_rollup_enable = true; + tx_rollup_max_unfinalized_levels = 15; + } + in + Context.init_with_constants constants 1 >>=? fun (b, contracts) -> + let contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + originate b contract >>=? fun (b, tx_rollup) -> + let range start top = + let rec aux n acc = if n < start then acc else aux (n - 1) (n :: acc) in + aux top [] + in + (* Transactions in blocks [2..17) *) + make_transactions_in tx_rollup contract (range 2 17) b >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + Op.tx_rollup_submit_batch (B b) contract tx_rollup "contents" >>=? fun op -> + Incremental.add_operation i op ~expect_failure:(function + | Environment.Ecoproto_error + (Tx_rollup_commitments.Too_many_unfinalized_levels as e) + :: _ -> + Assert.test_error_encodings e ; + return_unit + | _ -> failwith "Need to avoid too many unfinalized inboxes") + >>=? fun i -> + ignore i ; + return () + let tests = [ Tztest.tztest @@ -1137,4 +1173,5 @@ let tests = `Quick test_commitment_acceptance; Tztest.tztest "Test bond finalization" `Quick test_bond_finalization; + Tztest.tztest "Test full inbox" `Quick test_full_inbox; ] -- GitLab From d1c363db952c5b650648dc6f9bed04938561532b Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 24 Jan 2022 11:04:08 -0500 Subject: [PATCH 22/31] Proto,tx_rollup: Max levels to finalize constant Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- src/proto_alpha/lib_client/mockup.ml | 22 +- .../lib_parameters/default_parameters.ml | 1 + .../lib_protocol/alpha_context.mli | 3 + .../lib_protocol/constants_repr.ml | 15 +- .../lib_protocol/constants_repr.mli | 1 + .../lib_protocol/constants_storage.ml | 4 + .../lib_protocol/constants_storage.mli | 2 + src/proto_alpha/lib_protocol/raw_context.ml | 1 + tests_python/tests_alpha/test_mockup.py | 1 + .../_regressions/rpc/alpha.client.mempool.out | 190 ++++++++++++++++++ tezt/_regressions/rpc/alpha.client.others.out | 6 +- tezt/_regressions/rpc/alpha.light.others.out | 6 +- tezt/_regressions/rpc/alpha.proxy.mempool.out | 190 ++++++++++++++++++ tezt/_regressions/rpc/alpha.proxy.others.out | 6 +- .../rpc/alpha.proxy_server.others.out | 6 +- 15 files changed, 438 insertions(+), 16 deletions(-) diff --git a/src/proto_alpha/lib_client/mockup.ml b/src/proto_alpha/lib_client/mockup.ml index 1e627d02e128..b47e45e998cf 100644 --- a/src/proto_alpha/lib_client/mockup.ml +++ b/src/proto_alpha/lib_client/mockup.ml @@ -78,6 +78,7 @@ module Protocol_constants_overrides = struct tx_rollup_commitment_bond : Tez.t option; tx_rollup_finality_period : int option; tx_rollup_max_unfinalized_levels : int option; + tx_rollup_max_finalize_levels_per_commitment : int option; sc_rollup_enable : bool option; sc_rollup_origination_size : int option; (* Additional, "bastard" parameters (they are not protocol constants but partially treated the same way). *) @@ -135,7 +136,8 @@ module Protocol_constants_overrides = struct c.tx_rollup_hard_size_limit_per_message, c.tx_rollup_commitment_bond, c.tx_rollup_finality_period, - c.tx_rollup_max_unfinalized_levels ), + c.tx_rollup_max_unfinalized_levels, + c.tx_rollup_max_finalize_levels_per_commitment ), (c.sc_rollup_enable, c.sc_rollup_origination_size) ) ) ) ) ) )) (fun ( ( preserved_cycles, @@ -182,7 +184,8 @@ module Protocol_constants_overrides = struct tx_rollup_hard_size_limit_per_message, tx_rollup_commitment_bond, tx_rollup_finality_period, - tx_rollup_max_unfinalized_levels ), + tx_rollup_max_unfinalized_levels, + tx_rollup_max_finalize_levels_per_commitment ), (sc_rollup_enable, sc_rollup_origination_size) ) ) ) ) ) ) -> { @@ -228,6 +231,7 @@ module Protocol_constants_overrides = struct tx_rollup_commitment_bond; tx_rollup_finality_period; tx_rollup_max_unfinalized_levels; + tx_rollup_max_finalize_levels_per_commitment; sc_rollup_enable; sc_rollup_origination_size; chain_id; @@ -287,14 +291,17 @@ module Protocol_constants_overrides = struct (opt "cache_stake_distribution_cycles" int8) (opt "cache_sampler_state_cycles" int8)) (merge_objs - (obj7 + (obj8 (opt "tx_rollup_enable" Data_encoding.bool) (opt "tx_rollup_origination_size" int31) (opt "tx_rollup_hard_size_limit_per_inbox" int31) (opt "tx_rollup_hard_size_limit_per_message" int31) (opt "tx_rollup_commitment_bond" Tez.encoding) (opt "tx_rollup_finality_period" int31) - (opt "tx_rollup_max_unfinalized_levels" int31)) + (opt "tx_rollup_max_unfinalized_levels" int31) + (opt + "tx_rollup_max_finalize_levels_per_commitment" + int31)) (obj2 (opt "sc_rollup_enable" bool) (opt "sc_rollup_origination_size" int31)))))))) @@ -370,6 +377,8 @@ module Protocol_constants_overrides = struct tx_rollup_finality_period = Some parametric.tx_rollup_finality_period; tx_rollup_max_unfinalized_levels = Some parametric.tx_rollup_max_unfinalized_levels; + tx_rollup_max_finalize_levels_per_commitment = + Some parametric.tx_rollup_max_finalize_levels_per_commitment; sc_rollup_enable = Some parametric.sc_rollup_enable; sc_rollup_origination_size = Some parametric.sc_rollup_origination_size; (* Bastard additional parameters. *) @@ -424,6 +433,7 @@ module Protocol_constants_overrides = struct tx_rollup_commitment_bond = None; tx_rollup_finality_period = None; tx_rollup_max_unfinalized_levels = None; + tx_rollup_max_finalize_levels_per_commitment = None; sc_rollup_enable = None; sc_rollup_origination_size = None; chain_id = None; @@ -844,6 +854,10 @@ module Protocol_constants_overrides = struct Option.value ~default:c.tx_rollup_max_unfinalized_levels o.tx_rollup_max_unfinalized_levels; + tx_rollup_max_finalize_levels_per_commitment = + Option.value + ~default:c.tx_rollup_max_finalize_levels_per_commitment + o.tx_rollup_max_finalize_levels_per_commitment; sc_rollup_enable = Option.value ~default:c.sc_rollup_enable o.sc_rollup_enable; sc_rollup_origination_size = diff --git a/src/proto_alpha/lib_parameters/default_parameters.ml b/src/proto_alpha/lib_parameters/default_parameters.ml index e740c80a3530..2bdd893301fd 100644 --- a/src/proto_alpha/lib_parameters/default_parameters.ml +++ b/src/proto_alpha/lib_parameters/default_parameters.ml @@ -107,6 +107,7 @@ let constants_mainnet = tx_rollup_commitment_bond = Tez.of_mutez_exn 10_000_000_000L; tx_rollup_finality_period = 2_000; tx_rollup_max_unfinalized_levels = 2_100; + tx_rollup_max_finalize_levels_per_commitment = 5; sc_rollup_enable = false; (* The following value is chosen to prevent spam. *) sc_rollup_origination_size = 6_314; diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 95efe05aa877..2286226dc520 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -784,6 +784,7 @@ module Constants : sig tx_rollup_commitment_bond : Tez.t; tx_rollup_finality_period : int; tx_rollup_max_unfinalized_levels : int; + tx_rollup_max_finalize_levels_per_commitment : int; sc_rollup_enable : bool; sc_rollup_origination_size : int; } @@ -881,6 +882,8 @@ module Constants : sig val tx_rollup_max_unfinalized_levels : context -> int + val tx_rollup_max_finalize_levels_per_commitment : context -> int + val sc_rollup_enable : context -> bool val sc_rollup_origination_size : context -> int diff --git a/src/proto_alpha/lib_protocol/constants_repr.ml b/src/proto_alpha/lib_protocol/constants_repr.ml index 68a8db63b88f..09df17a408c5 100644 --- a/src/proto_alpha/lib_protocol/constants_repr.ml +++ b/src/proto_alpha/lib_protocol/constants_repr.ml @@ -165,6 +165,7 @@ type parametric = { tx_rollup_commitment_bond : Tez_repr.t; tx_rollup_finality_period : int; tx_rollup_max_unfinalized_levels : int; + tx_rollup_max_finalize_levels_per_commitment : int; sc_rollup_enable : bool; sc_rollup_origination_size : int; } @@ -215,7 +216,8 @@ let parametric_encoding = c.tx_rollup_hard_size_limit_per_message, c.tx_rollup_commitment_bond, c.tx_rollup_finality_period, - c.tx_rollup_max_unfinalized_levels ), + c.tx_rollup_max_unfinalized_levels, + c.tx_rollup_max_finalize_levels_per_commitment ), (c.sc_rollup_enable, c.sc_rollup_origination_size) ) ) ) ) ) )) (fun ( ( preserved_cycles, @@ -260,7 +262,8 @@ let parametric_encoding = tx_rollup_hard_size_limit_per_message, tx_rollup_commitment_bond, tx_rollup_finality_period, - tx_rollup_max_unfinalized_levels ), + tx_rollup_max_unfinalized_levels, + tx_rollup_max_finalize_levels_per_commitment ), (sc_rollup_enable, sc_rollup_origination_size) ) ) ) ) ) ) -> { preserved_cycles; @@ -306,6 +309,7 @@ let parametric_encoding = tx_rollup_commitment_bond; tx_rollup_finality_period; tx_rollup_max_unfinalized_levels; + tx_rollup_max_finalize_levels_per_commitment; sc_rollup_enable; sc_rollup_origination_size; }) @@ -362,14 +366,17 @@ let parametric_encoding = (req "cache_stake_distribution_cycles" int8) (req "cache_sampler_state_cycles" int8)) (merge_objs - (obj7 + (obj8 (req "tx_rollup_enable" bool) (req "tx_rollup_origination_size" int31) (req "tx_rollup_hard_size_limit_per_inbox" int31) (req "tx_rollup_hard_size_limit_per_message" int31) (req "tx_rollup_commitment_bond" Tez_repr.encoding) (req "tx_rollup_finality_period" int31) - (req "tx_rollup_max_unfinalized_levels" int31)) + (req "tx_rollup_max_unfinalized_levels" int31) + (req + "tx_rollup_max_finalize_levels_per_commitment" + int31)) (obj2 (req "sc_rollup_enable" bool) (req "sc_rollup_origination_size" int31)))))))) diff --git a/src/proto_alpha/lib_protocol/constants_repr.mli b/src/proto_alpha/lib_protocol/constants_repr.mli index 4b1757c614b2..c94e2bb5a60f 100644 --- a/src/proto_alpha/lib_protocol/constants_repr.mli +++ b/src/proto_alpha/lib_protocol/constants_repr.mli @@ -131,6 +131,7 @@ type parametric = { tx_rollup_commitment_bond : Tez_repr.t; tx_rollup_finality_period : int; tx_rollup_max_unfinalized_levels : int; + tx_rollup_max_finalize_levels_per_commitment : int; sc_rollup_enable : bool; sc_rollup_origination_size : int; } diff --git a/src/proto_alpha/lib_protocol/constants_storage.ml b/src/proto_alpha/lib_protocol/constants_storage.ml index 5ec3646f6d79..73ad981f01d4 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.ml +++ b/src/proto_alpha/lib_protocol/constants_storage.ml @@ -173,6 +173,10 @@ let tx_rollup_max_unfinalized_levels c = let constants = Raw_context.constants c in constants.tx_rollup_max_unfinalized_levels +let tx_rollup_max_finalize_levels_per_commitment c = + let constants = Raw_context.constants c in + constants.tx_rollup_max_finalize_levels_per_commitment + let ratio_of_frozen_deposits_slashed_per_double_endorsement c = let constants = Raw_context.constants c in constants.ratio_of_frozen_deposits_slashed_per_double_endorsement diff --git a/src/proto_alpha/lib_protocol/constants_storage.mli b/src/proto_alpha/lib_protocol/constants_storage.mli index 0b8fe1a63cb3..a0820abd0083 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.mli +++ b/src/proto_alpha/lib_protocol/constants_storage.mli @@ -97,6 +97,8 @@ val tx_rollup_finality_period : Raw_context.t -> int val tx_rollup_max_unfinalized_levels : Raw_context.t -> int +val tx_rollup_max_finalize_levels_per_commitment : Raw_context.t -> int + val ratio_of_frozen_deposits_slashed_per_double_endorsement : Raw_context.t -> Constants_repr.ratio diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index c93f69b63494..45ddcae1749e 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -884,6 +884,7 @@ let prepare_first_block ~level ~timestamp ctxt = tx_rollup_commitment_bond = Tez_repr.of_mutez_exn 10_000_000_000L; tx_rollup_finality_period = 2_000; tx_rollup_max_unfinalized_levels = 2_100; + tx_rollup_max_finalize_levels_per_commitment = 5; sc_rollup_enable = false; (* The following value is chosen to prevent spam. *) sc_rollup_origination_size = 6_314; diff --git a/tests_python/tests_alpha/test_mockup.py b/tests_python/tests_alpha/test_mockup.py index db0d2d42573f..8467d00de072 100644 --- a/tests_python/tests_alpha/test_mockup.py +++ b/tests_python/tests_alpha/test_mockup.py @@ -662,6 +662,7 @@ def _test_create_mockup_init_show_roundtrip( "tx_rollup_commitment_bond": "10000000000", "tx_rollup_finality_period": 2000, "tx_rollup_max_unfinalized_levels": 2100, + "tx_rollup_max_finalize_levels_per_commitment": 5, "sc_rollup_enable": False, "sc_rollup_origination_size": 6_314, } diff --git a/tezt/_regressions/rpc/alpha.client.mempool.out b/tezt/_regressions/rpc/alpha.client.mempool.out index 9b3b2d8dca42..9b820fb8f822 100644 --- a/tezt/_regressions/rpc/alpha.client.mempool.out +++ b/tezt/_regressions/rpc/alpha.client.mempool.out @@ -1945,9 +1945,14 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "type": "null" } ] + }, + "inbox_hash": { + "type": "string", + "pattern": "^([a-zA-Z0-9][a-zA-Z0-9])*$" } }, "required": [ + "inbox_hash", "predecessor", "batches", "level" @@ -1967,6 +1972,46 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "additionalProperties": false }, + { + "title": "Tx_rollup_return_bond", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "tx_rollup_return_bond" + ] + }, + "source": { + "$ref": "#/definitions/Signature.Public_key_hash" + }, + "fee": { + "$ref": "#/definitions/alpha.mutez" + }, + "counter": { + "$ref": "#/definitions/positive_bignum" + }, + "gas_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "storage_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "rollup": { + "$ref": "#/definitions/alpha.tx_rollup_id" + } + }, + "required": [ + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false + }, { "title": "Sc_rollup_originate", "type": "object", @@ -2592,6 +2637,21 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "kind": "Dynamic" }, "kind": "named" + }, + { + "kind": "dyn", + "num_fields": 1, + "size": "Uint30" + }, + { + "name": "inbox_hash", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "kind": "Variable" + }, + "kind": "named" } ] } @@ -4982,6 +5042,91 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "name": "Tx_rollup_commit" }, + { + "tag": 153, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "source", + "layout": { + "name": "public_key_hash", + "kind": "Ref" + }, + "data_kind": { + "size": 21, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "fee", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "counter", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "gas_limit", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "storage_limit", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "rollup", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 20, + "kind": "Float" + }, + "kind": "named" + } + ], + "name": "Tx_rollup_return_bond" + }, { "tag": 200, "fields": [ @@ -7182,9 +7327,14 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "type": "null" } ] + }, + "inbox_hash": { + "type": "string", + "pattern": "^([a-zA-Z0-9][a-zA-Z0-9])*$" } }, "required": [ + "inbox_hash", "predecessor", "batches", "level" @@ -7204,6 +7354,46 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "additionalProperties": false }, + { + "title": "Tx_rollup_return_bond", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "tx_rollup_return_bond" + ] + }, + "source": { + "$ref": "#/definitions/Signature.Public_key_hash" + }, + "fee": { + "$ref": "#/definitions/alpha.mutez" + }, + "counter": { + "$ref": "#/definitions/positive_bignum" + }, + "gas_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "storage_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "rollup": { + "$ref": "#/definitions/alpha.tx_rollup_id" + } + }, + "required": [ + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false + }, { "title": "Sc_rollup_originate", "type": "object", diff --git a/tezt/_regressions/rpc/alpha.client.others.out b/tezt/_regressions/rpc/alpha.client.others.out index 5092389d9005..a01256c93202 100644 --- a/tezt/_regressions/rpc/alpha.client.others.out +++ b/tezt/_regressions/rpc/alpha.client.others.out @@ -33,8 +33,10 @@ tezt/_regressions/rpc/alpha.client.others.out "tx_rollup_hard_size_limit_per_inbox": 100000, "tx_rollup_hard_size_limit_per_message": 5000, "tx_rollup_commitment_bond": "10000000000", - "tx_rollup_finality_period": 2000, "sc_rollup_enable": false, - "sc_rollup_origination_size": 6314 } + "tx_rollup_finality_period": 2000, + "tx_rollup_max_unfinalized_levels": 2100, + "tx_rollup_max_finalize_levels_per_commitment": 5, + "sc_rollup_enable": false, "sc_rollup_origination_size": 6314 } ./tezos-client rpc get /chains/main/blocks/head/helpers/baking_rights [ { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", diff --git a/tezt/_regressions/rpc/alpha.light.others.out b/tezt/_regressions/rpc/alpha.light.others.out index 231a443e94fa..97dc668b2ce1 100644 --- a/tezt/_regressions/rpc/alpha.light.others.out +++ b/tezt/_regressions/rpc/alpha.light.others.out @@ -34,8 +34,10 @@ protocol of light mode unspecified, using the node's protocol: ProtoGenesisGenes "tx_rollup_hard_size_limit_per_inbox": 100000, "tx_rollup_hard_size_limit_per_message": 5000, "tx_rollup_commitment_bond": "10000000000", - "tx_rollup_finality_period": 2000, "sc_rollup_enable": false, - "sc_rollup_origination_size": 6314 } + "tx_rollup_finality_period": 2000, + "tx_rollup_max_unfinalized_levels": 2100, + "tx_rollup_max_finalize_levels_per_commitment": 5, + "sc_rollup_enable": false, "sc_rollup_origination_size": 6314 } ./tezos-client --mode light rpc get /chains/main/blocks/head/helpers/baking_rights protocol of light mode unspecified, using the node's protocol: ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im diff --git a/tezt/_regressions/rpc/alpha.proxy.mempool.out b/tezt/_regressions/rpc/alpha.proxy.mempool.out index 6ae0b149b08b..f593d1b3b54f 100644 --- a/tezt/_regressions/rpc/alpha.proxy.mempool.out +++ b/tezt/_regressions/rpc/alpha.proxy.mempool.out @@ -1966,9 +1966,14 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "type": "null" } ] + }, + "inbox_hash": { + "type": "string", + "pattern": "^([a-zA-Z0-9][a-zA-Z0-9])*$" } }, "required": [ + "inbox_hash", "predecessor", "batches", "level" @@ -1988,6 +1993,46 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "additionalProperties": false }, + { + "title": "Tx_rollup_return_bond", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "tx_rollup_return_bond" + ] + }, + "source": { + "$ref": "#/definitions/Signature.Public_key_hash" + }, + "fee": { + "$ref": "#/definitions/alpha.mutez" + }, + "counter": { + "$ref": "#/definitions/positive_bignum" + }, + "gas_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "storage_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "rollup": { + "$ref": "#/definitions/alpha.tx_rollup_id" + } + }, + "required": [ + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false + }, { "title": "Sc_rollup_originate", "type": "object", @@ -2613,6 +2658,21 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "kind": "Dynamic" }, "kind": "named" + }, + { + "kind": "dyn", + "num_fields": 1, + "size": "Uint30" + }, + { + "name": "inbox_hash", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "kind": "Variable" + }, + "kind": "named" } ] } @@ -5003,6 +5063,91 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "name": "Tx_rollup_commit" }, + { + "tag": 153, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "source", + "layout": { + "name": "public_key_hash", + "kind": "Ref" + }, + "data_kind": { + "size": 21, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "fee", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "counter", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "gas_limit", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "storage_limit", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "rollup", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 20, + "kind": "Float" + }, + "kind": "named" + } + ], + "name": "Tx_rollup_return_bond" + }, { "tag": 200, "fields": [ @@ -7203,9 +7348,14 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "type": "null" } ] + }, + "inbox_hash": { + "type": "string", + "pattern": "^([a-zA-Z0-9][a-zA-Z0-9])*$" } }, "required": [ + "inbox_hash", "predecessor", "batches", "level" @@ -7225,6 +7375,46 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "additionalProperties": false }, + { + "title": "Tx_rollup_return_bond", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "tx_rollup_return_bond" + ] + }, + "source": { + "$ref": "#/definitions/Signature.Public_key_hash" + }, + "fee": { + "$ref": "#/definitions/alpha.mutez" + }, + "counter": { + "$ref": "#/definitions/positive_bignum" + }, + "gas_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "storage_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "rollup": { + "$ref": "#/definitions/alpha.tx_rollup_id" + } + }, + "required": [ + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false + }, { "title": "Sc_rollup_originate", "type": "object", diff --git a/tezt/_regressions/rpc/alpha.proxy.others.out b/tezt/_regressions/rpc/alpha.proxy.others.out index a6f8251ece3a..d3691de0dabc 100644 --- a/tezt/_regressions/rpc/alpha.proxy.others.out +++ b/tezt/_regressions/rpc/alpha.proxy.others.out @@ -34,8 +34,10 @@ protocol of proxy unspecified, using the node's protocol: ProtoGenesisGenesisGen "tx_rollup_hard_size_limit_per_inbox": 100000, "tx_rollup_hard_size_limit_per_message": 5000, "tx_rollup_commitment_bond": "10000000000", - "tx_rollup_finality_period": 2000, "sc_rollup_enable": false, - "sc_rollup_origination_size": 6314 } + "tx_rollup_finality_period": 2000, + "tx_rollup_max_unfinalized_levels": 2100, + "tx_rollup_max_finalize_levels_per_commitment": 5, + "sc_rollup_enable": false, "sc_rollup_origination_size": 6314 } ./tezos-client --mode proxy rpc get /chains/main/blocks/head/helpers/baking_rights protocol of proxy unspecified, using the node's protocol: ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im diff --git a/tezt/_regressions/rpc/alpha.proxy_server.others.out b/tezt/_regressions/rpc/alpha.proxy_server.others.out index f24ff71a7f96..b1fe7ca966e0 100644 --- a/tezt/_regressions/rpc/alpha.proxy_server.others.out +++ b/tezt/_regressions/rpc/alpha.proxy_server.others.out @@ -33,8 +33,10 @@ tezt/_regressions/rpc/alpha.proxy_server.others.out "tx_rollup_hard_size_limit_per_inbox": 100000, "tx_rollup_hard_size_limit_per_message": 5000, "tx_rollup_commitment_bond": "10000000000", - "tx_rollup_finality_period": 2000, "sc_rollup_enable": false, - "sc_rollup_origination_size": 6314 } + "tx_rollup_finality_period": 2000, + "tx_rollup_max_unfinalized_levels": 2100, + "tx_rollup_max_finalize_levels_per_commitment": 5, + "sc_rollup_enable": false, "sc_rollup_origination_size": 6314 } ./tezos-client rpc get /chains/main/blocks/head/helpers/baking_rights [ { "level": 3, "delegate": "[PUBLIC_KEY_HASH]", -- GitLab From 7ed952dd977d5c168cf3f750159775e553bc324d Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 3 Jan 2022 16:13:22 -0500 Subject: [PATCH 23/31] Proto,Tx_rollup: Limit the number of commitments to finalize at once Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- .../lib_protocol/tx_rollup_commitments_storage.ml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml index 4f7906eed1f0..80c580f205c6 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml @@ -226,11 +226,16 @@ let finalize_pending_commitments ctxt tx_rollup last_level_to_finalize = let first_unfinalized_level = Tx_rollup_state_repr.first_unfinalized_level state in + let max_count_to_finalize = + Constants_storage.tx_rollup_max_finalize_levels_per_commitment ctxt + in match first_unfinalized_level with | None -> return ctxt | Some first_unfinalized_level -> let rec finalize_level ctxt level top finalized_count = - if Raw_level_repr.(level > top) then + if Compare.Int.(finalized_count >= max_count_to_finalize) then + return (ctxt, finalized_count, Some level) + else if Raw_level_repr.(level > top) then return (ctxt, finalized_count, Some level) else retire_rollup_level ctxt tx_rollup level last_level_to_finalize -- GitLab From b6689a2853cbda062dccf998d74582af7f7989b1 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 14 Feb 2022 16:40:05 -0500 Subject: [PATCH 24/31] Proto,Tx_rollup: Inbox hashes Identify inboxes by their hash. Instead of relying on tenderbake for inbox finality, we can instead condition commitments on (the hash of) inbox contents, and fail commitments which don't match their inbox. Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- src/proto_alpha/lib_protocol/alpha_context.ml | 5 + .../lib_protocol/alpha_context.mli | 33 ++++ .../integration/operations/test_tx_rollup.ml | 143 ++++++++---------- .../tx_rollup_commitments_repr.ml | 53 +++++-- .../tx_rollup_commitments_repr.mli | 3 + .../tx_rollup_commitments_storage.ml | 11 +- .../lib_protocol/tx_rollup_inbox_repr.ml | 38 ++++- .../lib_protocol/tx_rollup_inbox_repr.mli | 28 +++- .../lib_protocol/tx_rollup_inbox_storage.ml | 23 ++- .../lib_protocol/tx_rollup_inbox_storage.mli | 8 + .../tx_rollup_simple_use_case.out | 4 +- 11 files changed, 241 insertions(+), 108 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index 18c99e8f7258..ca21ac3faa75 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -268,6 +268,11 @@ end module Tx_rollup_inbox = struct include Tx_rollup_inbox_repr include Tx_rollup_inbox_storage + + module Internal_for_tests = struct + include Tx_rollup_inbox_repr + include Tx_rollup_inbox_storage + end end module Tx_rollup_commitments = struct diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 2286226dc520..7bcf147c4361 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2068,6 +2068,20 @@ end module Tx_rollup_inbox : sig type t = {contents : Tx_rollup_message.hash list; cumulated_size : int} + module Hash : sig + type t + + include Compare.S with type t := t + + val pp : Format.formatter -> t -> unit + + val empty : t + + val encoding : t Data_encoding.t + + val extend : t -> Tx_rollup_message.hash -> t + end + val pp : Format.formatter -> t -> unit val encoding : t Data_encoding.t @@ -2109,6 +2123,22 @@ module Tx_rollup_inbox : sig Tx_rollup.t -> (context * Raw_level.t option * Raw_level.t option) tzresult Lwt.t + module Internal_for_tests : sig + type metadata = { + count : int; + cumulated_size : int; + hash : Hash.t; + predecessor : Raw_level_repr.t option; + successor : Raw_level_repr.t option; + } + + val get_metadata : + context -> + Raw_level.t -> + Tx_rollup.t -> + (context * metadata) tzresult Lwt.t + end + type error += | Tx_rollup_inbox_does_not_exist of Tx_rollup.t * Raw_level.t | Tx_rollup_inbox_size_would_exceed_limit of Tx_rollup.t @@ -2132,6 +2162,7 @@ module Tx_rollup_commitments : sig level : Raw_level.t; batches : batch_commitment list; predecessor : Commitment_hash.t option; + inbox_hash : Tx_rollup_inbox.Hash.t; } val ( = ) : t -> t -> bool @@ -2164,6 +2195,8 @@ module Tx_rollup_commitments : sig type error += Wrong_batch_count + type error += Wrong_inbox_hash + type error += Commitment_too_early of Raw_level.t * Raw_level.t type error += Bond_does_not_exist of Signature.public_key_hash diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index d8dc9d85b570..1ee2463b696d 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -190,6 +190,41 @@ let assert_retired retired = | `Retired -> return_unit | _ -> failwith "Expected retired" +(* Make a valid commitment for a batch. TODO/TORU: roots are still + wrong, of course, until we get Merkle proofs*) +let make_commitment_for_batch i level tx_rollup = + let ctxt = Incremental.alpha_ctxt i in + wrap + (Alpha_context.Tx_rollup_inbox.Internal_for_tests.get_metadata + ctxt + level + tx_rollup) + >>=? fun (ctxt, metadata) -> + Lwt.return + @@ List.init ~when_negative_length:[] metadata.count (fun i -> + let batch : Tx_rollup_commitments.Commitment.batch_commitment = + {root = Bytes.make 20 (Char.chr i)} + in + batch) + >>=? fun batches -> + (match metadata.predecessor with + | None -> return_none + | Some predecessor_level -> ( + wrap + (Lwt.return + @@ Raw_level.of_int32 (Raw_level_repr.to_int32 predecessor_level)) + >>=? fun predecessor_level -> + wrap + (Tx_rollup_commitments.get_commitments ctxt tx_rollup predecessor_level) + >|=? function + | (_, []) -> None + | (_, hd :: _) -> Some hd.hash)) + >>=? fun predecessor -> + let commitment : Tx_rollup_commitments.Commitment.t = + {level; batches; predecessor; inbox_hash = metadata.hash} + in + return commitment + (** ---- TESTS -------------------------------------------------------------- *) (** [test_origination] originates a transaction rollup and checks that @@ -610,23 +645,12 @@ let test_commitment_duplication () = let contents = "batch" in Op.tx_rollup_submit_batch (B b) contract1 tx_rollup contents >>=? fun operation -> + let level = raw_level 2l in Block.bake ~operation b >>=? fun b -> Incremental.begin_construction b >>=? fun i -> - let level_opt = - Raw_level.pred (Level.current (Incremental.alpha_ctxt i)).level - in - (* Need an extra block here to ensure finality *) Incremental.finalize_block i >>=? fun b -> Incremental.begin_construction b >>=? fun i -> - let level = - match level_opt with None -> assert false | Some level -> level - in - let batches : Tx_rollup_commitments.Commitment.batch_commitment list = - [{root = Bytes.make 20 '0'}] - in - let commitment : Tx_rollup_commitments.Commitment.t = - {level; batches; predecessor = None} - in + make_commitment_for_batch i level tx_rollup >>=? fun commitment -> let submitted_level = (Level.current (Incremental.alpha_ctxt i)).level in Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> Incremental.add_operation i op >>=? fun i -> @@ -646,9 +670,7 @@ let test_commitment_duplication () = let batches2 : Tx_rollup_commitments.Commitment.batch_commitment list = [{root = Bytes.make 20 '1'}] in - let commitment2 : Tx_rollup_commitments.Commitment.t = - {level; batches = batches2; predecessor = None} - in + let commitment2 = {commitment with batches = batches2} in (* Successfully fail to submit a different commitment from contract1 *) Op.tx_rollup_commit (I i) contract1 tx_rollup commitment2 >>=? fun op -> Incremental.add_operation i op ~expect_failure:(function @@ -663,7 +685,7 @@ let test_commitment_duplication () = [{root = Bytes.make 20 '1'}; {root = Bytes.make 20 '2'}] in let commitment3 : Tx_rollup_commitments.Commitment.t = - {level; batches = batches3; predecessor = None} + {commitment2 with batches = batches3} in (* Successfully fail to submit a different commitment from contract2 *) Op.tx_rollup_commit (I i) contract2 tx_rollup commitment3 >>=? fun op -> @@ -729,16 +751,14 @@ let test_commitment_predecessor () = (* Transactions in blocks 2, 3, 6 *) make_transactions_in tx_rollup contract1 [2; 3; 6] b >>=? fun b -> Incremental.begin_construction b >>=? fun i -> - (* Check error: Commitment with predecessor for first block *) - let batches : Tx_rollup_commitments.Commitment.batch_commitment list = - [{root = Bytes.make 20 '0'}] - in + (* Check error: Commitment for nonexistent block *) let some_hash = Tx_rollup_commitments.Commitment_hash.of_bytes_exn (Bytes.of_string "tcu1deadbeefdeadbeefdeadbeefdead") in - let commitment : Tx_rollup_commitments.Commitment.t = - {level = raw_level 1l; batches; predecessor = Some some_hash} + make_commitment_for_batch i (raw_level 2l) tx_rollup >>=? fun commitment -> + let commitment = + {commitment with level = raw_level 1l; predecessor = Some some_hash} in Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> let error = @@ -751,9 +771,8 @@ let test_commitment_predecessor () = | _ -> failwith "Need to check commitment predecessor") >>=? fun i -> (* Commitment without predecessor for block with predecessor*) - let commitment : Tx_rollup_commitments.Commitment.t = - {level = raw_level 3l; batches; predecessor = None} - in + make_commitment_for_batch i (raw_level 3l) tx_rollup >>=? fun commitment -> + let commitment = {commitment with predecessor = None} in Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> Incremental.add_operation i op ~expect_failure:(function | Environment.Ecoproto_error @@ -764,9 +783,8 @@ let test_commitment_predecessor () = | _ -> failwith "Need to check commitment predecessor") >>=? fun i -> (* Commitment refers to a predecessor which does not exist *) - let commitment : Tx_rollup_commitments.Commitment.t = - {level = raw_level 3l; batches; predecessor = Some some_hash} - in + make_commitment_for_batch i (raw_level 3l) tx_rollup >>=? fun commitment -> + let commitment = {commitment with predecessor = Some some_hash} in Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> Incremental.add_operation i op ~expect_failure:(function | Environment.Ecoproto_error @@ -778,7 +796,7 @@ let test_commitment_predecessor () = >>=? fun i -> (* Try to commit to an empty level between full ones *) let commitment : Tx_rollup_commitments.Commitment.t = - {level = raw_level 5l; batches; predecessor = Some some_hash} + {commitment with level = raw_level 5l} in Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> let error = @@ -823,13 +841,7 @@ let test_commitment_retire_simple () = | `No_commitment -> return_unit | _ -> failwith "Expected no commitment") >>=? fun () -> - (* Now, make a commitment *) - let batches : Tx_rollup_commitments.Commitment.batch_commitment list = - [{root = Bytes.make 20 '0'}] - in - let commitment : Tx_rollup_commitments.Commitment.t = - {level; batches; predecessor = None} - in + make_commitment_for_batch i level tx_rollup >>=? fun commitment -> Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> Incremental.add_operation i op >>=? fun i -> let commitment_submit_level = @@ -879,31 +891,21 @@ let test_commitment_retire_complex () = make_transactions_in tx_rollup contract1 [2; 3; 6] b >>=? fun b -> Incremental.begin_construction b >>=? fun i -> let batches : Tx_rollup_commitments.Commitment.batch_commitment list = - [{root = Bytes.make 20 '0'}] - in - let batches2 : Tx_rollup_commitments.Commitment.batch_commitment list = - [{root = Bytes.make 20 '1'}] - in - let commitment_a : Tx_rollup_commitments.Commitment.t = - {level = raw_level 2l; batches; predecessor = None} + [{root = Bytes.make 20 '5'}] in + make_commitment_for_batch i (raw_level 2l) tx_rollup >>=? fun commitment_a -> Op.tx_rollup_commit (I i) contract1 tx_rollup commitment_a >>=? fun op -> Incremental.add_operation i op >>=? fun i -> - let commitment_b : Tx_rollup_commitments.Commitment.t = - {level = raw_level 2l; batches = batches2; predecessor = None} - in + let commitment_b = {commitment_a with batches} in Op.tx_rollup_commit (I i) contract2 tx_rollup commitment_b >>=? fun op -> Incremental.add_operation i op >>=? fun i -> - let predecessor = Tx_rollup_commitments.Commitment.hash commitment_a in - let commitment_c : Tx_rollup_commitments.Commitment.t = - {level = raw_level 3l; batches; predecessor = Some predecessor} - in + make_commitment_for_batch i (raw_level 3l) tx_rollup >>=? fun commitment_c -> Op.tx_rollup_commit (I i) contract2 tx_rollup commitment_c >>=? fun op -> Incremental.add_operation i op >>=? fun i -> let predecessor = Tx_rollup_commitments.Commitment.hash commitment_b in let commitment_d : Tx_rollup_commitments.Commitment.t = - {level = raw_level 3l; batches; predecessor = Some predecessor} + {commitment_c with predecessor = Some predecessor} in Op.tx_rollup_commit (I i) contract1 tx_rollup commitment_d >>=? fun op -> Incremental.add_operation i op >>=? fun i -> @@ -911,15 +913,16 @@ let test_commitment_retire_complex () = Incremental.finalize_block i >>=? fun b -> Incremental.begin_construction b >>=? fun i -> let predecessor = Tx_rollup_commitments.Commitment.hash commitment_d in - + make_commitment_for_batch i (raw_level 6l) tx_rollup >>=? fun commitment_e -> let commitment_e : Tx_rollup_commitments.Commitment.t = - {level = raw_level 6l; batches; predecessor = Some predecessor} + {commitment_e with predecessor = Some predecessor} in Op.tx_rollup_commit (I i) contract2 tx_rollup commitment_e >>=? fun op -> Incremental.add_operation i op >>=? fun i -> let predecessor = Tx_rollup_commitments.Commitment.hash commitment_c in + make_commitment_for_batch i (raw_level 6l) tx_rollup >>=? fun commitment_f -> let commitment_f : Tx_rollup_commitments.Commitment.t = - {level = raw_level 6l; batches; predecessor = Some predecessor} + {commitment_f with predecessor = Some predecessor} in Op.tx_rollup_commit (I i) contract1 tx_rollup commitment_f >>=? fun op -> Incremental.add_operation i op >>=? fun i -> @@ -978,34 +981,25 @@ let test_commitment_acceptance () = originate b contract1 >>=? fun (b, tx_rollup) -> make_transactions_in tx_rollup contract1 [2; 3] b >>=? fun b -> Incremental.begin_construction b >>=? fun i -> - (* Need an extra block here to ensure finality *) Incremental.finalize_block i >>=? fun b -> Incremental.begin_construction b >>=? fun i -> - let batches1 : Tx_rollup_commitments.Commitment.batch_commitment list = - [{root = Bytes.make 20 '0'}] - in - let batches2 : Tx_rollup_commitments.Commitment.batch_commitment list = - [{root = Bytes.make 20 '1'}] - in - let commitment_a : Tx_rollup_commitments.Commitment.t = - {level = raw_level 2l; batches = batches1; predecessor = None} - in + make_commitment_for_batch i (raw_level 2l) tx_rollup >>=? fun commitment_a -> Op.tx_rollup_commit (I i) contract1 tx_rollup commitment_a >>=? fun op -> Incremental.add_operation i op >>=? fun i -> + let batches : Tx_rollup_commitments.Commitment.batch_commitment list = + [{root = Bytes.make 20 '1'}] + in let commitment_b : Tx_rollup_commitments.Commitment.t = - {level = raw_level 2l; batches = batches2; predecessor = None} + {commitment_a with batches} in Op.tx_rollup_commit (I i) contract2 tx_rollup commitment_b >>=? fun op -> Incremental.add_operation i op >>=? fun i -> - let predecessor = Tx_rollup_commitments.Commitment.hash commitment_a in - let commitment_c : Tx_rollup_commitments.Commitment.t = - {level = raw_level 3l; batches = batches1; predecessor = Some predecessor} - in + make_commitment_for_batch i (raw_level 3l) tx_rollup >>=? fun commitment_c -> Op.tx_rollup_commit (I i) contract2 tx_rollup commitment_c >>=? fun op -> Incremental.add_operation i op >>=? fun i -> let predecessor = Tx_rollup_commitments.Commitment.hash commitment_b in let commitment_d : Tx_rollup_commitments.Commitment.t = - {level = raw_level 3l; batches = batches2; predecessor = Some predecessor} + {commitment_c with predecessor = Some predecessor} in Op.tx_rollup_commit (I i) contract3 tx_rollup commitment_d >>=? fun op -> Incremental.add_operation i op >>=? fun i -> @@ -1059,12 +1053,7 @@ let test_bond_finalization () = return_unit | _ -> failwith "Commitment bond should not exist yet") >>=? fun i -> - let batches : Tx_rollup_commitments.Commitment.batch_commitment list = - [{root = Bytes.make 20 '0'}] - in - let commitment_a : Tx_rollup_commitments.Commitment.t = - {level = raw_level 2l; batches; predecessor = None} - in + make_commitment_for_batch i (raw_level 2l) tx_rollup >>=? fun commitment_a -> Op.tx_rollup_commit (I i) contract1 tx_rollup commitment_a >>=? fun op -> Incremental.add_operation i op >>=? fun i -> Op.tx_rollup_return_bond (I i) contract1 tx_rollup >>=? fun op -> diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml index 59697140573f..26e0045451b8 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml @@ -35,6 +35,8 @@ type error += (* `Temporary *) Missing_commitment_predecessor type error += (* `Branch *) Wrong_batch_count +type error += (* `Temporary *) Wrong_inbox_hash + type error += | (* `Temporary *) Commitment_too_early of Raw_level_repr.t * Raw_level_repr.t @@ -72,7 +74,7 @@ let () = ~id:"tx_rollup_wrong_commitment_predecessor_level" ~title:"This commitment's predecessor is invalid" ~description: - "This commitment has predecessor but shouldn't, or doesn't but should" + "This commitment has a predecessor but shouldn't, or doesn't but should" unit (function Wrong_commitment_predecessor_level -> Some () | _ -> None) (fun () -> Wrong_commitment_predecessor_level) ; @@ -95,6 +97,15 @@ let () = unit (function Wrong_batch_count -> Some () | _ -> None) (fun () -> Wrong_batch_count) ; + (* Wrong_inbox_hash *) + register_error_kind + `Temporary + ~id:"Wrong_inbox_hash" + ~title:"This commitment has the wrong inbox hash" + ~description:"This commitment has a different hash than its inbox" + unit + (function Wrong_inbox_hash -> Some () | _ -> None) + (fun () -> Wrong_inbox_hash) ; (* Commitment_too_early *) register_error_kind `Temporary @@ -210,6 +221,7 @@ module Commitment = struct level : Raw_level_repr.t; batches : batch_commitment list; predecessor : Commitment_hash.t option; + inbox_hash : Tx_rollup_inbox_repr.Hash.t; } include Compare.Make (struct @@ -220,23 +232,27 @@ module Commitment = struct let compare r1 r2 = compare_or Raw_level_repr.compare r1.level r2.level (fun () -> compare_or Compare_root_list.compare r1.batches r2.batches (fun () -> - Option.compare - Commitment_hash.compare + compare_or + (Option.compare Commitment_hash.compare) r1.predecessor - r2.predecessor)) + r2.predecessor + (fun () -> + Tx_rollup_inbox_repr.Hash.compare r1.inbox_hash r2.inbox_hash))) end) let pp : Format.formatter -> t -> unit = fun fmt t -> Format.fprintf fmt - "commitment %a : batches = %a predecessor %a" + "commitment %a : batches = %a predecessor %a for inbox %a" Raw_level_repr.pp t.level (Format.pp_print_list Batch.pp) t.batches (Format.pp_print_option Commitment_hash.pp) t.predecessor + Tx_rollup_inbox_repr.Hash.pp + t.inbox_hash (* FIXME/TORU: https://gitlab.com/tezos/tezos/-/issues/2470 @@ -244,26 +260,35 @@ module Commitment = struct let encoding = let open Data_encoding in conv - (fun {level; batches; predecessor} -> (level, batches, predecessor)) - (fun (level, batches, predecessor) -> {level; batches; predecessor}) - (obj3 + (fun {level; batches; predecessor; inbox_hash} -> + (level, batches, predecessor, inbox_hash)) + (fun (level, batches, predecessor, inbox_hash) -> + {level; batches; predecessor; inbox_hash}) + (obj4 (req "level" Raw_level_repr.encoding) (req "batches" (list Batch.encoding)) - (req "predecessor" (option Commitment_hash.encoding))) + (req "predecessor" (option Commitment_hash.encoding)) + (req "inbox_hash" Tx_rollup_inbox_repr.Hash.encoding)) - let hash t = + let hash {level; batches; predecessor; inbox_hash} = let to_bytes_exn = Data_encoding.Binary.to_bytes_exn in - let level_bytes = to_bytes_exn Raw_level_repr.encoding t.level in + let level_bytes = to_bytes_exn Raw_level_repr.encoding level in let predecessor_bytes = Option.fold ~none:Bytes.empty ~some:(fun pred -> Commitment_hash.to_bytes pred) - t.predecessor + predecessor in let batches_bytes = - to_bytes_exn (Data_encoding.list Batch.encoding) t.batches + to_bytes_exn (Data_encoding.list Batch.encoding) batches + in + let inbox_hash_bytes = + Data_encoding.Binary.to_bytes_exn + Tx_rollup_inbox_repr.Hash.encoding + inbox_hash in - Commitment_hash.hash_bytes [level_bytes; predecessor_bytes; batches_bytes] + Commitment_hash.hash_bytes + [level_bytes; predecessor_bytes; batches_bytes; inbox_hash_bytes] module Index = struct type t = Commitment_hash.t diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli index 9528c8789772..99a2a9020f37 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli @@ -35,6 +35,8 @@ type error += (* `Temporary *) Missing_commitment_predecessor type error += (* `Branch *) Wrong_batch_count +type error += (* `Temporary *) Wrong_inbox_hash + type error += | (* `Temporary *) Commitment_too_early of Raw_level_repr.t * Raw_level_repr.t @@ -71,6 +73,7 @@ module Commitment : sig level : Raw_level_repr.t; batches : batch_commitment list; predecessor : Commitment_hash.t option; + inbox_hash : Tx_rollup_inbox_repr.Hash.t; } val ( = ) : t -> t -> bool diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml index 80c580f205c6..964499568e25 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml @@ -99,11 +99,14 @@ let check_commitment_predecessor_hash ctxt tx_rollup (commitment : Commitment.t) let add_commitment ctxt tx_rollup pkh (commitment : Commitment.t) = let key = (commitment.level, tx_rollup) in get_or_empty_commitments ctxt key >>=? fun (ctxt, pending) -> - Tx_rollup_inbox_storage.get ctxt ~level:(`Level commitment.level) tx_rollup - >>=? fun (ctxt, inbox) -> - let expected_len = List.length inbox.contents in + Tx_rollup_inbox_storage.get_metadata ctxt commitment.level tx_rollup + >>=? fun (ctxt, {count; hash; _}) -> let actual_len = List.length commitment.batches in - fail_unless Compare.Int.(expected_len = actual_len) Wrong_batch_count + fail_unless Compare.Int.(count = actual_len) Wrong_batch_count >>=? fun () -> + fail_unless + Compare.Int.( + 0 = Tx_rollup_inbox_repr.Hash.compare commitment.inbox_hash hash) + Wrong_inbox_hash >>=? fun () -> check_commitment_predecessor_hash ctxt tx_rollup commitment >>=? fun ctxt -> Tx_rollup_commitments_repr.append diff --git a/src/proto_alpha/lib_protocol/tx_rollup_inbox_repr.ml b/src/proto_alpha/lib_protocol/tx_rollup_inbox_repr.ml index 7468b98526f9..0e4d4704bf74 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_inbox_repr.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_inbox_repr.ml @@ -43,8 +43,34 @@ let encoding = (req "contents" @@ list Tx_rollup_message_repr.hash_encoding) (req "cumulated_size" int31)) +module Hash = struct + type t = bytes + + include Compare.Make (Bytes) + + let pp : Format.formatter -> t -> unit = + fun fmt t -> Hex.pp fmt (Hex.of_bytes t) + + let empty = Bytes.empty + + let encoding = Data_encoding.bytes + + let extend t message = + let message = + Data_encoding.Binary.to_bytes_exn + Tx_rollup_message_repr.hash_encoding + message + in + Raw_hashes.blake2b (Bytes.cat t message) +end + +let hash_inbox : t -> Hash.t = + fun t -> List.fold_left (fun h msg -> Hash.extend h msg) Hash.empty t.contents + type metadata = { + count : int; cumulated_size : int; + hash : Hash.t; predecessor : Raw_level_repr.t option; successor : Raw_level_repr.t option; } @@ -52,11 +78,13 @@ type metadata = { let metadata_encoding = let open Data_encoding in conv - (fun {cumulated_size; predecessor; successor} -> - (cumulated_size, predecessor, successor)) - (fun (cumulated_size, predecessor, successor) -> - {cumulated_size; predecessor; successor}) - (obj3 + (fun {count; cumulated_size; hash; predecessor; successor} -> + (count, cumulated_size, hash, predecessor, successor)) + (fun (count, cumulated_size, hash, predecessor, successor) -> + {count; cumulated_size; hash; predecessor; successor}) + (obj5 + (req "count" int31) (req "cumulated_size" int31) + (req "hash" bytes) (req "predecessor" (option Raw_level_repr.encoding)) (req "successor" (option Raw_level_repr.encoding))) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_inbox_repr.mli b/src/proto_alpha/lib_protocol/tx_rollup_inbox_repr.mli index b104ae91d217..fe670da1d72e 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_inbox_repr.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_inbox_repr.mli @@ -41,14 +41,34 @@ val pp : Format.formatter -> t -> unit val encoding : t Data_encoding.t -(* The metadata for an inbox stores the [cumulated_size] in - bytes for the inbox, so that we do not need to retrieve the entries - for the inbox just to get the size. It also stores the +module Hash : sig + type t = private bytes + + include Compare.S with type t := t + + val pp : Format.formatter -> t -> unit + + val empty : t + + val encoding : t Data_encoding.t + + val extend : t -> Tx_rollup_message_repr.hash -> t +end + +val hash_inbox : t -> Hash.t + +(* The metadata for an inbox stores: (1) the count of messages (2) the + [cumulated_size] in bytes for the inbox, so that we do not need to + retrieve the entries for the inbox just to get the size. (3) the [predecessor] and [successor] levels. For the first inbox of a rollup, the [predecessor] will be None. For all inboxes, the - [successor] will be None until a subsequent inbox is created. *) + [successor] will be None until a subsequent inbox is created. + (4) the cumulative hash of the inbox contents -- that is, + h(h(h("" ^ contents[0]) ^ contents[1]), ...) *) type metadata = { + count : int; cumulated_size : int; + hash : Hash.t; predecessor : Raw_level_repr.t option; successor : Raw_level_repr.t option; } diff --git a/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml index 1a42fced1622..9c297d782fd0 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml @@ -74,7 +74,13 @@ let prepare_metadata : >|=? fun (ctxt, _, _) -> ctxt) >>=? fun ctxt -> let new_metadata : Tx_rollup_inbox_repr.metadata = - {cumulated_size = 0; predecessor; successor = None} + { + count = 0; + cumulated_size = 0; + hash = Tx_rollup_inbox_repr.Hash.empty; + predecessor; + successor = None; + } in return (ctxt, new_state, new_metadata) @@ -89,9 +95,12 @@ let append_message : let message_size = Tx_rollup_message_repr.size message in prepare_metadata ctxt rollup state level >>=? fun (ctxt, new_state, new_metadata) -> + let message_hash = Tx_rollup_message_repr.hash message in let new_metadata = { new_metadata with + count = new_metadata.count + 1; + hash = Tx_rollup_inbox_repr.Hash.extend new_metadata.hash message_hash; cumulated_size = message_size + new_metadata.cumulated_size; } in @@ -112,7 +121,7 @@ let append_message : Storage.Tx_rollup.Inbox_rev_contents.add (ctxt, level) rollup - (Tx_rollup_message_repr.hash message :: Option.value ~default:[] mcontents) + (message_hash :: Option.value ~default:[] mcontents) >>=? fun (ctxt, _, _) -> return (ctxt, new_state) let get_level : @@ -214,6 +223,16 @@ let get_adjacent_levels : return (ctxt, predecessor, successor) | (_, None) -> fail @@ Tx_rollup_inbox_does_not_exist (tx_rollup, level) +let get_metadata : + Raw_context.t -> + Raw_level_repr.t -> + Tx_rollup_repr.t -> + (Raw_context.t * Tx_rollup_inbox_repr.metadata) tzresult Lwt.t = + fun ctxt level tx_rollup -> + Storage.Tx_rollup.Inbox_metadata.find (ctxt, level) tx_rollup >>=? function + | (_, None) -> fail (Tx_rollup_inbox_does_not_exist (tx_rollup, level)) + | (ctxt, Some metadata) -> return (ctxt, metadata) + (* Error registration *) let () = diff --git a/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.mli b/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.mli index 3e0d3ac3e028..5e6619ef5389 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.mli @@ -138,3 +138,11 @@ val get_adjacent_levels : Tx_rollup_repr.t -> (Raw_context.t * Raw_level_repr.t option * Raw_level_repr.t option) tzresult Lwt.t + +(* [get_metadata ctxt level tx_rollup] returns the metadata for an inbox: + its count, byte size, next and previous levels, and hash *) +val get_metadata : + Raw_context.t -> + Raw_level_repr.t -> + Tx_rollup_repr.t -> + (Raw_context.t * Tx_rollup_inbox_repr.metadata) tzresult Lwt.t diff --git a/tezt/_regressions/tx_rollup_simple_use_case.out b/tezt/_regressions/tx_rollup_simple_use_case.out index fd6421644c43..6e03b1ba931f 100644 --- a/tezt/_regressions/tx_rollup_simple_use_case.out +++ b/tezt/_regressions/tx_rollup_simple_use_case.out @@ -7,7 +7,7 @@ tru1EL3YqhLS3kwni3ikbqMrui61fA5k7StHz ./tezos-client --wait none submit tx rollup batch 74657a6f73 to tru1EL3YqhLS3kwni3ikbqMrui61fA5k7StHz from '[PUBLIC_KEY_HASH]' Node is bootstrapped. -Estimated gas: 2640.322 units (will add 100 for safety) +Estimated gas: 2640.482 units (will add 100 for safety) Estimated storage: no bytes added Operation successfully injected in the node. Operation hash is '[OPERATION_HASH]' @@ -29,7 +29,7 @@ This sequence of operations was run: This tx rollup submit operation was successfully applied Balance updates: - Consumed gas: 2640.322 + Consumed gas: 2640.482 ./tezos-client rpc get /chains/main/blocks/head/context/tx_rollup/tru1EL3YqhLS3kwni3ikbqMrui61fA5k7StHz/inbox -- GitLab From 65166d2497f9b6fd63af49d6d5cd0df597795a86 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 14 Feb 2022 16:40:05 -0500 Subject: [PATCH 25/31] Proto,Tx_rollup: Allow commitments one block earlier Now that we no longer use tenderbake for finality, we don't have to wait to issue commitments. --- src/proto_alpha/lib_protocol/apply.ml | 2 +- .../test/integration/operations/test_tx_rollup.ml | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index fde7aead7484..d571fdb6c9d0 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -1416,7 +1416,7 @@ let precheck_manager_contents (type kind) ctxt (op : kind Kind.manager contents) application. *) let current_level = (Level.current ctxt).level in fail_when - Raw_level.(current_level <= Raw_level.succ commitment.level) + Raw_level.(current_level <= commitment.level) (Tx_rollup_commitments.Commitment_too_early (commitment.level, current_level)) >|=? fun () -> ctxt diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index 1ee2463b696d..2712ec0b6d3a 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -648,8 +648,6 @@ let test_commitment_duplication () = let level = raw_level 2l in Block.bake ~operation b >>=? fun b -> Incremental.begin_construction b >>=? fun i -> - Incremental.finalize_block i >>=? fun b -> - Incremental.begin_construction b >>=? fun i -> make_commitment_for_batch i level tx_rollup >>=? fun commitment -> let submitted_level = (Level.current (Incremental.alpha_ctxt i)).level in Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> @@ -827,8 +825,6 @@ let test_commitment_retire_simple () = Block.bake ~operation b >>=? fun b -> Incremental.begin_construction b >>=? fun i -> let level = raw_level 2l in - Incremental.finalize_block i >>=? fun b -> - Incremental.begin_construction b >>=? fun i -> (* Test retirement with no commitment *) wrap (Tx_rollup_commitments.Internal_for_tests.retire_rollup_level @@ -981,8 +977,6 @@ let test_commitment_acceptance () = originate b contract1 >>=? fun (b, tx_rollup) -> make_transactions_in tx_rollup contract1 [2; 3] b >>=? fun b -> Incremental.begin_construction b >>=? fun i -> - Incremental.finalize_block i >>=? fun b -> - Incremental.begin_construction b >>=? fun i -> make_commitment_for_batch i (raw_level 2l) tx_rollup >>=? fun commitment_a -> Op.tx_rollup_commit (I i) contract1 tx_rollup commitment_a >>=? fun op -> Incremental.add_operation i op >>=? fun i -> @@ -1041,8 +1035,6 @@ let test_bond_finalization () = (* Transactions in block 2, 3, 4 *) make_transactions_in tx_rollup contract1 [2; 3; 4] b >>=? fun b -> Incremental.begin_construction b >>=? fun i -> - Incremental.finalize_block i >>=? fun b -> - Incremental.begin_construction b >>=? fun i -> Op.tx_rollup_return_bond (I i) contract1 tx_rollup >>=? fun op -> Incremental.add_operation i op ~expect_failure:(function | Environment.Ecoproto_error -- GitLab From 64573e50f41bdc193bf5f6eaa8a0553a75fcd253 Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 16 Feb 2022 13:18:31 -0500 Subject: [PATCH 26/31] Proto,Tx_rollup: test for finalization at commitment time --- .../integration/operations/test_tx_rollup.ml | 147 ++++++++++++++++-- 1 file changed, 131 insertions(+), 16 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index 2712ec0b6d3a..8ee4d95480ac 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -225,6 +225,28 @@ let make_commitment_for_batch i level tx_rollup = in return commitment +let constants = + { + Tezos_protocol_alpha_parameters.Default_parameters.constants_test with + consensus_threshold = 0; + endorsing_reward_per_slot = Tez.zero; + baking_reward_bonus_per_slot = Tez.zero; + baking_reward_fixed_portion = Tez.zero; + tx_rollup_enable = true; + } + +let originate_with_constants constants n = + Context.init_with_constants constants n >>=? fun (b, contracts) -> + let contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + originate b contract >>=? fun (b, tx_rollup) -> + return (b, tx_rollup, contracts) + +let range start top = + let rec aux n acc = if n < start then acc else aux (n - 1) (n :: acc) in + aux top [] + (** ---- TESTS -------------------------------------------------------------- *) (** [test_origination] originates a transaction rollup and checks that @@ -1023,8 +1045,8 @@ let test_commitment_acceptance () = ignore i ; return () -(** [test_bond_finalization] tests that commitment operations - in fact finalize bonds. *) +(** [test_bond_finalization] tests that commitment retirement + in fact finalizes bonds. *) let test_bond_finalization () = context_init 2 >>=? fun (b, contracts) -> let contract1 = @@ -1072,26 +1094,111 @@ let test_bond_finalization () = ignore i ; return () -let test_full_inbox () = +(** [test_bond_finalization] tests that commitment operations + perform retirement. *) +let test_commitment_finalizes () = + let constants = {constants with tx_rollup_finality_period = 10} in + originate_with_constants constants 3 >>=? fun (b, tx_rollup, contracts) -> + let contract1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + let contract2 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 1 + in + let contract3 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 2 + in + (* Transactions in block 2, 3, 4 *) + make_transactions_in tx_rollup contract1 [2; 3; 4] b >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + make_commitment_for_batch i (raw_level 2l) tx_rollup >>=? fun commitment -> + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + (* Now wait for the most of the finality period to pass. *) + bake_until i 13l >>=? fun i -> + make_commitment_for_batch i (raw_level 3l) tx_rollup >>=? fun commitment -> + Op.tx_rollup_commit (I i) contract2 tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + (* We check that the commitment for level 2 was not finalized by + checking the bond for contract1. *) + check_bond (Incremental.alpha_ctxt i) tx_rollup contract1 1 >>=? fun () -> + (* Wait one and try again. *) + bake_until i 14l >>=? fun i -> + make_commitment_for_batch i (raw_level 4l) tx_rollup >>=? fun commitment -> + Op.tx_rollup_commit (I i) contract3 tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + check_bond (Incremental.alpha_ctxt i) tx_rollup contract1 0 >>=? fun () -> + (* Check that we don't finalize too far. *) + check_bond (Incremental.alpha_ctxt i) tx_rollup contract2 1 >>=? fun () -> + ignore i ; + return () + +(** [test_bond_finalization] tests that commitment operations + do not finalize more than the limit *) +let test_commitment_finality_limit () = let constants = { - Tezos_protocol_alpha_parameters.Default_parameters.constants_test with - consensus_threshold = 0; - endorsing_reward_per_slot = Tez.zero; - baking_reward_bonus_per_slot = Tez.zero; - baking_reward_fixed_portion = Tez.zero; - tx_rollup_enable = true; - tx_rollup_max_unfinalized_levels = 15; + constants with + tx_rollup_finality_period = 15; + tx_rollup_max_finalize_levels_per_commitment = 3; + hard_gas_limit_per_block = Gas.Arith.integral_exn (Z.of_int 10000000000); } in - Context.init_with_constants constants 1 >>=? fun (b, contracts) -> - let contract = + originate_with_constants constants 10 >>=? fun (b, tx_rollup, contracts) -> + let contract1 = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 in - originate b contract >>=? fun (b, tx_rollup) -> - let range start top = - let rec aux n acc = if n < start then acc else aux (n - 1) (n :: acc) in - aux top [] + let contract10 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 9 + in + let check_bond_for_contract i contract_n expected_bond = + let contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts contract_n + in + check_bond (Incremental.alpha_ctxt i) tx_rollup contract expected_bond + in + + (* Transactions in block 2-11 *) + make_transactions_in tx_rollup contract1 (range 2 12) b >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + let rec make_many_commitments i cur top = + if cur = top then return i + else + make_commitment_for_batch i (raw_level (Int32.of_int cur)) tx_rollup + >>=? fun commitment -> + let contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts cur + in + Op.tx_rollup_commit (I i) contract tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + make_many_commitments i (cur + 1) top + in + make_many_commitments i 2 10 >>=? fun i -> + (* Now wait for the the rest of the finality period to pass. *) + bake_until i 30l >>=? fun i -> + make_commitment_for_batch i (raw_level 10l) tx_rollup >>=? fun commitment -> + Op.tx_rollup_commit (I i) contract10 tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + check_bond_for_contract i 2 0 >>=? fun () -> + check_bond_for_contract i 3 0 >>=? fun () -> + check_bond_for_contract i 4 0 >>=? fun () -> + (* We hit the limit, so the next one is not final. *) + check_bond_for_contract i 5 1 >>=? fun () -> + make_commitment_for_batch i (raw_level 11l) tx_rollup >>=? fun commitment -> + Op.tx_rollup_commit (I i) contract10 tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + check_bond_for_contract i 5 0 >>=? fun () -> + check_bond_for_contract i 6 0 >>=? fun () -> + check_bond_for_contract i 7 0 >>=? fun () -> + check_bond_for_contract i 8 1 >>=? fun () -> + ignore i ; + return () + +let test_full_inbox () = + let constants = {constants with tx_rollup_max_unfinalized_levels = 15} in + originate_with_constants constants 1 >>=? fun (b, tx_rollup, contracts) -> + let contract = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 in (* Transactions in blocks [2..17) *) make_transactions_in tx_rollup contract (range 2 17) b >>=? fun b -> @@ -1155,4 +1262,12 @@ let tests = test_commitment_acceptance; Tztest.tztest "Test bond finalization" `Quick test_bond_finalization; Tztest.tztest "Test full inbox" `Quick test_full_inbox; + Tztest.tztest + "Test that commitment finalizes" + `Quick + test_commitment_finalizes; + Tztest.tztest + "Test that commitment finality limit" + `Quick + test_commitment_finality_limit; ] -- GitLab From 2da965ff4e889f6a57a2e7e0a4a2c5dea86cdc20 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 24 Jan 2022 11:04:08 -0500 Subject: [PATCH 27/31] Proto,Tx_rollup: Function to get commitment batches Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- .../lib_protocol/alpha_context.mli | 14 +++++ .../tx_rollup_commitments_repr.ml | 28 +++++++++- .../tx_rollup_commitments_repr.mli | 5 ++ .../tx_rollup_commitments_storage.ml | 53 +++++++++++++++++++ .../tx_rollup_commitments_storage.mli | 18 +++++++ 5 files changed, 117 insertions(+), 1 deletion(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 7bcf147c4361..5f2ecadf3f9a 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2205,6 +2205,10 @@ module Tx_rollup_commitments : sig type error += Too_many_unfinalized_levels + type error += No_such_batch of Raw_level.t * int + + type error += No_such_commitment + val add_commitment : context -> Tx_rollup.t -> @@ -2230,6 +2234,16 @@ module Tx_rollup_commitments : sig Signature.public_key_hash -> context tzresult Lwt.t + val get_commitment_roots : + context -> + Tx_rollup.t -> + Raw_level.t -> + Commitment_hash.t -> + int -> + (context * (Commitment.batch_commitment * Commitment.batch_commitment)) + tzresult + Lwt.t + module Internal_for_tests : sig (** See [Tx_rollup_commitments_storage.retire_rollup_level] for documentation *) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml index 26e0045451b8..4a0338777055 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.ml @@ -47,6 +47,11 @@ type error += (* `Temporary *) Bond_in_use of Signature.public_key_hash type error += (* `Temporary *) Too_many_unfinalized_levels +type error += (* `Permanent *) No_such_batch of Raw_level_repr.t * int + +type error += (* `Temporary *) + No_such_commitment + let () = let open Data_encoding in (* Commitment_hash_already_submitted *) @@ -149,7 +154,28 @@ let () = messages to keep commitment gas reasonable." empty (function Too_many_unfinalized_levels -> Some () | _ -> None) - (fun () -> Too_many_unfinalized_levels) + (fun () -> Too_many_unfinalized_levels) ; + (* No_such_batch *) + register_error_kind + `Temporary + ~id:"No_such_batch" + ~title:"This rejection wrongly attempts to reject a non-existent batch" + ~description: + "This rejection wrongly attempts to reject a non-existent batch" + (obj2 + (req "level" Raw_level_repr.encoding) + (req "index" Data_encoding.int31)) + (function No_such_batch (level, index) -> Some (level, index) | _ -> None) + (fun (level, index) -> No_such_batch (level, index)) ; + (* No_such_commitment *) + register_error_kind + `Temporary + ~id:"tx_rollup_no_such_commitment" + ~title:"No such commitment" + ~description:"No such commitment" + empty + (function No_such_commitment -> Some () | _ -> None) + (fun () -> No_such_commitment) let compare_or cmp c1 c2 f = match cmp c1 c2 with 0 -> f () | diff -> diff diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli index 99a2a9020f37..d36aabb1ef96 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_repr.mli @@ -47,6 +47,11 @@ type error += (* `Temporary *) Bond_in_use of Signature.public_key_hash type error += (* `Temporary *) Too_many_unfinalized_levels +type error += (* `Permanent *) No_such_batch of Raw_level_repr.t * int + +type error += (* `Temporary *) + No_such_commitment + (** A specialized Blake2B implementation for hashing commitments with "toc1" as a base58 prefix *) module Commitment_hash : sig diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml index 964499568e25..99f0c6811195 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml @@ -176,6 +176,59 @@ let rec remove_successors : remove_successors ctxt tx_rollup next_level top next_commitments else return ctxt +let get_commitment_roots ctxt tx_rollup (level : Raw_level_repr.t) + (commitment_id : Commitment_hash.t) (index : int) = + let find_commitment_by_hash ctxt level hash = + Storage.Tx_rollup.Commitment_list.get ctxt (level, tx_rollup) + >>=? fun (ctxt, commitments) -> + let pending_commitment = + List.find + (fun {commitment; _} -> + Commitment_hash.(hash = Commitment.hash commitment)) + commitments + in + Option.value_e + ~error:(Error_monad.trace_of_error No_such_commitment) + pending_commitment + >>?= fun pending -> return (ctxt, pending) + in + find_commitment_by_hash ctxt level commitment_id + >>=? fun (ctxt, pending_commitment) -> + let commitment = pending_commitment.commitment in + let nth_root (commitment : Commitment.t) n = + let nth = List.nth commitment.batches n in + Option.value_e + ~error:(Error_monad.trace_of_error (No_such_batch (level, index))) + nth + in + (match index with + | 0 -> ( + match commitment.predecessor with + | None -> + (* TODO: empty merkle tree when we have this*) + let empty : Tx_rollup_commitments_repr.Commitment.batch_commitment = + {root = Bytes.empty} + in + return (ctxt, empty) + | Some prev_hash -> + get_prev_level ctxt tx_rollup level >>=? fun (ctxt, prev_level) -> + let prev_level = + match prev_level with + | None -> assert false + | Some prev_level -> prev_level + in + find_commitment_by_hash ctxt prev_level prev_hash + >>=? fun (ctxt, {commitment = {batches; _}; _}) -> + (let last = List.last_opt batches in + Option.value_e + ~error:(Error_monad.trace_of_error (No_such_batch (level, -1))) + last) + >>?= fun p -> return (ctxt, p)) + | index -> nth_root commitment (index - 1) >>?= fun p -> return (ctxt, p)) + >>=? fun (ctxt, before_hash) -> + nth_root commitment index >>?= fun after_hash -> + return (ctxt, (before_hash, after_hash)) + let retire_rollup_level : Raw_context.t -> Tx_rollup_repr.t -> diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli index 88f102b0aff3..b64c1192c4f1 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli @@ -101,3 +101,21 @@ val finalize_pending_commitments : Tx_rollup_repr.t -> Raw_level_repr.t -> Raw_context.t tzresult Lwt.t + +(** [get_commitment_roots context tx_rollup level commitment_hash + batch] returns the before and after roots of the commitment + [commitment] at level [level], batch [batch]. If [batch] is 0, + then the before root will come from the last batch of the + predecessor commitment, or will be empty if this is the first + commitment on this rollup. *) +val get_commitment_roots : + Raw_context.t -> + Tx_rollup_repr.t -> + Raw_level_repr.t -> + Tx_rollup_commitments_repr.Commitment_hash.t -> + int -> + (Raw_context.t + * (Tx_rollup_commitments_repr.Commitment.batch_commitment + * Tx_rollup_commitments_repr.Commitment.batch_commitment)) + tzresult + Lwt.t -- GitLab From eeed54177fb867518f02895863ea89ff1332f221 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 24 Jan 2022 11:04:08 -0500 Subject: [PATCH 28/31] Proto,Tx_rollup: Rejection repr and initial storage Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- src/proto_alpha/lib_protocol/TEZOS_PROTOCOL | 1 + src/proto_alpha/lib_protocol/alpha_context.ml | 5 ++ .../lib_protocol/alpha_context.mli | 15 +++++ src/proto_alpha/lib_protocol/dune.inc | 5 ++ .../lib_protocol/tx_rollup_rejection_repr.ml | 60 +++++++++++++++++++ .../lib_protocol/tx_rollup_rejection_repr.mli | 37 ++++++++++++ 6 files changed, 123 insertions(+) create mode 100644 src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.ml create mode 100644 src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.mli diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index 7dc82c9159ed..db63fe13553f 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -49,6 +49,7 @@ "Tx_rollup_inbox_repr", "Tx_rollup_commitments_repr", "Rollup_bond_id_repr", + "Tx_rollup_rejection_repr", "Vote_repr", "Block_header_repr", "Entrypoint_repr", diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index ca21ac3faa75..d8beae9bce46 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -285,6 +285,11 @@ module Tx_rollup_commitments = struct end end +module Tx_rollup_rejection = struct + include Tx_rollup_rejection_repr + include Tx_rollup_commitments_storage +end + module Global_constants_storage = Global_constants_storage module Big_map = struct diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 5f2ecadf3f9a..ac27aba35158 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2257,6 +2257,21 @@ module Tx_rollup_commitments : sig end end +(** This simply re-exports {!Tx_rollup_rejection_repr}. See + {!Tx_rollup_rejection_repr} for additional documentation of this module. *) +module Tx_rollup_rejection : sig + type error += Wrong_rejection + + type t = { + rollup : Tx_rollup.t; + level : Raw_level.t; + hash : Tx_rollup_commitments.Commitment_hash.t; + batch_index : int; + } + + val encoding : t Data_encoding.t +end + module Kind : sig type preendorsement_consensus_kind = Preendorsement_consensus_kind diff --git a/src/proto_alpha/lib_protocol/dune.inc b/src/proto_alpha/lib_protocol/dune.inc index 2e7eabee26fc..02eceadde055 100644 --- a/src/proto_alpha/lib_protocol/dune.inc +++ b/src/proto_alpha/lib_protocol/dune.inc @@ -74,6 +74,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end tx_rollup_inbox_repr.mli tx_rollup_inbox_repr.ml tx_rollup_commitments_repr.mli tx_rollup_commitments_repr.ml rollup_bond_id_repr.mli rollup_bond_id_repr.ml + tx_rollup_rejection_repr.mli tx_rollup_rejection_repr.ml vote_repr.mli vote_repr.ml block_header_repr.mli block_header_repr.ml entrypoint_repr.mli entrypoint_repr.ml @@ -231,6 +232,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end tx_rollup_inbox_repr.mli tx_rollup_inbox_repr.ml tx_rollup_commitments_repr.mli tx_rollup_commitments_repr.ml rollup_bond_id_repr.mli rollup_bond_id_repr.ml + tx_rollup_rejection_repr.mli tx_rollup_rejection_repr.ml vote_repr.mli vote_repr.ml block_header_repr.mli block_header_repr.ml entrypoint_repr.mli entrypoint_repr.ml @@ -388,6 +390,7 @@ module CamlinternalFormatBasics = struct include CamlinternalFormatBasics end tx_rollup_inbox_repr.mli tx_rollup_inbox_repr.ml tx_rollup_commitments_repr.mli tx_rollup_commitments_repr.ml rollup_bond_id_repr.mli rollup_bond_id_repr.ml + tx_rollup_rejection_repr.mli tx_rollup_rejection_repr.ml vote_repr.mli vote_repr.ml block_header_repr.mli block_header_repr.ml entrypoint_repr.mli entrypoint_repr.ml @@ -567,6 +570,7 @@ include Tezos_raw_protocol_alpha.Main Tx_rollup_inbox_repr Tx_rollup_commitments_repr Rollup_bond_id_repr + Tx_rollup_rejection_repr Vote_repr Block_header_repr Entrypoint_repr @@ -765,6 +769,7 @@ include Tezos_raw_protocol_alpha.Main tx_rollup_inbox_repr.mli tx_rollup_inbox_repr.ml tx_rollup_commitments_repr.mli tx_rollup_commitments_repr.ml rollup_bond_id_repr.mli rollup_bond_id_repr.ml + tx_rollup_rejection_repr.mli tx_rollup_rejection_repr.ml vote_repr.mli vote_repr.ml block_header_repr.mli block_header_repr.ml entrypoint_repr.mli entrypoint_repr.ml diff --git a/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.ml b/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.ml new file mode 100644 index 000000000000..397f35793ccb --- /dev/null +++ b/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.ml @@ -0,0 +1,60 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Marigold *) +(* Copyright (c) 2022 Nomadic Labs *) +(* Copyright (c) 2022 Oxhead Alpha *) +(* *) +(* 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 += (* `Permanent *) Wrong_rejection + +let () = + let open Data_encoding in + (* Wrong_rejection *) + register_error_kind + `Temporary + ~id:"Wrong_rejection" + ~title:"This rejection wrongly attempts to reject a correct comitment" + ~description:"This rejection wrongly attempts to reject a correct comitment" + unit + (function Wrong_rejection -> Some () | _ -> None) + (fun () -> Wrong_rejection) + +type t = { + rollup : Tx_rollup_repr.t; + level : Raw_level_repr.t; + hash : Tx_rollup_commitments_repr.Commitment_hash.t; + batch_index : int; +} + +let encoding = + let open Data_encoding in + conv + (fun {rollup; level; hash; batch_index} -> + (rollup, level, hash, batch_index)) + (fun (rollup, level, hash, batch_index) -> + {rollup; level; hash; batch_index}) + (obj4 + (req "rollup" Tx_rollup_repr.encoding) + (req "level" Raw_level_repr.encoding) + (req "hash" Tx_rollup_commitments_repr.Commitment_hash.encoding) + (req "batch_index" int31)) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.mli b/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.mli new file mode 100644 index 000000000000..93d3fa1ba7a5 --- /dev/null +++ b/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.mli @@ -0,0 +1,37 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Marigold *) +(* Copyright (c) 2022 Nomadic Labs *) +(* Copyright (c) 2022 Oxhead Alpha *) +(* *) +(* 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 += (* `Permanent *) Wrong_rejection + +type t = { + rollup : Tx_rollup_repr.t; + level : Raw_level_repr.t; + hash : Tx_rollup_commitments_repr.Commitment_hash.t; + batch_index : int; +} + +val encoding : t Data_encoding.t -- GitLab From 74d5a754cb3ae301d5074150b7ad557344c80fb8 Mon Sep 17 00:00:00 2001 From: David Turner Date: Fri, 3 Dec 2021 16:26:27 -0500 Subject: [PATCH 29/31] Proto,Tx_rollup: Rejection functions Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- .../lib_protocol/alpha_context.mli | 7 + .../tx_rollup_commitments_storage.ml | 120 ++++++++++++++++++ .../tx_rollup_commitments_storage.mli | 14 ++ 3 files changed, 141 insertions(+) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index ac27aba35158..20b50fc089f0 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2216,6 +2216,13 @@ module Tx_rollup_commitments : sig Commitment.t -> context tzresult Lwt.t + val reject_commitment : + context -> + Tx_rollup.t -> + Raw_level.t -> + Commitment_hash.t -> + context tzresult Lwt.t + val get_commitments : context -> Tx_rollup.t -> Raw_level.t -> (context * t) tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml index 99f0c6811195..95cf5333e694 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.ml @@ -119,6 +119,7 @@ let add_commitment ctxt tx_rollup pkh (commitment : Commitment.t) = >>=? fun (ctxt, _, _) -> adjust_commitment_bond ctxt tx_rollup pkh 1 module Commitment_set = Set.Make (Commitment_hash) +module Contract_set = Set.Make (Signature.Public_key_hash) let rec remove_successors : Raw_context.t -> @@ -229,6 +230,125 @@ let get_commitment_roots ctxt tx_rollup (level : Raw_level_repr.t) nth_root commitment index >>?= fun after_hash -> return (ctxt, (before_hash, after_hash)) +let rec accumulate_bad_commitments : + Raw_context.t -> + Tx_rollup_repr.t -> + Raw_level_repr.t -> + Raw_level_repr.t -> + Commitment_set.t -> + Contract_set.t -> + (Commitment_set.t * Contract_set.t) tzresult Lwt.t = + fun ctxt tx_rollup level top commitments contracts -> + let add_bad_commitments (commitments, contracts) + {commitment; hash; committer; _} = + if + Option.value ~default:false + @@ Option.map + (fun predecessor -> Commitment_set.mem predecessor commitments) + commitment.predecessor + || Contract_set.mem committer contracts + then + (Commitment_set.add hash commitments, Contract_set.add committer contracts) + else (commitments, contracts) + in + if Raw_level_repr.(level > top) then return (commitments, contracts) + else + let key = (level, tx_rollup) in + Storage.Tx_rollup.Commitment_list.find ctxt key + >>=? fun (ctxt, commitment_list) -> + let pending = + match commitment_list with None -> [] | Some pending -> pending + in + let (commitments, contracts) = + List.fold_left add_bad_commitments (commitments, contracts) pending + in + get_next_level ctxt tx_rollup level >>=? fun (ctxt, next_level) -> + match next_level with + | None -> return (commitments, contracts) + | Some next_level -> + accumulate_bad_commitments + ctxt + tx_rollup + next_level + top + commitments + contracts + +let rec remove_commitments_by_hash : + Raw_context.t -> + Tx_rollup_repr.t -> + Raw_level_repr.t -> + Raw_level_repr.t -> + Commitment_set.t -> + Raw_context.t tzresult Lwt.t = + fun ctxt tx_rollup level top commitments -> + if Raw_level_repr.(level > top) then return ctxt + else + let key = (level, tx_rollup) in + Storage.Tx_rollup.Commitment_list.find ctxt key + >>=? fun (ctxt, commitment_list) -> + (match commitment_list with + | None -> + (* No commitments at this level -- just recurse *) + return ctxt + | Some pending -> + let new_pending = + List.filter + (fun {hash; _} -> not @@ Commitment_set.mem hash commitments) + pending + in + Storage.Tx_rollup.Commitment_list.add ctxt key new_pending + >|=? just_ctxt) + >>=? fun ctxt -> + get_next_level ctxt tx_rollup level >>=? fun (ctxt, next_level) -> + match next_level with + | None -> return ctxt + | Some next_level -> + remove_commitments_by_hash ctxt tx_rollup next_level top commitments + +let reject_commitment ctxt tx_rollup (level : Raw_level_repr.t) + (commitment_id : Commitment_hash.t) = + let top = (Raw_context.current_level ctxt).level in + Storage.Tx_rollup.Commitment_list.get ctxt (level, tx_rollup) + >>=? fun (ctxt, commitments) -> + let matching_commitments = + List.filter + (fun {hash; _} -> Commitment_hash.(hash = commitment_id)) + commitments + in + let matching = List.hd matching_commitments in + Option.value_e ~error:(Error_monad.trace_of_error No_such_commitment) matching + >>?= fun to_remove -> + let initial_bad_commitments = Commitment_set.of_list [commitment_id] in + let initial_evildoers = Contract_set.of_list [to_remove.committer] in + let rec aux bad_commitments evildoers = + accumulate_bad_commitments + ctxt + tx_rollup + level + top + bad_commitments + evildoers + >>=? fun (new_bad_commitments, new_evildoers) -> + if + Compare.Int.( + Contract_set.cardinal new_evildoers = Contract_set.cardinal evildoers + && Commitment_set.cardinal new_bad_commitments + = Commitment_set.cardinal bad_commitments) + then return (new_bad_commitments, new_evildoers) + else aux new_bad_commitments new_evildoers + in + aux initial_bad_commitments initial_evildoers + >>=? fun (bad_commitments, evildoers) -> + remove_commitments_by_hash ctxt tx_rollup level top bad_commitments + >>=? fun ctxt -> + Contract_set.fold_es + (fun contract ctxt -> + let key = (tx_rollup, contract) in + Storage.Tx_rollup.Commitment_bond.remove ctxt key >|=? just_ctxt) + evildoers + ctxt + let retire_rollup_level : Raw_context.t -> Tx_rollup_repr.t -> diff --git a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli index b64c1192c4f1..d27a09f37e83 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_commitments_storage.mli @@ -50,6 +50,20 @@ val remove_bond : Signature.public_key_hash -> Raw_context.t tzresult Lwt.t +(** [reject_commitment ctxt tx_rollup_repr level commitment_hash] + rejects a commitment with a given hash at a given level. All + successor commitments are removed, and any bonds associated with + them are removed. Some successor commitments might be from + different contracts, in which case, we recursively remove all + contracts from those contracts and their successors, and so forth. + *) +val reject_commitment : + Raw_context.t -> + Tx_rollup_repr.t -> + Raw_level_repr.t -> + Tx_rollup_commitments_repr.Commitment_hash.t -> + Raw_context.t tzresult Lwt.t + (** [retire_rollup_level context tx_rollup level] removes all data associated with a level. It decrements the bonded commitment count for any contracts whose commitments have been either accepted or -- GitLab From c59c5332b5a7a24a343ff9a9900b30a4779cd229 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 24 Jan 2022 11:04:08 -0500 Subject: [PATCH 30/31] Tx_rollup: Rejection operation Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- src/proto_alpha/lib_client/injection.ml | 3 + .../lib_client/operation_result.ml | 39 +++ .../lib_protocol/alpha_context.mli | 15 + src/proto_alpha/lib_protocol/apply.ml | 30 ++ src/proto_alpha/lib_protocol/apply_results.ml | 75 +++++ .../lib_protocol/apply_results.mli | 5 + .../lib_protocol/operation_repr.ml | 48 ++++ .../lib_protocol/operation_repr.mli | 15 + .../lib_protocol/test/helpers/block.ml | 4 +- .../lib_protocol/test/helpers/op.ml | 16 ++ .../lib_protocol/test/helpers/op.mli | 16 ++ .../integration/operations/test_tx_rollup.ml | 50 ++++ .../lib_protocol/ticket_operations_diff.ml | 1 + .../_regressions/rpc/alpha.client.mempool.out | 263 ++++++++++++++++++ tezt/_regressions/rpc/alpha.proxy.mempool.out | 263 ++++++++++++++++++ 15 files changed, 842 insertions(+), 1 deletion(-) diff --git a/src/proto_alpha/lib_client/injection.ml b/src/proto_alpha/lib_client/injection.ml index 70391c618356..d6c071b0964d 100644 --- a/src/proto_alpha/lib_client/injection.ml +++ b/src/proto_alpha/lib_client/injection.ml @@ -328,6 +328,7 @@ let estimated_gas_single (type kind) | Applied (Tx_rollup_commit_result {consumed_gas; _}) -> Ok consumed_gas | Applied (Tx_rollup_return_bond_result {consumed_gas; _}) -> Ok consumed_gas + | Applied (Tx_rollup_rejection_result {consumed_gas; _}) -> Ok consumed_gas | Applied (Sc_rollup_originate_result {consumed_gas; _}) -> Ok consumed_gas | Applied (Sc_rollup_add_messages_result {consumed_gas; _}) -> Ok consumed_gas @@ -372,6 +373,7 @@ let estimated_storage_single (type kind) ~tx_rollup_origination_size Ok Z.zero | Applied (Tx_rollup_commit_result _) -> Ok Z.zero | Applied (Tx_rollup_return_bond_result _) -> Ok Z.zero + | Applied (Tx_rollup_rejection_result _) -> Ok Z.zero | Applied (Sc_rollup_originate_result {size; _}) -> Ok size | Applied (Sc_rollup_add_messages_result _) -> Ok Z.zero | Skipped _ -> assert false @@ -426,6 +428,7 @@ let originated_contracts_single (type kind) | Applied (Tx_rollup_submit_batch_result _) -> Ok [] | Applied (Tx_rollup_commit_result _) -> Ok [] | Applied (Tx_rollup_return_bond_result _) -> Ok [] + | Applied (Tx_rollup_rejection_result _) -> Ok [] | Applied (Sc_rollup_originate_result _) -> Ok [] | Applied (Sc_rollup_add_messages_result _) -> Ok [] | Skipped _ -> assert false diff --git a/src/proto_alpha/lib_client/operation_result.ml b/src/proto_alpha/lib_client/operation_result.ml index 075c7a677b40..6e3f43d21ecf 100644 --- a/src/proto_alpha/lib_client/operation_result.ml +++ b/src/proto_alpha/lib_client/operation_result.ml @@ -213,6 +213,25 @@ let pp_manager_operation_content (type kind) source internal pp_result ppf source pp_result result + | Tx_rollup_rejection {rollup; level; hash; batch_index; nonce} -> + Format.fprintf + ppf + "@[%s:rollup %a level %a commitment %a index %d nonce %Lx @,\ + From: %a%a@]" + (if internal then "Internal tx rollup rejection" + else "Tx rollup rejection") + Tx_rollup.pp + rollup + Raw_level.pp + level + Tx_rollup_commitments.Commitment_hash.pp + hash + batch_index + nonce + Contract.pp + source + pp_result + result | Sc_rollup_originate {kind; boot_sector} -> let (module R : Sc_rollups.PVM.S) = Sc_rollups.of_kind kind in Format.fprintf @@ -486,6 +505,15 @@ let pp_manager_operation_contents_and_result ppf balance_updates ; Format.fprintf ppf "@,Consumed gas: %a" Gas.Arith.pp consumed_gas in + let pp_tx_rollup_rejection_result + (Tx_rollup_rejection_result {balance_updates; consumed_gas}) = + Format.fprintf + ppf + "@,Balance updates:@, %a" + pp_balance_updates + balance_updates ; + Format.fprintf ppf "@,Consumed gas: %a" Gas.Arith.pp consumed_gas + in let pp_sc_rollup_originate_result (Sc_rollup_originate_result {address; consumed_gas; size; balance_updates}) = @@ -606,6 +634,17 @@ let pp_manager_operation_contents_and_result ppf "@[This tx rollup return commitment bond operation was \ BACKTRACKED, its expected effects (as follow) were NOT applied.@]" ; pp_tx_rollup_return_bond_result op + | Applied (Tx_rollup_rejection_result _ as op) -> + Format.fprintf + ppf + "This tx rollup rejection operation was successfully applied" ; + pp_tx_rollup_rejection_result op + | Backtracked ((Tx_rollup_rejection_result _ as op), _err) -> + Format.fprintf + ppf + "@[This tx rollup rejection operation was BACKTRACKED, its \ + expected effects (as follow) were NOT applied.@]" ; + pp_tx_rollup_rejection_result op | Applied (Sc_rollup_originate_result _ as op) -> Format.fprintf ppf diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 20b50fc089f0..0ff661ed9cfa 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2333,6 +2333,8 @@ module Kind : sig type tx_rollup_return_bond = Tx_rollup_return_bond_kind + type tx_rollup_rejection = Tx_rollup_rejection_kind + type sc_rollup_originate = Sc_rollup_originate_kind type sc_rollup_add_messages = Sc_rollup_add_messages_kind @@ -2348,6 +2350,7 @@ module Kind : sig | Tx_rollup_submit_batch_manager_kind : tx_rollup_submit_batch manager | Tx_rollup_commit_manager_kind : tx_rollup_commit manager | Tx_rollup_return_bond_manager_kind : tx_rollup_return_bond manager + | Tx_rollup_rejection_manager_kind : tx_rollup_rejection manager | Sc_rollup_originate_manager_kind : sc_rollup_originate manager | Sc_rollup_add_messages_manager_kind : sc_rollup_add_messages manager end @@ -2482,6 +2485,14 @@ and _ manager_operation = tx_rollup : Tx_rollup.t; } -> Kind.tx_rollup_return_bond manager_operation + | Tx_rollup_rejection : { + rollup : Tx_rollup.t; + level : Raw_level.t; + hash : Tx_rollup_commitments.Commitment_hash.t; + batch_index : int; + nonce : int64; + } + -> Kind.tx_rollup_rejection manager_operation | Sc_rollup_originate : { kind : Sc_rollup.Kind.t; boot_sector : Sc_rollup.PVM.boot_sector; @@ -2640,6 +2651,8 @@ module Operation : sig val tx_rollup_return_bond_case : Kind.tx_rollup_return_bond Kind.manager case + val tx_rollup_rejection_case : Kind.tx_rollup_rejection Kind.manager case + val register_global_constant_case : Kind.register_global_constant Kind.manager case @@ -2682,6 +2695,8 @@ module Operation : sig val tx_rollup_return_bond_case : Kind.tx_rollup_return_bond case + val tx_rollup_rejection_case : Kind.tx_rollup_rejection case + val sc_rollup_originate_case : Kind.sc_rollup_originate case val sc_rollup_add_messages_case : Kind.sc_rollup_add_messages case diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index d571fdb6c9d0..67a15c263f91 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -1266,6 +1266,32 @@ let apply_manager_operation_content : } in return (ctxt, result, []) + | Tx_rollup_rejection {rollup; level; hash; batch_index; nonce = _} -> + Tx_rollup_commitments.get_commitment_roots + ctxt + rollup + level + hash + batch_index + >>=? fun (ctxt, (before_batch, after_batch)) -> + (* TODO/TORU replay just this one batch -- for now, we'll assume that + rejection succeeds if before_root = after_root*) + fail_unless + (Tx_rollup_commitments.Commitment.batch_commitment_equal + before_batch + after_batch) + Tx_rollup_rejection.Wrong_rejection + >>=? fun () -> + Tx_rollup_commitments.reject_commitment ctxt rollup level hash + >>=? fun ctxt -> + let result = + Tx_rollup_rejection_result + { + consumed_gas = Gas.consumed ~since:before_operation ~until:ctxt; + balance_updates = []; + } + in + return (ctxt, result, []) | Sc_rollup_originate {kind; boot_sector} -> Sc_rollup_operations.originate ctxt ~kind ~boot_sector >>=? fun ({address; size}, ctxt) -> @@ -1422,6 +1448,8 @@ let precheck_manager_contents (type kind) ctxt (op : kind Kind.manager contents) >|=? fun () -> ctxt | Tx_rollup_return_bond _ -> assert_tx_rollup_feature_enabled ctxt >|=? fun () -> ctxt + | Tx_rollup_rejection _ -> + assert_tx_rollup_feature_enabled ctxt >|=? fun () -> ctxt | Sc_rollup_originate _ | Sc_rollup_add_messages _ -> assert_sc_rollup_feature_enabled ctxt >|=? fun () -> ctxt) >>=? fun ctxt -> @@ -1539,6 +1567,8 @@ let burn_storage_fees : return (ctxt, storage_limit, smopr) | Tx_rollup_return_bond_result payload -> return (ctxt, storage_limit, Tx_rollup_return_bond_result payload) + | Tx_rollup_rejection_result payload -> + return (ctxt, storage_limit, Tx_rollup_rejection_result payload) | Sc_rollup_originate_result payload -> let payer = `Contract payer in Fees.burn_sc_rollup_origination_fees diff --git a/src/proto_alpha/lib_protocol/apply_results.ml b/src/proto_alpha/lib_protocol/apply_results.ml index eb500f2fe480..59c76962497c 100644 --- a/src/proto_alpha/lib_protocol/apply_results.ml +++ b/src/proto_alpha/lib_protocol/apply_results.ml @@ -111,6 +111,11 @@ type _ successful_manager_operation_result = consumed_gas : Gas.Arith.fp; } -> Kind.tx_rollup_return_bond successful_manager_operation_result + | Tx_rollup_rejection_result : { + balance_updates : Receipt.balance_updates; + consumed_gas : Gas.Arith.fp; + } + -> Kind.tx_rollup_rejection successful_manager_operation_result | Sc_rollup_originate_result : { balance_updates : Receipt.balance_updates; address : Sc_rollup.Address.t; @@ -608,6 +613,33 @@ module Manager_result = struct Tx_rollup_return_bond_result {balance_updates; consumed_gas = consumed_milligas}) + let[@coq_axiom_with_reason "gadt"] tx_rollup_rejection_case = + make + ~op_case:Operation.Encoding.Manager_operations.tx_rollup_rejection_case + ~encoding: + Data_encoding.( + obj3 + (req "balance_updates" Receipt.balance_updates_encoding) + (dft "consumed_gas" Gas.Arith.n_integral_encoding Gas.Arith.zero) + (dft "consumed_milligas" Gas.Arith.n_fp_encoding Gas.Arith.zero)) + ~iselect:(function + | Internal_operation_result + (({operation = Tx_rollup_rejection _; _} as op), res) -> + Some (op, res) + | _ -> None) + ~select:(function + | Successful_manager_result (Tx_rollup_rejection_result _ as op) -> + Some op + | _ -> None) + ~kind:Kind.Tx_rollup_rejection_manager_kind + ~proj:(function + | Tx_rollup_rejection_result {balance_updates; consumed_gas} -> + (balance_updates, Gas.Arith.ceil consumed_gas, consumed_gas)) + ~inj:(fun (balance_updates, consumed_gas, consumed_milligas) -> + assert (Gas.Arith.(equal (ceil consumed_milligas) consumed_gas)) ; + Tx_rollup_rejection_result + {balance_updates; consumed_gas = consumed_milligas}) + let[@coq_axiom_with_reason "gadt"] sc_rollup_originate_case = make ~op_case:Operation.Encoding.Manager_operations.sc_rollup_originate_case @@ -819,6 +851,10 @@ let equal_manager_kind : Kind.Tx_rollup_return_bond_manager_kind ) -> Some Eq | (Kind.Tx_rollup_return_bond_manager_kind, _) -> None + | ( Kind.Tx_rollup_rejection_manager_kind, + Kind.Tx_rollup_rejection_manager_kind ) -> + Some Eq + | (Kind.Tx_rollup_rejection_manager_kind, _) -> None | ( Kind.Sc_rollup_originate_manager_kind, Kind.Sc_rollup_originate_manager_kind ) -> Some Eq @@ -1222,6 +1258,17 @@ module Encoding = struct Some (op, res) | _ -> None) + let[@coq_axiom_with_reason "gadt"] tx_rollup_rejection_case = + make_manager_case + Operation.Encoding.tx_rollup_rejection_case + Manager_result.tx_rollup_rejection_case + (function + | Contents_and_result + ( (Manager_operation {operation = Tx_rollup_rejection _; _} as op), + res ) -> + Some (op, res) + | _ -> None) + let[@coq_axiom_with_reason "gadt"] sc_rollup_originate_case = make_manager_case Operation.Encoding.sc_rollup_originate_case @@ -1283,6 +1330,7 @@ let contents_result_encoding = make tx_rollup_submit_batch_case; make tx_rollup_commit_case; make tx_rollup_return_bond_case; + make tx_rollup_rejection_case; make sc_rollup_originate_case; make sc_rollup_add_messages_case; ] @@ -1330,6 +1378,7 @@ let contents_and_result_encoding = make tx_rollup_submit_batch_case; make tx_rollup_commit_case; make tx_rollup_return_bond_case; + make tx_rollup_rejection_case; make sc_rollup_originate_case; make sc_rollup_add_messages_case; ] @@ -1712,6 +1761,32 @@ let kind_equal : } ) -> Some Eq | (Manager_operation {operation = Tx_rollup_return_bond _; _}, _) -> None + | ( Manager_operation {operation = Tx_rollup_rejection _; _}, + Manager_operation_result + {operation_result = Applied (Tx_rollup_rejection_result _); _} ) -> + Some Eq + | ( Manager_operation {operation = Tx_rollup_rejection _; _}, + Manager_operation_result + {operation_result = Backtracked (Tx_rollup_rejection_result _, _); _} ) + -> + Some Eq + | ( Manager_operation {operation = Tx_rollup_rejection _; _}, + Manager_operation_result + { + operation_result = + Failed (Alpha_context.Kind.Tx_rollup_rejection_manager_kind, _); + _; + } ) -> + Some Eq + | ( Manager_operation {operation = Tx_rollup_rejection _; _}, + Manager_operation_result + { + operation_result = + Skipped Alpha_context.Kind.Tx_rollup_rejection_manager_kind; + _; + } ) -> + Some Eq + | (Manager_operation {operation = Tx_rollup_rejection _; _}, _) -> None | ( Manager_operation {operation = Sc_rollup_originate _; _}, Manager_operation_result {operation_result = Applied (Sc_rollup_originate_result _); _} ) -> diff --git a/src/proto_alpha/lib_protocol/apply_results.mli b/src/proto_alpha/lib_protocol/apply_results.mli index 287c9e03f04f..6bd80edcba67 100644 --- a/src/proto_alpha/lib_protocol/apply_results.mli +++ b/src/proto_alpha/lib_protocol/apply_results.mli @@ -184,6 +184,11 @@ and _ successful_manager_operation_result = consumed_gas : Gas.Arith.fp; } -> Kind.tx_rollup_return_bond successful_manager_operation_result + | Tx_rollup_rejection_result : { + balance_updates : Receipt.balance_updates; + consumed_gas : Gas.Arith.fp; + } + -> Kind.tx_rollup_rejection successful_manager_operation_result | Sc_rollup_originate_result : { balance_updates : Receipt.balance_updates; address : Sc_rollup.Address.t; diff --git a/src/proto_alpha/lib_protocol/operation_repr.ml b/src/proto_alpha/lib_protocol/operation_repr.ml index 3bbe2b75040f..6d2e3fc66725 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.ml +++ b/src/proto_alpha/lib_protocol/operation_repr.ml @@ -79,6 +79,8 @@ module Kind = struct type tx_rollup_return_bond = Tx_rollup_return_bond_kind + type tx_rollup_rejection = Tx_rollup_rejection_kind + type sc_rollup_originate = Sc_rollup_originate_kind type sc_rollup_add_messages = Sc_rollup_add_messages_kind @@ -94,6 +96,7 @@ module Kind = struct | Tx_rollup_submit_batch_manager_kind : tx_rollup_submit_batch manager | Tx_rollup_commit_manager_kind : tx_rollup_commit manager | Tx_rollup_return_bond_manager_kind : tx_rollup_return_bond manager + | Tx_rollup_rejection_manager_kind : tx_rollup_rejection manager | Sc_rollup_originate_manager_kind : sc_rollup_originate manager | Sc_rollup_add_messages_manager_kind : sc_rollup_add_messages manager end @@ -288,6 +291,14 @@ and _ manager_operation = tx_rollup : Tx_rollup_repr.t; } -> Kind.tx_rollup_return_bond manager_operation + | Tx_rollup_rejection : { + rollup : Tx_rollup_repr.t; + level : Raw_level_repr.t; + hash : Tx_rollup_commitments_repr.Commitment_hash.t; + batch_index : int; + nonce : int64; + } + -> Kind.tx_rollup_rejection manager_operation | Sc_rollup_originate : { kind : Sc_rollup_repr.Kind.t; boot_sector : Sc_rollup_repr.PVM.boot_sector; @@ -313,6 +324,7 @@ let manager_kind : type kind. kind manager_operation -> kind Kind.manager = | Tx_rollup_submit_batch _ -> Kind.Tx_rollup_submit_batch_manager_kind | Tx_rollup_commit _ -> Kind.Tx_rollup_commit_manager_kind | Tx_rollup_return_bond _ -> Kind.Tx_rollup_return_bond_manager_kind + | Tx_rollup_rejection _ -> Kind.Tx_rollup_rejection_manager_kind | Sc_rollup_originate _ -> Kind.Sc_rollup_originate_manager_kind | Sc_rollup_add_messages _ -> Kind.Sc_rollup_add_messages_manager_kind @@ -595,6 +607,30 @@ module Encoding = struct inj = (fun tx_rollup -> Tx_rollup_return_bond {tx_rollup}); } + let[@coq_axiom_with_reason "gadt"] tx_rollup_rejection_case = + MCase + { + tag = tx_rollup_operation_tag_offset + 4; + name = "tx_rollup_rejection"; + encoding = + obj5 + (req "rollup" Tx_rollup_repr.encoding) + (req "level" Raw_level_repr.encoding) + (req "hash" Tx_rollup_commitments_repr.Commitment_hash.encoding) + (req "batch_index" int31) + (req "nonce" int64); + select = + (function + | Manager (Tx_rollup_rejection _ as op) -> Some op | _ -> None); + proj = + (function + | Tx_rollup_rejection {rollup; level; hash; batch_index; nonce} -> + (rollup, level, hash, batch_index, nonce)); + inj = + (fun (rollup, level, hash, batch_index, nonce) -> + Tx_rollup_rejection {rollup; level; hash; batch_index; nonce}); + } + let[@coq_axiom_with_reason "gadt"] sc_rollup_originate_case = MCase { @@ -657,6 +693,7 @@ module Encoding = struct make tx_rollup_submit_batch_case; make tx_rollup_commit_case; make tx_rollup_return_bond_case; + make tx_rollup_rejection_case; make sc_rollup_originate_case; make sc_rollup_add_messages_case; ] @@ -977,6 +1014,11 @@ module Encoding = struct (tx_rollup_operation_tag_offset + 3) Manager_operations.tx_rollup_return_bond_case + let tx_rollup_rejection_case = + make_manager_case + (tx_rollup_operation_tag_offset + 4) + Manager_operations.tx_rollup_rejection_case + let sc_rollup_originate_case = make_manager_case sc_rollup_operation_origination_tag @@ -1019,6 +1061,7 @@ module Encoding = struct make tx_rollup_submit_batch_case; make tx_rollup_commit_case; make tx_rollup_return_bond_case; + make tx_rollup_rejection_case; make sc_rollup_originate_case; make sc_rollup_add_messages_case; ] @@ -1228,6 +1271,8 @@ let equal_manager_operation_kind : | (Tx_rollup_commit _, _) -> None | (Tx_rollup_return_bond _, Tx_rollup_return_bond _) -> Some Eq | (Tx_rollup_return_bond _, _) -> None + | (Tx_rollup_rejection _, Tx_rollup_rejection _) -> Some Eq + | (Tx_rollup_rejection _, _) -> None | (Sc_rollup_originate _, Sc_rollup_originate _) -> Some Eq | (Sc_rollup_originate _, _) -> None | (Sc_rollup_add_messages _, Sc_rollup_add_messages _) -> Some Eq @@ -1346,6 +1391,9 @@ let internal_manager_operation_size (type a) (op : a manager_operation) = | Tx_rollup_return_bond _ -> (* Tx_rollup_return_bond operation can’t occur as internal operations *) assert false + | Tx_rollup_rejection _ -> + (* Tx_rollup_rejection operation can’t occur as internal operations *) + assert false let packed_internal_operation_in_memory_size : packed_internal_operation -> nodes_and_size = function diff --git a/src/proto_alpha/lib_protocol/operation_repr.mli b/src/proto_alpha/lib_protocol/operation_repr.mli index 0f5f31fa380a..e87d811ea064 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.mli +++ b/src/proto_alpha/lib_protocol/operation_repr.mli @@ -105,6 +105,8 @@ module Kind : sig type tx_rollup_return_bond = Tx_rollup_return_bond_kind + type tx_rollup_rejection = Tx_rollup_rejection_kind + type sc_rollup_originate = Sc_rollup_originate_kind type sc_rollup_add_messages = Sc_rollup_add_messages_kind @@ -120,6 +122,7 @@ module Kind : sig | Tx_rollup_submit_batch_manager_kind : tx_rollup_submit_batch manager | Tx_rollup_commit_manager_kind : tx_rollup_commit manager | Tx_rollup_return_bond_manager_kind : tx_rollup_return_bond manager + | Tx_rollup_rejection_manager_kind : tx_rollup_rejection manager | Sc_rollup_originate_manager_kind : sc_rollup_originate manager | Sc_rollup_add_messages_manager_kind : sc_rollup_add_messages manager end @@ -267,6 +270,14 @@ and _ manager_operation = tx_rollup : Tx_rollup_repr.t; } -> Kind.tx_rollup_return_bond manager_operation + | Tx_rollup_rejection : { + rollup : Tx_rollup_repr.t; + level : Raw_level_repr.t; + hash : Tx_rollup_commitments_repr.Commitment_hash.t; + batch_index : int; + nonce : int64; + } + -> Kind.tx_rollup_rejection manager_operation | Sc_rollup_originate : { kind : Sc_rollup_repr.Kind.t; boot_sector : Sc_rollup_repr.PVM.boot_sector; @@ -405,6 +416,8 @@ module Encoding : sig val tx_rollup_return_bond_case : Kind.tx_rollup_return_bond Kind.manager case + val tx_rollup_rejection_case : Kind.tx_rollup_rejection Kind.manager case + val sc_rollup_originate_case : Kind.sc_rollup_originate Kind.manager case val sc_rollup_add_messages_case : @@ -442,6 +455,8 @@ module Encoding : sig val tx_rollup_return_bond_case : Kind.tx_rollup_return_bond case + val tx_rollup_rejection_case : Kind.tx_rollup_rejection case + val sc_rollup_originate_case : Kind.sc_rollup_originate case val sc_rollup_add_messages_case : Kind.sc_rollup_add_messages case diff --git a/src/proto_alpha/lib_protocol/test/helpers/block.ml b/src/proto_alpha/lib_protocol/test/helpers/block.ml index eb19a648cea6..af9015de82c4 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/block.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/block.ml @@ -701,7 +701,8 @@ let bake_n_with_all_balance_updates ?(baking_mode = Application) ?policy | Set_deposits_limit_result _ | Tx_rollup_origination_result _ | Tx_rollup_submit_batch_result _ | Tx_rollup_commit_result _ | Tx_rollup_return_bond_result _ | Sc_rollup_originate_result _ - | Sc_rollup_add_messages_result _ -> + | Tx_rollup_rejection_result _ | Sc_rollup_add_messages_result _ + -> balance_updates_rev | Transaction_result (Transaction_to_contract_result {balance_updates; _}) @@ -734,6 +735,7 @@ let bake_n_with_origination_results ?(baking_mode = Application) ?policy n b = | Successful_manager_result (Tx_rollup_submit_batch_result _) | Successful_manager_result (Tx_rollup_commit_result _) | Successful_manager_result (Tx_rollup_return_bond_result _) + | Successful_manager_result (Tx_rollup_rejection_result _) | Successful_manager_result (Sc_rollup_originate_result _) | Successful_manager_result (Sc_rollup_add_messages_result _) -> origination_results_rev diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index 2e6350f7de07..60509f99ca53 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -567,3 +567,19 @@ let tx_rollup_return_bond ?counter ?fee ?gas_limit ?storage_limit ctxt >>=? fun to_sign_op -> Context.Contract.manager ctxt source >|=? fun account -> sign account.sk ctxt to_sign_op + +let tx_rollup_reject ?counter ?fee ?gas_limit ?storage_limit ctxt + (source : Contract.t) (rollup : Tx_rollup.t) (level : Raw_level.t) + (hash : Tx_rollup_commitments.Commitment_hash.t) (batch_index : int) + (nonce : int64) = + manager_operation + ?counter + ?fee + ?gas_limit + ?storage_limit + ~source + ctxt + (Tx_rollup_rejection {rollup; level; hash; batch_index; nonce}) + >>=? fun to_sign_op -> + Context.Contract.manager ctxt source >|=? fun account -> + sign account.sk ctxt to_sign_op diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index 2caed6377d09..0012c4534ee8 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -254,3 +254,19 @@ val tx_rollup_return_bond : Contract.t -> Tx_rollup.t -> Operation.packed tzresult Lwt.t + +(** [tx_rollup_reject ctxt source tx_rollup level hash batch_index nonce] + rejects a commitment. *) +val tx_rollup_reject : + ?counter:counter -> + ?fee:Tez.t -> + ?gas_limit:Gas.Arith.integral -> + ?storage_limit:counter -> + Context.t -> + Contract.t -> + Tx_rollup.t -> + Raw_level.t -> + Tx_rollup_commitments.Commitment_hash.t -> + int -> + int64 -> + Operation.packed tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index 8ee4d95480ac..3d2193c409a7 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -1194,6 +1194,55 @@ let test_commitment_finality_limit () = ignore i ; return () +(** [test_rejection] tests that rejection works. *) +let test_rejection () = + context_init 1 >>=? fun (b, contracts) -> + let contract1 = + WithExceptions.Option.get ~loc:__LOC__ @@ List.nth contracts 0 + in + originate b contract1 >>=? fun (b, tx_rollup) -> + (* Transactions in block 2 *) + make_transactions_in tx_rollup contract1 [2] b >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + Incremental.finalize_block i >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + let batches : Tx_rollup_commitments.Commitment.batch_commitment list = + [{root = Bytes.empty}] + in + (* "Random" numbers *) + let nonce = 1000L in + let nonce2 = 1001L in + make_commitment_for_batch i (raw_level 2l) tx_rollup >>=? fun commitment -> + let commitment = {commitment with batches} in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + let hash = Tx_rollup_commitments.Commitment.hash commitment in + (* Correct rejection *) + Op.tx_rollup_reject (I i) contract1 tx_rollup (raw_level 2l) hash 0 nonce + >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + (* Right commitment *) + make_commitment_for_batch i (raw_level 2l) tx_rollup + >>=? fun correct_commitment -> + Op.tx_rollup_commit (I i) contract1 tx_rollup correct_commitment + >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + Incremental.finalize_block i >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + let hash = Tx_rollup_commitments.Commitment.hash correct_commitment in + Op.tx_rollup_reject (I i) contract1 tx_rollup (raw_level 2l) hash 0 nonce2 + >>=? fun op -> + (* Wrong rejection *) + Incremental.add_operation i op ~expect_failure:(function + | Environment.Ecoproto_error (Tx_rollup_rejection.Wrong_rejection as e) + :: _ -> + Assert.test_error_encodings e ; + return_unit + | _ -> failwith "Should not reject correct commitments") + >>=? fun i -> + ignore i ; + return () + let test_full_inbox () = let constants = {constants with tx_rollup_max_unfinalized_levels = 15} in originate_with_constants constants 1 >>=? fun (b, tx_rollup, contracts) -> @@ -1261,6 +1310,7 @@ let tests = `Quick test_commitment_acceptance; Tztest.tztest "Test bond finalization" `Quick test_bond_finalization; + Tztest.tztest "Test rejection" `Quick test_rejection; Tztest.tztest "Test full inbox" `Quick test_full_inbox; Tztest.tztest "Test that commitment finalizes" diff --git a/src/proto_alpha/lib_protocol/ticket_operations_diff.ml b/src/proto_alpha/lib_protocol/ticket_operations_diff.ml index ff019e24bafa..d5ebab8861bd 100644 --- a/src/proto_alpha/lib_protocol/ticket_operations_diff.ml +++ b/src/proto_alpha/lib_protocol/ticket_operations_diff.ml @@ -252,6 +252,7 @@ let tickets_of_operation ctxt | Tx_rollup_submit_batch _ -> return (None, ctxt) | Tx_rollup_commit _ -> return (None, ctxt) | Tx_rollup_return_bond _ -> return (None, ctxt) + | Tx_rollup_rejection _ -> return (None, ctxt) | Sc_rollup_originate {kind = _; boot_sector = _} -> return (None, ctxt) | Sc_rollup_add_messages {rollup = _; messages = _} -> return (None, ctxt) diff --git a/tezt/_regressions/rpc/alpha.client.mempool.out b/tezt/_regressions/rpc/alpha.client.mempool.out index 9b820fb8f822..6f993b28a5d2 100644 --- a/tezt/_regressions/rpc/alpha.client.mempool.out +++ b/tezt/_regressions/rpc/alpha.client.mempool.out @@ -2012,6 +2012,66 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "additionalProperties": false }, + { + "title": "Tx_rollup_rejection", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "tx_rollup_rejection" + ] + }, + "source": { + "$ref": "#/definitions/Signature.Public_key_hash" + }, + "fee": { + "$ref": "#/definitions/alpha.mutez" + }, + "counter": { + "$ref": "#/definitions/positive_bignum" + }, + "gas_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "storage_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "rollup": { + "$ref": "#/definitions/alpha.tx_rollup_id" + }, + "level": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "hash": { + "$ref": "#/definitions/Commitment_hash" + }, + "batch_index": { + "type": "integer", + "minimum": -1073741824, + "maximum": 1073741823 + }, + "nonce": { + "$ref": "#/definitions/int64" + } + }, + "required": [ + "nonce", + "batch_index", + "hash", + "level", + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false + }, { "title": "Sc_rollup_originate", "type": "object", @@ -2313,6 +2373,11 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "pattern": "^([a-zA-Z0-9][a-zA-Z0-9])*$" } }, + "int64": { + "title": "64 bit integers", + "description": "Decimal representation of 64 bit integers", + "type": "string" + }, "micheline.alpha.michelson_v1.expression": { "oneOf": [ { @@ -5127,6 +5192,139 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "name": "Tx_rollup_return_bond" }, + { + "tag": 154, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "source", + "layout": { + "name": "public_key_hash", + "kind": "Ref" + }, + "data_kind": { + "size": 21, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "fee", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "counter", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "gas_limit", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "storage_limit", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "rollup", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 20, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "level", + "layout": { + "size": "Int32", + "kind": "Int" + }, + "data_kind": { + "size": 4, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "hash", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 32, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "batch_index", + "layout": { + "min": -1073741824, + "max": 1073741823, + "kind": "RangedInt" + }, + "data_kind": { + "size": 4, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "nonce", + "layout": { + "size": "Int64", + "kind": "Int" + }, + "data_kind": { + "size": 8, + "kind": "Float" + }, + "kind": "named" + } + ], + "name": "Tx_rollup_rejection" + }, { "tag": 200, "fields": [ @@ -7394,6 +7592,66 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "additionalProperties": false }, + { + "title": "Tx_rollup_rejection", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "tx_rollup_rejection" + ] + }, + "source": { + "$ref": "#/definitions/Signature.Public_key_hash" + }, + "fee": { + "$ref": "#/definitions/alpha.mutez" + }, + "counter": { + "$ref": "#/definitions/positive_bignum" + }, + "gas_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "storage_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "rollup": { + "$ref": "#/definitions/alpha.tx_rollup_id" + }, + "level": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "hash": { + "$ref": "#/definitions/Commitment_hash" + }, + "batch_index": { + "type": "integer", + "minimum": -1073741824, + "maximum": 1073741823 + }, + "nonce": { + "$ref": "#/definitions/int64" + } + }, + "required": [ + "nonce", + "batch_index", + "hash", + "level", + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false + }, { "title": "Sc_rollup_originate", "type": "object", @@ -7695,6 +7953,11 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "pattern": "^([a-zA-Z0-9][a-zA-Z0-9])*$" } }, + "int64": { + "title": "64 bit integers", + "description": "Decimal representation of 64 bit integers", + "type": "string" + }, "micheline.alpha.michelson_v1.expression": { "oneOf": [ { diff --git a/tezt/_regressions/rpc/alpha.proxy.mempool.out b/tezt/_regressions/rpc/alpha.proxy.mempool.out index f593d1b3b54f..ee50059f8dcb 100644 --- a/tezt/_regressions/rpc/alpha.proxy.mempool.out +++ b/tezt/_regressions/rpc/alpha.proxy.mempool.out @@ -2033,6 +2033,66 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "additionalProperties": false }, + { + "title": "Tx_rollup_rejection", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "tx_rollup_rejection" + ] + }, + "source": { + "$ref": "#/definitions/Signature.Public_key_hash" + }, + "fee": { + "$ref": "#/definitions/alpha.mutez" + }, + "counter": { + "$ref": "#/definitions/positive_bignum" + }, + "gas_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "storage_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "rollup": { + "$ref": "#/definitions/alpha.tx_rollup_id" + }, + "level": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "hash": { + "$ref": "#/definitions/Commitment_hash" + }, + "batch_index": { + "type": "integer", + "minimum": -1073741824, + "maximum": 1073741823 + }, + "nonce": { + "$ref": "#/definitions/int64" + } + }, + "required": [ + "nonce", + "batch_index", + "hash", + "level", + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false + }, { "title": "Sc_rollup_originate", "type": "object", @@ -2334,6 +2394,11 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "pattern": "^([a-zA-Z0-9][a-zA-Z0-9])*$" } }, + "int64": { + "title": "64 bit integers", + "description": "Decimal representation of 64 bit integers", + "type": "string" + }, "micheline.alpha.michelson_v1.expression": { "oneOf": [ { @@ -5148,6 +5213,139 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "name": "Tx_rollup_return_bond" }, + { + "tag": 154, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "source", + "layout": { + "name": "public_key_hash", + "kind": "Ref" + }, + "data_kind": { + "size": 21, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "fee", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "counter", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "gas_limit", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "storage_limit", + "layout": { + "name": "N.t", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "rollup", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 20, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "level", + "layout": { + "size": "Int32", + "kind": "Int" + }, + "data_kind": { + "size": 4, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "hash", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 32, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "batch_index", + "layout": { + "min": -1073741824, + "max": 1073741823, + "kind": "RangedInt" + }, + "data_kind": { + "size": 4, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "nonce", + "layout": { + "size": "Int64", + "kind": "Int" + }, + "data_kind": { + "size": 8, + "kind": "Float" + }, + "kind": "named" + } + ], + "name": "Tx_rollup_rejection" + }, { "tag": 200, "fields": [ @@ -7415,6 +7613,66 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ], "additionalProperties": false }, + { + "title": "Tx_rollup_rejection", + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "tx_rollup_rejection" + ] + }, + "source": { + "$ref": "#/definitions/Signature.Public_key_hash" + }, + "fee": { + "$ref": "#/definitions/alpha.mutez" + }, + "counter": { + "$ref": "#/definitions/positive_bignum" + }, + "gas_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "storage_limit": { + "$ref": "#/definitions/positive_bignum" + }, + "rollup": { + "$ref": "#/definitions/alpha.tx_rollup_id" + }, + "level": { + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "hash": { + "$ref": "#/definitions/Commitment_hash" + }, + "batch_index": { + "type": "integer", + "minimum": -1073741824, + "maximum": 1073741823 + }, + "nonce": { + "$ref": "#/definitions/int64" + } + }, + "required": [ + "nonce", + "batch_index", + "hash", + "level", + "rollup", + "storage_limit", + "gas_limit", + "counter", + "fee", + "source", + "kind" + ], + "additionalProperties": false + }, { "title": "Sc_rollup_originate", "type": "object", @@ -7716,6 +7974,11 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "pattern": "^([a-zA-Z0-9][a-zA-Z0-9])*$" } }, + "int64": { + "title": "64 bit integers", + "description": "Decimal representation of 64 bit integers", + "type": "string" + }, "micheline.alpha.michelson_v1.expression": { "oneOf": [ { -- GitLab From 50ced58da670b2bf2e100331f85ee7c410b624be Mon Sep 17 00:00:00 2001 From: David Turner Date: Wed, 12 Jan 2022 13:07:24 -0500 Subject: [PATCH 31/31] Tx_rollups: Send batch along with rejection Annoyingly, at the time of rejection, we don't have in hand the batch itself, since it's from an earlier block. So rejections need to re-send it. Later, we will check that the included batch has a hash which actually matches the hash recorded in the inbox. Co-author-by: Marigold Co-author-by: Nomadic Labs Co-author-by: Oxhead Alpha --- .../lib_client/operation_result.ml | 2 +- .../client_proto_context_commands.ml | 1 + .../lib_protocol/alpha_context.mli | 10 + src/proto_alpha/lib_protocol/apply.ml | 4 +- .../lib_protocol/operation_repr.ml | 14 +- .../lib_protocol/operation_repr.mli | 1 + .../lib_protocol/test/helpers/op.ml | 4 +- .../lib_protocol/test/helpers/op.mli | 3 +- .../integration/operations/test_tx_rollup.ml | 23 +- .../lib_protocol/tx_rollup_inbox_storage.ml | 13 +- .../lib_protocol/tx_rollup_inbox_storage.mli | 11 + .../lib_protocol/tx_rollup_rejection_repr.ml | 14 +- .../lib_protocol/tx_rollup_rejection_repr.mli | 1 + .../_regressions/rpc/alpha.client.mempool.out | 344 +++++++++++++++++- tezt/_regressions/rpc/alpha.proxy.mempool.out | 344 +++++++++++++++++- tezt/lib_tezos/client.ml | 2 + tezt/tests/tx_rollup.ml | 28 +- 17 files changed, 774 insertions(+), 45 deletions(-) diff --git a/src/proto_alpha/lib_client/operation_result.ml b/src/proto_alpha/lib_client/operation_result.ml index 6e3f43d21ecf..756388807589 100644 --- a/src/proto_alpha/lib_client/operation_result.ml +++ b/src/proto_alpha/lib_client/operation_result.ml @@ -213,7 +213,7 @@ let pp_manager_operation_content (type kind) source internal pp_result ppf source pp_result result - | Tx_rollup_rejection {rollup; level; hash; batch_index; nonce} -> + | Tx_rollup_rejection {rollup; level; hash; batch_index; batch = _; nonce} -> Format.fprintf ppf "@[%s:rollup %a level %a commitment %a index %d nonce %Lx @,\ diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index fba5705a49ae..3c38176a4008 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -2229,6 +2229,7 @@ let commands_rw () = ~fee_parameter ~tx_rollup ~content + ~gas_limit:(Gas.Arith.integral_of_int_exn 10000) () >>=? fun _res -> return_unit); command diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 0ff661ed9cfa..86ae1d404eed 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2123,6 +2123,14 @@ module Tx_rollup_inbox : sig Tx_rollup.t -> (context * Raw_level.t option * Raw_level.t option) tzresult Lwt.t + val check_batch_hash : + context -> + Raw_level.t -> + Tx_rollup.t -> + int -> + Tx_rollup_message.t -> + context tzresult Lwt.t + module Internal_for_tests : sig type metadata = { count : int; @@ -2274,6 +2282,7 @@ module Tx_rollup_rejection : sig level : Raw_level.t; hash : Tx_rollup_commitments.Commitment_hash.t; batch_index : int; + batch : Tx_rollup_message.t; } val encoding : t Data_encoding.t @@ -2490,6 +2499,7 @@ and _ manager_operation = level : Raw_level.t; hash : Tx_rollup_commitments.Commitment_hash.t; batch_index : int; + batch : Tx_rollup_message.t; nonce : int64; } -> Kind.tx_rollup_rejection manager_operation diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 67a15c263f91..09af3a1b84b8 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -1266,7 +1266,9 @@ let apply_manager_operation_content : } in return (ctxt, result, []) - | Tx_rollup_rejection {rollup; level; hash; batch_index; nonce = _} -> + | Tx_rollup_rejection {rollup; level; hash; batch_index; nonce = _; batch} -> + Tx_rollup_inbox.check_batch_hash ctxt level rollup batch_index batch + >>=? fun ctxt -> Tx_rollup_commitments.get_commitment_roots ctxt rollup diff --git a/src/proto_alpha/lib_protocol/operation_repr.ml b/src/proto_alpha/lib_protocol/operation_repr.ml index 6d2e3fc66725..93352617f1f1 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.ml +++ b/src/proto_alpha/lib_protocol/operation_repr.ml @@ -296,6 +296,7 @@ and _ manager_operation = level : Raw_level_repr.t; hash : Tx_rollup_commitments_repr.Commitment_hash.t; batch_index : int; + batch : Tx_rollup_message_repr.t; nonce : int64; } -> Kind.tx_rollup_rejection manager_operation @@ -613,22 +614,25 @@ module Encoding = struct tag = tx_rollup_operation_tag_offset + 4; name = "tx_rollup_rejection"; encoding = - obj5 + obj6 (req "rollup" Tx_rollup_repr.encoding) (req "level" Raw_level_repr.encoding) (req "hash" Tx_rollup_commitments_repr.Commitment_hash.encoding) (req "batch_index" int31) + (req "batch" Tx_rollup_message_repr.encoding) (req "nonce" int64); select = (function | Manager (Tx_rollup_rejection _ as op) -> Some op | _ -> None); proj = (function - | Tx_rollup_rejection {rollup; level; hash; batch_index; nonce} -> - (rollup, level, hash, batch_index, nonce)); + | Tx_rollup_rejection + {rollup; level; hash; batch_index; batch; nonce} -> + (rollup, level, hash, batch_index, batch, nonce)); inj = - (fun (rollup, level, hash, batch_index, nonce) -> - Tx_rollup_rejection {rollup; level; hash; batch_index; nonce}); + (fun (rollup, level, hash, batch_index, batch, nonce) -> + Tx_rollup_rejection + {rollup; level; hash; batch_index; batch; nonce}); } let[@coq_axiom_with_reason "gadt"] sc_rollup_originate_case = diff --git a/src/proto_alpha/lib_protocol/operation_repr.mli b/src/proto_alpha/lib_protocol/operation_repr.mli index e87d811ea064..03d68c8a1758 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.mli +++ b/src/proto_alpha/lib_protocol/operation_repr.mli @@ -275,6 +275,7 @@ and _ manager_operation = level : Raw_level_repr.t; hash : Tx_rollup_commitments_repr.Commitment_hash.t; batch_index : int; + batch : Tx_rollup_message_repr.t; nonce : int64; } -> Kind.tx_rollup_rejection manager_operation diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index 60509f99ca53..36a21b6eeb1a 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -571,7 +571,7 @@ let tx_rollup_return_bond ?counter ?fee ?gas_limit ?storage_limit ctxt let tx_rollup_reject ?counter ?fee ?gas_limit ?storage_limit ctxt (source : Contract.t) (rollup : Tx_rollup.t) (level : Raw_level.t) (hash : Tx_rollup_commitments.Commitment_hash.t) (batch_index : int) - (nonce : int64) = + (batch : Tx_rollup_message.t) (nonce : int64) = manager_operation ?counter ?fee @@ -579,7 +579,7 @@ let tx_rollup_reject ?counter ?fee ?gas_limit ?storage_limit ctxt ?storage_limit ~source ctxt - (Tx_rollup_rejection {rollup; level; hash; batch_index; nonce}) + (Tx_rollup_rejection {rollup; level; hash; batch_index; batch; nonce}) >>=? fun to_sign_op -> Context.Contract.manager ctxt source >|=? fun account -> sign account.sk ctxt to_sign_op diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index 0012c4534ee8..94813029ddfe 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -255,7 +255,7 @@ val tx_rollup_return_bond : Tx_rollup.t -> Operation.packed tzresult Lwt.t -(** [tx_rollup_reject ctxt source tx_rollup level hash batch_index nonce] +(** [tx_rollup_reject ctxt source tx_rollup level hash batch_index batch nonce] rejects a commitment. *) val tx_rollup_reject : ?counter:counter -> @@ -268,5 +268,6 @@ val tx_rollup_reject : Raw_level.t -> Tx_rollup_commitments.Commitment_hash.t -> int -> + Tx_rollup_message.t -> int64 -> Operation.packed tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index 3d2193c409a7..2185669e558b 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -247,6 +247,9 @@ let range start top = let rec aux n acc = if n < start then acc else aux (n - 1) (n :: acc) in aux top [] +let message txt = + fst @@ Tx_rollup_message.make_batch txt + (** ---- TESTS -------------------------------------------------------------- *) (** [test_origination] originates a transaction rollup and checks that @@ -1218,7 +1221,15 @@ let test_rejection () = Incremental.add_operation i op >>=? fun i -> let hash = Tx_rollup_commitments.Commitment.hash commitment in (* Correct rejection *) - Op.tx_rollup_reject (I i) contract1 tx_rollup (raw_level 2l) hash 0 nonce + Op.tx_rollup_reject + (I i) + contract1 + tx_rollup + (raw_level 2l) + hash + 0 + (message "batch") + nonce >>=? fun op -> Incremental.add_operation i op >>=? fun i -> (* Right commitment *) @@ -1230,7 +1241,15 @@ let test_rejection () = Incremental.finalize_block i >>=? fun b -> Incremental.begin_construction b >>=? fun i -> let hash = Tx_rollup_commitments.Commitment.hash correct_commitment in - Op.tx_rollup_reject (I i) contract1 tx_rollup (raw_level 2l) hash 0 nonce2 + Op.tx_rollup_reject + (I i) + contract1 + tx_rollup + (raw_level 2l) + hash + 0 + (message "batch") + nonce2 >>=? fun op -> (* Wrong rejection *) Incremental.add_operation i op ~expect_failure:(function diff --git a/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml b/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml index 9c297d782fd0..d1ea2715e1eb 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.ml @@ -203,7 +203,7 @@ let get : (Raw_context.t * Tx_rollup_inbox_repr.t) tzresult Lwt.t = fun ctxt ~level tx_rollup -> (* - [inbox_opt] checks whether or not [tx_rollup] is valid, so we + [inbox_opt] c_hecks whether or not [tx_rollup] is valid, so we don’t have to do it here. *) find ctxt ~level tx_rollup >>=? function @@ -233,6 +233,17 @@ let get_metadata : | (_, None) -> fail (Tx_rollup_inbox_does_not_exist (tx_rollup, level)) | (ctxt, Some metadata) -> return (ctxt, metadata) +let check_batch_hash : + Raw_context.t -> + Raw_level_repr.t -> + Tx_rollup_repr.t -> + int -> + Tx_rollup_message_repr.t -> + Raw_context.t tzresult Lwt.t = + fun ctxt _level _rollup _batch_index _batch -> + (* TODO/TORU: write this! *) + return ctxt + (* Error registration *) let () = diff --git a/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.mli b/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.mli index 5e6619ef5389..498dd5cdea82 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_inbox_storage.mli @@ -146,3 +146,14 @@ val get_metadata : Raw_level_repr.t -> Tx_rollup_repr.t -> (Raw_context.t * Tx_rollup_inbox_repr.metadata) tzresult Lwt.t + +(* [check_batch_hash ctxt level rollup index batch] checks that a + batch for an inbox has the expected hash, and fails if it does + not. *) +val check_batch_hash : + Raw_context.t -> + Raw_level_repr.t -> + Tx_rollup_repr.t -> + int -> + Tx_rollup_message_repr.t -> + Raw_context.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.ml b/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.ml index 397f35793ccb..9bb755b804d8 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.ml +++ b/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.ml @@ -44,17 +44,19 @@ type t = { level : Raw_level_repr.t; hash : Tx_rollup_commitments_repr.Commitment_hash.t; batch_index : int; + batch : Tx_rollup_message_repr.t; } let encoding = let open Data_encoding in conv - (fun {rollup; level; hash; batch_index} -> - (rollup, level, hash, batch_index)) - (fun (rollup, level, hash, batch_index) -> - {rollup; level; hash; batch_index}) - (obj4 + (fun {rollup; level; hash; batch_index; batch} -> + (rollup, level, hash, batch_index, batch)) + (fun (rollup, level, hash, batch_index, batch) -> + {rollup; level; hash; batch_index; batch}) + (obj5 (req "rollup" Tx_rollup_repr.encoding) (req "level" Raw_level_repr.encoding) (req "hash" Tx_rollup_commitments_repr.Commitment_hash.encoding) - (req "batch_index" int31)) + (req "batch_index" int31) + (req "batch" Tx_rollup_message_repr.encoding)) diff --git a/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.mli b/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.mli index 93d3fa1ba7a5..1c617d68f7ca 100644 --- a/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.mli +++ b/src/proto_alpha/lib_protocol/tx_rollup_rejection_repr.mli @@ -32,6 +32,7 @@ type t = { level : Raw_level_repr.t; hash : Tx_rollup_commitments_repr.Commitment_hash.t; batch_index : int; + batch : Tx_rollup_message_repr.t; } val encoding : t Data_encoding.t diff --git a/tezt/_regressions/rpc/alpha.client.mempool.out b/tezt/_regressions/rpc/alpha.client.mempool.out index 6f993b28a5d2..0e863891423a 100644 --- a/tezt/_regressions/rpc/alpha.client.mempool.out +++ b/tezt/_regressions/rpc/alpha.client.mempool.out @@ -693,6 +693,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "title": "A Ed25519, Secp256k1, or P256 public key hash (Base58Check-encoded)", "$ref": "#/definitions/unistring" }, + "Tx_rollup_l2_address": { + "title": "The hash of a BLS public key used to identify a L2 ticket holders (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "alpha.block_header.alpha.full_header": { "title": "Shell header", "description": "Block header's shell-related content. It contains information such as the block level, its predecessor and timestamp.", @@ -2053,12 +2057,71 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "minimum": -1073741824, "maximum": 1073741823 }, + "batch": { + "oneOf": [ + { + "title": "Batch", + "type": "object", + "properties": { + "batch": { + "$ref": "#/definitions/unistring" + } + }, + "required": [ + "batch" + ], + "additionalProperties": false + }, + { + "title": "Deposit", + "type": "object", + "properties": { + "deposit": { + "type": "object", + "properties": { + "destination": { + "oneOf": [ + { + "title": "Key", + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + { + "title": "Value", + "$ref": "#/definitions/Tx_rollup_l2_address" + } + ] + }, + "ticket_hash": { + "$ref": "#/definitions/script_expr" + }, + "amount": { + "$ref": "#/definitions/int64" + } + }, + "required": [ + "amount", + "ticket_hash", + "destination" + ], + "additionalProperties": false + } + }, + "required": [ + "deposit" + ], + "additionalProperties": false + } + ] + }, "nonce": { "$ref": "#/definitions/int64" } }, "required": [ "nonce", + "batch", "batch_index", "hash", "level", @@ -2460,6 +2523,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "description": "Decimal representation of a positive big number", "type": "string" }, + "script_expr": { + "title": "A script expression ID (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "timestamp.protocol": { "description": "A timestamp as seen by the protocol: second-level precision, epoch based.", "$ref": "#/definitions/unistring" @@ -2585,10 +2652,199 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ] } }, + { + "description": { + "title": "X_4" + }, + "encoding": { + "tag_size": "Uint8", + "kind": { + "kind": "Dynamic" + }, + "cases": [ + { + "tag": 0, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "layout": { + "size": "Int32", + "kind": "Int" + }, + "kind": "anon", + "data_kind": { + "size": 4, + "kind": "Float" + } + } + ], + "name": "Key" + }, + { + "tag": 1, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "Tx_rollup_l2_address", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 20, + "kind": "Float" + }, + "kind": "named" + } + ], + "name": "Value" + } + ] + } + }, + { + "description": { + "title": "X_3" + }, + "encoding": { + "fields": [ + { + "name": "destination", + "layout": { + "name": "X_4", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "ticket_hash", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 32, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "amount", + "layout": { + "size": "Int64", + "kind": "Int" + }, + "data_kind": { + "size": 8, + "kind": "Float" + }, + "kind": "named" + } + ] + } + }, { "description": { "title": "X_5" }, + "encoding": { + "tag_size": "Uint8", + "kind": { + "kind": "Dynamic" + }, + "cases": [ + { + "tag": 0, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "kind": "dyn", + "num_fields": 1, + "size": "Uint30" + }, + { + "name": "batch", + "layout": { + "kind": "String" + }, + "data_kind": { + "kind": "Variable" + }, + "kind": "named" + } + ], + "name": "Batch" + }, + { + "tag": 1, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "deposit", + "layout": { + "name": "X_3", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + } + ], + "name": "Deposit" + } + ] + } + }, + { + "description": { + "title": "X_8" + }, "encoding": { "tag_size": "Uint8", "kind": { @@ -2657,7 +2913,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' }, { "description": { - "title": "X_3" + "title": "X_6" }, "encoding": { "fields": [ @@ -2695,7 +2951,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' { "name": "predecessor", "layout": { - "name": "X_5", + "name": "X_8", "kind": "Ref" }, "data_kind": { @@ -3031,7 +3287,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' }, { "description": { - "title": "X_6" + "title": "X_9" }, "encoding": { "fields": [ @@ -4446,7 +4702,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' { "name": "parameters", "layout": { - "name": "X_6", + "name": "X_9", "kind": "Ref" }, "data_kind": { @@ -5096,7 +5352,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' { "name": "commitment", "layout": { - "name": "X_3", + "name": "X_6", "kind": "Ref" }, "data_kind": { @@ -5310,6 +5566,17 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' }, "kind": "named" }, + { + "name": "batch", + "layout": { + "name": "X_5", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, { "name": "nonce", "layout": { @@ -6273,6 +6540,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "title": "A Ed25519, Secp256k1, or P256 public key hash (Base58Check-encoded)", "$ref": "#/definitions/unistring" }, + "Tx_rollup_l2_address": { + "title": "The hash of a BLS public key used to identify a L2 ticket holders (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "alpha.block_header.alpha.full_header": { "title": "Shell header", "description": "Block header's shell-related content. It contains information such as the block level, its predecessor and timestamp.", @@ -7633,12 +7904,71 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "minimum": -1073741824, "maximum": 1073741823 }, + "batch": { + "oneOf": [ + { + "title": "Batch", + "type": "object", + "properties": { + "batch": { + "$ref": "#/definitions/unistring" + } + }, + "required": [ + "batch" + ], + "additionalProperties": false + }, + { + "title": "Deposit", + "type": "object", + "properties": { + "deposit": { + "type": "object", + "properties": { + "destination": { + "oneOf": [ + { + "title": "Key", + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + { + "title": "Value", + "$ref": "#/definitions/Tx_rollup_l2_address" + } + ] + }, + "ticket_hash": { + "$ref": "#/definitions/script_expr" + }, + "amount": { + "$ref": "#/definitions/int64" + } + }, + "required": [ + "amount", + "ticket_hash", + "destination" + ], + "additionalProperties": false + } + }, + "required": [ + "deposit" + ], + "additionalProperties": false + } + ] + }, "nonce": { "$ref": "#/definitions/int64" } }, "required": [ "nonce", + "batch", "batch_index", "hash", "level", @@ -8071,6 +8401,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "description": "Decimal representation of a positive big number", "type": "string" }, + "script_expr": { + "title": "A script expression ID (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "timestamp.protocol": { "description": "A timestamp as seen by the protocol: second-level precision, epoch based.", "$ref": "#/definitions/unistring" diff --git a/tezt/_regressions/rpc/alpha.proxy.mempool.out b/tezt/_regressions/rpc/alpha.proxy.mempool.out index ee50059f8dcb..fad54fc966a7 100644 --- a/tezt/_regressions/rpc/alpha.proxy.mempool.out +++ b/tezt/_regressions/rpc/alpha.proxy.mempool.out @@ -714,6 +714,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "title": "A Ed25519, Secp256k1, or P256 public key hash (Base58Check-encoded)", "$ref": "#/definitions/unistring" }, + "Tx_rollup_l2_address": { + "title": "The hash of a BLS public key used to identify a L2 ticket holders (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "alpha.block_header.alpha.full_header": { "title": "Shell header", "description": "Block header's shell-related content. It contains information such as the block level, its predecessor and timestamp.", @@ -2074,12 +2078,71 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "minimum": -1073741824, "maximum": 1073741823 }, + "batch": { + "oneOf": [ + { + "title": "Batch", + "type": "object", + "properties": { + "batch": { + "$ref": "#/definitions/unistring" + } + }, + "required": [ + "batch" + ], + "additionalProperties": false + }, + { + "title": "Deposit", + "type": "object", + "properties": { + "deposit": { + "type": "object", + "properties": { + "destination": { + "oneOf": [ + { + "title": "Key", + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + { + "title": "Value", + "$ref": "#/definitions/Tx_rollup_l2_address" + } + ] + }, + "ticket_hash": { + "$ref": "#/definitions/script_expr" + }, + "amount": { + "$ref": "#/definitions/int64" + } + }, + "required": [ + "amount", + "ticket_hash", + "destination" + ], + "additionalProperties": false + } + }, + "required": [ + "deposit" + ], + "additionalProperties": false + } + ] + }, "nonce": { "$ref": "#/definitions/int64" } }, "required": [ "nonce", + "batch", "batch_index", "hash", "level", @@ -2481,6 +2544,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "description": "Decimal representation of a positive big number", "type": "string" }, + "script_expr": { + "title": "A script expression ID (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "timestamp.protocol": { "description": "A timestamp as seen by the protocol: second-level precision, epoch based.", "$ref": "#/definitions/unistring" @@ -2606,10 +2673,199 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' ] } }, + { + "description": { + "title": "X_4" + }, + "encoding": { + "tag_size": "Uint8", + "kind": { + "kind": "Dynamic" + }, + "cases": [ + { + "tag": 0, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "layout": { + "size": "Int32", + "kind": "Int" + }, + "kind": "anon", + "data_kind": { + "size": 4, + "kind": "Float" + } + } + ], + "name": "Key" + }, + { + "tag": 1, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "Tx_rollup_l2_address", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 20, + "kind": "Float" + }, + "kind": "named" + } + ], + "name": "Value" + } + ] + } + }, + { + "description": { + "title": "X_3" + }, + "encoding": { + "fields": [ + { + "name": "destination", + "layout": { + "name": "X_4", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, + { + "name": "ticket_hash", + "layout": { + "kind": "Bytes" + }, + "data_kind": { + "size": 32, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "amount", + "layout": { + "size": "Int64", + "kind": "Int" + }, + "data_kind": { + "size": 8, + "kind": "Float" + }, + "kind": "named" + } + ] + } + }, { "description": { "title": "X_5" }, + "encoding": { + "tag_size": "Uint8", + "kind": { + "kind": "Dynamic" + }, + "cases": [ + { + "tag": 0, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "kind": "dyn", + "num_fields": 1, + "size": "Uint30" + }, + { + "name": "batch", + "layout": { + "kind": "String" + }, + "data_kind": { + "kind": "Variable" + }, + "kind": "named" + } + ], + "name": "Batch" + }, + { + "tag": 1, + "fields": [ + { + "name": "Tag", + "layout": { + "size": "Uint8", + "kind": "Int" + }, + "data_kind": { + "size": 1, + "kind": "Float" + }, + "kind": "named" + }, + { + "name": "deposit", + "layout": { + "name": "X_3", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + } + ], + "name": "Deposit" + } + ] + } + }, + { + "description": { + "title": "X_8" + }, "encoding": { "tag_size": "Uint8", "kind": { @@ -2678,7 +2934,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' }, { "description": { - "title": "X_3" + "title": "X_6" }, "encoding": { "fields": [ @@ -2716,7 +2972,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' { "name": "predecessor", "layout": { - "name": "X_5", + "name": "X_8", "kind": "Ref" }, "data_kind": { @@ -3052,7 +3308,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' }, { "description": { - "title": "X_6" + "title": "X_9" }, "encoding": { "fields": [ @@ -4467,7 +4723,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' { "name": "parameters", "layout": { - "name": "X_6", + "name": "X_9", "kind": "Ref" }, "data_kind": { @@ -5117,7 +5373,7 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' { "name": "commitment", "layout": { - "name": "X_3", + "name": "X_6", "kind": "Ref" }, "data_kind": { @@ -5331,6 +5587,17 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' }, "kind": "named" }, + { + "name": "batch", + "layout": { + "name": "X_5", + "kind": "Ref" + }, + "data_kind": { + "kind": "Dynamic" + }, + "kind": "named" + }, { "name": "nonce", "layout": { @@ -6294,6 +6561,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "title": "A Ed25519, Secp256k1, or P256 public key hash (Base58Check-encoded)", "$ref": "#/definitions/unistring" }, + "Tx_rollup_l2_address": { + "title": "The hash of a BLS public key used to identify a L2 ticket holders (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "alpha.block_header.alpha.full_header": { "title": "Shell header", "description": "Block header's shell-related content. It contains information such as the block level, its predecessor and timestamp.", @@ -7654,12 +7925,71 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "minimum": -1073741824, "maximum": 1073741823 }, + "batch": { + "oneOf": [ + { + "title": "Batch", + "type": "object", + "properties": { + "batch": { + "$ref": "#/definitions/unistring" + } + }, + "required": [ + "batch" + ], + "additionalProperties": false + }, + { + "title": "Deposit", + "type": "object", + "properties": { + "deposit": { + "type": "object", + "properties": { + "destination": { + "oneOf": [ + { + "title": "Key", + "type": "integer", + "minimum": -2147483648, + "maximum": 2147483647 + }, + { + "title": "Value", + "$ref": "#/definitions/Tx_rollup_l2_address" + } + ] + }, + "ticket_hash": { + "$ref": "#/definitions/script_expr" + }, + "amount": { + "$ref": "#/definitions/int64" + } + }, + "required": [ + "amount", + "ticket_hash", + "destination" + ], + "additionalProperties": false + } + }, + "required": [ + "deposit" + ], + "additionalProperties": false + } + ] + }, "nonce": { "$ref": "#/definitions/int64" } }, "required": [ "nonce", + "batch", "batch_index", "hash", "level", @@ -8092,6 +8422,10 @@ curl -s 'http://localhost:[PORT]/describe/chains/main/mempool?recurse=yes' "description": "Decimal representation of a positive big number", "type": "string" }, + "script_expr": { + "title": "A script expression ID (Base58Check-encoded)", + "$ref": "#/definitions/unistring" + }, "timestamp.protocol": { "description": "A timestamp as seen by the protocol: second-level precision, epoch based.", "$ref": "#/definitions/unistring" diff --git a/tezt/lib_tezos/client.ml b/tezt/lib_tezos/client.ml index 3bfe847cd4bc..26acf952f9a5 100644 --- a/tezt/lib_tezos/client.ml +++ b/tezt/lib_tezos/client.ml @@ -1147,6 +1147,8 @@ let spawn_submit_tx_rollup_batch ?(wait = "none") ?burn_cap ?storage_limit tx_rollup; "from"; src; + "--fee-cap"; + "10000000000"; ] @ Option.fold ~none:[] diff --git a/tezt/tests/tx_rollup.ml b/tezt/tests/tx_rollup.ml index 95d650a93976..d43bd5cf3ff6 100644 --- a/tezt/tests/tx_rollup.ml +++ b/tezt/tests/tx_rollup.ml @@ -155,6 +155,8 @@ let test_submit_batch ~protocols = ~content:batch ~tx_rollup ~src:Constant.bootstrap1.public_key_hash + ~burn_cap:Tez.(of_int 9999999) + ~storage_limit:60_000 client in let* () = Client.bake_for client in @@ -251,6 +253,8 @@ let test_submit_from_originated_source ~protocols = ~content:batch ~tx_rollup ~src:originated_contract + ~burn_cap:Tez.(of_int 9999999) + ~storage_limit:60_000 client |> Process.check_error ~exit_code:1 @@ -340,6 +344,7 @@ let test_tx_node_is_ready = unit) let test_tx_node_store_inbox = + (* HERE HERE HERE *) let open Tezt_tezos in test_with_setup ~__FILE__ @@ -376,6 +381,8 @@ let test_tx_node_store_inbox = ~content:batch ~tx_rollup:tx_rollup_hash ~src:Constant.bootstrap1.public_key_hash + ~burn_cap:Tez.(of_int 9999999) + ~storage_limit:60_000 client in let* () = Client.bake_for client in @@ -399,7 +406,7 @@ let test_tx_node_store_inbox = node_inbox.contents inbox.contents ~error_msg: - "Content of inboxes on the client side should be equal to the \ + "Content of inboxes on the client side should be equal to the \ content of inboxes on the node side" (list string)) ; @@ -411,22 +418,11 @@ let test_tx_node_store_inbox = ~content:snd_batch ~tx_rollup:tx_rollup_hash ~src:Constant.bootstrap1.public_key_hash + ~burn_cap:Tez.(of_int 99999999) + ~storage_limit:65_000_000 client in - let* () = Client.bake_for client in - let* _ = Node.wait_for_level node 4 in - let* node_inbox = get_node_inbox tx_node in - let* inbox = get_inbox ~hooks tx_rollup_hash client in - (* Enusre that stored inboxes on daemon side are equivalent of inboxes - returned by the rpc call. *) - assert (Int.equal node_inbox.cumulated_size inbox.cumulated_size) ; - assert (List.equal String.equal node_inbox.contents inbox.contents) ; + unit) -let register ~protocols = - test_submit_batch ~protocols ; - test_invalid_rollup_address ~protocols ; - test_submit_from_originated_source ~protocols ; - test_node_configuration ~protocols ; - test_tx_node_is_ready ~protocols ; - test_tx_node_store_inbox ~protocols +let register ~protocols = test_tx_node_store_inbox ~protocols -- GitLab