diff --git a/CHANGES.rst b/CHANGES.rst index 309d6ba3c1ec00e66710de6971f7c8b421561a9d..53df1a40b8f5c456ae6c0469abfd1ea9d1b7d468 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -223,6 +223,10 @@ Node message ``no validation plugin found for protocol ``. (MR :gl:`!9583`) +- Add RPC to get smart rollup's balance of ticket with specified ticketer, content type, and content: + ``POST chains//blocks//context/smart_rollups/smart_rollup//ticket_balance`` + (MR :gl:`!9535`) + Client ------ - Adding client commands to generate, open and verify a time-lock. diff --git a/src/proto_016_PtMumbai/lib_plugin/RPC.ml b/src/proto_016_PtMumbai/lib_plugin/RPC.ml index 722c001df1f0b75e4807137bafb7176e45b86110..00cdf1f874cb1db252c31ea332377f715f65ff96 100644 --- a/src/proto_016_PtMumbai/lib_plugin/RPC.ml +++ b/src/proto_016_PtMumbai/lib_plugin/RPC.ml @@ -2182,6 +2182,17 @@ module Sc_rollup = struct ~query:RPC_query.empty ~output:Sc_rollup.Inbox.encoding RPC_path.(path_sc_rollups / "inbox") + + let ticket_balance = + let open Data_encoding in + RPC_service.post_service + ~description: + "Access the smart rollup's balance of ticket with specified \ + ticketer, content type, and content." + ~query:RPC_query.empty + ~input:Ticket_token.unparsed_token_encoding + ~output:n + RPC_path.(path_sc_rollup / "ticket_balance") end let kind ctxt block sc_rollup_address = @@ -2370,6 +2381,23 @@ module Sc_rollup = struct in match res with Ok _context -> return_true | Error _ -> return_false) + let register_ticket_balance () = + Registration.register1 + ~chunked:false + S.ticket_balance + (fun ctxt sc_rollup () Ticket_token.{ticketer; contents_type; contents} -> + let open Lwt_result_syntax in + let* ticket_hash, ctxt = + Ticket_balance_key.make + ctxt + ~owner:(Sc_rollup sc_rollup) + ~ticketer + ~contents_type:(Micheline.root contents_type) + ~contents:(Micheline.root contents) + in + let* amount, _ctxt = Ticket_balance.get_balance ctxt ticket_hash in + return @@ Option.value amount ~default:Z.zero) + let register () = register_kind () ; register_inbox () ; @@ -2388,7 +2416,8 @@ module Sc_rollup = struct register_timeout () ; register_timeout_reached () ; register_can_be_cemented () ; - register_initial_pvm_state_hash () + register_initial_pvm_state_hash () ; + register_ticket_balance () let list ctxt block = RPC_context.make_call0 S.root ctxt block () () @@ -2482,6 +2511,9 @@ module Sc_rollup = struct commitment_hash () () + + let get_ticket_balance ctxt block sc_rollup key = + RPC_context.make_call1 S.ticket_balance ctxt block sc_rollup () key end module Dal = struct diff --git a/src/proto_017_PtNairob/lib_plugin/RPC.ml b/src/proto_017_PtNairob/lib_plugin/RPC.ml index 5ee643fa46a75e946bdcdddf35111fd6c198e4b4..e572d304225c6b91e08f2305a06de6b7c97ea0ac 100644 --- a/src/proto_017_PtNairob/lib_plugin/RPC.ml +++ b/src/proto_017_PtNairob/lib_plugin/RPC.ml @@ -2278,6 +2278,17 @@ module Sc_rollup = struct ~query:RPC_query.empty ~output:Sc_rollup.Inbox.encoding RPC_path.(path_sc_rollups / "inbox") + + let ticket_balance = + let open Data_encoding in + RPC_service.post_service + ~description: + "Access the smart rollup's balance of ticket with specified \ + ticketer, content type, and content." + ~query:RPC_query.empty + ~input:Ticket_token.unparsed_token_encoding + ~output:n + RPC_path.(path_sc_rollup / "ticket_balance") end let kind ctxt block sc_rollup_address = @@ -2467,6 +2478,23 @@ module Sc_rollup = struct return_true | Ok _ | Error _ -> return_false) + let register_ticket_balance () = + Registration.register1 + ~chunked:false + S.ticket_balance + (fun ctxt sc_rollup () Ticket_token.{ticketer; contents_type; contents} -> + let open Lwt_result_syntax in + let* ticket_hash, ctxt = + Ticket_balance_key.make + ctxt + ~owner:(Sc_rollup sc_rollup) + ~ticketer + ~contents_type:(Micheline.root contents_type) + ~contents:(Micheline.root contents) + in + let* amount, _ctxt = Ticket_balance.get_balance ctxt ticket_hash in + return @@ Option.value amount ~default:Z.zero) + let register () = register_kind () ; register_inbox () ; @@ -2485,7 +2513,8 @@ module Sc_rollup = struct register_timeout () ; register_timeout_reached () ; register_can_be_cemented () ; - register_initial_pvm_state_hash () + register_initial_pvm_state_hash () ; + register_ticket_balance () let list ctxt block = RPC_context.make_call0 S.root ctxt block () () @@ -2579,6 +2608,9 @@ module Sc_rollup = struct commitment_hash () () + + let get_ticket_balance ctxt block sc_rollup key = + RPC_context.make_call1 S.ticket_balance ctxt block sc_rollup () key end module Dal = struct diff --git a/src/proto_018_Proxford/lib_plugin/RPC.ml b/src/proto_018_Proxford/lib_plugin/RPC.ml index 97efaa43d804206686a2b926ba01addc93c8eec6..6bff9bb765fd5b211b4c643cafcead086217496f 100644 --- a/src/proto_018_Proxford/lib_plugin/RPC.ml +++ b/src/proto_018_Proxford/lib_plugin/RPC.ml @@ -2385,6 +2385,17 @@ module Sc_rollup = struct ~query:RPC_query.empty ~output:Sc_rollup.Inbox.encoding RPC_path.(path_sc_rollups / "inbox") + + let ticket_balance = + let open Data_encoding in + RPC_service.post_service + ~description: + "Access the smart rollup's balance of ticket with specified \ + ticketer, content type, and content." + ~query:RPC_query.empty + ~input:Ticket_token.unparsed_token_encoding + ~output:n + RPC_path.(path_sc_rollup / "ticket_balance") end let kind ctxt block sc_rollup_address = @@ -2567,6 +2578,23 @@ module Sc_rollup = struct return_true | Ok _ | Error _ -> return_false) + let register_ticket_balance () = + Registration.register1 + ~chunked:false + S.ticket_balance + (fun ctxt sc_rollup () Ticket_token.{ticketer; contents_type; contents} -> + let open Lwt_result_syntax in + let* ticket_hash, ctxt = + Ticket_balance_key.make + ctxt + ~owner:(Sc_rollup sc_rollup) + ~ticketer + ~contents_type:(Micheline.root contents_type) + ~contents:(Micheline.root contents) + in + let* amount, _ctxt = Ticket_balance.get_balance ctxt ticket_hash in + return @@ Option.value amount ~default:Z.zero) + let register () = register_kind () ; register_inbox () ; @@ -2584,7 +2612,8 @@ module Sc_rollup = struct register_timeout () ; register_timeout_reached () ; register_can_be_cemented () ; - register_initial_pvm_state_hash () + register_initial_pvm_state_hash () ; + register_ticket_balance () let list ctxt block = RPC_context.make_call0 S.root ctxt block () () @@ -2675,6 +2704,9 @@ module Sc_rollup = struct commitment_hash () () + + let get_ticket_balance ctxt block sc_rollup key = + RPC_context.make_call1 S.ticket_balance ctxt block sc_rollup () key end module Dal = struct diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index db111977465c55c52bd07235e752984d6da3cbe3..64e7f80d287bb31582c659a7566ced3b759becdc 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -2455,6 +2455,17 @@ module Sc_rollup = struct ~query:RPC_query.empty ~output:Sc_rollup.Inbox.encoding RPC_path.(path_sc_rollups / "inbox") + + let ticket_balance = + let open Data_encoding in + RPC_service.post_service + ~description: + "Access the smart rollup's balance of ticket with specified \ + ticketer, content type, and content." + ~query:RPC_query.empty + ~input:Ticket_token.unparsed_token_encoding + ~output:n + RPC_path.(path_sc_rollup / "ticket_balance") end let kind ctxt block sc_rollup_address = @@ -2641,6 +2652,23 @@ module Sc_rollup = struct return_true | Ok _ | Error _ -> return_false) + let register_ticket_balance () = + Registration.register1 + ~chunked:false + S.ticket_balance + (fun ctxt sc_rollup () Ticket_token.{ticketer; contents_type; contents} -> + let open Lwt_result_syntax in + let* ticket_hash, ctxt = + Ticket_balance_key.make + ctxt + ~owner:(Sc_rollup sc_rollup) + ~ticketer + ~contents_type:(Micheline.root contents_type) + ~contents:(Micheline.root contents) + in + let* amount, _ctxt = Ticket_balance.get_balance ctxt ticket_hash in + return @@ Option.value amount ~default:Z.zero) + let register () = register_kind () ; register_inbox () ; @@ -2658,7 +2686,8 @@ module Sc_rollup = struct register_timeout () ; register_timeout_reached () ; register_can_be_cemented () ; - register_initial_pvm_state_hash () + register_initial_pvm_state_hash () ; + register_ticket_balance () let list ctxt block = RPC_context.make_call0 S.root ctxt block () () @@ -2749,6 +2778,9 @@ module Sc_rollup = struct commitment_hash () () + + let get_ticket_balance ctxt block sc_rollup key = + RPC_context.make_call1 S.ticket_balance ctxt block sc_rollup () key end module Dal = struct diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index a5856281123f80e2488e0d131d2dcaf34a4b378e..849f0199c4779df44c14f7fa99ba0db739881d01 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -1039,6 +1039,24 @@ let get_chain_block_context_smart_rollups_smart_rollup_staker_staked_on_commitme ] Fun.id +let post_chain_block_context_smart_rollups_smart_rollup_ticket_balance + ?(chain = "main") ?(block = "head") ~sc_rollup ~data () = + make + POST + [ + "chains"; + chain; + "blocks"; + block; + "context"; + "smart_rollups"; + "smart_rollup"; + sc_rollup; + "ticket_balance"; + ] + ~data + JSON.as_int + let get_chain_block_context_delegates ?(chain = "main") ?(block = "head") () = make GET diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index 6e8fb46038cc4dfad27600e774b6c79ea753a9d8..d5c6e2ec91be688d908bcba6cca501ed2feeea15 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -923,6 +923,15 @@ val get_chain_block_context_smart_rollups_smart_rollup_commitment : val get_chain_block_context_smart_rollups_smart_rollup_staker_staked_on_commitment : ?chain:string -> ?block:string -> sc_rollup:string -> string -> JSON.t t +(** RPC: [POST: chains//blocks//context/smart_rollups/smart_rollup//ticket_balance] *) +val post_chain_block_context_smart_rollups_smart_rollup_ticket_balance : + ?chain:string -> + ?block:string -> + sc_rollup:string -> + data:data -> + unit -> + int t + (** {2 Delegates RPC module } *) (** RPC: [GET /chains//blocks//context/delegates] diff --git a/tezt/tests/tickets.ml b/tezt/tests/tickets.ml index ee86a3157bed088151444bb314fda4a7e4545f3a..6f0d6555f99c357b35843009b82117ec4def3f1a 100644 --- a/tezt/tests/tickets.ml +++ b/tezt/tests/tickets.ml @@ -871,13 +871,38 @@ let setup_sc_enabled_node protocol ~parameters_ty = let* () = Client.bake_for_and_wait tezos_client in return (tezos_node, tezos_client, sc_rollup) +let assert_sc_rollup_ticket_balance client ~sc_rollup ~ticketer ~content_type + ~content ~expected = + let data : RPC_core.data = + Data + (Ezjsonm.value_from_string + @@ sf + {|{"ticketer": "%s", "content_type": {"prim": "%s"}, "content": {"string": "%s"}}|} + ticketer + content_type + content) + in + let* actual = + RPC.Client.call client + @@ RPC.post_chain_block_context_smart_rollups_smart_rollup_ticket_balance + ~sc_rollup + ~data + () + in + return + @@ Check.( + (actual = expected) + int + ~__LOC__ + ~error_msg:"expected ticket amount %R, got %L") + let test_send_tickets_to_sc_rollup = Protocol.register_regression_test ~__FILE__ ~title: "Minting then sending tickets to smart-contract rollup should succeed \ with appropriate ticket updates field in receipt." - ~tags:["client"; "michelson"] + ~tags:["client"; "michelson"; "sc_rollup"] ~supports:(Protocol.From_protocol 16) @@ fun protocol -> let* _node, client, sc_rollup = @@ -905,6 +930,57 @@ let test_send_tickets_to_sc_rollup = client in let* () = Client.bake_for_and_wait client in + (* The rollup should have 1 "Ticket" ticket and 1 "Ticket2" ticket. *) + let* () = + assert_sc_rollup_ticket_balance + client + ~sc_rollup + ~ticketer + ~content_type:"string" + ~content:"Ticket" + ~expected:1 + in + let* () = + assert_sc_rollup_ticket_balance + client + ~sc_rollup + ~ticketer + ~content_type:"string" + ~content:"Ticket2" + ~expected:1 + in + (* The rollup only received tickets with: + - ticketer: [ticketer] + - content_type: string + - content: "Ticket" or "Ticket2" + Hence it should return 0 for any other kind of tickets. *) + let* () = + assert_sc_rollup_ticket_balance + client + ~sc_rollup + ~ticketer + ~content_type:"string" + ~content:"foobar" + ~expected:0 + in + let* () = + assert_sc_rollup_ticket_balance + client + ~sc_rollup + ~ticketer + ~content_type:"int" + ~content:"Ticket" + ~expected:0 + in + let* () = + assert_sc_rollup_ticket_balance + client + ~sc_rollup + ~ticketer:Constant.bootstrap2.public_key_hash + ~content_type:"string" + ~content:"Ticket" + ~expected:0 + in unit let test_send_tickets_from_storage_to_sc_rollup = @@ -913,7 +989,7 @@ let test_send_tickets_from_storage_to_sc_rollup = ~title: "Sending tickets from storage to smart-contract rollup should succeed \ with appropriate ticket updates field in receipt." - ~tags:["client"; "michelson"] + ~tags:["client"; "michelson"; "sc_rollup"] ~supports:(Protocol.From_protocol 16) @@ fun protocol -> let* _node, client, sc_rollup =