Lib_client_base: add branch option to wait for confirmation command

This commit is contained in:
Victor Allombert 2019-02-19 12:56:11 +00:00 committed by Grégoire Henry
parent d30894b2f9
commit cf3390448a
4 changed files with 97 additions and 33 deletions

View File

@ -33,7 +33,7 @@ let in_block operation_hash operations =
raise (Found (i,j))) ops)
operations ;
None
with Found (i,j) -> Some (i, j)
with Found (i,j) -> Some (i, j)
let wait_for_bootstrapped (ctxt : #Client_context.full) =
let display = ref false in
@ -59,13 +59,22 @@ let wait_for_bootstrapped (ctxt : #Client_context.full) =
ctxt#answer "Node is bootstrapped, ready for injecting operations." >>= fun () ->
return_unit
type operation_status =
| Confirmed of (Block_hash.t * int * int)
| Pending
| Still_not_found
let wait_for_operation_inclusion
(ctxt : #Client_context.full)
~chain
?(predecessors = 10)
?(confirmations = 1)
?branch
operation_hash =
let exception WrapError of error list in
let exception Outdated of Operation_hash.t in
(* Table of known blocks:
- None: if neither the block or its predecessors contains the operation
- (Some ((hash, i, j), n)):
@ -109,54 +118,82 @@ let wait_for_operation_inclusion
(n+1) Block_hash.pp hash >>= fun () ->
Block_hash.Table.add blocks hash (Some (block_with_op, n+1)) ;
if n+1 < confirmations then begin
return_none
return Pending
end else
return_some block_with_op
return (Confirmed block_with_op)
| None ->
Shell_services.Blocks.Operation_hashes.operation_hashes
ctxt ~chain ~block () >>=? fun operations ->
match in_block operation_hash operations with
| None ->
Block_hash.Table.add blocks hash None ;
return_none
return Still_not_found
| Some (i, j) -> begin
ctxt#answer
"Operation found in block: %a (pass: %d, offset: %d)"
Block_hash.pp hash i j >>= fun () ->
Block_hash.Table.add blocks hash (Some ((hash, i, j), 0)) ;
if confirmations <= 0 then
return_some (hash, i, j)
else begin
return_none
end
return (Confirmed (hash, i, j))
else
return Pending
end in
(* Checks if the given branch is considered alive.*)
let check_branch_alive () =
match branch with
| Some branch_hash ->
Shell_services.Blocks.live_blocks
ctxt ~chain ~block:(`Head 0) () >>= begin function
| Ok live_blocks ->
if Block_hash.Set.mem branch_hash live_blocks then
Lwt.return_unit
else
ctxt#error
"The operation %a is outdated and may \
never be included in the chain.@,\
We recommand to use an external block explorer."
Operation_hash.pp operation_hash >>= fun () ->
Lwt.fail (Outdated operation_hash)
| Error err -> Lwt.fail (WrapError err)
end
| None -> Lwt.return_unit
in
Shell_services.Monitor.heads ctxt chain >>=? fun (stream, stop) ->
Lwt_stream.get stream >>= function
| None -> assert false
| Some (head, _) ->
let rec loop n =
if n >= 0 then
(*Search for the operation in the n head predecessors*)
let block = `Hash (head, n) in
Shell_services.Blocks.hash ctxt ~chain ~block () >>=? fun hash ->
Shell_services.Blocks.Header.shell_header ctxt
~chain ~block () >>=? fun shell ->
process hash shell >>=? function
| Some block ->
| Confirmed block ->
stop () ;
return block
| None ->
| Pending | Still_not_found ->
loop (n-1)
else
let exception WrapError of error list in
(*Search for the operation in new heads*)
Lwt.catch
(fun () ->
(*Fetching potential unknown blocks from potential new heads*)
let stream = Lwt_stream.map_list_s fetch_predecessors stream in
Lwt_stream.find_s
(fun (hash, header) ->
process hash header >>= function
| Ok None -> Lwt.return_false
| Ok (Some _) -> Lwt.return_true
| Ok Pending ->
Lwt.return_false
| Ok Still_not_found ->
check_branch_alive () >>= fun () ->
Lwt.return_false
| Ok (Confirmed _) ->
Lwt.return_true
| Error err ->
Lwt.fail (WrapError err)) stream >>= return)
(function
@ -170,29 +207,42 @@ let wait_for_operation_inclusion
| None | Some None -> assert false
| Some (Some (hash, _)) ->
return hash in
begin
match branch with
| Some branch_hash ->
Shell_services.Blocks.Header.shell_header
ctxt ~chain ~block:(`Hash(branch_hash,0)) () >>=? fun branch_header ->
let branch_level = branch_header.Block_header.level in
Shell_services.Blocks.Header.shell_header
ctxt ~chain ~block:(`Hash (head,0)) () >>=? fun head_shell ->
let head_level = head_shell.Block_header.level in
return (Int32.(to_int (sub head_level branch_level)))
| None -> return predecessors
end
>>=? fun block_hook ->
Block_services.Empty.hash
ctxt ~block:(`Hash (head, predecessors+1)) () >>=? fun oldest ->
ctxt ~block:(`Hash (head, block_hook+1)) () >>=? fun oldest ->
Block_hash.Table.add blocks oldest None ;
loop predecessors
loop block_hook
let lookup_operation_in_previous_block ctxt chain operation_hash i =
Block_services.Empty.hash ctxt ~block:(`Head i) ()
Block_services.Empty.hash ctxt ~block:(`Head i) ()
>>=? fun block ->
Shell_services.Blocks.Operation_hashes.operation_hashes ctxt ~chain
Shell_services.Blocks.Operation_hashes.operation_hashes ctxt ~chain
~block:(`Hash (block, 0)) ()
>>=? fun operations ->
>>=? fun operations ->
match in_block operation_hash operations with
| None -> return_none
| Some (a, b) -> return_some (block, a, b)
| Some (a, b) -> return_some (block, a, b)
let lookup_operation_in_previous_blocks
(ctxt : #Client_context.full)
~chain
~predecessors
operation_hash =
let rec loop i =
let rec loop i =
if i = predecessors + 1 then
return_none
return_none
else begin
lookup_operation_in_previous_block ctxt chain operation_hash i >>=?
function
@ -200,4 +250,4 @@ let lookup_operation_in_previous_blocks
| Some (block, a, b) -> return_some (block, a, b)
end
in
loop 0
loop 0

View File

@ -35,6 +35,7 @@ val wait_for_operation_inclusion:
chain:Chain_services.chain ->
?predecessors:int ->
?confirmations:int ->
?branch:Block_hash.t ->
Operation_hash.t ->
(Block_hash.t * int * int) tzresult Lwt.t
@ -48,4 +49,4 @@ val lookup_operation_in_previous_blocks:
chain:Block_services.chain ->
predecessors:int ->
Operation_list_hash.elt ->
(Block_hash.t * int * int) option tzresult Lwt.t
(Block_hash.t * int * int) option tzresult Lwt.t

View File

@ -551,14 +551,14 @@ let inject_operation
| None ->
cctxt#message "@[<v 0>NOT waiting for the operation to be included.@,\
Use command@,\
\ tezos-client wait for %a to be included --confirmations 30@,\
\ tezos-client wait for %a to be included --confirmations 30 --branch %a@,\
and/or an external block explorer to make sure that it has been included.@]"
Operation_hash.pp oph >>= fun () ->
Operation_hash.pp oph Block_hash.pp op.shell.branch >>= fun () ->
return result
| Some confirmations ->
cctxt#message "Waiting for the operation to be included..." >>= fun () ->
Client_confirmations.wait_for_operation_inclusion
~confirmations cctxt ~chain oph >>=? fun (h, i , j) ->
~branch:op.shell.branch ~confirmations cctxt ~chain oph >>=? fun (h, i , j) ->
Alpha_block_services.Operations.operation
cctxt ~block:(`Hash (h, 0)) i j >>=? fun op' ->
match op'.receipt with
@ -594,9 +594,10 @@ let inject_operation
"@[<v 0>The operation has only been included %d blocks ago.@,\
We recommend to wait more.@,\
Use command@,\
\ tezos-client wait for %a to be included --confirmations 30@,\
\ tezos-client wait for %a to be included --confirmations 30 \
--branch %a@,\
and/or an external block explorer.@]"
number Operation_hash.pp oph
number Operation_hash.pp oph Block_hash.pp op.shell.branch
end >>= fun () ->
return (oph, op.protocol_data.contents, result.contents)

View File

@ -73,6 +73,12 @@ let non_negative_param =
| Some i when i >= 0 -> return i
| _ -> failwith "Parameter should be a non-negative integer literal")
let block_hash_param =
Clic.parameter (fun _ s ->
try return (Block_hash.of_b58check_exn s)
with _ ->
failwith "Parameter '%s' is an invalid block hash" s)
let group =
{ Clic.name = "context" ;
title = "Block contextual commands (see option -block)" }
@ -567,11 +573,12 @@ let commands version () =
]) @
[
command ~desc:"Wait until an operation is included in a block"
(args2
(args3
(default_arg
~long:"confirmations"
~placeholder:"num_blocks"
~doc:"do not end until after 'N' additional blocks after the operation appears"
~doc:"wait until 'N' additional blocks after the operation \
appears in the considered chain"
~default:"0"
non_negative_param)
(default_arg
@ -579,7 +586,12 @@ let commands version () =
~placeholder:"num_blocks"
~doc:"number of previous blocks to check"
~default:"10"
non_negative_param))
non_negative_param)
(arg
~long:"branch"
~placeholder:"block_hash"
~doc:"hash of the oldest block where we should look for the operation"
block_hash_param))
(prefixes [ "wait" ; "for" ]
@@ param
~name:"operation"
@ -591,9 +603,9 @@ let commands version () =
| Some hash -> return hash))
@@ prefixes [ "to" ; "be" ; "included" ]
@@ stop)
begin fun (confirmations, predecessors) operation_hash (ctxt : Proto_alpha.full) ->
begin fun (confirmations, predecessors, branch) operation_hash (ctxt : Proto_alpha.full) ->
Client_confirmations.wait_for_operation_inclusion ctxt
~chain:`Main ~confirmations ~predecessors operation_hash >>=? fun _ ->
~chain:`Main ~confirmations ~predecessors ?branch operation_hash >>=? fun _ ->
return_unit
end ;