Shell/RPC: rework /blocks

- start using `GET` and query parameters instead of `POST`  when
  meaningful

- inline parsed protocol data and metadata in block headers

- inline parsed protocol data and metadata in operations

- split the RPC in four categories:

  - static data, available explicitly in block headers and operations

  - static "metadata", information that were computed while validating
    a block or an operation, but which are not explicit in the block
    header (e.g. the baker of a block, the list of internal
    transfer... (currently not implemented, but that's WIP))

  - "context" all the static data we may read in the context
    (contracts balance, list of delegates, ...)

  - "helpers" are some RPC that may perform some computation.
This commit is contained in:
Grégoire Henry 2018-04-16 00:44:24 +02:00 committed by Benjamin Canou
parent f02972bb8a
commit d6f79edae2
86 changed files with 3384 additions and 2470 deletions

View File

@ -5,7 +5,7 @@ Usage
***** *****
In order to interact with a Tezos node, you may use RPC calls through the In order to interact with a Tezos node, you may use RPC calls through the
client using this command ``tezos-admin-client rpc post <url>``. client using this command ``tezos-admin-client rpc (get|post) <url>``.
For instance, if you wish to request the current balance of a given For instance, if you wish to request the current balance of a given
block and contract, you can call the associated RPC via the command : block and contract, you can call the associated RPC via the command :

View File

@ -318,7 +318,7 @@ the appropriate value:
$ ./alphanet.sh client list known identities $ ./alphanet.sh client list known identities
my_identity: tz1iFY8aDskx9QGbgBy68SNAGgkc7AE2iG9H (public key known) (secret key known) my_identity: tz1iFY8aDskx9QGbgBy68SNAGgkc7AE2iG9H (public key known) (secret key known)
$ ./alphanet.sh client rpc post /blocks/head/proto/helpers/rights/baking/delegate/tz1iFY8aDskx9QGbgBy68SNAGgkc7AE2iG9H with '{}' $ ./alphanet.sh client rpc post /chains/main/blocks/head/helpers/rights/baking/delegate/tz1iFY8aDskx9QGbgBy68SNAGgkc7AE2iG9H with {}
{ "ok": { "ok":
[ { "level": 1400.000000, "priority": 2.000000, [ { "level": 1400.000000, "priority": 2.000000,
"timestamp": "2017-05-19T03:21:52Z" }, "timestamp": "2017-05-19T03:21:52Z" },

View File

@ -277,7 +277,7 @@ preconfigured for communicating the same-numbered node. For instance:
:: ::
$ tezos-client rpc post blocks/head/hash $ tezos-client rpc get /chains/main/blocks/head/hash
{ "hash": "BLockGenesisGenesisGenesisGenesisGenesisGeneskvg68z" } { "hash": "BLockGenesisGenesisGenesisGenesisGenesisGeneskvg68z" }
When you bootstrap a new network, the network is initialized with a When you bootstrap a new network, the network is initialized with a
@ -288,11 +288,11 @@ activating the whole network. For instance:
:: ::
$ tezos-client rpc post blocks/head/protocol $ tezos-client rpc get /chains/main/blocks/head/metadata/next_protocol_hash
{ "protocol": "ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im" } { "protocol": "ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im" }
$ tezos-activate-alpha $ tezos-activate-alpha
Injected BMBcK869jaHQDc Injected BMBcK869jaHQDc
$ tezos-client rpc post blocks/head/protocol $ tezos-client rpc get /chains/main/blocks/head/metadata/next_protocol_hash
{ "protocol": "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK" } { "protocol": "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK" }
Tune protocol alpha parameters Tune protocol alpha parameters

View File

@ -381,8 +381,8 @@ run_shell() {
display_head() { display_head() {
assert_node_uptodate assert_node_uptodate
exec_docker tezos-client rpc post /blocks/head with '{}' exec_docker tezos-client rpc get /chains/main/blocks/head
exec_docker tezos-client rpc post /blocks/head/proto/context/level with '{}' exec_docker tezos-client rpc post /chains/main/blocks/head/context/level with {}
} }
## Main #################################################################### ## Main ####################################################################

View File

@ -19,10 +19,10 @@ configure_client() {
wait_for_the_node_to_be_ready() { wait_for_the_node_to_be_ready() {
local count=0 local count=0
if "$client" rpc post /blocks/head/hash >/dev/null 2>&1; then return; fi if "$client" rpc get /chains/main/blocks/head/hash >/dev/null 2>&1; then return; fi
printf "Waiting for the node to initialize..." printf "Waiting for the node to initialize..."
sleep 1 sleep 1
while ! "$client" rpc post /blocks/head/hash >/dev/null 2>&1 while ! "$client" rpc get /chains/main/blocks/head/hash >/dev/null 2>&1
do do
count=$((count+1)) count=$((count+1))
if [ "$count" -ge 30 ]; then if [ "$count" -ge 30 ]; then

View File

@ -10,7 +10,7 @@
open Client_config open Client_config
let get_commands_for_version ctxt block protocol = let get_commands_for_version ctxt block protocol =
Block_services.protocol ctxt block >>= function Block_services.Empty.Metadata.next_protocol_hash ctxt ~block () >>= function
| Ok version -> begin | Ok version -> begin
match protocol with match protocol with
| None -> | None ->

View File

@ -13,13 +13,13 @@ $client -w none config update
sleep 2 sleep 2
#tests for the rpc service raw_context #tests for the rpc service raw_context
$client rpc post '/blocks/head/raw_context/version' | assert '{ "content": "616c706861" }' $client rpc get '/chains/main/blocks/head/context/raw/version' | assert '"616c706861"'
$client rpc post '/blocks/head/raw_context/non-existent' | assert 'No service found at this URL' $client rpc get '/chains/main/blocks/head/context/raw/non-existent' | assert 'No service found at this URL'
$client rpc post '/blocks/head/raw_context/delegates/?depth=2' | assert '{ "content": $client rpc get '/chains/main/blocks/head/context/raw/delegates/?depth=3' | assert '{ "ed25519":
{ "ed25519": { "02": { "29": null }, "a9": { "ce": null }, "c5": { "5c": null },
{ "02": null, "a9": null, "c5": null, "da": null, "e7": null } } }' "da": { "c9": null }, "e7": { "67": null } } }'
$client rpc post '/blocks/head/raw_context/non-existent?depth=-1' | assert 'No service found at this URL' $client rpc get '/chains/main/blocks/head/context/raw/non-existent?depth=-1' | assert 'Unexpected server answer'
$client rpc post '/blocks/head/raw_context/non-existent?depth=0' | assert 'No service found at this URL' $client rpc get '/chains/main/blocks/head/context/raw/non-existent?depth=0' | assert 'No service found at this URL'
bake bake

View File

@ -22,20 +22,19 @@ run_preflight() {
-H "Access-Control-Request-Method: $cors_method" \ -H "Access-Control-Request-Method: $cors_method" \
-H "Access-Control-Request-Headers: $header" \ -H "Access-Control-Request-Headers: $header" \
-X $method \ -X $method \
-I -s http://localhost:18731/blocks/head/protocol > CURL.$id 2>&1 -I -s http://localhost:18731/chains/main/blocks/head/header/shell > CURL.$id 2>&1
} }
run_request() { run_request() {
local origin="$1" local origin="$1"
curl -H "Origin: $origin" \ curl -H "Origin: $origin" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
--data-binary "{}" \
-D CURL.$id \ -D CURL.$id \
-s http://localhost:18731/blocks/head/protocol 2>&1 > /dev/null -s http://localhost:18731/chains/main/blocks/head/header/shell 2>&1 > /dev/null
} }
# Preflight # Preflight
run_preflight "localhost" "OPTIONS" "POST" "Content-Type" run_preflight "localhost" "OPTIONS" "GET" "Content-Type"
cat CURL.$id cat CURL.$id
grep -q "access-control-allow-origin" CURL.$id grep -q "access-control-allow-origin" CURL.$id
grep -q "access-control-allow-methods" CURL.$id grep -q "access-control-allow-methods" CURL.$id

View File

@ -37,7 +37,7 @@ $admin_client list protocols
#these commands cannot be used in this case because the client does not #these commands cannot be used in this case because the client does not
#know about the new protocol #know about the new protocol
#$client --protocol $protocol_short bake for bootstrap1 -max-priority 512 #$client --protocol $protocol_short bake for bootstrap1 -max-priority 512
#$client --protocol $protocol_version rpc post /blocks/head with {} #$client --protocol $protocol_version rpc get /chains/main/blocks/head
echo echo
echo End of test echo End of test

View File

@ -19,7 +19,7 @@ protocol_version="PtamL2BUfeNFM2A8Thq2Wde8vNaVD9DhoARDVB41QsHFj89kQpT"
$admin_client inject protocol "$test_dir/demo" $admin_client inject protocol "$test_dir/demo"
$admin_client list protocols $admin_client list protocols
$client activate protocol $protocol_version with fitness 1 and key dictator and parameters $parameters_file $client activate protocol $protocol_version with fitness 1 and key dictator and parameters $parameters_file
answ=$($client -p ProtoALphaALph rpc post /blocks/head/protocol with {} 2>/dev/null) answ=$($client -p ProtoALphaALph rpc get /chains/main/blocks/head/metadata/next_protocol_hash 2>/dev/null)
if ! grep "$protocol_version" <<< $answ ; then if ! grep "$protocol_version" <<< $answ ; then
exit 1 exit 1

View File

@ -37,7 +37,7 @@ $admin_client list protocols
#these commands cannot be used in this case because the client does not #these commands cannot be used in this case because the client does not
#know about the new protocol #know about the new protocol
#$client --protocol $protocol_short bake for bootstrap1 -max-priority 512 #$client --protocol $protocol_short bake for bootstrap1 -max-priority 512
#$client --protocol $protocol_version rpc post /blocks/head with {} #$client --protocol $protocol_version rpc get /chains/main/blocks/head
echo echo
echo End of test echo End of test

View File

@ -40,7 +40,7 @@ assert_propagation_level() {
level=$1 level=$1
printf "\n\nAsserting all nodes have reached level %s\n" "$level" printf "\n\nAsserting all nodes have reached level %s\n" "$level"
for client in "${client_instances[@]}"; do for client in "${client_instances[@]}"; do
( $client rpc post /blocks/head/proto/context/level \ ( $client rpc post /chains/main/blocks/head/context/level with {} \
| assert_in_output "\"level\": $level" ) \ | assert_in_output "\"level\": $level" ) \
|| exit 2 || exit 2
done done
@ -51,7 +51,7 @@ assert_protocol() {
proto=$1 proto=$1
printf "\n\nAsserting protocol propagation\n" printf "\n\nAsserting protocol propagation\n"
for client in "${client_instances[@]}"; do for client in "${client_instances[@]}"; do
( $client rpc post /blocks/head/protocol | assert_in_output "$proto" ) \ ( $client rpc get /chains/main/blocks/head/metadata/next_protocol_hash | assert_in_output "$proto" ) \
|| exit 2 || exit 2
done done
} }
@ -102,7 +102,7 @@ assert_contains_operation() {
hash="$1" hash="$1"
printf "Asserting operations list contains '$hash'\n" printf "Asserting operations list contains '$hash'\n"
for client in "${client_instances[@]}"; do for client in "${client_instances[@]}"; do
( $client rpc post /blocks/head/operations with {} \ ( $client rpc get /chains/main/blocks/head/operation_hashes \
| assert_in_output $hash ) \ | assert_in_output $hash ) \
|| exit 2 || exit 2
done done

View File

@ -57,10 +57,10 @@ cleanup_clients() {
wait_for_the_node_to_be_ready() { wait_for_the_node_to_be_ready() {
local count=0 local count=0
if $client rpc post blocks/head/hash >/dev/null 2>&1; then return; fi if $client rpc get /chains/main/blocks/head/hash >/dev/null 2>&1; then return; fi
printf "Waiting for the node to initialize..." printf "Waiting for the node to initialize..."
sleep 1 sleep 1
while ! $client rpc post blocks/head/hash >/dev/null 2>&1 while ! $client rpc get /chains/main/blocks/head/hash >/dev/null 2>&1
do do
count=$((count+1)) count=$((count+1))
if [ "$count" -ge 30 ]; then if [ "$count" -ge 30 ]; then
@ -301,7 +301,7 @@ The client is now properly initialized. In the rest of this shell
session, you might now run \`tezos-client\` to communicate with a session, you might now run \`tezos-client\` to communicate with a
tezos node launched with \`launch-sandboxed-node $1\`. For instance: tezos node launched with \`launch-sandboxed-node $1\`. For instance:
tezos-client rpc post blocks/head/protocol tezos-client rpc get /chains/main/blocks/head/metadata/protocol_hash
Note: if the current protocol version, as reported by the previous Note: if the current protocol version, as reported by the previous
command, is "ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im", you command, is "ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im", you

View File

@ -207,7 +207,7 @@ let init_rpc (rpc_config: Node_config_file.rpc) node =
failwith "Cannot resolve listening address: %S" addr failwith "Cannot resolve listening address: %S" addr
| (addr, port) :: _ -> | (addr, port) :: _ ->
let host = Ipaddr.V6.to_string addr in let host = Ipaddr.V6.to_string addr in
let dir = Node_rpc.build_rpc_directory node in let dir = Node.build_rpc_directory node in
let mode = let mode =
match rpc_config.tls with match rpc_config.tls with
| None -> `TCP (`Port port) | None -> `TCP (`Port port)

View File

@ -9,54 +9,98 @@
let wait_for_operation_inclusion let wait_for_operation_inclusion
(ctxt : #Client_context.full) (ctxt : #Client_context.full)
~chain
?(predecessors = 10) ?(predecessors = 10)
?(confirmations = 1) ?(confirmations = 1)
operation_hash = operation_hash =
let confirmed_blocks = Hashtbl.create confirmations in
(* Table of known blocks:
- None: if neither the block or its predecessors contains the operation
- (Some n): if the `n-th` predecessors of the block contains the operation *)
let blocks : int option Block_hash.Table.t =
Block_hash.Table.create confirmations in
(* Fetch _all_ the 'unknown' predecessors af a block. *)
let fetch_predecessors block =
let rec loop acc block =
Block_services.Empty.Header.Shell.predecessor
ctxt ~chain ~block:(`Hash (block, 0)) () >>=? fun predecessor ->
if Block_hash.Table.mem blocks predecessor then
return acc
else
loop (predecessor :: acc) predecessor
in
loop [block] block >>= function
| Ok blocks -> Lwt.return blocks
| Error err ->
ctxt#warning
"Error while fetching block (ignored): %a"
pp_print_error err >>= fun () ->
(* Will be retried when a new head arrives *)
Lwt.return [] in
(* Check whether a block as enough confirmations. This function
assumes that the block predecessor has been processed already. *)
let process block = let process block =
Block_services.hash ctxt block >>=? fun hash -> Block_services.Empty.hash ctxt ~chain ~block () >>=? fun hash ->
Block_services.predecessor ctxt block >>=? fun predecessor -> Block_services.Empty.Header.Shell.predecessor
match Hashtbl.find_opt confirmed_blocks predecessor with ctxt ~chain ~block () >>=? fun predecessor ->
match Block_hash.Table.find blocks predecessor with
| Some n -> | Some n ->
ctxt#answer ctxt#answer
"Operation received %d confirmations as of block: %a" "Operation received %d confirmations as of block: %a"
(n+1) Block_hash.pp hash >>= fun () -> (n+1) Block_hash.pp hash >>= fun () ->
if n+1 < confirmations then begin if n+1 < confirmations then begin
Hashtbl.add confirmed_blocks hash (n+1) ; Block_hash.Table.add blocks hash (Some (n+1)) ;
return false return false
end else end else
return true return true
| None -> | None ->
Block_services.operations Block_services.Empty.Operation_hash.operation_hashes
ctxt ~contents:false block >>=? fun operations -> ctxt ~chain ~block () >>=? fun operations ->
let in_block = let in_block =
List.exists List.exists
(List.exists (List.exists
(fun (oph, _) -> Operation_hash.equal operation_hash oph)) (Operation_hash.equal operation_hash))
operations in operations in
if not in_block then if not in_block then begin
Block_hash.Table.add blocks hash None ;
return false return false
else begin end else begin
ctxt#answer ctxt#answer
"Operation found in block: %a" "Operation found in block: %a"
Block_hash.pp hash >>= fun () -> Block_hash.pp hash >>= fun () ->
if confirmations <= 0 then if confirmations <= 0 then
return true return true
else begin else begin
Hashtbl.add confirmed_blocks hash 0 ; Block_hash.Table.add blocks hash (Some 0) ;
return false return false
end end
end in end in
Block_services.monitor
~include_ops:false Shell_services.Monitor.heads ctxt chain >>=? fun (stream, stop) ->
~length:predecessors ctxt >>=? fun (stream, stop) -> Lwt_stream.get stream >>= function
| None -> assert false
| Some head ->
let rec loop n =
if n >= 0 then
process (`Hash (head, n)) >>=? function
| true ->
stop () ;
return ()
| false ->
loop (n-1)
else
let exception WrapError of error list in let exception WrapError of error list in
let stream = Lwt_stream.map_list List.concat stream in
Lwt.catch Lwt.catch
(fun () -> (fun () ->
let stream = Lwt_stream.map_list_s fetch_predecessors stream in
Lwt_stream.find_s Lwt_stream.find_s
(fun bi -> (fun block ->
process (`Hash (bi.Block_services.hash, 0)) >>= function process (`Hash (block, 0)) >>= function
| Ok b -> Lwt.return b | Ok b -> Lwt.return b
| Error err -> | Error err ->
Lwt.fail (WrapError err)) stream >>= return) Lwt.fail (WrapError err)) stream >>= return)
@ -64,4 +108,9 @@ let wait_for_operation_inclusion
| WrapError e -> Lwt.return (Error e) | WrapError e -> Lwt.return (Error e)
| exn -> Lwt.fail exn) >>=? fun _ -> | exn -> Lwt.fail exn) >>=? fun _ ->
stop () ; stop () ;
return () return () in
Block_services.Empty.hash
ctxt ~block:(`Hash (head, predecessors+1)) () >>=? fun oldest ->
Block_hash.Table.add blocks oldest None ;
loop predecessors

View File

@ -9,6 +9,7 @@
val wait_for_operation_inclusion: val wait_for_operation_inclusion:
#Client_context.full -> #Client_context.full ->
chain:Chain_services.chain ->
?predecessors:int -> ?predecessors:int ->
?confirmations:int -> ?confirmations:int ->
Operation_hash.t -> Operation_hash.t ->

View File

@ -20,7 +20,7 @@ let commands () =
(fun () blocks (cctxt : #Client_context.full) -> (fun () blocks (cctxt : #Client_context.full) ->
iter_s iter_s
(fun block -> (fun block ->
Block_services.unmark_invalid cctxt block >>=? fun () -> Chain_services.Invalid_blocks.delete cctxt block >>=? fun () ->
cctxt#message cctxt#message
"Block %a no longer marked invalid." "Block %a no longer marked invalid."
Block_hash.pp block >>= fun () -> Block_hash.pp block >>= fun () ->

View File

@ -26,7 +26,7 @@ let commands () = Clic.[
~desc: "the prefix of the hash to complete" @@ ~desc: "the prefix of the hash to complete" @@
stop) stop)
(fun unique prefix (cctxt : #Client_context.full) -> (fun unique prefix (cctxt : #Client_context.full) ->
Shell_services.complete Block_services.Empty.Helpers.complete
cctxt ~block:cctxt#block prefix >>=? fun completions -> cctxt ~block:cctxt#block prefix >>=? fun completions ->
match completions with match completions with
| [] -> Pervasives.exit 3 | [] -> Pervasives.exit 3

View File

@ -13,32 +13,14 @@ let skip_line ppf =
Format.pp_print_newline ppf (); Format.pp_print_newline ppf ();
return @@ Format.pp_print_newline ppf () return @@ Format.pp_print_newline ppf ()
let print_heads ppf heads = let print_invalid_blocks ppf (b: Chain_services.invalid_block) =
Format.pp_print_list ~pp_sep:Format.pp_print_newline
(fun ppf blocks ->
Format.pp_print_list
~pp_sep:Format.pp_print_newline
Block_services.pp_block_info
ppf
blocks)
ppf heads
let print_rejected ppf = function
| [] -> Format.fprintf ppf "No invalid blocks."
| invalid ->
Format.pp_print_list
(fun ppf (hash, level, errors) ->
Format.fprintf ppf Format.fprintf ppf
"@[<v 2>Hash: %a\ "@[<v 2>Hash: %a\
@ Level: %ld\ @ Level: %ld\
@ Errors: @[<v>%a@]@]" @ %a@]"
Block_hash.pp hash Block_hash.pp b.hash
level b.level
(Format.pp_print_list ~pp_sep:Format.pp_print_newline pp_print_error b.errors
Error_monad.pp)
errors)
ppf
invalid
let commands () = let commands () =
let open Clic in let open Clic in
@ -63,28 +45,22 @@ let commands () =
(args1 output_arg) (args1 output_arg)
(fixed [ "list" ; "heads" ]) (fixed [ "list" ; "heads" ])
(fun ppf cctxt -> (fun ppf cctxt ->
Block_services.list ~include_ops:true ~length:1 cctxt >>=? fun heads -> Chain_services.Blocks.list cctxt () >>=? fun heads ->
Format.fprintf ppf "%a@." print_heads heads ; Format.fprintf ppf "@[<v>%a@]@."
(Format.pp_print_list Block_hash.pp)
(List.concat heads) ;
return ()) ; return ()) ;
command ~group ~desc: "The blocks that have been marked invalid by the node." command ~group ~desc: "The blocks that have been marked invalid by the node."
(args1 output_arg) (args1 output_arg)
(fixed [ "list" ; "rejected" ; "blocks" ]) (fixed [ "list" ; "rejected" ; "blocks" ])
(fun ppf cctxt -> (fun ppf cctxt ->
Block_services.list_invalid cctxt >>=? fun invalid -> Chain_services.Invalid_blocks.list cctxt () >>=? function
Format.fprintf ppf "%a@." print_rejected invalid ; | [] ->
return ()) ; Format.fprintf ppf "No invalid blocks." ;
command ~group ~desc: "A full report of the node's state." return ()
(args1 output_arg) | _ :: _ as invalid ->
(fixed [ "full" ; "report" ]) Format.fprintf ppf "@[<v>%a@]@."
(fun ppf cctxt -> (Format.pp_print_list print_invalid_blocks)
Block_services.list ~include_ops:true ~length:1 cctxt >>=? fun heads -> invalid ;
Block_services.list_invalid cctxt >>=? fun invalid ->
Format.fprintf ppf
"@[<v 0>@{<title>Date@} %a@,\
@[<v 2>@{<title>Heads@}@,%a@]@,\
@[<v 2>@{<title>Rejected blocks@}@,%a@]@]"
Time.pp_hum (Time.now ())
print_heads heads
print_rejected invalid ;
return ()) ; return ()) ;
] ]

View File

@ -50,9 +50,7 @@ type quota = {
type rpc_context = { type rpc_context = {
block_hash: Block_hash.t ; block_hash: Block_hash.t ;
block_header: Block_header.t ; block_header: Block_header.shell_header ;
operation_hashes: unit -> Operation_hash.t list list Lwt.t ;
operations: unit -> Operation.t list list Lwt.t ;
context: Context.t ; context: Context.t ;
} }

View File

@ -47,9 +47,7 @@ module Make (Context : CONTEXT) = struct
type rpc_context = { type rpc_context = {
block_hash: Block_hash.t ; block_hash: Block_hash.t ;
block_header: Block_header.t ; block_header: Block_header.shell_header ;
operation_hashes: unit -> Operation_hash.t list list Lwt.t ;
operations: unit -> Operation.t list list Lwt.t ;
context: Context.t ; context: Context.t ;
} }
@ -171,9 +169,9 @@ module Make (Context : CONTEXT) = struct
and type operation = P.operation and type operation = P.operation
and type validation_state = P.validation_state and type validation_state = P.validation_state
class ['block] proto_rpc_context : class ['chain, 'block] proto_rpc_context :
Tezos_rpc.RPC_context.t -> (unit, unit * 'block) RPC_path.t -> Tezos_rpc.RPC_context.t -> (unit, (unit * 'chain) * 'block) RPC_path.t ->
['block] RPC_context.simple [('chain * 'block)] RPC_context.simple
class ['block] proto_rpc_context_of_directory : class ['block] proto_rpc_context_of_directory :
('block -> RPC_context.t) -> RPC_context.t RPC_directory.t -> ('block -> RPC_context.t) -> RPC_context.t RPC_directory.t ->
@ -589,9 +587,7 @@ module Make (Context : CONTEXT) = struct
type nonrec rpc_context = rpc_context = { type nonrec rpc_context = rpc_context = {
block_hash: Block_hash.t ; block_hash: Block_hash.t ;
block_header: Block_header.t ; block_header: Block_header.shell_header ;
operation_hashes: unit -> Operation_hash.t list list Lwt.t ;
operations: unit -> Operation.t list list Lwt.t ;
context: Context.t ; context: Context.t ;
} }
@ -663,47 +659,47 @@ module Make (Context : CONTEXT) = struct
let init c bh = init c bh >|= wrap_error let init c bh = init c bh >|= wrap_error
end end
class ['block] proto_rpc_context class ['chain, 'block] proto_rpc_context
(t : Tezos_rpc.RPC_context.t) (t : Tezos_rpc.RPC_context.t)
(prefix : (unit, unit * 'block) RPC_path.t) = (prefix : (unit, (unit * 'chain) * 'block) RPC_path.t) =
object object
method call_proto_service0 method call_proto_service0
: 'm 'q 'i 'o. : 'm 'q 'i 'o.
([< RPC_service.meth ] as 'm, RPC_context.t, ([< RPC_service.meth ] as 'm, RPC_context.t,
RPC_context.t, 'q, 'i, 'o) RPC_service.t -> RPC_context.t, 'q, 'i, 'o) RPC_service.t ->
'block -> 'q -> 'i -> 'o tzresult Lwt.t ('chain * 'block) -> 'q -> 'i -> 'o tzresult Lwt.t
= fun s block q i -> = fun s (chain, block) q i ->
let s = RPC_service.subst0 s in let s = RPC_service.subst0 s in
let s = RPC_service.prefix prefix s in let s = RPC_service.prefix prefix s in
t#call_service s ((), block) q i t#call_service s (((), chain), block) q i
method call_proto_service1 method call_proto_service1
: 'm 'a 'q 'i 'o. : 'm 'a 'q 'i 'o.
([< RPC_service.meth ] as 'm, RPC_context.t, ([< RPC_service.meth ] as 'm, RPC_context.t,
RPC_context.t * 'a, 'q, 'i, 'o) RPC_service.t -> RPC_context.t * 'a, 'q, 'i, 'o) RPC_service.t ->
'block -> 'a -> 'q -> 'i -> 'o tzresult Lwt.t ('chain * 'block) -> 'a -> 'q -> 'i -> 'o tzresult Lwt.t
= fun s block a1 q i -> = fun s (chain, block) a1 q i ->
let s = RPC_service.subst1 s in let s = RPC_service.subst1 s in
let s = RPC_service.prefix prefix s in let s = RPC_service.prefix prefix s in
t#call_service s (((), block), a1) q i t#call_service s ((((), chain), block), a1) q i
method call_proto_service2 method call_proto_service2
: 'm 'a 'b 'q 'i 'o. : 'm 'a 'b 'q 'i 'o.
([< RPC_service.meth ] as 'm, RPC_context.t, ([< RPC_service.meth ] as 'm, RPC_context.t,
(RPC_context.t * 'a) * 'b, 'q, 'i, 'o) RPC_service.t -> (RPC_context.t * 'a) * 'b, 'q, 'i, 'o) RPC_service.t ->
'block -> 'a -> 'b -> 'q -> 'i -> 'o tzresult Lwt.t ('chain * 'block) -> 'a -> 'b -> 'q -> 'i -> 'o tzresult Lwt.t
= fun s block a1 a2 q i -> = fun s (chain, block) a1 a2 q i ->
let s = RPC_service.subst2 s in let s = RPC_service.subst2 s in
let s = RPC_service.prefix prefix s in let s = RPC_service.prefix prefix s in
t#call_service s ((((), block), a1), a2) q i t#call_service s (((((), chain), block), a1), a2) q i
method call_proto_service3 method call_proto_service3
: 'm 'a 'b 'c 'q 'i 'o. : 'm 'a 'b 'c 'q 'i 'o.
([< RPC_service.meth ] as 'm, RPC_context.t, ([< RPC_service.meth ] as 'm, RPC_context.t,
((RPC_context.t * 'a) * 'b) * 'c, ((RPC_context.t * 'a) * 'b) * 'c,
'q, 'i, 'o) RPC_service.t -> 'q, 'i, 'o) RPC_service.t ->
'block -> 'a -> 'b -> 'c -> 'q -> 'i -> 'o tzresult Lwt.t ('chain * 'block) -> 'a -> 'b -> 'c -> 'q -> 'i -> 'o tzresult Lwt.t
= fun s block a1 a2 a3 q i -> = fun s (chain, block) a1 a2 a3 q i ->
let s = RPC_service.subst3 s in let s = RPC_service.subst3 s in
let s = RPC_service.prefix prefix s in let s = RPC_service.prefix prefix s in
t#call_service s (((((), block), a1), a2), a3) q i t#call_service s ((((((), chain), block), a1), a2), a3) q i
end end
class ['block] proto_rpc_context_of_directory conv dir : ['block] RPC_context.simple = class ['block] proto_rpc_context_of_directory conv dir : ['block] RPC_context.simple =

View File

@ -40,9 +40,7 @@ module Make (Context : CONTEXT) : sig
type rpc_context = { type rpc_context = {
block_hash: Block_hash.t ; block_hash: Block_hash.t ;
block_header: Block_header.t ; block_header: Block_header.shell_header ;
operation_hashes: unit -> Operation_hash.t list list Lwt.t ;
operations: unit -> Operation.t list list Lwt.t ;
context: Context.t ; context: Context.t ;
} }
@ -164,9 +162,9 @@ module Make (Context : CONTEXT) : sig
and type operation = P.operation and type operation = P.operation
and type validation_state = P.validation_state and type validation_state = P.validation_state
class ['block] proto_rpc_context : class ['chain, 'block] proto_rpc_context :
Tezos_rpc.RPC_context.t -> (unit, unit * 'block) RPC_path.t -> Tezos_rpc.RPC_context.t -> (unit, (unit * 'chain) * 'block) RPC_path.t ->
['block] RPC_context.simple [('chain * 'block)] RPC_context.simple
class ['block] proto_rpc_context_of_directory : class ['block] proto_rpc_context_of_directory :
('block -> RPC_context.t) -> RPC_context.t RPC_directory.t -> ('block -> RPC_context.t) -> RPC_context.t RPC_directory.t ->

View File

@ -6,6 +6,7 @@
(libraries (tezos-base (libraries (tezos-base
tezos-stdlib-unix tezos-stdlib-unix
tezos-micheline tezos-micheline
tezos-shell-services
tezos-protocol-environment-shell tezos-protocol-environment-shell
tezos-protocol-compiler.registerer tezos-protocol-compiler.registerer
tezos-protocol-compiler.native tezos-protocol-compiler.native
@ -16,6 +17,7 @@
-open Tezos_base__TzPervasives -open Tezos_base__TzPervasives
-open Tezos_stdlib_unix -open Tezos_stdlib_unix
-open Tezos_micheline -open Tezos_micheline
-open Tezos_shell_services
-open Tezos_storage)))) -open Tezos_storage))))
(alias (alias

View File

@ -8,8 +8,13 @@
(**************************************************************************) (**************************************************************************)
module type T = sig module type T = sig
module P : sig
val hash: Protocol_hash.t val hash: Protocol_hash.t
include Tezos_protocol_environment_shell.PROTOCOL include Tezos_protocol_environment_shell.PROTOCOL
end
include (module type of (struct include P end))
module Block_services :
(module type of (struct include Block_services.Make(P)(P) end))
val complete_b58prefix : Context.t -> string -> string list Lwt.t val complete_b58prefix : Context.t -> string -> string list Lwt.t
end end
@ -22,9 +27,13 @@ let build_v1 hash =
end in end in
let module Env = Tezos_protocol_environment_shell.MakeV1(Name)() in let module Env = Tezos_protocol_environment_shell.MakeV1(Name)() in
(module struct (module struct
module Raw = F(Env)
module P = struct
let hash = hash let hash = hash
module P = F(Env) include Env.Lift(Raw)
include Env.Lift(P) end
include P
module Block_services = Block_services.Make(P)(P)
let complete_b58prefix = Env.Context.complete let complete_b58prefix = Env.Context.complete
end : T) end : T)
@ -68,8 +77,12 @@ module Register
VersionTable.add VersionTable.add
versions hash versions hash
(module struct (module struct
module P = struct
let hash = hash let hash = hash
include Env.Lift(Proto) include Env.Lift(Proto)
end
include P
module Block_services = Block_services.Make(P)(P)
let complete_b58prefix = Env.Context.complete let complete_b58prefix = Env.Context.complete
end : T) end : T)

View File

@ -8,8 +8,13 @@
(**************************************************************************) (**************************************************************************)
module type T = sig module type T = sig
module P : sig
val hash: Protocol_hash.t val hash: Protocol_hash.t
include Tezos_protocol_environment_shell.PROTOCOL include Tezos_protocol_environment_shell.PROTOCOL
end
include (module type of (struct include P end))
module Block_services :
(module type of (struct include Block_services.Make(P)(P) end))
val complete_b58prefix : Context.t -> string -> string list Lwt.t val complete_b58prefix : Context.t -> string -> string list Lwt.t
end end

View File

@ -0,0 +1,340 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
let rec read_partial_context context path depth =
(* non tail-recursive *)
if depth = 0 then
Lwt.return Block_services.Cut
else
(* try to read as file *)
Context.get context path >>= function
| Some v ->
Lwt.return (Block_services.Key v)
| None ->
(* try to read as directory *)
Context.fold context path ~init:[] ~f: begin fun k acc ->
match k with
| `Key k | `Dir k ->
read_partial_context context k (depth-1) >>= fun v ->
let k = List.nth k ((List.length k)-1) in
Lwt.return ((k,v)::acc)
end >>= fun l ->
Lwt.return (Block_services.Dir (List.rev l))
let rpc_directory
(module Proto : Block_services.PROTO)
(module Next_proto : Registered_protocol.T) =
let dir : State.Block.t RPC_directory.t ref =
ref RPC_directory.empty in
let register0 s f =
dir :=
RPC_directory.register !dir (RPC_service.subst0 s)
(fun block p q -> f block p q) in
let register1 s f =
dir :=
RPC_directory.register !dir (RPC_service.subst1 s)
(fun (block, a) p q -> f block a p q) in
let register2 s f =
dir :=
RPC_directory.register !dir (RPC_service.subst2 s)
(fun ((block, a), b) p q -> f block a b p q) in
let module Block_services = Block_services.Make(Proto)(Next_proto) in
let module S = Block_services.S in
register0 S.hash begin fun block () () ->
return (State.Block.hash block)
end ;
(* block header *)
register0 S.Header.header begin fun block () () ->
let chain_id = State.Block.chain_id block in
let hash = State.Block.hash block in
let header = State.Block.header block in
let protocol_data =
Data_encoding.Binary.of_bytes_exn
Proto.block_header_data_encoding
header.protocol_data in
return { Block_services.hash ; chain_id ;
shell = header.shell ; protocol_data }
end ;
register0 S.Header.shell_header begin fun block () () ->
return (State.Block.header block).shell
end ;
register0 S.Header.Shell.level begin fun block () () ->
return (State.Block.header block).shell.level
end ;
register0 S.Header.Shell.protocol_level begin fun block () () ->
return (State.Block.header block).shell.proto_level
end ;
register0 S.Header.Shell.predecessor begin fun block () () ->
return (State.Block.header block).shell.predecessor
end ;
register0 S.Header.Shell.timestamp begin fun block () () ->
return (State.Block.header block).shell.timestamp
end ;
register0 S.Header.Shell.validation_passes begin fun block () () ->
return (State.Block.header block).shell.validation_passes
end ;
register0 S.Header.Shell.operations_hash begin fun block () () ->
return (State.Block.header block).shell.operations_hash
end ;
register0 S.Header.Shell.fitness begin fun block () () ->
return (State.Block.header block).shell.fitness
end ;
register0 S.Header.Shell.context_hash begin fun block () () ->
return (State.Block.header block).shell.context
end ;
register0 S.Header.protocol_data begin fun block () () ->
let header = State.Block.header block in
return
(Data_encoding.Binary.of_bytes_exn
Proto.block_header_data_encoding
header.protocol_data)
end ;
(* block metadata *)
let metadata block =
let protocol_data =
Data_encoding.Binary.of_bytes_exn
Proto.block_header_metadata_encoding
(State.Block.metadata block) in
State.Block.test_chain block >>= fun test_chain_status ->
return {
Block_services.protocol_data ;
test_chain_status ;
max_operations_ttl = State.Block.max_operations_ttl block ;
max_operation_data_length = State.Block.max_operation_data_length block ;
max_block_header_length = Next_proto.max_block_length ;
operation_list_quota =
List.map
(fun { Tezos_protocol_environment_shell.max_size; max_op } ->
{ Tezos_shell_services.Block_services.max_size ; max_op } )
Next_proto.validation_passes ;
} in
register0 S.Metadata.metadata begin fun block () () ->
metadata block
end ;
register0 S.Metadata.protocol_data begin fun block () () ->
return
(Data_encoding.Binary.of_bytes_exn
Proto.block_header_metadata_encoding
(State.Block.metadata block))
end ;
register0 S.Metadata.protocol_hash begin fun _block () () ->
return Proto.hash
end ;
register0 S.Metadata.next_protocol_hash begin fun _block () () ->
return Next_proto.hash
end ;
register0 S.Metadata.test_chain_status begin fun block () () ->
State.Block.test_chain block >>= return
end ;
register0 S.Metadata.max_operations_ttl begin fun block () () ->
return (State.Block.max_operations_ttl block)
end ;
register0 S.Metadata.max_operation_data_length begin fun block () () ->
return (State.Block.max_operation_data_length block)
end ;
register0 S.Metadata.max_block_header_length begin fun _block () () ->
return (Next_proto.max_block_length) ;
end ;
register0 S.Metadata.operation_list_quota begin fun _block () () ->
return
(List.map
(fun { Tezos_protocol_environment_shell.max_size; max_op } ->
{ Tezos_shell_services.Block_services.max_size ; max_op } )
Next_proto.validation_passes)
end ;
(* operations *)
let convert chain_id (op : Operation.t) metadata =
let protocol_data =
Data_encoding.Binary.of_bytes_exn
Proto.operation_data_encoding
op.proto in
let metadata =
Data_encoding.Binary.of_bytes_exn
Proto.operation_metadata_encoding
metadata in
{ Block_services.chain_id ;
hash = Operation.hash op ;
shell = op.shell ;
protocol_data ;
metadata ;
} in
let operations block =
State.Block.all_operations block >>= fun ops ->
State.Block.all_operations_metadata block >>= fun metadata ->
let chain_id = State.Block.chain_id block in
return (List.map2 (List.map2 (convert chain_id)) ops metadata) in
register0 S.Operation.operations begin fun block () () ->
operations block
end ;
register1 S.Operation.operations_in_pass begin fun block i () () ->
State.Block.operations block i >>= fun (ops, _path) ->
State.Block.operations_metadata block i >>= fun metadata ->
let chain_id = State.Block.chain_id block in
return (List.map2 (convert chain_id) ops metadata)
end ;
register2 S.Operation.operation begin fun block i j () () ->
State.Block.operations block i >>= fun (ops, _path) ->
State.Block.operations_metadata block i >>= fun metadata ->
let chain_id = State.Block.chain_id block in
return (convert chain_id (List.nth ops j) (List.nth metadata j))
end ;
(* operation_hashes *)
register0 S.Operation_hash.operation_hashes begin fun block () () ->
State.Block.all_operation_hashes block >>= return
end ;
register1 S.Operation_hash.operation_hashes_in_pass begin fun block i () () ->
State.Block.operation_hashes block i >>= fun (ops, _) ->
return ops
end ;
register2 S.Operation_hash.operation_hash begin fun block i j () () ->
State.Block.operation_hashes block i >>= fun (ops, _) ->
return (List.nth ops j)
end ;
(* context *)
register1 S.Context.Raw.read begin fun block path q () ->
let depth = Option.unopt ~default:max_int q#depth in
fail_unless (depth >= 0)
(Tezos_shell_services.Block_services.Invalid_depth_arg (path, depth)) >>=? fun () ->
State.Block.context block >>= fun context ->
Context.mem context path >>= fun mem ->
Context.dir_mem context path >>= fun dir_mem ->
if not (mem || dir_mem) then
Lwt.fail Not_found
else
read_partial_context context path depth >>= fun dir ->
return dir
end ;
(* info *)
register0 S.info begin fun block () () ->
let chain_id = State.Block.chain_id block in
let hash = State.Block.hash block in
let header = State.Block.header block in
let shell = header.shell in
let protocol_data =
Data_encoding.Binary.of_bytes_exn
Proto.block_header_data_encoding
header.protocol_data in
metadata block >>=? fun metadata ->
operations block >>=? fun operations ->
return { Block_services.hash ; chain_id ;
header = { shell ; protocol_data } ;
metadata ; operations }
end ;
(* helpers *)
register0 S.Helpers.preapply begin fun block q p ->
let protocol_data =
Data_encoding.Binary.to_bytes_exn
Next_proto.block_header_data_encoding
p.protocol_data in
let operations =
List.map
(List.map
(fun (op : Next_proto.operation) ->
let proto =
Data_encoding.Binary.to_bytes_exn
Next_proto.operation_data_encoding
op.protocol_data in
{ Operation.shell = op.shell ; proto }))
p.operations in
Prevalidation.preapply
~predecessor:block
~timestamp:p.timestamp
~protocol_data
~sort_operations:q#sort_operations
operations
end ;
register1 S.Helpers.complete begin fun block prefix () () ->
State.Block.context block >>= fun ctxt ->
Base58.complete prefix >>= fun l1 ->
Next_proto.complete_b58prefix ctxt prefix >>= fun l2 ->
return (l1 @ l2)
end ;
(* merge protocol rpcs... *)
RPC_directory.merge
!dir
(RPC_directory.map
(fun block ->
State.Block.context block >>= fun context ->
Lwt.return Tezos_protocol_environment_shell.{
block_hash = State.Block.hash block ;
block_header = State.Block.shell_header block ;
context })
Next_proto.rpc_services)
let get_protocol hash =
match Registered_protocol.get hash with
| None -> raise Not_found
| Some protocol -> protocol
let get_directory block =
State.Block.get_rpc_directory block >>= function
| Some dir -> Lwt.return dir
| None ->
State.Block.protocol_hash block >>= fun next_protocol_hash ->
let next_protocol = get_protocol next_protocol_hash in
State.Block.predecessor block >>= function
| None ->
Lwt.return (rpc_directory
(module Block_services.Fake_protocol)
next_protocol)
| Some pred ->
State.Block.protocol_hash pred >>= fun protocol_hash ->
let (module Proto) = get_protocol protocol_hash in
State.Block.get_rpc_directory block >>= function
| Some dir -> Lwt.return dir
| None ->
let dir = rpc_directory (module Proto) next_protocol in
State.Block.set_rpc_directory block dir >>= fun () ->
Lwt.return dir
let get_block chain_state = function
| `Genesis ->
Chain.genesis chain_state
| `Head n ->
Chain.head chain_state >>= fun head ->
if n = 0 then
Lwt.return head
else
State.Block.read_exn chain_state ~pred:n (State.Block.hash head)
| `Hash (hash, n) ->
State.Block.read_exn chain_state ~pred:n hash
let build_rpc_directory chain_state block =
get_block chain_state block >>= fun block ->
get_directory block >>= fun dir ->
Lwt.return (RPC_directory.map (fun _ -> block) dir)

View File

@ -0,0 +1,15 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
val get_block: State.Chain.t -> Block_services.block -> State.Block.t Lwt.t
val build_rpc_directory:
State.Chain.t ->
Block_services.block ->
'a RPC_directory.t Lwt.t

View File

@ -0,0 +1,159 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
open Chain_services
let get_chain_id state = function
| `Main -> Lwt.return (State.Chain.main state)
| `Test -> begin
State.Chain.get_exn state (State.Chain.main state) >>= fun main_chain ->
State.Chain.test main_chain >>= function
| None -> Lwt.fail Not_found
| Some chain_id -> Lwt.return chain_id
end
| `Hash chain_id ->
Lwt.return chain_id
let get_chain state chain =
get_chain_id state chain >>= fun chain_id ->
State.Chain.get_exn state chain_id
let predecessors ignored length head =
let rec loop acc length block =
if length <= 0 then
Lwt.return (List.rev acc)
else
State.Block.predecessor block >>= function
| None ->
Lwt.return (List.rev acc)
| Some pred ->
if Block_hash.Set.mem (State.Block.hash block) ignored then
Lwt.return (List.rev acc)
else
loop (State.Block.hash pred :: acc) (length-1) pred
in
loop [State.Block.hash head] (length-1) head
let list_blocks chain_state ?(length = 1) ?min_date heads =
begin
match heads with
| [] ->
Chain.known_heads chain_state >>= fun heads ->
let heads =
match min_date with
| None -> heads
| Some min_date ->
List.fold_left
(fun acc block ->
let timestamp = State.Block.timestamp block in
if Time.(min_date <= timestamp) then block :: acc
else acc)
[] heads in
let sorted_heads =
List.sort
(fun b1 b2 ->
let f1 = State.Block.fitness b1 in
let f2 = State.Block.fitness b2 in
~- (Fitness.compare f1 f2))
heads in
Lwt.return (List.map (fun b -> Some b) sorted_heads)
| _ :: _ as heads ->
Lwt_list.map_p (State.Block.read_opt chain_state) heads
end >>= fun requested_heads ->
Lwt_list.fold_left_s
(fun (ignored, acc) head ->
match head with
| None -> Lwt.return (ignored, [])
| Some block ->
predecessors ignored length block >>= fun predecessors ->
let ignored =
List.fold_right Block_hash.Set.add predecessors ignored in
Lwt.return (ignored, predecessors :: acc))
(Block_hash.Set.empty, [])
requested_heads >>= fun (_, blocks) ->
return (List.rev blocks)
let rpc_directory =
let dir : State.Chain.t Lwt.t RPC_directory.t ref =
ref RPC_directory.empty in
let register0 s f =
dir :=
RPC_directory.register !dir (RPC_service.subst0 s)
(fun chain p q -> chain >>= fun chain -> f chain p q) in
let register1 s f =
dir :=
RPC_directory.register !dir (RPC_service.subst1 s)
(fun (chain, a) p q -> chain >>= fun chain -> f chain a p q) in
let register_dynamic_directory2 ?descr s f =
dir :=
RPC_directory.register_dynamic_directory
!dir ?descr (RPC_path.subst1 s)
(fun (chain, a) -> chain >>= fun chain -> f chain a) in
register0 S.chain_id begin fun chain () () ->
return (State.Chain.id chain)
end ;
(* blocks *)
register0 S.Blocks.list begin fun chain q () ->
list_blocks chain ?length:q#length ?min_date:q#min_date q#heads
end ;
register_dynamic_directory2
Block_services.path
Block_directory.build_rpc_directory ;
(* invalid_blocks *)
register0 S.Invalid_blocks.list begin fun chain () () ->
let convert (hash, level, errors) = { hash ; level ; errors } in
State.Block.list_invalid chain >>= fun blocks ->
return (List.map convert blocks)
end ;
register1 S.Invalid_blocks.get begin fun chain hash () () ->
State.Block.read_invalid chain hash >>= function
| None -> Lwt.fail Not_found
| Some { level ; errors } -> return { hash ; level ; errors }
end ;
register1 S.Invalid_blocks.delete begin fun chain hash () () ->
State.Block.unmark_invalid chain hash
end ;
!dir
let build_rpc_directory state validator =
let dir = ref rpc_directory in
(* Mempool *)
let register0 s f =
dir :=
RPC_directory.register !dir (RPC_service.subst0 s)
(fun chain p q -> chain >>= fun chain -> f chain p q) in
register0 S.Mempool.pending_operations begin fun chain () () ->
Validator.get_exn validator (State.Chain.id chain) >>= fun chain_validator ->
let pv_opt = Chain_validator.prevalidator chain_validator in
match pv_opt with
| Some pv ->
return (Prevalidator.operations pv)
| None ->
return (Preapply_result.empty, Operation_hash.Map.empty)
end ;
RPC_directory.prefix Chain_services.path @@
RPC_directory.map (fun ((), chain) -> get_chain state chain) !dir

View File

@ -7,16 +7,9 @@
(* *) (* *)
(**************************************************************************) (**************************************************************************)
val get_chain_id: State.t -> Chain_services.chain -> Chain_id.t Lwt.t
val get_chain: State.t -> Chain_services.chain -> State.Chain.t Lwt.t
module S : sig val rpc_directory: State.Chain.t Lwt.t RPC_directory.t
val pending_operations:
([ `POST ], unit,
unit , unit, unit,
error Preapply_result.t * Operation.t Operation_hash.Map.t) RPC_service.t
end
open RPC_context val build_rpc_directory: State.t -> Validator.t -> unit RPC_directory.t
val pending_operations:
#simple ->
(error Preapply_result.t * Operation.t Operation_hash.Map.t) tzresult Lwt.t

View File

@ -10,57 +10,11 @@
open Lwt.Infix open Lwt.Infix
open Worker_logging open Worker_logging
let inject_operation validator ?chain_id bytes =
let t =
match Data_encoding.Binary.of_bytes Operation.encoding bytes with
| None -> failwith "Can't parse the operation"
| Some op ->
Validator.inject_operation validator ?chain_id op
in
let hash = Operation_hash.hash_bytes [bytes] in
Lwt.return (hash, t)
let inject_protocol state ?force:_ proto =
let proto_bytes =
Data_encoding.Binary.to_bytes_exn Protocol.encoding proto in
let hash = Protocol_hash.hash_bytes [proto_bytes] in
let validation =
Updater.compile hash proto >>= function
| false ->
failwith
"Compilation failed (%a)"
Protocol_hash.pp_short hash
| true ->
State.Protocol.store state proto >>= function
| None ->
failwith
"Previously registered protocol (%a)"
Protocol_hash.pp_short hash
| Some _ -> return ()
in
Lwt.return (hash, validation)
let inject_block validator ?force ?chain_id bytes operations =
Validator.validate_block
validator ?force ?chain_id bytes operations >>=? fun (hash, block) ->
return (hash, (block >>=? fun _ -> return ()))
type t = { type t = {
state: State.t ; state: State.t ;
distributed_db: Distributed_db.t ; distributed_db: Distributed_db.t ;
validator: Validator.t ; validator: Validator.t ;
mainchain_validator: Chain_validator.t ; mainchain_validator: Chain_validator.t ;
inject_block:
?force:bool ->
?chain_id:Chain_id.t ->
MBytes.t -> Operation.t list list ->
(Block_hash.t * unit tzresult Lwt.t) tzresult Lwt.t ;
inject_operation:
?chain_id:Chain_id.t -> MBytes.t ->
(Operation_hash.t * unit tzresult Lwt.t) Lwt.t ;
inject_protocol:
?force:bool -> Protocol.t ->
(Protocol_hash.t * unit tzresult Lwt.t) Lwt.t ;
p2p: Distributed_db.p2p ; (* For P2P RPCs *) p2p: Distributed_db.p2p ; (* For P2P RPCs *)
shutdown: unit -> unit Lwt.t ; shutdown: unit -> unit Lwt.t ;
} }
@ -139,12 +93,6 @@ and chain_validator_limits = Chain_validator.limits = {
worker_limits : Worker_types.limits ; worker_limits : Worker_types.limits ;
} }
let may_create_chain state genesis =
State.Chain.get state (Chain_id.of_block_hash genesis.State.Chain.block) >>= function
| Ok chain -> Lwt.return chain
| Error _ ->
State.Chain.create state genesis
let create { genesis ; store_root ; context_root ; let create { genesis ; store_root ; context_root ;
patch_context ; p2p = p2p_params ; patch_context ; p2p = p2p_params ;
test_chain_max_tll = max_child_ttl } test_chain_max_tll = max_child_ttl }
@ -178,381 +126,28 @@ let create { genesis ; store_root ; context_root ;
distributed_db ; distributed_db ;
validator ; validator ;
mainchain_validator ; mainchain_validator ;
inject_block = inject_block validator ;
inject_operation = inject_operation validator ;
inject_protocol = inject_protocol state ;
p2p ; p2p ;
shutdown ; shutdown ;
} }
let shutdown node = node.shutdown () let shutdown node = node.shutdown ()
module RPC = struct let build_rpc_directory node =
let dir : unit RPC_directory.t ref = ref RPC_directory.empty in
let merge d = dir := RPC_directory.merge !dir d in
let register0 s f =
dir := RPC_directory.register !dir s (fun () p q -> f p q) in
type block = Block_services.block merge (Protocol_directory.build_rpc_directory node.state node.distributed_db) ;
type block_info = Block_services.block_info = { merge (Shell_directory.build_rpc_directory
hash: Block_hash.t ; node.state node.validator node.mainchain_validator) ;
chain_id: Chain_id.t ; merge (Chain_directory.build_rpc_directory node.state node.validator) ;
level: Int32.t ; merge (P2p.build_rpc_directory node.p2p) ;
proto_level: int ; (* uint8 *) merge Worker_directory.rpc_directory ;
predecessor: Block_hash.t ;
timestamp: Time.t ;
validation_passes: int ; (* uint8 *)
operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ;
context: Context_hash.t ;
protocol_data: MBytes.t ;
operations: (Operation_hash.t * Operation.t) list list option ;
protocol: Protocol_hash.t ;
test_chain: Test_chain_status.t ;
}
let convert (block: State.Block.t) = register0 RPC_service.error_service begin fun () () ->
let hash = State.Block.hash block in return (Data_encoding.Json.schema Error_monad.error_encoding)
let header = State.Block.header block in end ;
State.Block.all_operations block >>= fun operations ->
let operations =
List.map (List.map (fun op -> (Operation.hash op, op))) operations in
State.Block.context block >>= fun context ->
Context.get_protocol context >>= fun protocol ->
Context.get_test_chain context >>= fun test_chain ->
Lwt.return {
hash ;
chain_id = State.Block.chain_id block ;
level = header.shell.level ;
proto_level = header.shell.proto_level ;
predecessor = header.shell.predecessor ;
timestamp = header.shell.timestamp ;
validation_passes = header.shell.validation_passes ;
operations_hash = header.shell.operations_hash ;
fitness = header.shell.fitness ;
context = header.shell.context ;
protocol_data = header.protocol_data ;
operations = Some operations ;
protocol ;
test_chain ;
}
let inject_block node = node.inject_block RPC_directory.register_describe_directory_service
let inject_operation node = node.inject_operation !dir RPC_service.description_service
let inject_protocol node = node.inject_protocol
let raw_block_info node hash =
State.read_block node.state hash >>= function
| Some block ->
convert block
| None ->
Lwt.fail Not_found
let prevalidation_hash =
Block_hash.of_b58check_exn
"BLockPrevaLidationPrevaLidationPrevaLidationPrZ4mr6"
let get_validator node = function
| `Genesis | `Head _ -> node.mainchain_validator
| `Test_head _ ->
match Chain_validator.child node.mainchain_validator with
| None -> raise Not_found
| Some v -> v
let get_validator_per_hash node hash =
State.read_block_exn node.state hash >>= fun block ->
let chain_id = State.Block.chain_id block in
if Chain_id.equal (Chain_validator.chain_id node.mainchain_validator) chain_id then
Lwt.return (Some node.mainchain_validator)
else
match Chain_validator.child node.mainchain_validator with
| Some test_validator ->
if Chain_id.equal (Chain_validator.chain_id test_validator) chain_id then
Lwt.return_some test_validator
else
Lwt.return_none
| _ -> Lwt.return_none
let read_valid_block node h n =
State.read_block node.state ~pred:n h
let read_valid_block_exn node h n =
State.read_block_exn node.state ~pred:n h
let get_block node = function
| `Genesis ->
let chain_state = Chain_validator.chain_state node.mainchain_validator in
Chain.genesis chain_state
| ( `Head n | `Test_head n ) as block ->
let validator = get_validator node block in
let chain_state = Chain_validator.chain_state validator in
Chain.head chain_state >>= fun head ->
if n = 0 then
Lwt.return head
else
read_valid_block_exn node (State.Block.hash head) n
| `Hash (hash, n) ->
read_valid_block node hash n >>= function
| None -> Lwt.fail Not_found
| Some b -> Lwt.return b
let block_info node (block: block) =
get_block node block >>= convert
let rpc_context block : Tezos_protocol_environment_shell.rpc_context Lwt.t =
let block_hash = State.Block.hash block in
let block_header = State.Block.header block in
State.Block.context block >|= fun context ->
{ Tezos_protocol_environment_shell.block_hash ;
block_header ;
operation_hashes = (fun () -> State.Block.all_operation_hashes block) ;
operations = (fun () -> State.Block.all_operations block) ;
context ;
}
let get_rpc_context node block =
Lwt.catch begin fun () ->
get_block node block >>= fun block ->
rpc_context block >>= fun ctxt ->
Lwt.return (Some ctxt)
end begin
fun _ -> Lwt.return None
end
let operation_hashes node block =
get_block node block >>= fun block ->
State.Block.all_operation_hashes block
let operations node block =
get_block node block >>= fun block ->
State.Block.all_operations block
let pending_operations node =
let validator = get_validator node (`Head 0) in
let pv_opt = Chain_validator.prevalidator validator in
match pv_opt with
| Some pv ->
Lwt.return (Prevalidator.operations pv)
| None ->
Lwt.return (Preapply_result.empty, Operation_hash.Map.empty)
let protocols { state } =
State.Protocol.list state >>= fun set ->
Lwt.return (Protocol_hash.Set.elements set)
let protocol_content node hash =
State.Protocol.read node.state hash
let preapply
node block
~timestamp ~protocol_data ~sort_operations:sort ops =
get_block node block >>= fun predecessor ->
Prevalidation.start_prevalidation
~protocol_data ~predecessor ~timestamp () >>=? fun validation_state ->
let ops = List.map (List.map (fun x -> Operation.hash x, x)) ops in
Lwt_list.fold_left_s
(fun (validation_state, rs) ops ->
Prevalidation.prevalidate
validation_state ~sort ops >>= fun (validation_state, r) ->
Lwt.return (validation_state, rs @ [r]))
(validation_state, []) ops >>= fun (validation_state, rs) ->
let operations_hash =
Operation_list_list_hash.compute
(List.map
(fun r ->
Operation_list_hash.compute
(List.map fst r.Preapply_result.applied))
rs) in
Prevalidation.end_prevalidation
validation_state >>=? fun { fitness ; context ; message } ->
let pred_shell_header = State.Block.shell_header predecessor in
State.Block.protocol_hash predecessor >>= fun pred_protocol ->
Context.get_protocol context >>= fun protocol ->
let proto_level =
if Protocol_hash.equal protocol pred_protocol then
pred_shell_header.proto_level
else
((pred_shell_header.proto_level + 1) mod 256) in
let shell_header : Block_header.shell_header = {
level = Int32.succ pred_shell_header.level ;
proto_level ;
predecessor = State.Block.hash predecessor ;
timestamp ;
validation_passes = List.length rs ;
operations_hash ;
fitness ;
context = Context_hash.zero ; (* place holder *)
} in
begin
if Protocol_hash.equal protocol pred_protocol then
return (context, message)
else
match Registered_protocol.get protocol with
| None ->
fail (Block_validator_errors.Unavailable_protocol
{ block = State.Block.hash predecessor ; protocol })
| Some (module NewProto) ->
NewProto.init context shell_header >>=? fun { context ; message ; _ } ->
return (context, message)
end >>=? fun (context, message) ->
Context.commit ?message ~time:timestamp context >>= fun context ->
return ({ shell_header with context }, rs)
let complete node ?block str =
match block with
| None ->
Base58.complete str
| Some block ->
get_rpc_context node block >>= function
| None -> Lwt.fail Not_found
| Some { context = ctxt } ->
Context.get_protocol ctxt >>= fun protocol_hash ->
let (module Proto) = Registered_protocol.get_exn protocol_hash in
Base58.complete str >>= fun l1 ->
Proto.complete_b58prefix ctxt str >>= fun l2 ->
Lwt.return (l1 @ l2)
let context_dir node block =
get_rpc_context node block >>= function
| None -> Lwt.return None
| Some rpc_context ->
Context.get_protocol rpc_context.context >>= fun protocol_hash ->
let (module Proto) = Registered_protocol.get_exn protocol_hash in
let dir = RPC_directory.map (fun () -> Lwt.return rpc_context) Proto.rpc_services in
Lwt.return (Some (RPC_directory.map (fun _ -> ()) dir))
let context_raw_get node block ~path ~depth =
let open Block_services in
(* negative depth could be handled by a more informative error *)
if depth < 0 then Lwt.return_none else
get_rpc_context node block >>= function
| None -> Lwt.return_none
| Some rpc_context ->
let rec loop path depth = (* non tail-recursive *)
if depth = 0 then Lwt.return Cut else
(* try to read as file *)
Context.get rpc_context.context path >>= function
| Some v -> Lwt.return (Key v)
| None -> (* try to read as directory *)
Context.fold rpc_context.context path ~init:[]
~f:(fun k acc ->
match k with
| `Key k | `Dir k ->
loop k (depth-1) >>= fun v ->
let k = List.nth k ((List.length k)-1) in
Lwt.return ((k,v)::acc)) >>= fun l ->
Lwt.return (Dir (List.rev l))
in
Context.mem rpc_context.context path >>= fun mem ->
Context.dir_mem rpc_context.context path >>= fun dir_mem ->
if mem || dir_mem then
loop path depth >>= Lwt.return_some
else Lwt.return_none
let heads node =
let chain_state = Chain_validator.chain_state node.mainchain_validator in
Chain.known_heads chain_state >>= fun heads ->
begin
match Chain_validator.child node.mainchain_validator with
| None -> Lwt.return_nil
| Some test_validator ->
let chain_state = Chain_validator.chain_state test_validator in
Chain.known_heads chain_state
end >>= fun test_heads ->
Lwt_list.fold_left_s
(fun map block ->
convert block >|= fun bi ->
Block_hash.Map.add
(State.Block.hash block) bi map)
Block_hash.Map.empty (test_heads @ heads)
let predecessors node len head =
let rec loop acc len block =
if len = 0 then
Lwt.return (List.rev acc)
else
State.Block.predecessor block >>= function
| None -> Lwt.return (List.rev acc)
| Some block ->
loop (State.Block.hash block :: acc) (len-1) block
in
try
State.read_block_exn node.state head >>= fun block ->
loop [] len block
with Not_found -> Lwt.return_nil
let predecessors_bi ignored len head =
try
let rec loop acc len block =
convert block >>= fun bi ->
State.Block.predecessor block >>= function
| None ->
Lwt.return (List.rev (bi :: acc))
| Some pred ->
if len = 0 ||
Block_hash.Set.mem (State.Block.hash block) ignored then
Lwt.return (List.rev acc)
else
loop (bi :: acc) (len-1) pred
in
loop [] len head
with Not_found -> Lwt.return_nil
let list node len heads =
Lwt_list.fold_left_s
(fun (ignored, acc) head ->
State.read_block_exn node.state head >>= fun block ->
predecessors_bi ignored len block >>= fun predecessors ->
let ignored =
List.fold_right
(fun x s -> Block_hash.Set.add x.hash s)
predecessors ignored in
Lwt.return (ignored, predecessors :: acc)
)
(Block_hash.Set.empty, [])
heads >>= fun (_, blocks) ->
Lwt.return (List.rev blocks)
let list_invalid node =
State.Block.list_invalid (Chain_validator.chain_state node.mainchain_validator)
let unmark_invalid node block =
State.Block.unmark_invalid (Chain_validator.chain_state node.mainchain_validator) block
let block_header_watcher node =
Distributed_db.watch_block_header node.distributed_db
let block_watcher node =
let stream, shutdown = Validator.watcher node.validator in
Lwt_stream.map_s (fun block -> convert block) stream,
shutdown
let operation_watcher node =
Distributed_db.watch_operation node.distributed_db
let protocol_watcher node =
Distributed_db.Protocol.watch node.distributed_db
let bootstrapped node =
let block_stream, stopper =
Chain_validator.new_head_watcher node.mainchain_validator in
let first_run = ref true in
let next () =
if !first_run then begin
first_run := false ;
let chain_state = Chain_validator.chain_state node.mainchain_validator in
Chain.head chain_state >>= fun head ->
let head_hash = State.Block.hash head in
let head_header = State.Block.header head in
Lwt.return (Some (head_hash, head_header.shell.timestamp))
end else begin
Lwt.pick [
( Lwt_stream.get block_stream >|=
Option.map ~f:(fun b ->
(State.Block.hash b, (State.Block.header b).shell.timestamp)) ) ;
(Chain_validator.bootstrapped node.mainchain_validator >|= fun () -> None) ;
]
end in
let shutdown () = Lwt_watcher.shutdown stopper in
RPC_answer.{ next ; shutdown }
let build_p2p_rpc_directory (t : t) =
P2p.build_rpc_directory t.p2p
end

View File

@ -47,94 +47,6 @@ val create:
chain_validator_limits -> chain_validator_limits ->
t tzresult Lwt.t t tzresult Lwt.t
module RPC : sig
type block = Block_services.block
type block_info = Block_services.block_info
val inject_block:
t -> ?force:bool -> ?chain_id:Chain_id.t ->
MBytes.t -> Operation.t list list ->
(Block_hash.t * unit tzresult Lwt.t) tzresult Lwt.t
(** [inject_block node ?force bytes] tries to insert [bytes]
(supposedly the serialization of a block header) inside
[node]. If [?force] is true, the block will be inserted even on
non strictly increasing fitness. *)
val inject_operation:
t -> ?chain_id:Chain_id.t -> MBytes.t ->
(Operation_hash.t * unit tzresult Lwt.t) Lwt.t
val inject_protocol:
t -> ?force:bool -> Protocol.t ->
(Protocol_hash.t * unit tzresult Lwt.t) Lwt.t
val raw_block_info:
t -> Block_hash.t -> block_info Lwt.t
val block_header_watcher:
t -> (Block_hash.t * Block_header.t) Lwt_stream.t * Lwt_watcher.stopper
val block_watcher:
t -> (block_info Lwt_stream.t * Lwt_watcher.stopper)
val heads: t -> block_info Block_hash.Map.t Lwt.t
val predecessors:
t -> int -> Block_hash.t -> Block_hash.t list Lwt.t
val list:
t -> int -> Block_hash.t list -> block_info list list Lwt.t
val list_invalid:
t -> (Block_hash.t * int32 * error list) list Lwt.t
val unmark_invalid:
t -> Block_hash.t -> unit tzresult Lwt.t
val block_info:
t -> block -> block_info Lwt.t
val operation_hashes:
t -> block -> Operation_hash.t list list Lwt.t
val operations:
t -> block -> Operation.t list list Lwt.t
val operation_watcher:
t -> (Operation_hash.t * Operation.t) Lwt_stream.t * Lwt_watcher.stopper
val pending_operations:
t ->
(error Preapply_result.t * Operation.t Operation_hash.Map.t) Lwt.t
val protocols:
t -> Protocol_hash.t list Lwt.t
val protocol_content:
t -> Protocol_hash.t -> Protocol.t tzresult Lwt.t
val protocol_watcher:
t -> (Protocol_hash.t * Protocol.t) Lwt_stream.t * Lwt_watcher.stopper
val context_dir:
t -> block -> 'a RPC_directory.t option Lwt.t
(** Returns the content of the context at the given [path] descending
recursively into directories as far as [depth] allows.
Returns [None] if a path in not in the context or if [depth] is
negative. *)
val context_raw_get:
t -> block -> path:string list -> depth:int ->
Block_services.raw_context_result option Lwt.t
val preapply:
t -> block ->
timestamp:Time.t -> protocol_data:MBytes.t ->
sort_operations:bool -> Operation.t list list ->
(Block_header.shell_header * error Preapply_result.t list) tzresult Lwt.t
val complete:
t -> ?block:block -> string -> string list Lwt.t
val bootstrapped:
t -> (Block_hash.t * Time.t) RPC_answer.stream
val build_p2p_rpc_directory: t -> unit RPC_directory.t
end
val shutdown: t -> unit Lwt.t val shutdown: t -> unit Lwt.t
val build_rpc_directory: t -> unit RPC_directory.t

View File

@ -1,503 +0,0 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
open RPC_logging
let filter_bi operations (bi: Block_services.block_info) =
let bi = if operations then bi else { bi with operations = None } in
bi
let register_bi_dir node dir =
let dir =
let implementation b () include_ops =
Node.RPC.block_info node b >>= fun bi ->
return (filter_bi include_ops bi) in
RPC_directory.register1 dir
Block_services.S.info implementation in
let dir =
let implementation b () () =
Node.RPC.block_info node b >>= fun bi ->
return bi.hash in
RPC_directory.register1 dir
Block_services.S.hash
implementation in
let dir =
let implementation b () () =
Node.RPC.block_info node b >>= fun bi ->
return bi.chain_id in
RPC_directory.register1 dir
Block_services.S.chain_id implementation in
let dir =
let implementation b () () =
Node.RPC.block_info node b >>= fun bi ->
return bi.level in
RPC_directory.register1 dir
Block_services.S.level implementation in
let dir =
let implementation b () () =
Node.RPC.block_info node b >>= fun bi ->
return bi.predecessor in
RPC_directory.register1 dir
Block_services.S.predecessor implementation in
let dir =
let implementation b () len =
Node.RPC.block_info node b >>= fun bi ->
Node.RPC.predecessors node len bi.hash >>= fun hashes ->
return hashes in
RPC_directory.register1 dir
Block_services.S.predecessors implementation in
let dir =
let implementation b () () =
Node.RPC.block_info node b >>= fun bi ->
return bi.fitness in
RPC_directory.register1 dir
Block_services.S.fitness implementation in
let dir =
let implementation b () () =
Node.RPC.block_info node b >>= fun bi ->
return bi.timestamp in
RPC_directory.register1 dir
Block_services.S.timestamp implementation in
let dir =
let implementation b () () =
Node.RPC.block_info node b >>= fun bi ->
return bi.protocol in
RPC_directory.register1 dir
Block_services.S.protocol implementation in
let dir =
let implementation b () () =
Node.RPC.block_info node b >>= fun bi ->
return bi.test_chain in
RPC_directory.register1 dir
Block_services.S.test_chain implementation in
let dir =
let implementation b () { Block_services.S.contents } =
Node.RPC.operation_hashes node b >>= fun hashes ->
if contents then
Node.RPC.operations node b >>= fun ops ->
RPC_answer.return @@
List.map2 (List.map2 (fun h op -> h, Some op)) hashes ops
else
RPC_answer.return @@
List.map (List.map (fun h -> h, None)) hashes
in
RPC_directory.gen_register1 dir
Block_services.S.operations implementation in
let dir =
let implementation
b ()
{ Block_services.S.operations ; sort_operations ;
timestamp ; protocol_data } =
Node.RPC.preapply node b
~timestamp ~protocol_data ~sort_operations operations
>>=? fun (shell_header, operations) ->
return { Block_services.shell_header ; operations } in
RPC_directory.register1 dir
Block_services.S.preapply implementation in
dir
let rec insert_future_block (bi: Block_services.block_info) = function
| [] -> [bi]
| ({timestamp} as head: Block_services.block_info) :: tail as all ->
if Time.compare bi.timestamp timestamp < 0 then
bi :: all
else
head :: insert_future_block bi tail
let create_delayed_stream
~filtering ~include_ops requested_heads bi_stream delay =
let stream, push = Lwt_stream.create () in
let current_blocks =
ref (List.fold_left
(fun acc h -> Block_hash.Set.add h acc)
Block_hash.Set.empty requested_heads) in
let next_future_block, is_futur_block,
insert_future_block, pop_future_block =
let future_blocks = ref [] in (* FIXME *)
let future_blocks_set = ref Block_hash.Set.empty in
let next () =
match !future_blocks with
| [] -> None
| bi :: _ -> Some bi
and mem hash = Block_hash.Set.mem hash !future_blocks_set
and insert bi =
future_blocks := insert_future_block bi !future_blocks ;
future_blocks_set :=
Block_hash.Set.add bi.hash !future_blocks_set
and pop time =
match !future_blocks with
| {timestamp} as bi :: rest when Time.(timestamp <= time) ->
future_blocks := rest ;
future_blocks_set :=
Block_hash.Set.remove bi.hash !future_blocks_set ;
Some bi
| _ -> None in
next, mem, insert, pop in
let _block_watcher_worker =
let never_ending = fst (Lwt.wait ()) in
let rec worker_loop () =
lwt_debug "WWW worker_loop" >>= fun () ->
let time = Time.(add (now ()) (Int64.of_int ~-delay)) in
let migration_delay =
match next_future_block () with
| None -> never_ending
| Some bi ->
let delay = Time.diff bi.timestamp time in
if delay <= 0L then
Lwt.return_unit
else
Lwt_unix.sleep (Int64.to_float delay) in
Lwt.choose [(migration_delay >|= fun () -> `Migrate) ;
(Lwt_stream.get bi_stream >|= fun x -> `Block x) ]
>>= function
| `Block None ->
lwt_debug "WWW worker_loop None" >>= fun () ->
Lwt.return_unit
| `Block (Some (bi : Block_services.block_info)) ->
lwt_debug "WWW worker_loop Some" >>= fun () ->
begin
if not filtering
|| Block_hash.Set.mem bi.predecessor !current_blocks
|| is_futur_block bi.predecessor
then begin
let time = Time.(add (now ()) (Int64.of_int ~-delay)) in
if Time.(time < bi.timestamp) then begin
insert_future_block bi ;
Lwt.return_unit
end else begin
current_blocks :=
Block_hash.Set.remove bi.predecessor !current_blocks
|> Block_hash.Set.add bi.hash ;
push (Some [[filter_bi include_ops bi]]) ;
Lwt.return_unit
end
end else begin
Lwt.return_unit
end
end >>= fun () ->
worker_loop ()
| `Migrate ->
lwt_debug "WWW worker_loop Migrate" >>= fun () ->
let time = Time.(add (now ()) (Int64.of_int ~-delay)) in
let rec migrate_future_blocks () =
match pop_future_block time with
| Some bi ->
push (Some [[filter_bi include_ops bi]]) ;
migrate_future_blocks ()
| None -> Lwt.return_unit in
migrate_future_blocks () >>= fun () ->
worker_loop ()
in
Lwt_utils.worker "block_watcher"
~run:worker_loop ~cancel:(fun () -> Lwt.return_unit) in
stream
let list_blocks
node ()
{ Block_services.S.include_ops ; length ; heads ; monitor ; delay ;
min_date; min_heads} =
let len = match length with None -> 1 | Some x -> x in
let monitor = match monitor with None -> false | Some x -> x in
let time =
match delay with
| None -> None
| Some delay -> Some (Time.(add (now ()) (Int64.of_int ~-delay))) in
begin
match heads with
| None ->
Node.RPC.heads node >>= fun heads ->
let heads = List.map snd (Block_hash.Map.bindings heads) in
let heads =
match min_date with
| None -> heads
| Some date ->
let min_heads =
match min_heads with
| None -> 0
| Some min_heads -> min_heads in
snd @@
List.fold_left (fun (min_heads, acc) (bi : Node.RPC.block_info) ->
min_heads - 1,
if Time.(>) bi.timestamp date || min_heads > 0 then bi :: acc
else acc)
(min_heads, []) heads in
begin
match time with
| None -> Lwt.return heads
| Some time ->
let rec current_predecessor (bi: Node.RPC.block_info) =
if Time.compare bi.timestamp time <= 0
|| bi.hash = bi.predecessor then
Lwt.return bi
else
Node.RPC.raw_block_info node bi.predecessor >>=
current_predecessor in
Lwt_list.map_p current_predecessor heads
end >|= fun heads_info ->
let sorted_infos =
List.sort
(fun
(bi1: Block_services.block_info)
(bi2: Block_services.block_info) ->
~- (Fitness.compare bi1.fitness bi2.fitness))
heads_info in
List.map
(fun ({ hash } : Block_services.block_info) -> hash)
sorted_infos
| Some heads ->
let known_block h =
try ignore (Node.RPC.raw_block_info node h) ; true
with Not_found -> false in
Lwt.return (List.filter known_block heads)
end >>= fun requested_heads ->
Node.RPC.list node len requested_heads >>= fun requested_blocks ->
if not monitor then
let infos =
List.map
(List.map (filter_bi include_ops))
requested_blocks in
RPC_answer.return infos
else begin
let (bi_stream, stopper) = Node.RPC.block_watcher node in
let stream =
match delay with
| None ->
Lwt_stream.map (fun bi -> [[filter_bi include_ops bi]]) bi_stream
| Some delay ->
let filtering = heads <> None in
create_delayed_stream
~filtering ~include_ops requested_heads bi_stream delay in
let shutdown () = Lwt_watcher.shutdown stopper in
let first_request = ref true in
let next () =
if not !first_request then begin
Lwt_stream.get stream
end else begin
first_request := false ;
let infos =
List.map (List.map (filter_bi include_ops)) requested_blocks in
Lwt.return (Some infos)
end in
RPC_answer.return_stream { next ; shutdown }
end
let list_invalid node () () =
Node.RPC.list_invalid node >>= return
let unmark_invalid node block () () =
Node.RPC.unmark_invalid node block
let list_protocols node () { Protocol_services.S.monitor ; contents } =
let monitor = match monitor with None -> false | Some x -> x in
let include_contents = match contents with None -> false | Some x -> x in
Node.RPC.protocols node >>= fun protocols ->
Lwt_list.map_p
(fun hash ->
if include_contents then
Node.RPC.protocol_content node hash >>= function
| Error _ -> Lwt.return (hash, None)
| Ok bytes -> Lwt.return (hash, Some bytes)
else
Lwt.return (hash, None))
protocols >>= fun protocols ->
if not monitor then
RPC_answer.return protocols
else
let stream, stopper = Node.RPC.protocol_watcher node in
let shutdown () = Lwt_watcher.shutdown stopper in
let first_request = ref true in
let next () =
if not !first_request then
Lwt_stream.get stream >>= function
| None -> Lwt.return_none
| Some (h, op) when include_contents -> Lwt.return (Some [h, Some op])
| Some (h, _) -> Lwt.return (Some [h, None])
else begin
first_request := false ;
Lwt.return (Some protocols)
end in
RPC_answer.return_stream { next ; shutdown }
let get_protocols node hash () () =
Node.RPC.protocol_content node hash
let build_rpc_directory node =
let dir = RPC_directory.empty in
let dir =
RPC_directory.gen_register0 dir Block_services.S.list
(list_blocks node) in
let dir =
RPC_directory.register0 dir Block_services.S.list_invalid
(list_invalid node) in
let dir =
RPC_directory.register1 dir Block_services.S.unmark_invalid
(unmark_invalid node) in
let dir = register_bi_dir node dir in
let dir =
let implementation block =
Lwt.catch (fun () ->
Node.RPC.context_dir node block >>= function
| None -> Lwt.fail Not_found
| Some context_dir -> Lwt.return context_dir)
(fun _ -> Lwt.return RPC_directory.empty) in
RPC_directory.register_dynamic_directory1
~descr:
"All the RPCs which are specific to the protocol version."
dir (Block_services.S.proto_path ()) implementation in
let dir =
RPC_directory.gen_register0 dir Protocol_services.S.list
(list_protocols node) in
let dir =
RPC_directory.register1 dir Protocol_services.S.contents
(get_protocols node) in
let dir =
let implementation () header =
let res =
Data_encoding.Binary.to_bytes_exn Block_header.encoding header in
RPC_answer.return res in
RPC_directory.gen_register0 dir Shell_services.S.forge_block_header
implementation in
let dir =
let implementation ()
{ Shell_services.S.raw ; blocking ; force ; operations } =
begin
Node.RPC.inject_block
node ~force
raw operations >>=? fun (hash, wait) ->
(if blocking then wait else return ()) >>=? fun () -> return hash
end in
RPC_directory.register0 dir Shell_services.S.inject_block implementation in
let dir =
let implementation () (contents, blocking, chain_id) =
Node.RPC.inject_operation
node ?chain_id contents >>= fun (hash, wait) ->
begin
(if blocking then wait else return ()) >>=? fun () -> return hash
end in
RPC_directory.register0 dir Shell_services.S.inject_operation implementation in
let dir =
let implementation () (proto, blocking, force) =
Node.RPC.inject_protocol ?force node proto >>= fun (hash, wait) ->
begin
(if blocking then wait else return ()) >>=? fun () -> return hash
end in
RPC_directory.register0 dir Shell_services.S.inject_protocol implementation in
let dir =
let implementation () () =
RPC_answer.return_stream (Node.RPC.bootstrapped node) in
RPC_directory.gen_register0 dir Shell_services.S.bootstrapped implementation in
let dir =
let implementation () () =
return Data_encoding.Json.(schema Error_monad.error_encoding) in
RPC_directory.register0 dir RPC_service.error_service implementation in
let dir =
RPC_directory.register1 dir Shell_services.S.complete
(fun s () () -> Node.RPC.complete node s >>= return) in
let dir =
RPC_directory.register2 dir Block_services.S.complete
(fun block s () () -> Node.RPC.complete node ~block s >>= return) in
let dir =
RPC_directory.register2 dir Block_services.S.raw_context
(fun block path q () ->
Node.RPC.context_raw_get node block ~path ~depth:q#depth >>= function
| None -> raise Not_found
| Some v -> return v)
in
(* Workers : Prevalidators *)
let dir =
RPC_directory.register0 dir Worker_services.Prevalidators.S.list
(fun () () ->
return
(List.map
(fun (id, w) -> (id, Prevalidator.status w))
(Prevalidator.running_workers ()))) in
let dir =
RPC_directory.register1 dir Worker_services.Prevalidators.S.state
(fun chain_id () () ->
let w = List.assoc chain_id (Prevalidator.running_workers ()) in
return
{ Worker_types.status = Prevalidator.status w ;
pending_requests = Prevalidator.pending_requests w ;
backlog = Prevalidator.last_events w ;
current_request = Prevalidator.current_request w }) in
(* Workers : Block_validator *)
let dir =
RPC_directory.register0 dir Worker_services.Block_validator.S.state
(fun () () ->
let w = Block_validator.running_worker () in
return
{ Worker_types.status = Block_validator.status w ;
pending_requests = Block_validator.pending_requests w ;
backlog = Block_validator.last_events w ;
current_request = Block_validator.current_request w }) in
(* Workers : Peer validators *)
let dir =
RPC_directory.register1 dir Worker_services.Peer_validators.S.list
(fun chain_id () () ->
return
(List.filter_map
(fun ((id, peer_id), w) ->
if Chain_id.equal id chain_id then
Some (peer_id, Peer_validator.status w)
else None)
(Peer_validator.running_workers ()))) in
let dir =
RPC_directory.register2 dir Worker_services.Peer_validators.S.state
(fun chain_id peer_id () () ->
let w = List.assoc (chain_id, peer_id) (Peer_validator.running_workers ()) in
return
{ Worker_types.status = Peer_validator.status w ;
pending_requests = [] ;
backlog = Peer_validator.last_events w ;
current_request = Peer_validator.current_request w }) in
(* Workers : Net validators *)
let dir =
RPC_directory.register0 dir Worker_services.Chain_validators.S.list
(fun () () ->
return
(List.map
(fun (id, w) -> (id, Chain_validator.status w))
(Chain_validator.running_workers ()))) in
let dir =
RPC_directory.register1 dir Worker_services.Chain_validators.S.state
(fun chain_id () () ->
let w = List.assoc chain_id (Chain_validator.running_workers ()) in
return
{ Worker_types.status = Chain_validator.status w ;
pending_requests = Chain_validator.pending_requests w ;
backlog = Chain_validator.last_events w ;
current_request = Chain_validator.current_request w }) in
(* Network *)
let dir = RPC_directory.merge dir (Node.RPC.build_p2p_rpc_directory node) in
(* Mempool *)
let dir =
let implementation () () () =
Node.RPC.pending_operations node >>= fun res ->
return res in
RPC_directory.register dir
Mempool_services.S.pending_operations
implementation in
let dir =
RPC_directory.register_describe_directory_service
dir RPC_service.description_service in
dir

View File

@ -54,7 +54,7 @@ type prevalidation_state =
-> prevalidation_state -> prevalidation_state
and 'a proto = and 'a proto =
(module Registered_protocol.T with type validation_state = 'a) (module Registered_protocol.T with type P.validation_state = 'a)
let start_prevalidation let start_prevalidation
?protocol_data ?protocol_data
@ -166,3 +166,54 @@ let prevalidate
let end_prevalidation (State { proto = (module Proto) ; state }) = let end_prevalidation (State { proto = (module Proto) ; state }) =
Proto.finalize_block state >>=? fun (result, _metadata) -> Proto.finalize_block state >>=? fun (result, _metadata) ->
return result return result
let preapply ~predecessor ~timestamp ~protocol_data ~sort_operations:sort ops =
start_prevalidation
~protocol_data ~predecessor ~timestamp () >>=? fun validation_state ->
let ops = List.map (List.map (fun x -> Operation.hash x, x)) ops in
Lwt_list.fold_left_s
(fun (validation_state, rs) ops ->
prevalidate
validation_state ~sort ops >>= fun (validation_state, r) ->
Lwt.return (validation_state, rs @ [r]))
(validation_state, []) ops >>= fun (validation_state, rs) ->
let operations_hash =
Operation_list_list_hash.compute
(List.map
(fun r ->
Operation_list_hash.compute
(List.map fst r.Preapply_result.applied))
rs) in
end_prevalidation validation_state >>=? fun { fitness ; context ; message } ->
let pred_shell_header = State.Block.shell_header predecessor in
State.Block.protocol_hash predecessor >>= fun pred_protocol ->
Context.get_protocol context >>= fun protocol ->
let proto_level =
if Protocol_hash.equal protocol pred_protocol then
pred_shell_header.proto_level
else
((pred_shell_header.proto_level + 1) mod 256) in
let shell_header : Block_header.shell_header = {
level = Int32.succ pred_shell_header.level ;
proto_level ;
predecessor = State.Block.hash predecessor ;
timestamp ;
validation_passes = List.length rs ;
operations_hash ;
fitness ;
context = Context_hash.zero ; (* place holder *)
} in
begin
if Protocol_hash.equal protocol pred_protocol then
return (context, message)
else
match Registered_protocol.get protocol with
| None ->
fail (Block_validator_errors.Unavailable_protocol
{ block = State.Block.hash predecessor ; protocol })
| Some (module NewProto) ->
NewProto.init context shell_header >>=? fun { context ; message ; _ } ->
return (context, message)
end >>=? fun (context, message) ->
Context.commit ?message ~time:timestamp context >>= fun context ->
return ({ shell_header with context }, rs)

View File

@ -23,3 +23,12 @@ val prevalidate :
val end_prevalidation : val end_prevalidation :
prevalidation_state -> prevalidation_state ->
Tezos_protocol_environment_shell.validation_result tzresult Lwt.t Tezos_protocol_environment_shell.validation_result tzresult Lwt.t
val preapply :
predecessor:State.Block.t ->
timestamp:Time.t ->
protocol_data:MBytes.t ->
sort_operations:bool ->
Operation.t list list ->
(Block_header.shell_header * error Preapply_result.t list) tzresult Lwt.t

View File

@ -0,0 +1,57 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
let build_rpc_directory state distributed_db =
let dir : unit RPC_directory.t ref = ref RPC_directory.empty in
let gen_register0 s f =
dir := RPC_directory.gen_register !dir s (fun () p q -> f p q) in
let register1 s f =
dir := RPC_directory.register !dir s (fun ((), a) p q -> f a p q) in
gen_register0 Protocol_services.S.list begin fun () p ->
let { Protocol_services.S.monitor ; contents } = p in
let monitor = match monitor with None -> false | Some x -> x in
let include_contents = match contents with None -> false | Some x -> x in
State.Protocol.list state >>= fun set ->
let protocols = Protocol_hash.Set.elements set in
Lwt_list.map_p
(fun hash ->
if include_contents then
State.Protocol.read state hash >>= function
| Error _ -> Lwt.return (hash, None)
| Ok bytes -> Lwt.return (hash, Some bytes)
else
Lwt.return (hash, None))
protocols >>= fun protocols ->
if not monitor then
RPC_answer.return protocols
else
let stream, stopper =
Distributed_db.Protocol.watch distributed_db in
let shutdown () = Lwt_watcher.shutdown stopper in
let first_request = ref true in
let next () =
if not !first_request then
Lwt_stream.get stream >>= function
| None -> Lwt.return_none
| Some (h, op) when include_contents -> Lwt.return (Some [h, Some op])
| Some (h, _) -> Lwt.return (Some [h, None])
else begin
first_request := false ;
Lwt.return (Some protocols)
end in
RPC_answer.return_stream { next ; shutdown }
end;
register1 Protocol_services.S.contents begin fun hash () () ->
State.Protocol.read state hash
end ;
!dir

View File

@ -0,0 +1,11 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
val build_rpc_directory:
State.t -> Distributed_db.t -> unit RPC_directory.t

View File

@ -0,0 +1,179 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
let inject_block validator ?force ?chain_id bytes operations =
Validator.validate_block
validator ?force ?chain_id bytes operations >>=? fun (hash, block) ->
return (hash, (block >>=? fun _ -> return ()))
let inject_operation validator ?chain_id bytes =
let t =
match Data_encoding.Binary.of_bytes Operation.encoding bytes with
| None -> failwith "Can't parse the operation"
| Some op ->
Validator.inject_operation validator ?chain_id op
in
let hash = Operation_hash.hash_bytes [bytes] in
Lwt.return (hash, t)
let inject_protocol state ?force:_ proto =
let proto_bytes =
Data_encoding.Binary.to_bytes_exn Protocol.encoding proto in
let hash = Protocol_hash.hash_bytes [proto_bytes] in
let validation =
Updater.compile hash proto >>= function
| false ->
failwith
"Compilation failed (%a)"
Protocol_hash.pp_short hash
| true ->
State.Protocol.store state proto >>= function
| None ->
failwith
"Previously registered protocol (%a)"
Protocol_hash.pp_short hash
| Some _ -> return ()
in
Lwt.return (hash, validation)
let build_rpc_directory state validator mainchain_validator =
let dir : unit RPC_directory.t ref = ref RPC_directory.empty in
let gen_register0 s f =
dir := RPC_directory.gen_register !dir s (fun () p q -> f p q) in
let register0 s f =
dir := RPC_directory.register !dir s (fun () p q -> f p q) in
let gen_register1 s f =
dir := RPC_directory.gen_register !dir s (fun ((), a) p q -> f a p q) in
register0 Shell_services.S.forge_block_header begin fun () header ->
return (Data_encoding.Binary.to_bytes_exn Block_header.encoding header)
end ;
register0 Shell_services.S.inject_block begin fun () p ->
let { Shell_services.S.raw ; blocking ; force ; operations } = p in
inject_block validator ~force raw operations >>=? fun (hash, wait) ->
(if blocking then wait else return ()) >>=? fun () ->
return hash
end ;
register0 Shell_services.S.inject_operation begin fun () p ->
let (contents, blocking, chain_id) = p in
inject_operation validator ?chain_id contents >>= fun (hash, wait) ->
(if blocking then wait else return ()) >>=? fun () ->
return hash
end ;
register0 Shell_services.S.inject_protocol begin fun () p ->
let (proto, blocking, force) = p in
inject_protocol state ?force proto >>= fun (hash, wait) ->
(if blocking then wait else return ()) >>=? fun () ->
return hash
end ;
gen_register0 Shell_services.S.bootstrapped begin fun () () ->
let block_stream, stopper =
Chain_validator.new_head_watcher mainchain_validator in
let first_run = ref true in
let next () =
if !first_run then begin
first_run := false ;
let chain_state = Chain_validator.chain_state mainchain_validator in
Chain.head chain_state >>= fun head ->
let head_hash = State.Block.hash head in
let head_header = State.Block.header head in
Lwt.return (Some (head_hash, head_header.shell.timestamp))
end else begin
Lwt.pick [
( Lwt_stream.get block_stream >|=
Option.map ~f:(fun b ->
(State.Block.hash b, (State.Block.header b).shell.timestamp)) ) ;
(Chain_validator.bootstrapped mainchain_validator >|= fun () -> None) ;
]
end in
let shutdown () = Lwt_watcher.shutdown stopper in
RPC_answer.return_stream { next ; shutdown }
end ;
gen_register0 Shell_services.S.Monitor.valid_blocks begin fun q () ->
let block_stream, stopper = State.watcher state in
let shutdown () = Lwt_watcher.shutdown stopper in
let in_chains block =
Lwt_list.map_p (Chain_directory.get_chain_id state) q#chains >>= function
| [] -> Lwt.return_true
| chains ->
let chain_id = State.Block.chain_id block in
Lwt.return (List.exists (Chain_id.equal chain_id) chains) in
let in_protocols block =
match q#protocols with
| [] -> Lwt.return_true
| protocols ->
State.Block.predecessor block >>= function
| None -> Lwt.return_false (* won't happen *)
| Some pred ->
State.Block.context pred >>= fun context ->
Context.get_protocol context >>= fun protocol ->
Lwt.return (List.exists (Protocol_hash.equal protocol) protocols) in
let in_next_protocols block =
match q#next_protocols with
| [] -> Lwt.return_true
| protocols ->
State.Block.context block >>= fun context ->
Context.get_protocol context >>= fun next_protocol ->
Lwt.return (List.exists (Protocol_hash.equal next_protocol) protocols) in
let stream =
Lwt_stream.filter_map_s
(fun block ->
in_chains block >>= fun in_chains ->
in_next_protocols block >>= fun in_next_protocols ->
in_protocols block >>= fun in_protocols ->
if in_chains && in_protocols && in_next_protocols then
Lwt.return_some
(State.Block.chain_id block, State.Block.hash block)
else
Lwt.return_none)
block_stream in
let next () = Lwt_stream.get stream in
RPC_answer.return_stream { next ; shutdown }
end ;
gen_register1 Shell_services.S.Monitor.heads begin fun chain q () ->
(* TODO: when `chain = `Test`, should we reset then stream when
the `testnet` change, or dias we currently do ?? *)
Chain_directory.get_chain state chain >>= fun chain ->
Validator.get_exn validator (State.Chain.id chain) >>= fun chain_validator ->
let block_stream, stopper = Chain_validator.new_head_watcher chain_validator in
Chain.head chain >>= fun head ->
let shutdown () = Lwt_watcher.shutdown stopper in
let in_next_protocols block =
match q#next_protocols with
| [] -> Lwt.return_true
| protocols ->
State.Block.context block >>= fun context ->
Context.get_protocol context >>= fun next_protocol ->
Lwt.return (List.exists (Protocol_hash.equal next_protocol) protocols) in
let stream =
Lwt_stream.filter_map_s
(fun block ->
in_next_protocols block >>= fun in_next_protocols ->
if in_next_protocols then
Lwt.return_some (State.Block.hash block)
else
Lwt.return_none)
block_stream in
let first_call = ref true in
let next () =
if !first_call then begin
first_call := false ; Lwt.return_some (State.Block.hash head)
end else
Lwt_stream.get stream in
RPC_answer.return_stream { next ; shutdown }
end ;
!dir

View File

@ -0,0 +1,11 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
val build_rpc_directory:
State.t -> Validator.t -> Chain_validator.t -> unit RPC_directory.t

View File

@ -44,6 +44,8 @@ and chain_state = {
context_index: Context.index Shared.t ; context_index: Context.index Shared.t ;
block_watcher: block Lwt_watcher.input ; block_watcher: block Lwt_watcher.input ;
chain_data: chain_data_state Shared.t ; chain_data: chain_data_state Shared.t ;
block_rpc_directories:
block RPC_directory.t Protocol_hash.Map.t Protocol_hash.Table.t ;
} }
and genesis = { and genesis = {
@ -282,6 +284,7 @@ module Chain = struct
block_store = Shared.create block_store ; block_store = Shared.create block_store ;
context_index = Shared.create context_index ; context_index = Shared.create context_index ;
block_watcher = Lwt_watcher.create_input () ; block_watcher = Lwt_watcher.create_input () ;
block_rpc_directories = Protocol_hash.Table.create 7 ;
} in } in
Lwt.return chain_state Lwt.return chain_state
@ -722,6 +725,33 @@ module Block = struct
read_exn chain_state tail >>= fun block -> read_exn chain_state tail >>= fun block ->
Lwt.return_some (block, locator) Lwt.return_some (block, locator)
let get_rpc_directory ({ chain_state ; _ } as block) =
read_opt chain_state block.contents.header.shell.predecessor >>= function
| None -> Lwt.return_none (* genesis *)
| Some pred ->
protocol_hash pred >>= fun protocol ->
match
Protocol_hash.Table.find_opt
chain_state.block_rpc_directories protocol
with
| None -> Lwt.return_none
| Some map ->
protocol_hash block >>= fun next_protocol ->
Lwt.return (Protocol_hash.Map.find_opt next_protocol map)
let set_rpc_directory ({ chain_state ; _ } as block) dir =
read_exn chain_state block.contents.header.shell.predecessor >>= fun pred ->
protocol_hash block >>= fun next_protocol ->
protocol_hash pred >>= fun protocol ->
let map =
Option.unopt ~default:Protocol_hash.Map.empty
(Protocol_hash.Table.find_opt chain_state.block_rpc_directories protocol)
in
Protocol_hash.Table.replace
chain_state.block_rpc_directories protocol
(Protocol_hash.Map.add next_protocol dir map) ;
Lwt.return_unit
end end
let watcher (state : global_state) = let watcher (state : global_state) =

View File

@ -153,6 +153,9 @@ module Block : sig
function returns [None] when no block in the locator are known or function returns [None] when no block in the locator are known or
if the first known block is invalid. *) if the first known block is invalid. *)
val get_rpc_directory: block -> block RPC_directory.t option Lwt.t
val set_rpc_directory: block -> block RPC_directory.t -> unit Lwt.t
end end
val read_block: val read_block:

View File

@ -0,0 +1,88 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
let rpc_directory =
let dir : unit RPC_directory.t ref = ref RPC_directory.empty in
let register0 s f =
dir := RPC_directory.register !dir s (fun () p q -> f p q) in
let register1 s f =
dir := RPC_directory.register !dir s (fun ((), a) p q -> f a p q) in
let register2 s f =
dir := RPC_directory.register !dir s (fun (((), a), b) p q -> f a b p q) in
(* Workers : Prevalidators *)
register0 Worker_services.Prevalidators.S.list begin fun () () ->
return
(List.map
(fun (id, w) -> (id, Prevalidator.status w))
(Prevalidator.running_workers ()))
end ;
register1 Worker_services.Prevalidators.S.state begin fun chain_id () () ->
let w = List.assoc chain_id (Prevalidator.running_workers ()) in
return
{ Worker_types.status = Prevalidator.status w ;
pending_requests = Prevalidator.pending_requests w ;
backlog = Prevalidator.last_events w ;
current_request = Prevalidator.current_request w }
end ;
(* Workers : Block_validator *)
register0 Worker_services.Block_validator.S.state begin fun () () ->
let w = Block_validator.running_worker () in
return
{ Worker_types.status = Block_validator.status w ;
pending_requests = Block_validator.pending_requests w ;
backlog = Block_validator.last_events w ;
current_request = Block_validator.current_request w }
end ;
(* Workers : Peer validators *)
register1 Worker_services.Peer_validators.S.list begin fun chain_id () () ->
return
(List.filter_map
(fun ((id, peer_id), w) ->
if Chain_id.equal id chain_id then
Some (peer_id, Peer_validator.status w)
else None)
(Peer_validator.running_workers ()))
end ;
register2 Worker_services.Peer_validators.S.state begin fun chain_id peer_id () () ->
let w = List.assoc (chain_id, peer_id) (Peer_validator.running_workers ()) in
return
{ Worker_types.status = Peer_validator.status w ;
pending_requests = [] ;
backlog = Peer_validator.last_events w ;
current_request = Peer_validator.current_request w }
end ;
(* Workers : Net validators *)
register0 Worker_services.Chain_validators.S.list begin fun () () ->
return
(List.map
(fun (id, w) -> (id, Chain_validator.status w))
(Chain_validator.running_workers ()))
end ;
register1 Worker_services.Chain_validators.S.state begin fun chain_id () () ->
let w = List.assoc chain_id (Chain_validator.running_workers ()) in
return
{ Worker_types.status = Chain_validator.status w ;
pending_requests = Chain_validator.pending_requests w ;
backlog = Chain_validator.last_events w ;
current_request = Chain_validator.current_request w }
end ;
!dir

View File

@ -7,4 +7,4 @@
(* *) (* *)
(**************************************************************************) (**************************************************************************)
val build_rpc_directory: Node.t -> unit RPC_directory.t val rpc_directory: unit RPC_directory.t

File diff suppressed because it is too large Load Diff

View File

@ -7,223 +7,433 @@
(* *) (* *)
(**************************************************************************) (**************************************************************************)
open Chain_services
type block = [ type block = [
| `Genesis | `Genesis
| `Head of int | `Head of int
| `Test_head of int
| `Hash of Block_hash.t * int | `Hash of Block_hash.t * int
] ]
val parse_block: string -> (block, string) result val parse_block: string -> (block, string) result
val to_string: block -> string val to_string: block -> string
type block_info = { type prefix = (unit * Chain_services.chain) * block
hash: Block_hash.t ; val path: (Chain_services.prefix, Chain_services.prefix * block) RPC_path.t
chain_id: Chain_id.t ;
level: Int32.t ; type operation_list_quota = {
proto_level: int ; (* uint8 *) max_size: int ;
predecessor: Block_hash.t ; max_op: int option ;
timestamp: Time.t ;
validation_passes: int ; (* uint8 *)
operations_hash: Operation_list_list_hash.t ;
fitness: MBytes.t list ;
context: Context_hash.t ;
protocol_data: MBytes.t ;
operations: (Operation_hash.t * Operation.t) list list option ;
protocol: Protocol_hash.t ;
test_chain: Test_chain_status.t ;
} }
val pp_block_info: Format.formatter -> block_info -> unit type raw_context =
type preapply_result = {
shell_header: Block_header.shell_header ;
operations: error Preapply_result.t list ;
}
open RPC_context
val chain_id:
#simple -> block -> Chain_id.t tzresult Lwt.t
val level:
#simple -> block -> Int32.t tzresult Lwt.t
val predecessor:
#simple -> block -> Block_hash.t tzresult Lwt.t
val predecessors:
#simple -> block -> int -> Block_hash.t list tzresult Lwt.t
val hash:
#simple -> block -> Block_hash.t tzresult Lwt.t
val timestamp:
#simple -> block -> Time.t tzresult Lwt.t
val fitness:
#simple -> block -> MBytes.t list tzresult Lwt.t
val operations:
#simple -> ?contents:bool ->
block -> (Operation_hash.t * Operation.t option) list list tzresult Lwt.t
val protocol:
#simple -> block -> Protocol_hash.t tzresult Lwt.t
val test_chain:
#simple -> block -> Test_chain_status.t tzresult Lwt.t
val info:
#simple ->
?include_ops:bool -> block -> block_info tzresult Lwt.t
val list:
?include_ops:bool -> ?length:int -> ?heads:Block_hash.t list ->
?delay:int -> ?min_date:Time.t -> ?min_heads:int ->
#simple ->
block_info list list tzresult Lwt.t
val monitor:
?include_ops:bool -> ?length:int -> ?heads:Block_hash.t list ->
?delay:int -> ?min_date:Time.t -> ?min_heads:int ->
#streamed ->
(block_info list list Lwt_stream.t * stopper) tzresult Lwt.t
val preapply:
#simple -> block ->
?timestamp:Time.t ->
?sort:bool ->
protocol_data:MBytes.t ->
Operation.t list list -> preapply_result tzresult Lwt.t
val complete:
#simple -> block -> string -> string list tzresult Lwt.t
(** Encodes a directory structure returned from a context
query as a tree plus a special case [Cut] used when
the query is limited by a [depth] value.
[Cut] is encoded as [null] in json. *)
type raw_context_result =
| Key of MBytes.t | Key of MBytes.t
| Dir of (string * raw_context_result) list | Dir of (string * raw_context) list
| Cut | Cut
(** Pretty-printer for raw_context_result *) val pp_raw_context: Format.formatter -> raw_context -> unit
val raw_context_result_pp : raw_context_result -> string
val raw_context: type error +=
#simple -> block -> string list -> int -> raw_context_result tzresult Lwt.t | Invalid_depth_arg of (string list * int)
| Missing_key of string list
val unmark_invalid: module type PROTO = sig
#simple -> Block_hash.t -> unit Error_monad.tzresult Lwt.t val hash: Protocol_hash.t
val list_invalid: type block_header_data
#simple -> (Block_hash.t * int32 * error list) list tzresult Lwt.t val block_header_data_encoding: block_header_data Data_encoding.t
type block_header_metadata
val block_header_metadata_encoding:
block_header_metadata Data_encoding.t
type operation_data
val operation_data_encoding: operation_data Data_encoding.t
type operation_metadata
val operation_metadata_encoding: operation_metadata Data_encoding.t
type operation = {
shell: Operation.shell_header ;
protocol_data: operation_data ;
}
end
(** Signatures of all RPCs. module Make(Proto : PROTO)(Next_proto : PROTO) : sig
This module is shared between the Client and the Node. *)
module S : sig
val blocks_arg : block RPC_arg.arg val path: (unit, Chain_services.prefix * block) RPC_path.t
type raw_block_header = {
shell: Block_header.shell_header ;
protocol_data: Proto.block_header_data ;
}
type block_header = {
chain_id: Chain_id.t ;
hash: Block_hash.t ;
shell: Block_header.shell_header ;
protocol_data: Proto.block_header_data ;
}
type block_metadata = {
protocol_data: Proto.block_header_metadata ;
test_chain_status: Test_chain_status.t ;
max_operations_ttl: int ;
max_operation_data_length: int ;
max_block_header_length: int ;
operation_list_quota: operation_list_quota list ;
}
type operation = {
chain_id: Chain_id.t ;
hash: Operation_hash.t ;
shell: Operation.shell_header ;
protocol_data: Proto.operation_data ;
metadata: Proto.operation_metadata ;
}
type block_info = {
chain_id: Chain_id.t ;
hash: Block_hash.t ;
header: raw_block_header ;
metadata: block_metadata ;
operations: operation list list ;
}
open RPC_context
val info: val info:
([ `POST ], unit, #simple -> ?chain:chain -> ?block:block ->
unit * block, unit, bool, unit -> block_info tzresult Lwt.t
block_info) RPC_service.t
val chain_id:
([ `POST ], unit,
unit * block, unit, unit,
Chain_id.t) RPC_service.t
val level:
([ `POST ], unit,
unit * block, unit, unit,
Int32.t) RPC_service.t
val predecessor:
([ `POST ], unit,
unit * block, unit, unit,
Block_hash.t) RPC_service.t
val predecessors:
([ `POST ], unit,
unit * block , unit, int,
Block_hash.t list) RPC_service.t
val hash: val hash:
([ `POST ], unit, #simple -> ?chain:chain -> ?block:block ->
unit * block, unit, unit, unit -> Block_hash.t tzresult Lwt.t
Block_hash.t) RPC_service.t
module Header : sig
val header:
#simple -> ?chain:chain -> ?block:block ->
unit -> block_header tzresult Lwt.t
val shell_header:
#simple -> ?chain:chain -> ?block:block ->
unit -> Block_header.shell_header tzresult Lwt.t
val protocol_data:
#simple -> ?chain:chain -> ?block:block ->
unit -> Proto.block_header_data tzresult Lwt.t
module Shell : sig
val level:
#simple -> ?chain:chain -> ?block:block ->
unit -> Int32.t tzresult Lwt.t
val protocol_level:
#simple -> ?chain:chain -> ?block:block ->
unit -> int tzresult Lwt.t
val predecessor:
#simple -> ?chain:chain -> ?block:block ->
unit -> Block_hash.t tzresult Lwt.t
val timestamp: val timestamp:
([ `POST ], unit, #simple -> ?chain:chain -> ?block:block ->
unit * block, unit, unit, unit -> Time.t tzresult Lwt.t
Time.t) RPC_service.t val validation_passes:
#simple -> ?chain:chain -> ?block:block ->
unit -> int tzresult Lwt.t
val operations_hash:
#simple -> ?chain:chain -> ?block:block ->
unit -> Operation_list_list_hash.t tzresult Lwt.t
val fitness: val fitness:
([ `POST ], unit, #simple -> ?chain:chain -> ?block:block ->
unit * block, unit, unit, unit -> Fitness.t tzresult Lwt.t
MBytes.t list) RPC_service.t val context_hash:
val context: #simple -> ?chain:chain -> ?block:block ->
([ `POST ], unit, unit -> Context_hash.t tzresult Lwt.t
unit * block, unit, unit,
end
end
module Metadata : sig
val metadata:
#simple -> ?chain:chain -> ?block:block ->
unit -> block_metadata tzresult Lwt.t
val protocol_data:
#simple -> ?chain:chain -> ?block:block ->
unit -> Proto.block_header_metadata tzresult Lwt.t
val protocol_hash:
#simple -> ?chain:chain -> ?block:block ->
unit -> Protocol_hash.t tzresult Lwt.t
val next_protocol_hash:
#simple -> ?chain:chain -> ?block:block ->
unit -> Protocol_hash.t tzresult Lwt.t
val test_chain_status:
#simple -> ?chain:chain -> ?block:block ->
unit -> Test_chain_status.t tzresult Lwt.t
val max_operations_ttl:
#simple -> ?chain:chain -> ?block:block ->
unit -> int tzresult Lwt.t
val max_operation_data_length:
#simple -> ?chain:chain -> ?block:block ->
unit -> int tzresult Lwt.t
val max_block_header_length:
#simple -> ?chain:chain -> ?block:block ->
unit -> int tzresult Lwt.t
val max_operation_list_length:
#simple -> ?chain:chain -> ?block:block ->
unit -> operation_list_quota list tzresult Lwt.t
end
module Operation : sig
val operations:
#simple -> ?chain:chain -> ?block:block ->
unit -> operation list list tzresult Lwt.t
val operations_in_pass:
#simple -> ?chain:chain -> ?block:block ->
int -> operation list tzresult Lwt.t
val operation:
#simple -> ?chain:chain -> ?block:block ->
int -> int -> operation tzresult Lwt.t
end
module Operation_hash : sig
val operation_hashes:
#simple -> ?chain:chain -> ?block:block ->
unit -> Operation_hash.t list list tzresult Lwt.t
val operation_hashes_in_pass:
#simple -> ?chain:chain -> ?block:block ->
int -> Operation_hash.t list tzresult Lwt.t
val operation_hash:
#simple -> ?chain:chain -> ?block:block ->
int -> int -> Operation_hash.t tzresult Lwt.t
end
module Context : sig
module Raw : sig
val read:
#simple -> ?chain:chain -> ?block:block ->
?depth: int ->
string list -> raw_context tzresult Lwt.t
end
end
module Helpers : sig
val preapply:
#simple -> ?chain:chain -> ?block:block ->
?sort:bool ->
timestamp:Time.t ->
protocol_data:Next_proto.block_header_data ->
Next_proto.operation list list ->
(Block_header.shell_header * error Preapply_result.t list) tzresult Lwt.t
val complete:
#simple -> ?chain:chain -> ?block:block ->
string -> string list tzresult Lwt.t
end
module S : sig
val hash:
([ `GET ], prefix,
prefix, unit, unit,
Block_hash.t) RPC_service.t
val info:
([ `GET ], prefix,
prefix, unit, unit,
block_info) RPC_service.t
module Header : sig
val header:
([ `GET ], prefix,
prefix, unit, unit,
block_header) RPC_service.t
val shell_header:
([ `GET ], prefix,
prefix, unit, unit,
Block_header.shell_header) RPC_service.t
val protocol_data:
([ `GET ], prefix,
prefix, unit, unit,
Proto.block_header_data) RPC_service.t
module Shell : sig
val level:
([ `GET ], prefix,
prefix, unit, unit,
Int32.t) RPC_service.t
val protocol_level:
([ `GET ], prefix,
prefix, unit, unit,
int) RPC_service.t
val predecessor:
([ `GET ], prefix,
prefix, unit, unit,
Block_hash.t) RPC_service.t
val timestamp:
([ `GET ], prefix,
prefix, unit, unit,
Time.t) RPC_service.t
val validation_passes:
([ `GET ], prefix,
prefix, unit, unit,
int) RPC_service.t
val operations_hash:
([ `GET ], prefix,
prefix, unit, unit,
Operation_list_list_hash.t) RPC_service.t
val fitness:
([ `GET ], prefix,
prefix, unit, unit,
Fitness.t) RPC_service.t
val context_hash:
([ `GET ], prefix,
prefix, unit, unit,
Context_hash.t) RPC_service.t Context_hash.t) RPC_service.t
(** Accepts queries of the form end
/blocks/<id>/raw_context/<path>?depth=<n>
returning the sub-tree corresponding to <path> inside the context of
block <id>. The optional parameter <depth> controls the size of the
tree, default is 1.
Example:
tezos-client rpc post /blocks/head/raw_context/v1?depth=2
*)
val raw_context:
([ `POST ], unit,
(unit * block) * string list, <depth:int>, unit,
raw_context_result) RPC_service.t
type operations_param = { end
contents: bool ;
}
val operations:
([ `POST ], unit,
unit * block, unit, operations_param,
(Operation_hash.t * Operation.t option) list list) RPC_service.t
val protocol: module Metadata : sig
([ `POST ], unit,
unit * block, unit, unit, val metadata:
([ `GET ], prefix,
prefix, unit, unit,
block_metadata) RPC_service.t
val protocol_data:
([ `GET ], prefix,
prefix, unit, unit,
Proto.block_header_metadata) RPC_service.t
val protocol_hash:
([ `GET ], prefix,
prefix, unit, unit,
Protocol_hash.t) RPC_service.t Protocol_hash.t) RPC_service.t
val test_chain:
([ `POST ], unit, val next_protocol_hash:
unit * block, unit, unit, ([ `GET ], prefix,
prefix, unit, unit,
Protocol_hash.t) RPC_service.t
val test_chain_status:
([ `GET ], prefix,
prefix, unit, unit,
Test_chain_status.t) RPC_service.t Test_chain_status.t) RPC_service.t
type list_param = { val max_operations_ttl:
include_ops: bool ; ([ `GET ], prefix,
length: int option ; prefix, unit, unit,
heads: Block_hash.t list option ; int) RPC_service.t
monitor: bool option ;
delay: int option ;
min_date: Time.t option;
min_heads: int option;
}
val list:
([ `POST ], unit,
unit, unit, list_param,
block_info list list) RPC_service.t
val list_invalid: val max_operation_data_length:
([ `POST ], unit, ([ `GET ], prefix,
unit, unit, unit, prefix, unit, unit,
(Block_hash.t * int32 * error list) list) RPC_service.t int) RPC_service.t
val unmark_invalid: val max_block_header_length:
([ `POST ], unit, ([ `GET ], prefix,
unit * Block_hash.t, unit, unit, prefix, unit, unit,
unit) RPC_service.t int) RPC_service.t
val operation_list_quota:
([ `GET ], prefix,
prefix, unit, unit,
operation_list_quota list) RPC_service.t
end
module Operation : sig
val operations:
([ `GET ], prefix,
prefix, unit, unit,
operation list list) RPC_service.t
val operations_in_pass:
([ `GET ], prefix,
prefix * int, unit, unit,
operation list) RPC_service.t
val operation:
([ `GET ], prefix,
(prefix * int) * int, unit, unit,
operation) RPC_service.t
end
module Operation_hash : sig
val operation_hashes:
([ `GET ], prefix,
prefix, unit, unit,
Tezos_crypto.Operation_hash.t list list) RPC_service.t
val operation_hashes_in_pass:
([ `GET ], prefix,
prefix * int, unit, unit,
Tezos_crypto.Operation_hash.t list) RPC_service.t
val operation_hash:
([ `GET ], prefix,
(prefix * int) * int, unit, unit,
Tezos_crypto.Operation_hash.t) RPC_service.t
end
module Context : sig
module Raw : sig
val read:
([ `GET ], prefix,
prefix * string list, < depth : int option >, unit,
raw_context) RPC_service.t
end
end
module Helpers : sig
type preapply_param = { type preapply_param = {
timestamp: Time.t ; timestamp: Time.t ;
protocol_data: MBytes.t ; protocol_data: Next_proto.block_header_data ;
operations: Operation.t list list ; operations: Next_proto.operation list list ;
sort_operations: bool ;
} }
val preapply: val preapply:
([ `POST ], unit, ([ `POST ], prefix,
unit * block, unit, preapply_param, prefix, < sort_operations : bool >, preapply_param,
preapply_result) RPC_service.t Block_header.shell_header * error Preapply_result.t list) RPC_service.t
val complete: val complete:
([ `POST ], unit, ([ `GET ], prefix,
(unit * block) * string, unit, unit, prefix * string, unit, unit,
string list) RPC_service.t string list) RPC_service.t
val proto_path: unit -> ('a, 'a * block) RPC_path.path end
end
end end
module Fake_protocol : PROTO
module Empty : (module type of Make(Fake_protocol)(Fake_protocol))

View File

@ -0,0 +1,228 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
open Data_encoding
type chain = [
| `Main
| `Test
| `Hash of Chain_id.t
]
let parse_chain s =
try
match s with
| "main" -> Ok `Main
| "test" -> Ok `Test
| h -> Ok (`Hash (Chain_id.of_b58check_exn h))
with _ -> Error "Cannot parse block identifier."
let to_string = function
| `Main -> "main"
| `Test -> "test"
| `Hash h -> Chain_id.to_b58check h
let chain_arg =
let name = "chain_id" in
let descr =
"A chain identifier. This is either a chain hash in Base58Check notation \
or a one the predefined aliases: 'main', 'test'." in
let construct = to_string in
let destruct = parse_chain in
RPC_arg.make ~name ~descr ~construct ~destruct ()
type prefix = unit * chain
let path = RPC_path.(root / "chains" /: chain_arg)
type invalid_block = {
hash: Block_hash.t ;
level: Int32.t ;
errors: error list ;
}
let invalid_block_encoding =
conv
(fun { hash ; level ; errors } -> (hash, level, errors))
(fun (hash, level, errors) -> { hash ; level ; errors })
(obj3
(req "block" Block_hash.encoding)
(req "level" int32)
(req "errors" RPC_error.encoding))
module S = struct
let path : prefix RPC_path.context = RPC_path.open_root
let chain_id =
RPC_service.get_service
~description:"The chain unique identifier."
~query: RPC_query.empty
~output: Chain_id.encoding
RPC_path.(path / "chain_id")
module Mempool = struct
let operation_encoding =
merge_objs
(obj1 (req "hash" Operation_hash.encoding))
Operation.encoding
let pending_operations =
(* TODO: branch_delayed/... *)
RPC_service.get_service
~description:
"List the not-yet-prevalidated operations."
~query: RPC_query.empty
~output:
(conv
(fun (preapplied, unprocessed) ->
({ preapplied with
Preapply_result.refused = Operation_hash.Map.empty },
Operation_hash.Map.bindings unprocessed))
(fun (preapplied, unprocessed) ->
(preapplied,
List.fold_right
(fun (h, op) m -> Operation_hash.Map.add h op m)
unprocessed Operation_hash.Map.empty))
(merge_objs
(dynamic_size
(Preapply_result.encoding RPC_error.encoding))
(obj1 (req "unprocessed" (list (dynamic_size operation_encoding))))))
RPC_path.(path / "mempool")
end
module Blocks = struct
let list_query =
let open RPC_query in
query (fun length heads min_date ->
object
method length = length
method heads = heads
method min_date = min_date
end)
|+ opt_field "length"
~descr:
"The requested number of predecessors to returns (per \
requested head)."
RPC_arg.int (fun x -> x#length)
|+ multi_field "head"
~descr:
"An empty argument requests blocks from the current heads. \
A non empty list allow to request specific fragment \
of the chain."
Block_hash.rpc_arg (fun x -> x#heads)
|+ opt_field "min_date"
~descr: "When `min_date` is provided, heads with a \
timestamp before `min_date` are filtered out"
Time.rpc_arg (fun x -> x#min_date)
|> seal
let path = RPC_path.(path / "blocks")
let list =
let open Data_encoding in
RPC_service.get_service
~description:
"Lists known heads of the blockchain sorted with decreasing fitness. \
Optional arguments allows to returns the list of predecessors for \
known heads or the list of predecessors for a given list of blocks."
~query: list_query
~output: (list (list Block_hash.encoding))
path
end
module Invalid_blocks = struct
let path = RPC_path.(path / "invalid_blocks")
let list =
RPC_service.get_service
~description:
"Lists blocks that have been declared invalid along with the errors \
that led to them being declared invalid."
~query: RPC_query.empty
~output: (list invalid_block_encoding)
path
let get =
RPC_service.get_service
~description: "The errors that appears during the block (in)validation."
~query: RPC_query.empty
~output: invalid_block_encoding
RPC_path.(path /: Block_hash.rpc_arg)
let delete =
RPC_service.delete_service
~description: "Remove an invalid block for the tezos storage"
~query: RPC_query.empty
~output: Data_encoding.empty
RPC_path.(path /: Block_hash.rpc_arg)
end
end
let make_call0 s ctxt chain q p =
let s = RPC_service.prefix path s in
RPC_context.make_call1 s ctxt chain q p
let make_call1 s ctxt chain a q p =
let s = RPC_service.prefix path s in
RPC_context.make_call2 s ctxt chain a q p
let chain_id ctxt =
let f = make_call0 S.chain_id ctxt in
fun ?(chain = `Main) () ->
match chain with
| `Hash h -> return h
| _ -> f chain () ()
module Mempool = struct
let pending_operations ctxt ?(chain = `Main) () =
make_call0 S.Mempool.pending_operations ctxt chain () ()
end
module Blocks = struct
let list ctxt =
let f = make_call0 S.Blocks.list ctxt in
fun ?(chain = `Main) ?(heads = []) ?length ?min_date () ->
f chain
(object
method heads = heads
method length = length
method min_date = min_date
end)
()
end
module Invalid_blocks = struct
let list ctxt =
let f = make_call0 S.Invalid_blocks.list ctxt in
fun ?(chain = `Main) () ->
f chain () ()
let get ctxt =
let f = make_call1 S.Invalid_blocks.get ctxt in
fun ?(chain = `Main) block ->
f chain block () ()
let delete ctxt =
let f = make_call1 S.Invalid_blocks.delete ctxt in
fun ?(chain = `Main) block ->
f chain block () ()
end

View File

@ -0,0 +1,126 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
type chain = [
| `Main
| `Test
| `Hash of Chain_id.t
]
val parse_chain: string -> (chain, string) result
val to_string: chain -> string
val chain_arg: chain RPC_arg.t
type invalid_block = {
hash: Block_hash.t ;
level: Int32.t ;
errors: error list ;
}
type prefix = unit * chain
val path: (unit, prefix) RPC_path.path
open RPC_context
val chain_id:
#simple ->
?chain:chain ->
unit -> Chain_id.t tzresult Lwt.t
module Mempool : sig
val pending_operations:
#simple ->
?chain:chain ->
unit ->
(error Preapply_result.t * Operation.t Operation_hash.Map.t) tzresult Lwt.t
end
module Blocks : sig
val list:
#simple ->
?chain:chain ->
?heads:Block_hash.t list ->
?length:int ->
?min_date:Time.t ->
unit -> Block_hash.t list list tzresult Lwt.t
end
module Invalid_blocks : sig
val list:
#simple ->
?chain:chain ->
unit -> invalid_block list tzresult Lwt.t
val get:
#simple ->
?chain:chain ->
Block_hash.t -> invalid_block tzresult Lwt.t
val delete:
#simple ->
?chain:chain ->
Block_hash.t -> unit tzresult Lwt.t
end
module S : sig
val chain_id:
([ `GET ], prefix,
prefix, unit, unit,
Chain_id.t) RPC_service.t
module Mempool : sig
val pending_operations:
([ `GET ], prefix,
prefix , unit, unit,
error Preapply_result.t * Operation.t Operation_hash.Map.t) RPC_service.t
end
module Blocks : sig
val path: (prefix, prefix) RPC_path.t
val list:
([ `GET ], prefix,
prefix, < heads : Block_hash.t list;
length : int option;
min_date : Time.t option >, unit,
Block_hash.t list list) RPC_service.t
end
module Invalid_blocks : sig
val list:
([ `GET ], prefix,
prefix, unit, unit,
invalid_block list) RPC_service.t
val get:
([ `GET ], prefix,
prefix * Block_hash.t, unit, unit,
invalid_block) RPC_service.t
val delete:
([ `DELETE ], prefix,
prefix * Block_hash.t, unit, unit,
unit) RPC_service.t
end
end

View File

@ -4,7 +4,7 @@
((name tezos_shell_services) ((name tezos_shell_services)
(public_name tezos-shell-services) (public_name tezos-shell-services)
(libraries (tezos-base)) (libraries (tezos-base))
(flags (:standard -w -9+27-30-32-40@8 (flags (:standard -w +27@8
-safe-string -safe-string
-open Tezos_base__TzPervasives)))) -open Tezos_base__TzPervasives))))

View File

@ -1,48 +0,0 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
open Data_encoding
module S = struct
let pending_operations =
let operation_encoding =
merge_objs
(obj1 (req "hash" Operation_hash.encoding))
Operation.encoding in
(* TODO: branch_delayed/... *)
RPC_service.post_service
~description:
"List the not-yet-prevalidated operations."
~query: RPC_query.empty
~input: empty
~output:
(conv
(fun (preapplied, unprocessed) ->
({ preapplied with
Preapply_result.refused = Operation_hash.Map.empty },
Operation_hash.Map.bindings unprocessed))
(fun (preapplied, unprocessed) ->
(preapplied,
List.fold_right
(fun (h, op) m -> Operation_hash.Map.add h op m)
unprocessed Operation_hash.Map.empty))
(merge_objs
(dynamic_size
(Preapply_result.encoding RPC_error.encoding))
(obj1 (req "unprocessed" (list (dynamic_size operation_encoding))))))
RPC_path.(root / "mempool" / "pending_operations")
end
open RPC_context
let pending_operations ctxt = make_call S.pending_operations ctxt () () ()

View File

@ -124,19 +124,51 @@ module S = struct
(req "timestamp" Time.encoding)) (req "timestamp" Time.encoding))
RPC_path.(root / "bootstrapped") RPC_path.(root / "bootstrapped")
let complete = module Monitor = struct
let prefix_arg =
let destruct s = Ok s let path = RPC_path.(root / "monitor")
and construct s = s in
RPC_arg.make ~name:"prefix" ~destruct ~construct () in let valid_blocks_query =
RPC_service.post_service let open RPC_query in
~description: "Try to complete a prefix of a Base58Check-encoded data. \ query (fun protocols next_protocols chains -> object
This RPC is actually able to complete hashes of \ method protocols = protocols
block and hashes of operations." method next_protocols = next_protocols
~query: RPC_query.empty method chains = chains
~input: empty end)
~output: (list string) |+ multi_field "protocol"
RPC_path.(root / "complete" /: prefix_arg ) Protocol_hash.rpc_arg (fun t -> t#protocols)
|+ multi_field "next_protocol"
Protocol_hash.rpc_arg (fun t -> t#next_protocols)
|+ multi_field "chain"
Chain_services.chain_arg (fun t -> t#chains)
|> seal
let valid_blocks =
RPC_service.get_service
~description:""
~query: valid_blocks_query
~output: (obj2
(req "chain_id" Chain_id.encoding)
(req "hash" Block_hash.encoding))
RPC_path.(path / "valid_blocks")
let heads_query =
let open RPC_query in
query (fun next_protocols -> object
method next_protocols = next_protocols
end)
|+ multi_field "next_protocol"
Protocol_hash.rpc_arg (fun t -> t#next_protocols)
|> seal
let heads =
RPC_service.get_service
~description:""
~query: heads_query
~output: Block_hash.encoding
RPC_path.(path / "heads" /: Chain_services.chain_arg)
end
end end
@ -162,9 +194,21 @@ let inject_protocol ctxt ?(async = false) ?force protocol =
let bootstrapped ctxt = let bootstrapped ctxt =
make_streamed_call S.bootstrapped ctxt () () () make_streamed_call S.bootstrapped ctxt () () ()
let complete ctxt ?block prefix = module Monitor = struct
match block with
| None -> module S = S.Monitor
make_call1 S.complete ctxt prefix () ()
| Some block -> let valid_blocks
Block_services.complete ctxt block prefix ctxt ?(chains = [`Main]) ?(protocols = []) ?(next_protocols = []) () =
make_streamed_call S.valid_blocks ctxt () (object
method chains = chains
method protocols = protocols
method next_protocols = next_protocols
end) ()
let heads ctxt ?(next_protocols = []) chain =
make_streamed_call S.heads ctxt ((), chain) (object
method next_protocols = next_protocols
end) ()
end

View File

@ -41,9 +41,22 @@ val inject_protocol:
val bootstrapped: val bootstrapped:
#streamed -> ((Block_hash.t * Time.t) Lwt_stream.t * stopper) tzresult Lwt.t #streamed -> ((Block_hash.t * Time.t) Lwt_stream.t * stopper) tzresult Lwt.t
val complete: module Monitor : sig
#simple ->
?block:Block_services.block -> string -> string list tzresult Lwt.t val valid_blocks:
#streamed ->
?chains:Chain_services.chain list ->
?protocols:Protocol_hash.t list ->
?next_protocols:Protocol_hash.t list ->
unit -> ((Chain_id.t * Block_hash.t) Lwt_stream.t * stopper) tzresult Lwt.t
val heads:
#streamed ->
?next_protocols:Protocol_hash.t list ->
Chain_services.chain ->
(Block_hash.t Lwt_stream.t * stopper) tzresult Lwt.t
end
module S : sig module S : sig
@ -80,9 +93,21 @@ module S : sig
unit, unit, unit, unit, unit, unit,
Block_hash.t * Time.t) RPC_service.t Block_hash.t * Time.t) RPC_service.t
val complete: module Monitor : sig
([ `POST ], unit,
unit * string, unit, unit, val valid_blocks:
string list) RPC_service.t ([ `GET ], unit,
unit, < chains : Chain_services.chain list;
next_protocols : Protocol_hash.t list;
protocols : Protocol_hash.t list >, unit,
Chain_id.t * Block_hash.t) RPC_service.t
val heads:
([ `GET ], unit,
unit * Chain_services.chain,
< next_protocols : Protocol_hash.t list >, unit,
Block_hash.t) RPC_service.t
end
end end

View File

@ -13,12 +13,6 @@ module Prevalidators = struct
module S = struct module S = struct
let (chain_id_arg : Chain_id.t RPC_arg.t) =
RPC_arg.like
Chain_id.rpc_arg
~descr:"The chain identifier of whom the prevalidator is responsible."
"chain_id"
let list = let list =
RPC_service.post_service RPC_service.post_service
~description:"Lists the Prevalidator workers and their status." ~description:"Lists the Prevalidator workers and their status."

View File

@ -17,68 +17,48 @@ type block_info = {
fitness: MBytes.t list ; fitness: MBytes.t list ;
timestamp: Time.t ; timestamp: Time.t ;
protocol: Protocol_hash.t ; protocol: Protocol_hash.t ;
next_protocol: Protocol_hash.t ;
level: Level.t ; level: Level.t ;
} }
let convert_block_info cctxt let info cctxt ?(chain = `Main) block =
( { hash ; chain_id ; predecessor ; fitness ; timestamp ; protocol } Chain_services.chain_id cctxt ~chain () >>=? fun chain_id ->
: Block_services.block_info ) = Block_services.hash cctxt ~chain ~block () >>=? fun hash ->
Alpha_services.Context.level cctxt (`Hash (hash, 0)) >>= function Block_services.Header.shell_header cctxt ~chain ~block () >>=? fun header ->
| Ok level -> Block_services.Metadata.next_protocol_hash
Lwt.return cctxt ~chain ~block () >>=? fun next_protocol ->
(Some { hash ; chain_id ; predecessor ; Block_services.Metadata.protocol_hash
fitness ; timestamp ; protocol ; level }) cctxt ~chain ~block () >>=? fun protocol ->
| Error _ -> Alpha_services.Context.level cctxt (chain, block) >>=? fun level ->
(* TODO log error *) let { Tezos_base.Block_header.predecessor ; fitness ; timestamp ; _ } = header in
Lwt.return_none return { hash ; chain_id ; predecessor ; fitness ;
timestamp ; protocol ; next_protocol ; level }
let convert_block_info_err cctxt let monitor_valid_blocks cctxt ?chains ?protocols ?next_protocols () =
( { hash ; chain_id ; predecessor ; fitness ; timestamp ; protocol } Shell_services.Monitor.valid_blocks cctxt
: Block_services.block_info ) = ?chains ?protocols ?next_protocols () >>=? fun (block_stream, _stop) ->
Alpha_services.Context.level cctxt (`Hash (hash, 0)) >>=? fun level -> return (Lwt_stream.map_s
return { hash ; chain_id ; predecessor ; fitness ; timestamp ; protocol ; level } (fun (chain, block) ->
info cctxt ~chain:(`Hash chain) (`Hash (block, 0))) block_stream)
let info cctxt ?include_ops block = let monitor_heads cctxt ?next_protocols chain =
Block_services.info cctxt ?include_ops block >>=? fun block -> Shell_services.Monitor.heads
convert_block_info_err cctxt block cctxt ?next_protocols chain >>=? fun (block_stream, _stop) ->
return (Lwt_stream.map_s
(fun block -> info cctxt ~chain (`Hash (block, 0)))
block_stream)
let compare (bi1 : block_info) (bi2 : block_info) = let blocks_from_cycle cctxt ?(chain = `Main) block cycle =
match Fitness.compare bi1.fitness bi2.fitness with Block_services.hash cctxt ~chain ~block () >>=? fun hash ->
| 0 -> begin Alpha_services.Context.level cctxt (chain, block) >>=? fun level ->
match compare bi1.level bi2.level with Alpha_services.Helpers.levels cctxt (chain, block) cycle >>=? fun (first, last) ->
| 0 -> begin
match Time.compare bi1.timestamp bi2.timestamp with
| 0 -> Block_hash.compare bi1.predecessor bi2.predecessor
| x -> - x
end
| x -> - x
end
| x -> x
let sort_blocks cctxt ?(compare = compare) blocks =
Lwt_list.filter_map_p (convert_block_info cctxt) blocks >|= fun blocks ->
List.sort compare blocks
let monitor cctxt
?include_ops ?length ?heads ?delay
?min_date ?min_heads ?compare () =
Block_services.monitor
?include_ops ?length ?heads ?delay ?min_date ?min_heads
cctxt >>=? fun (block_stream, _stop) ->
let convert blocks =
sort_blocks cctxt ?compare (List.flatten blocks) >>= return in
return (Lwt_stream.map_s convert block_stream)
let blocks_from_cycle cctxt block cycle =
Alpha_services.Context.level cctxt block >>=? fun level ->
Alpha_services.Helpers.levels cctxt block cycle >>=? fun (first, last) ->
let length = Int32.to_int (Raw_level.diff level.level first) in let length = Int32.to_int (Raw_level.diff level.level first) in
Block_services.predecessors cctxt block length >>=? fun blocks -> Chain_services.Blocks.list cctxt ~heads:[hash] ~length () >>=? fun blocks ->
let blocks = let blocks =
List.remove List.remove
(length - (1 + Int32.to_int (Raw_level.diff last first))) blocks in (length - (Int32.to_int (Raw_level.diff last first)))
(List.hd blocks) in
if Raw_level.(level.level = last) then if Raw_level.(level.level = last) then
Block_services.hash cctxt block >>=? fun last -> return (hash :: blocks)
return (last :: blocks)
else else
return blocks return blocks

View File

@ -17,25 +17,32 @@ type block_info = {
fitness: MBytes.t list ; fitness: MBytes.t list ;
timestamp: Time.t ; timestamp: Time.t ;
protocol: Protocol_hash.t ; protocol: Protocol_hash.t ;
next_protocol: Protocol_hash.t ;
level: Level.t ; level: Level.t ;
} }
val info: val info:
#Proto_alpha.rpc_context -> #Proto_alpha.rpc_context ->
?include_ops:bool -> Block_services.block -> block_info tzresult Lwt.t ?chain:Chain_services.chain ->
Block_services.block ->
block_info tzresult Lwt.t
val compare: val monitor_valid_blocks:
block_info -> block_info -> int
val monitor:
#Proto_alpha.rpc_context -> #Proto_alpha.rpc_context ->
?include_ops:bool -> ?length:int -> ?heads:Block_hash.t list -> ?chains:Chain_services.chain list ->
?delay:int -> ?min_date:Time.t -> ?min_heads:int -> ?protocols:Protocol_hash.t list ->
?compare:(block_info -> block_info -> int) -> ?next_protocols:Protocol_hash.t list ->
unit -> block_info list tzresult Lwt_stream.t tzresult Lwt.t unit -> block_info tzresult Lwt_stream.t tzresult Lwt.t
val monitor_heads:
#Proto_alpha.rpc_context ->
?next_protocols:Protocol_hash.t list ->
Chain_services.chain ->
block_info tzresult Lwt_stream.t tzresult Lwt.t
val blocks_from_cycle: val blocks_from_cycle:
#Proto_alpha.rpc_context -> #Proto_alpha.rpc_context ->
?chain:Chain_services.chain ->
Block_services.block -> Block_services.block ->
Cycle.t -> Cycle.t ->
Block_hash.t list tzresult Lwt.t Block_hash.t list tzresult Lwt.t

View File

@ -7,7 +7,7 @@
(* *) (* *)
(**************************************************************************) (**************************************************************************)
let run (cctxt : #Proto_alpha.full) ?max_priority ~delay ?min_date delegates ~endorsement ~denunciation ~baking = let run (cctxt : #Proto_alpha.full) ?max_priority ~delay delegates ~endorsement ~denunciation ~baking =
begin begin
match delegates with match delegates with
| [] -> | [] ->
@ -23,8 +23,7 @@ let run (cctxt : #Proto_alpha.full) ?max_priority ~delay ?min_date delegates ~en
(* TODO really detach... *) (* TODO really detach... *)
let endorsement = let endorsement =
if endorsement then if endorsement then
Client_baking_blocks.monitor Client_baking_blocks.monitor_heads cctxt `Main >>=? fun block_stream ->
cctxt ?min_date ~min_heads:1 () >>=? fun block_stream ->
Client_baking_endorsement.create cctxt ~delay delegates block_stream >>= fun () -> Client_baking_endorsement.create cctxt ~delay delegates block_stream >>= fun () ->
return () return ()
else else
@ -41,12 +40,10 @@ let run (cctxt : #Proto_alpha.full) ?max_priority ~delay ?min_date delegates ~en
in in
let forge = let forge =
if baking then begin if baking then begin
Client_baking_blocks.monitor Client_baking_blocks.monitor_heads
cctxt ?min_date ~min_heads:1 () >>=? fun block_stream -> cctxt `Main >>=? fun block_stream ->
Client_baking_operations.monitor_endorsement
cctxt >>=? fun endorsement_stream ->
Client_baking_forge.create cctxt Client_baking_forge.create cctxt
?max_priority delegates block_stream endorsement_stream >>=? fun () -> ?max_priority delegates block_stream >>=? fun () ->
return () return ()
end else end else
return () return ()

View File

@ -14,7 +14,6 @@ val run:
#Proto_alpha.full -> #Proto_alpha.full ->
?max_priority: int -> ?max_priority: int ->
delay: int -> delay: int ->
?min_date: Time.t ->
public_key_hash list -> public_key_hash list ->
endorsement:bool -> endorsement:bool ->
denunciation:bool -> denunciation:bool ->

View File

@ -82,33 +82,35 @@ end = struct
end end
let get_signing_slots cctxt ?max_priority block delegate level = let get_signing_slots cctxt ?max_priority ?(chain = `Main) block delegate level =
Alpha_services.Delegate.Endorser.rights_for_delegate cctxt Alpha_services.Delegate.Endorser.rights_for_delegate cctxt
?max_priority ~first_level:level ~last_level:level ?max_priority ~first_level:level ~last_level:level
block delegate >>=? fun possibilities -> (chain, block) delegate >>=? fun possibilities ->
let slots = let slots =
List.map (fun (_,slot) -> slot) List.map (fun (_,slot) -> slot)
@@ List.filter (fun (l, _) -> l = level) possibilities in @@ List.filter (fun (l, _) -> l = level) possibilities in
return slots return slots
let inject_endorsement (cctxt : #Proto_alpha.full) let inject_endorsement
block level ?async (cctxt : #Proto_alpha.full)
?(chain = `Main) block level ?async
src_sk slots = src_sk slots =
Block_services.info cctxt block >>=? fun bi -> Chain_services.chain_id cctxt ~chain () >>=? fun chain_id ->
Block_services.hash cctxt ~chain ~block () >>=? fun hash ->
Alpha_services.Forge.Consensus.endorsement cctxt Alpha_services.Forge.Consensus.endorsement cctxt
block (chain, block)
~branch:bi.hash ~branch:hash
~block:bi.hash ~block:hash
~level:level ~level:level
~slots ~slots
() >>=? fun bytes -> () >>=? fun bytes ->
Client_keys.append Client_keys.append
src_sk ~watermark:Endorsement bytes >>=? fun signed_bytes -> src_sk ~watermark:Endorsement bytes >>=? fun signed_bytes ->
Shell_services.inject_operation Shell_services.inject_operation
cctxt ?async ~chain_id:bi.chain_id signed_bytes >>=? fun oph -> cctxt ?async ~chain_id signed_bytes >>=? fun oph ->
iter_s iter_s
(fun slot -> (fun slot ->
State.record_endorsement cctxt level bi.hash slot oph) State.record_endorsement cctxt level hash slot oph)
slots >>=? fun () -> slots >>=? fun () ->
return oph return oph
@ -127,22 +129,22 @@ let check_endorsement cctxt level slot =
let forge_endorsement (cctxt : #Proto_alpha.full) let forge_endorsement (cctxt : #Proto_alpha.full)
block ?(chain = `Main) block
~src_sk ?slots ?max_priority src_pk = ~src_sk ?slots ?max_priority src_pk =
let src_pkh = Signature.Public_key.hash src_pk in let src_pkh = Signature.Public_key.hash src_pk in
Alpha_services.Context.level cctxt block >>=? fun { level } -> Alpha_services.Context.level cctxt (chain, block) >>=? fun { level } ->
begin begin
match slots with match slots with
| Some slots -> return slots | Some slots -> return slots
| None -> | None ->
get_signing_slots get_signing_slots
cctxt ?max_priority block src_pkh level >>=? function cctxt ?max_priority ~chain block src_pkh level >>=? function
| [] -> cctxt#error "No slot found at level %a" Raw_level.pp level | [] -> cctxt#error "No slot found at level %a" Raw_level.pp level
| slots -> return slots | slots -> return slots
end >>=? fun slots -> end >>=? fun slots ->
iter_s (check_endorsement cctxt level) slots >>=? fun () -> iter_s (check_endorsement cctxt level) slots >>=? fun () ->
inject_endorsement cctxt inject_endorsement cctxt
block level ~chain block level
src_sk slots src_sk slots
@ -188,7 +190,7 @@ let drop_old_endorsement ~before state =
(fun { block } -> Fitness.compare before block.fitness <= 0) (fun { block } -> Fitness.compare before block.fitness <= 0)
state.to_endorse state.to_endorse
let schedule_endorsements (cctxt : #Proto_alpha.full) state bis = let schedule_endorsements (cctxt : #Proto_alpha.full) state bi =
let may_endorse (block: Client_baking_blocks.block_info) delegate time = let may_endorse (block: Client_baking_blocks.block_info) delegate time =
Client_keys.Public_key_hash.name cctxt delegate >>=? fun name -> Client_keys.Public_key_hash.name cctxt delegate >>=? fun name ->
lwt_log_info "May endorse block %a for %s" lwt_log_info "May endorse block %a for %s"
@ -253,9 +255,7 @@ let schedule_endorsements (cctxt : #Proto_alpha.full) state bis =
get_delegates cctxt state >>=? fun delegates -> get_delegates cctxt state >>=? fun delegates ->
iter_p iter_p
(fun delegate -> (fun delegate ->
iter_p may_endorse bi delegate time)
(fun bi -> may_endorse bi delegate time)
bis)
delegates delegates
let schedule_endorsements (cctxt : #Proto_alpha.full) state bis = let schedule_endorsements (cctxt : #Proto_alpha.full) state bis =
@ -316,9 +316,9 @@ let compute_timeout state =
let create (cctxt : #Proto_alpha.full) ~delay contracts block_stream = let create (cctxt : #Proto_alpha.full) ~delay contracts block_stream =
lwt_log_info "Starting endorsement daemon" >>= fun () -> lwt_log_info "Starting endorsement daemon" >>= fun () ->
Lwt_stream.get block_stream >>= function Lwt_stream.get block_stream >>= function
| None | Some (Ok []) | Some (Error _) -> | None | Some (Error _) ->
cctxt#error "Can't fetch the current block head." cctxt#error "Can't fetch the current block head."
| Some (Ok (bi :: _ as initial_heads)) -> | Some (Ok head) ->
let last_get_block = ref None in let last_get_block = ref None in
let get_block () = let get_block () =
match !last_get_block with match !last_get_block with
@ -327,17 +327,17 @@ let create (cctxt : #Proto_alpha.full) ~delay contracts block_stream =
last_get_block := Some t ; last_get_block := Some t ;
t t
| Some t -> t in | Some t -> t in
let state = create_state contracts bi (Int64.of_int delay) in let state = create_state contracts head (Int64.of_int delay) in
let rec worker_loop () = let rec worker_loop () =
let timeout = compute_timeout state in let timeout = compute_timeout state in
Lwt.choose [ (timeout >|= fun () -> `Timeout) ; Lwt.choose [ (timeout >|= fun () -> `Timeout) ;
(get_block () >|= fun b -> `Hash b) ] >>= function (get_block () >|= fun b -> `Hash b) ] >>= function
| `Hash (None | Some (Error _)) -> | `Hash (None | Some (Error _)) ->
Lwt.return_unit Lwt.return_unit
| `Hash (Some (Ok bis)) -> | `Hash (Some (Ok bi)) ->
Lwt.cancel timeout ; Lwt.cancel timeout ;
last_get_block := None ; last_get_block := None ;
schedule_endorsements cctxt state bis >>= fun () -> schedule_endorsements cctxt state bi >>= fun () ->
worker_loop () worker_loop ()
| `Timeout -> | `Timeout ->
begin begin
@ -350,5 +350,5 @@ let create (cctxt : #Proto_alpha.full) ~delay contracts block_stream =
Lwt.return_unit Lwt.return_unit
end >>= fun () -> end >>= fun () ->
worker_loop () in worker_loop () in
schedule_endorsements cctxt state initial_heads >>= fun () -> schedule_endorsements cctxt state head >>= fun () ->
worker_loop () worker_loop ()

View File

@ -12,6 +12,7 @@ open Alpha_context
val forge_endorsement: val forge_endorsement:
#Proto_alpha.full -> #Proto_alpha.full ->
?chain:Chain_services.chain ->
Block_services.block -> Block_services.block ->
src_sk:Client_keys.sk_uri -> src_sk:Client_keys.sk_uri ->
?slots:int list -> ?slots:int list ->
@ -23,4 +24,4 @@ val create :
#Proto_alpha.full -> #Proto_alpha.full ->
delay:int -> delay:int ->
public_key_hash list -> public_key_hash list ->
Client_baking_blocks.block_info list tzresult Lwt_stream.t -> unit Lwt.t Client_baking_blocks.block_info tzresult Lwt_stream.t -> unit Lwt.t

View File

@ -22,9 +22,10 @@ let generate_seed_nonce () =
| Ok nonce -> nonce | Ok nonce -> nonce
let forge_block_header let forge_block_header
(cctxt : #Proto_alpha.full) block delegate_sk shell priority seed_nonce_hash = (cctxt : #Proto_alpha.full)
?(chain = `Main) block delegate_sk shell priority seed_nonce_hash =
Alpha_services.Constants.proof_of_work_threshold Alpha_services.Constants.proof_of_work_threshold
cctxt block >>=? fun stamp_threshold -> cctxt (chain, block) >>=? fun stamp_threshold ->
let rec loop () = let rec loop () =
let proof_of_work_nonce = generate_proof_of_work_nonce () in let proof_of_work_nonce = generate_proof_of_work_nonce () in
let contents = let contents =
@ -44,11 +45,11 @@ let empty_proof_of_work_nonce =
(String.make Constants_repr.proof_of_work_nonce_size '\000') (String.make Constants_repr.proof_of_work_nonce_size '\000')
let forge_faked_protocol_data ~priority ~seed_nonce_hash = let forge_faked_protocol_data ~priority ~seed_nonce_hash =
Data_encoding.Binary.to_bytes_exn Alpha_context.Block_header.{
Alpha_context.Block_header.protocol_data_encoding contents = { priority ; seed_nonce_hash ;
{ contents = { priority ; seed_nonce_hash ;
proof_of_work_nonce = empty_proof_of_work_nonce } ; proof_of_work_nonce = empty_proof_of_work_nonce } ;
signature = Signature.zero } signature = Signature.zero
}
let assert_valid_operations_hash shell_header operations = let assert_valid_operations_hash shell_header operations =
let operations_hash = let operations_hash =
@ -64,14 +65,15 @@ let assert_valid_operations_hash shell_header operations =
inconsistent header.") inconsistent header.")
let inject_block cctxt let inject_block cctxt
?force ?chain_id ?force ?(chain = `Main)
~shell_header ~priority ?seed_nonce_hash ~src_sk operations = ~shell_header ~priority ?seed_nonce_hash ~src_sk operations =
assert_valid_operations_hash shell_header operations >>=? fun () -> assert_valid_operations_hash shell_header operations >>=? fun () ->
let block = `Hash (shell_header.Tezos_base.Block_header.predecessor, 0) in let block = `Hash (shell_header.Tezos_base.Block_header.predecessor, 0) in
forge_block_header cctxt block forge_block_header cctxt ~chain block
src_sk shell_header priority seed_nonce_hash >>=? fun signed_header -> src_sk shell_header priority seed_nonce_hash >>=? fun signed_header ->
Chain_services.chain_id cctxt ~chain () >>=? fun chain_id ->
Shell_services.inject_block cctxt Shell_services.inject_block cctxt
?force ?chain_id signed_header operations >>=? fun block_hash -> ?force ~chain_id signed_header operations >>=? fun block_hash ->
return block_hash return block_hash
type error += type error +=
@ -97,21 +99,33 @@ let () =
| _ -> None) | _ -> None)
(fun (hash, err) -> Failed_to_preapply (hash, err)) (fun (hash, err) -> Failed_to_preapply (hash, err))
let classify_operations (ops: Operation.raw list) = let classify_operations (ops: Operation.t list) =
let t = Array.make (List.length Proto_alpha.Main.validation_passes) [] in let t = Array.make (List.length Proto_alpha.Main.validation_passes) [] in
List.iter List.iter
(fun (op: Operation.raw) -> (fun (op: Operation.t) ->
match Data_encoding.Binary.of_bytes Operation.protocol_data_encoding op.proto with
| Some o ->
List.iter List.iter
(fun pass -> t.(pass) <- op :: t.(pass)) (fun pass -> t.(pass) <- op :: t.(pass))
(Proto_alpha.Main.acceptable_passes (Proto_alpha.Main.acceptable_passes op))
{ shell = op.shell ; protocol_data = o })
| None -> ())
ops ; ops ;
Array.fold_right (fun ops acc -> List.rev ops :: acc) t [] Array.fold_right (fun ops acc -> List.rev ops :: acc) t []
let forge_block cctxt block let parse (op : Operation.raw) : Operation.t = {
shell = op.shell ;
protocol_data =
Data_encoding.Binary.of_bytes_exn
Alpha_context.Operation.protocol_data_encoding
op.proto
}
let forge (op : Operation.t) : Operation.raw = {
shell = op.shell ;
proto =
Data_encoding.Binary.to_bytes_exn
Alpha_context.Operation.protocol_data_encoding
op.protocol_data
}
let forge_block cctxt ?(chain = `Main) block
?force ?force
?operations ?(best_effort = operations = None) ?(sort = best_effort) ?operations ?(best_effort = operations = None) ?(sort = best_effort)
?timestamp ?timestamp
@ -120,9 +134,10 @@ let forge_block cctxt block
begin begin
match operations with match operations with
| None -> | None ->
Mempool_services.pending_operations Chain_services.Mempool.pending_operations
cctxt >>=? fun (ops, pendings) -> cctxt ~chain () >>=? fun (ops, pendings) ->
let ops = let ops =
List.map parse @@
List.map snd @@ List.map snd @@
Operation_hash.Map.bindings @@ Operation_hash.Map.bindings @@
Operation_hash.Map.fold Operation_hash.Map.fold
@ -137,20 +152,20 @@ let forge_block cctxt block
match priority with match priority with
| `Set priority -> begin | `Set priority -> begin
Alpha_services.Helpers.minimal_time Alpha_services.Helpers.minimal_time
cctxt block ~priority >>=? fun time -> cctxt (chain, block) ~priority >>=? fun time ->
return (priority, time) return (priority, time)
end end
| `Auto (src_pkh, max_priority, free_baking) -> | `Auto (src_pkh, max_priority, free_baking) ->
Alpha_services.Context.next_level cctxt block >>=? fun { level } -> Alpha_services.Context.next_level cctxt (chain, block) >>=? fun { level } ->
Alpha_services.Delegate.Baker.rights_for_delegate cctxt Alpha_services.Delegate.Baker.rights_for_delegate cctxt
?max_priority ?max_priority
~first_level:level ~first_level:level
~last_level:level ~last_level:level
block src_pkh >>=? fun possibilities -> (chain, block) src_pkh >>=? fun possibilities ->
try try
begin begin
if free_baking then if free_baking then
Alpha_services.Constants.first_free_baking_slot cctxt block Alpha_services.Constants.first_free_baking_slot cctxt (chain, block)
else else
return 0 return 0
end >>=? fun min_prio -> end >>=? fun min_prio ->
@ -177,10 +192,13 @@ let forge_block cctxt block
let request = List.length operations in let request = List.length operations in
let protocol_data = forge_faked_protocol_data ~priority ~seed_nonce_hash in let protocol_data = forge_faked_protocol_data ~priority ~seed_nonce_hash in
let operations = classify_operations operations in let operations = classify_operations operations in
Block_services.preapply Block_services.Helpers.preapply
cctxt block ~timestamp ~sort ~protocol_data operations >>=? cctxt ~block ~timestamp ~sort ~protocol_data operations >>=?
fun { operations = result ; shell_header } -> fun (shell_header, result) ->
let valid = List.fold_left (fun acc r -> acc + List.length r.Preapply_result.applied) 0 result in let valid =
List.fold_left
(fun acc r -> acc + List.length r.Preapply_result.applied)
0 result in
lwt_log_info "Found %d valid operations (%d refused) for timestamp %a" lwt_log_info "Found %d valid operations (%d refused) for timestamp %a"
valid (request - valid) valid (request - valid)
Time.pp_hum timestamp >>= fun () -> Time.pp_hum timestamp >>= fun () ->
@ -194,11 +212,12 @@ let forge_block cctxt block
result result
then then
let operations = let operations =
if not best_effort then operations if not best_effort then
else List.map (fun l -> List.map snd l.Preapply_result.applied) result in List.map (List.map forge) operations
Block_services.info cctxt block >>=? fun {chain_id} -> else
List.map (fun l -> List.map snd l.Preapply_result.applied) result in
inject_block cctxt inject_block cctxt
?force ~chain_id ~shell_header ~priority ?seed_nonce_hash ~src_sk ?force ~chain ~shell_header ~priority ?seed_nonce_hash ~src_sk
operations operations
else else
let result = let result =
@ -226,6 +245,7 @@ let forge_block cctxt block
Lwt.return_error @@ Lwt.return_error @@
List.filter_map List.filter_map
(fun op -> (fun op ->
let op = forge op in
let h = Tezos_base.Operation.hash op in let h = Tezos_base.Operation.hash op in
try Some (Failed_to_preapply try Some (Failed_to_preapply
(op, snd @@ Operation_hash.Map.find h result.refused)) (op, snd @@ Operation_hash.Map.find h result.refused))
@ -302,6 +322,7 @@ end
let get_baking_slot cctxt let get_baking_slot cctxt
?max_priority (bi: Client_baking_blocks.block_info) delegates = ?max_priority (bi: Client_baking_blocks.block_info) delegates =
let chain = `Hash bi.chain_id in
let block = `Hash (bi.hash, 0) in let block = `Hash (bi.hash, 0) in
let level = Raw_level.succ bi.level.level in let level = Raw_level.succ bi.level.level in
Lwt_list.filter_map_p Lwt_list.filter_map_p
@ -310,7 +331,7 @@ let get_baking_slot cctxt
?max_priority ?max_priority
~first_level:level ~first_level:level
~last_level:level ~last_level:level
block delegate >>= function (chain, block) delegate >>= function
| Error errs -> | Error errs ->
log_error "Error while fetching baking possibilities:\n%a" log_error "Error while fetching baking possibilities:\n%a"
pp_print_error errs ; pp_print_error errs ;
@ -370,8 +391,9 @@ let compute_timeout { future_slots } =
else else
Lwt_unix.sleep (Int64.to_float delay) Lwt_unix.sleep (Int64.to_float delay)
let get_unrevealed_nonces (cctxt : #Proto_alpha.full) ?(force = false) block = let get_unrevealed_nonces
Alpha_services.Context.next_level cctxt block >>=? fun level -> (cctxt : #Proto_alpha.full) ?(force = false) ?(chain = `Main) block =
Alpha_services.Context.next_level cctxt (chain, block) >>=? fun level ->
let cur_cycle = level.cycle in let cur_cycle = level.cycle in
match Cycle.pred cur_cycle with match Cycle.pred cur_cycle with
| None -> return [] | None -> return []
@ -383,12 +405,12 @@ let get_unrevealed_nonces (cctxt : #Proto_alpha.full) ?(force = false) block =
| None -> return None | None -> return None
| Some nonce -> | Some nonce ->
Alpha_services.Context.level Alpha_services.Context.level
cctxt (`Hash (hash, 0)) >>=? fun level -> cctxt (chain, `Hash (hash, 0)) >>=? fun level ->
if force then if force then
return (Some (hash, (level.level, nonce))) return (Some (hash, (level.level, nonce)))
else else
Alpha_services.Nonce.get Alpha_services.Nonce.get
cctxt block level.level >>=? function cctxt (chain, block) level.level >>=? function
| Missing nonce_hash | Missing nonce_hash
when Nonce.check_hash nonce nonce_hash -> when Nonce.check_hash nonce nonce_hash ->
cctxt#warning "Found nonce for %a (level: %a)@." cctxt#warning "Found nonce for %a (level: %a)@."
@ -455,8 +477,8 @@ let pop_baking_slots state =
state.future_slots <- future_slots ; state.future_slots <- future_slots ;
slots slots
let insert_blocks cctxt ?max_priority state bis = let insert_blocks cctxt ?max_priority state bi =
iter_s (insert_block cctxt ?max_priority state) bis >>= function insert_block cctxt ?max_priority state bi >>= function
| Ok () -> | Ok () ->
Lwt.return_unit Lwt.return_unit
| Error err -> | Error err ->
@ -468,8 +490,9 @@ let bake (cctxt : #Proto_alpha.full) state =
let seed_nonce_hash = Nonce.hash seed_nonce in let seed_nonce_hash = Nonce.hash seed_nonce in
filter_map_s filter_map_s
(fun (timestamp, (bi, priority, delegate)) -> (fun (timestamp, (bi, priority, delegate)) ->
let block = `Hash (bi.Client_baking_blocks.hash, 0) in let chain = `Hash bi.Client_baking_blocks.chain_id in
Alpha_services.Context.next_level cctxt block >>=? fun next_level -> let block = `Hash (bi.hash, 0) in
Alpha_services.Context.next_level cctxt (chain, block) >>=? fun next_level ->
let timestamp = let timestamp =
if Block_hash.equal bi.Client_baking_blocks.hash state.genesis then if Block_hash.equal bi.Client_baking_blocks.hash state.genesis then
Time.now () Time.now ()
@ -479,9 +502,10 @@ let bake (cctxt : #Proto_alpha.full) state =
lwt_debug "Try baking after %a (slot %d) for %s (%a)" lwt_debug "Try baking after %a (slot %d) for %s (%a)"
Block_hash.pp_short bi.hash Block_hash.pp_short bi.hash
priority name Time.pp_hum timestamp >>= fun () -> priority name Time.pp_hum timestamp >>= fun () ->
Mempool_services.pending_operations cctxt Chain_services.Mempool.pending_operations
>>=? fun (res, ops) -> cctxt ~chain () >>=? fun (res, ops) ->
let operations = let operations =
List.map parse @@
List.map snd @@ List.map snd @@
Operation_hash.Map.bindings @@ Operation_hash.Map.bindings @@
Operation_hash.Map.(fold add) Operation_hash.Map.(fold add)
@ -495,14 +519,14 @@ let bake (cctxt : #Proto_alpha.full) state =
let protocol_data = let protocol_data =
forge_faked_protocol_data ~priority ~seed_nonce_hash in forge_faked_protocol_data ~priority ~seed_nonce_hash in
let operations = classify_operations operations in let operations = classify_operations operations in
Block_services.preapply cctxt block Block_services.Helpers.preapply cctxt ~chain ~block
~timestamp ~sort:true ~protocol_data operations >>= function ~timestamp ~sort:true ~protocol_data operations >>= function
| Error errs -> | Error errs ->
lwt_log_error "Error while prevalidating operations:@\n%a" lwt_log_error "Error while prevalidating operations:@\n%a"
pp_print_error pp_print_error
errs >>= fun () -> errs >>= fun () ->
return None return None
| Ok { operations ; shell_header } -> | Ok (shell_header, operations) ->
lwt_debug lwt_debug
"Computed candidate block after %a (slot %d): %a/%d fitness: %a" "Computed candidate block after %a (slot %d): %a/%d fitness: %a"
Block_hash.pp_short bi.hash priority Block_hash.pp_short bi.hash priority
@ -538,8 +562,9 @@ let bake (cctxt : #Proto_alpha.full) state =
Block_hash.pp_short bi.hash priority Block_hash.pp_short bi.hash priority
Fitness.pp shell_header.fitness >>= fun () -> Fitness.pp shell_header.fitness >>= fun () ->
Client_keys.get_key cctxt delegate >>=? fun (_,_,src_sk) -> Client_keys.get_key cctxt delegate >>=? fun (_,_,src_sk) ->
let chain = `Hash bi.Client_baking_blocks.chain_id in
inject_block cctxt inject_block cctxt
~force:true ~chain_id:bi.chain_id ~force:true ~chain
~shell_header ~priority ?seed_nonce_hash ~src_sk ~shell_header ~priority ?seed_nonce_hash ~src_sk
operations operations
|> trace_exn (Failure "Error while injecting block") >>=? fun block_hash -> |> trace_exn (Failure "Error while injecting block") >>=? fun block_hash ->
@ -572,14 +597,12 @@ let bake (cctxt : #Proto_alpha.full) state =
let create let create
(cctxt : #Proto_alpha.full) ?max_priority delegates (cctxt : #Proto_alpha.full) ?max_priority delegates
(block_stream: (block_stream:
Client_baking_blocks.block_info list tzresult Lwt_stream.t) Client_baking_blocks.block_info tzresult Lwt_stream.t) =
(endorsement_stream:
Client_baking_operations.valid_endorsement tzresult Lwt_stream.t) =
Lwt_stream.get block_stream >>= function Lwt_stream.get block_stream >>= function
| None | Some (Ok [] | Error _) -> | None | Some (Error _) ->
cctxt#error "Can't fetch the current block head." cctxt#error "Can't fetch the current block head."
| Some (Ok (bi :: _ as initial_heads)) -> | Some (Ok bi) ->
Block_services.hash cctxt `Genesis >>=? fun genesis_hash -> Block_services.hash cctxt ~block:`Genesis () >>=? fun genesis_hash ->
let last_get_block = ref None in let last_get_block = ref None in
let get_block () = let get_block () =
match !last_get_block with match !last_get_block with
@ -588,45 +611,24 @@ let create
last_get_block := Some t ; last_get_block := Some t ;
t t
| Some t -> t in | Some t -> t in
let last_get_endorsement = ref None in
let get_endorsement () =
match !last_get_endorsement with
| None ->
let t = Lwt_stream.get endorsement_stream in
last_get_endorsement := Some t ;
t
| Some t -> t in
let state = create_state genesis_hash delegates bi in let state = create_state genesis_hash delegates bi in
insert_blocks cctxt ?max_priority state initial_heads >>= fun () -> insert_blocks cctxt ?max_priority state bi >>= fun () ->
let rec worker_loop () = let rec worker_loop () =
let timeout = compute_timeout state in let timeout = compute_timeout state in
Lwt.choose [ (timeout >|= fun () -> `Timeout) ; Lwt.choose [ (timeout >|= fun () -> `Timeout) ;
(get_block () >|= fun b -> `Hash b) ; (get_block () >|= fun b -> `Hash b) ;
(get_endorsement () >|= fun e -> `Endorsement e) ;
] >>= function ] >>= function
| `Hash (None | Some (Error _)) | `Hash (None | Some (Error _)) ->
| `Endorsement (None | Some (Error _)) ->
Lwt.return_unit Lwt.return_unit
| `Hash (Some (Ok bis)) -> begin | `Hash (Some (Ok bi)) -> begin
Lwt.cancel timeout ; Lwt.cancel timeout ;
last_get_block := None ; last_get_block := None ;
lwt_debug lwt_debug
"@[<hov 2>Discoverer blocks:@ %a@]" "Discoverered block: %a"
(Format.pp_print_list Block_hash.pp_short bi.Client_baking_blocks.hash >>= fun () ->
(fun ppf bi -> insert_blocks cctxt ?max_priority state bi >>= fun () ->
Block_hash.pp_short ppf bi.Client_baking_blocks.hash))
bis
>>= fun () ->
insert_blocks cctxt ?max_priority state bis >>= fun () ->
worker_loop () worker_loop ()
end end
| `Endorsement (Some (Ok e)) ->
Lwt.cancel timeout ;
last_get_endorsement := None ;
Client_keys.Public_key_hash.name cctxt
e.Client_baking_operations.source >>= fun _source ->
(* TODO *)
worker_loop ()
| `Timeout -> | `Timeout ->
lwt_debug "Waking up for baking..." >>= fun () -> lwt_debug "Waking up for baking..." >>= fun () ->
begin begin

View File

@ -19,7 +19,7 @@ val generate_seed_nonce: unit -> Nonce.t
val inject_block: val inject_block:
#Proto_alpha.full -> #Proto_alpha.full ->
?force:bool -> ?force:bool ->
?chain_id:Chain_id.t -> ?chain:Chain_services.chain ->
shell_header:Block_header.shell_header -> shell_header:Block_header.shell_header ->
priority:int -> priority:int ->
?seed_nonce_hash:Nonce_hash.t -> ?seed_nonce_hash:Nonce_hash.t ->
@ -37,9 +37,10 @@ type error +=
val forge_block: val forge_block:
#Proto_alpha.full -> #Proto_alpha.full ->
?chain:Chain_services.chain ->
Block_services.block -> Block_services.block ->
?force:bool -> ?force:bool ->
?operations:Operation.raw list -> ?operations:Operation.t list ->
?best_effort:bool -> ?best_effort:bool ->
?sort:bool -> ?sort:bool ->
?timestamp:Time.t -> ?timestamp:Time.t ->
@ -79,12 +80,12 @@ val create:
#Proto_alpha.full -> #Proto_alpha.full ->
?max_priority: int -> ?max_priority: int ->
public_key_hash list -> public_key_hash list ->
Client_baking_blocks.block_info list tzresult Lwt_stream.t -> Client_baking_blocks.block_info tzresult Lwt_stream.t ->
Client_baking_operations.valid_endorsement tzresult Lwt_stream.t ->
unit tzresult Lwt.t unit tzresult Lwt.t
val get_unrevealed_nonces: val get_unrevealed_nonces:
#Proto_alpha.full -> #Proto_alpha.full ->
?force:bool -> ?force:bool ->
?chain:Chain_services.chain ->
Block_services.block -> Block_services.block ->
(Block_hash.t * (Raw_level.t * Nonce.t)) list tzresult Lwt.t (Block_hash.t * (Raw_level.t * Nonce.t)) list tzresult Lwt.t

View File

@ -10,7 +10,8 @@
open Proto_alpha open Proto_alpha
open Alpha_context open Alpha_context
let bake_block (cctxt : #Proto_alpha.full) block let bake_block (cctxt : #Proto_alpha.full)
?(chain = `Main) block
?force ?max_priority ?(free_baking=false) ?(minimal_timestamp=false) ?force ?max_priority ?(free_baking=false) ?(minimal_timestamp=false)
?src_sk delegate = ?src_sk delegate =
begin begin
@ -20,7 +21,7 @@ let bake_block (cctxt : #Proto_alpha.full) block
return src_sk return src_sk
| Some sk -> return sk | Some sk -> return sk
end >>=? fun src_sk -> end >>=? fun src_sk ->
Alpha_services.Context.next_level cctxt block >>=? fun level -> Alpha_services.Context.next_level cctxt (chain, block) >>=? fun level ->
let seed_nonce, seed_nonce_hash = let seed_nonce, seed_nonce_hash =
if level.expected_commitment then if level.expected_commitment then
let seed_nonce = Client_baking_forge.generate_seed_nonce () in let seed_nonce = Client_baking_forge.generate_seed_nonce () in
@ -104,6 +105,5 @@ let run_daemon cctxt ?max_priority ~endorsement_delay delegates ~endorsement ~ba
Client_baking_daemon.run cctxt Client_baking_daemon.run cctxt
?max_priority ?max_priority
~delay:endorsement_delay ~delay:endorsement_delay
~min_date:((Time.add (Time.now ()) (Int64.neg 1800L)))
~endorsement ~baking ~denunciation ~endorsement ~baking ~denunciation
delegates delegates

View File

@ -13,6 +13,7 @@ open Alpha_context
(** Mine a block *) (** Mine a block *)
val bake_block: val bake_block:
#Proto_alpha.full -> #Proto_alpha.full ->
?chain:Chain_services.chain ->
Block_services.block -> Block_services.block ->
?force:bool -> ?force:bool ->
?max_priority: int -> ?max_priority: int ->

View File

@ -10,30 +10,31 @@
open Proto_alpha open Proto_alpha
open Alpha_context open Alpha_context
let inject_seed_nonce_revelation rpc_config block ?async nonces = let inject_seed_nonce_revelation rpc_config ?(chain = `Main) block ?async nonces =
let operations = let operations =
List.map List.map
(fun (level, nonce) -> (fun (level, nonce) ->
Seed_nonce_revelation { level ; nonce }) nonces in Seed_nonce_revelation { level ; nonce }) nonces in
Block_services.info rpc_config block >>=? fun bi -> Chain_services.chain_id rpc_config ~chain () >>=? fun chain_id ->
Block_services.hash rpc_config ~chain ~block () >>=? fun branch ->
Alpha_services.Forge.Anonymous.operations rpc_config Alpha_services.Forge.Anonymous.operations rpc_config
block ~branch:bi.hash operations >>=? fun bytes -> (chain, block) ~branch operations >>=? fun bytes ->
Shell_services.inject_operation Shell_services.inject_operation
rpc_config ?async ~chain_id:bi.chain_id rpc_config ?async ~chain_id bytes >>=? fun oph ->
bytes >>=? fun oph ->
return oph return oph
let forge_seed_nonce_revelation let forge_seed_nonce_revelation
(cctxt: #Proto_alpha.full) (cctxt: #Proto_alpha.full)
?(chain = `Main)
block nonces = block nonces =
Block_services.hash cctxt block >>=? fun hash -> Block_services.hash cctxt ~chain ~block () >>=? fun hash ->
match nonces with match nonces with
| [] -> | [] ->
cctxt#message "No nonce to reveal for block %a" cctxt#message "No nonce to reveal for block %a"
Block_hash.pp_short hash >>= fun () -> Block_hash.pp_short hash >>= fun () ->
return () return ()
| _ -> | _ ->
inject_seed_nonce_revelation cctxt block nonces >>=? fun oph -> inject_seed_nonce_revelation cctxt ~chain block nonces >>=? fun oph ->
cctxt#answer cctxt#answer
"Operation successfully injected %d revelation(s) for %a." "Operation successfully injected %d revelation(s) for %a."
(List.length nonces) (List.length nonces)

View File

@ -12,6 +12,7 @@ open Alpha_context
val inject_seed_nonce_revelation: val inject_seed_nonce_revelation:
#Proto_alpha.rpc_context -> #Proto_alpha.rpc_context ->
?chain: Chain_services.chain ->
Block_services.block -> Block_services.block ->
?async:bool -> ?async:bool ->
(Raw_level.t * Nonce.t) list -> (Raw_level.t * Nonce.t) list ->
@ -19,6 +20,7 @@ val inject_seed_nonce_revelation:
val forge_seed_nonce_revelation: val forge_seed_nonce_revelation:
#Proto_alpha.full -> #Proto_alpha.full ->
?chain: Chain_services.chain ->
Block_services.block -> Block_services.block ->
(Raw_level.t * Nonce.t) list -> (Raw_level.t * Nonce.t) list ->
unit tzresult Lwt.t unit tzresult Lwt.t

View File

@ -150,7 +150,7 @@ let level block =
Alpha_services.Context.level !rpc_ctxt block Alpha_services.Context.level !rpc_ctxt block
let rpc_raw_context block path depth = let rpc_raw_context block path depth =
Block_services.raw_context !rpc_ctxt block path depth Block_services.Context.Raw.read !rpc_ctxt ~block ~depth path
module Account = struct module Account = struct
@ -254,7 +254,8 @@ module Account = struct
Tezos_signer_backends.Unencrypted.make_sk account.sk in Tezos_signer_backends.Unencrypted.make_sk account.sk in
Client_proto_context.transfer Client_proto_context.transfer
(new wrap_full (no_write_context !rpc_config ~block)) (new wrap_full (no_write_context !rpc_config ~block))
block ~chain:`Main
~block
~source:account.contract ~source:account.contract
~src_pk:account.pk ~src_pk:account.pk
~src_sk ~src_sk
@ -278,7 +279,8 @@ module Account = struct
Tezos_signer_backends.Unencrypted.make_sk src.sk in Tezos_signer_backends.Unencrypted.make_sk src.sk in
Client_proto_context.originate_account Client_proto_context.originate_account
(new wrap_full (no_write_context !rpc_config)) (new wrap_full (no_write_context !rpc_config))
block ~chain:`Main
~block
~source:src.contract ~source:src.contract
~src_pk:src.pk ~src_pk:src.pk
~src_sk ~src_sk
@ -299,7 +301,8 @@ module Account = struct
delegate_opt = delegate_opt =
Client_proto_context.set_delegate Client_proto_context.set_delegate
(new wrap_full (no_write_context ~block !rpc_config)) (new wrap_full (no_write_context ~block !rpc_config))
block ~chain:`Main
~block
~fee ~fee
contract contract
~src_pk ~src_pk
@ -309,45 +312,55 @@ module Account = struct
let balance ?(block = `Head 0) (account : t) = let balance ?(block = `Head 0) (account : t) =
Alpha_services.Contract.balance !rpc_ctxt Alpha_services.Contract.balance !rpc_ctxt
block account.contract (`Main, block) account.contract
(* TODO: gather contract related functions in a Contract module? *) (* TODO: gather contract related functions in a Contract module? *)
let delegate ?(block = `Head 0) (contract : Contract.t) = let delegate ?(block = `Head 0) (contract : Contract.t) =
Alpha_services.Contract.delegate_opt !rpc_ctxt block contract Alpha_services.Contract.delegate_opt !rpc_ctxt (`Main, block) contract
end end
let sign ?watermark src_sk shell contents =
let contents = Sourced_operation contents in
let bytes =
Data_encoding.Binary.to_bytes_exn
Operation.unsigned_encoding
(shell, contents) in
let signature = Some (Signature.sign ?watermark src_sk bytes) in
let protocol_data = { contents ; signature } in
return { shell ; protocol_data }
module Protocol = struct module Protocol = struct
open Account open Account
let voting_period_kind ?(block = `Head 0) () = let voting_period_kind ?(block = `Head 0) () =
Alpha_services.Context.voting_period_kind !rpc_ctxt block Alpha_services.Context.voting_period_kind !rpc_ctxt (`Main, block)
let proposals ?(block = `Head 0) ~src:({ pkh; sk } : Account.t) proposals = let proposals ?(block = `Head 0) ~src:({ pkh; sk } : Account.t) proposals =
Block_services.info !rpc_ctxt block >>=? fun block_info -> Block_services.hash !rpc_ctxt ~block () >>=? fun hash ->
Alpha_services.Context.next_level !rpc_ctxt block >>=? fun next_level -> Alpha_services.Context.next_level
Alpha_services.Forge.Amendment.proposals !rpc_ctxt block !rpc_ctxt (`Main, block) >>=? fun next_level ->
~branch:block_info.hash let shell = { Tezos_base.Operation.branch = hash } in
~source:pkh let contents =
~period:next_level.voting_period Amendment_operation
~proposals { source = pkh ;
() >>=? fun bytes -> operation = Proposals { period = next_level.voting_period ;
let signed_bytes = Signature.append ~watermark:Generic_operation sk bytes in proposals } } in
return (Tezos_base.Operation.of_bytes_exn signed_bytes) sign ~watermark:Generic_operation sk shell contents
let ballot ?(block = `Head 0) ~src:({ pkh; sk } : Account.t) ~proposal ballot = let ballot ?(block = `Head 0) ~src:({ pkh; sk } : Account.t) ~proposal ballot =
Block_services.info !rpc_ctxt block >>=? fun block_info -> Block_services.hash !rpc_ctxt ~block () >>=? fun hash ->
Alpha_services.Context.next_level !rpc_ctxt block >>=? fun next_level -> Alpha_services.Context.next_level
Alpha_services.Forge.Amendment.ballot !rpc_ctxt block !rpc_ctxt (`Main, block) >>=? fun next_level ->
~branch:block_info.hash let shell = { Tezos_base.Operation.branch = hash } in
~source:pkh let contents =
~period:next_level.voting_period Amendment_operation
~proposal { source = pkh ;
~ballot operation = Ballot { period = next_level.voting_period ;
() >>=? fun bytes -> proposal ;
let signed_bytes = Signature.append ~watermark:Generic_operation sk bytes in ballot } } in
return (Tezos_base.Operation.of_bytes_exn signed_bytes) sign ~watermark:Generic_operation sk shell contents
end end
@ -415,7 +428,7 @@ module Assert = struct
match op with match op with
| None -> true | None -> true
| Some op -> | Some op ->
let h = hash op and h' = hash op' in let h = Operation.hash op and h' = hash op' in
Operation_hash.equal h h' Operation_hash.equal h h'
end && List.exists (ecoproto_error f) err end && List.exists (ecoproto_error f) err
| _ -> false | _ -> false
@ -473,7 +486,8 @@ module Assert = struct
end end
let check_protocol ?msg ~block h = let check_protocol ?msg ~block h =
Block_services.protocol !rpc_ctxt block >>=? fun block_proto -> Block_services.Metadata.next_protocol_hash
!rpc_ctxt ~block () >>=? fun block_proto ->
return @@ equal return @@ equal
?msg ?msg
~prn:Protocol_hash.to_b58check ~prn:Protocol_hash.to_b58check
@ -481,7 +495,7 @@ module Assert = struct
block_proto h block_proto h
let check_voting_period_kind ?msg ~block kind = let check_voting_period_kind ?msg ~block kind =
Alpha_services.Context.voting_period_kind !rpc_ctxt block Alpha_services.Context.voting_period_kind !rpc_ctxt (`Main, block)
>>=? fun current_kind -> >>=? fun current_kind ->
return @@ equal return @@ equal
?msg ?msg
@ -498,7 +512,7 @@ module Baking = struct
let bake block (contract: Account.t) operations = let bake block (contract: Account.t) operations =
let ctxt = (new wrap_full (no_write_context ~block !rpc_config)) in let ctxt = (new wrap_full (no_write_context ~block !rpc_config)) in
Alpha_services.Context.next_level ctxt block >>=? fun level -> Alpha_services.Context.next_level ctxt (`Main, block) >>=? fun level ->
let seed_nonce_hash = let seed_nonce_hash =
if level.Level.expected_commitment then if level.Level.expected_commitment then
let seed_nonce = let seed_nonce =
@ -531,17 +545,13 @@ module Endorse = struct
block block
src_sk src_sk
slot = slot =
Block_services.info !rpc_ctxt block >>=? fun { hash ; _ } -> Block_services.hash !rpc_ctxt ~block () >>=? fun hash ->
Alpha_services.Context.level !rpc_ctxt (`Hash (hash, 0)) >>=? fun level -> Alpha_services.Context.level !rpc_ctxt (`Main, block) >>=? fun { level } ->
Alpha_services.Forge.Consensus.endorsement !rpc_ctxt let shell = { Tezos_base.Operation.branch = hash } in
block let contents =
~branch:hash Consensus_operation
~block:hash (Endorsements { block = hash ; level ; slots = [ slot ]}) in
~level:level.level sign ~watermark:Endorsement src_sk shell contents
~slots:[slot]
() >>=? fun bytes ->
let signed_bytes = Signature.append ~watermark:Endorsement src_sk bytes in
return (Tezos_base.Operation.of_bytes_exn signed_bytes)
let signing_slots let signing_slots
?(max_priority = 1024) ?(max_priority = 1024)
@ -550,7 +560,7 @@ module Endorse = struct
level = level =
Alpha_services.Delegate.Endorser.rights_for_delegate Alpha_services.Delegate.Endorser.rights_for_delegate
!rpc_ctxt ~max_priority ~first_level:level ~last_level:level !rpc_ctxt ~max_priority ~first_level:level ~last_level:level
block delegate >>=? fun possibilities -> (`Main, block) delegate >>=? fun possibilities ->
let slots = let slots =
List.map (fun (_,slot) -> slot) List.map (fun (_,slot) -> slot)
@@ List.filter (fun (l, _) -> l = level) possibilities in @@ List.filter (fun (l, _) -> l = level) possibilities in
@ -560,7 +570,7 @@ module Endorse = struct
?slot ?slot
(contract : Account.t) (contract : Account.t)
block = block =
Alpha_services.Context.level !rpc_ctxt block >>=? fun { level } -> Alpha_services.Context.level !rpc_ctxt (`Main, block) >>=? fun { level } ->
begin begin
match slot with match slot with
| Some slot -> return slot | Some slot -> return slot
@ -579,7 +589,7 @@ module Endorse = struct
let endorsers_list block = let endorsers_list block =
let get_endorser_list result (account : Account.t) level block = let get_endorser_list result (account : Account.t) level block =
Alpha_services.Delegate.Endorser.rights_for_delegate Alpha_services.Delegate.Endorser.rights_for_delegate
!rpc_ctxt block account.pkh !rpc_ctxt (`Main, block) account.pkh
~max_priority:16 ~max_priority:16
~first_level:level ~first_level:level
~last_level:level >>|? fun slots -> ~last_level:level >>|? fun slots ->
@ -587,7 +597,7 @@ module Endorse = struct
in in
let { Account.b1 ; b2 ; b3 ; b4 ; b5 } = Account.bootstrap_accounts in let { Account.b1 ; b2 ; b3 ; b4 ; b5 } = Account.bootstrap_accounts in
let result = Array.make 16 b1 in let result = Array.make 16 b1 in
Alpha_services.Context.level !rpc_ctxt block >>=? fun level -> Alpha_services.Context.level !rpc_ctxt (`Main, block) >>=? fun level ->
let level = level.level in let level = level.level in
get_endorser_list result b1 level block >>=? fun () -> get_endorser_list result b1 level block >>=? fun () ->
get_endorser_list result b2 level block >>=? fun () -> get_endorser_list result b2 level block >>=? fun () ->
@ -599,7 +609,7 @@ module Endorse = struct
let endorsement_rights let endorsement_rights
?(max_priority = 1024) ?(max_priority = 1024)
(contract : Account.t) block = (contract : Account.t) block =
Alpha_services.Context.level !rpc_ctxt block >>=? fun level -> Alpha_services.Context.level !rpc_ctxt (`Main, block) >>=? fun level ->
let delegate = contract.pkh in let delegate = contract.pkh in
let level = level.level in let level = level.level in
Alpha_services.Delegate.Endorser.rights_for_delegate Alpha_services.Delegate.Endorser.rights_for_delegate
@ -607,17 +617,17 @@ module Endorse = struct
~max_priority ~max_priority
~first_level:level ~first_level:level
~last_level:level ~last_level:level
block delegate (`Main, block) delegate
end end
let display_level block = let display_level block =
Alpha_services.Context.level !rpc_ctxt block >>=? fun lvl -> Alpha_services.Context.level !rpc_ctxt (`Main, block) >>=? fun lvl ->
Format.eprintf "Level: %a@." Level.pp_full lvl ; Format.eprintf "Level: %a@." Level.pp_full lvl ;
return () return ()
let endorsement_security_deposit block = let endorsement_security_deposit block =
Constants_services.endorsement_security_deposit !rpc_ctxt block Constants_services.endorsement_security_deposit !rpc_ctxt (`Main, block)
let () = let () =
Client_keys.register_signer Client_keys.register_signer

View File

@ -19,11 +19,11 @@ val init :
forked Tezos node and the block info of the block from where the forked Tezos node and the block info of the block from where the
tests will begin. *) tests will begin. *)
val level : Block_services.block -> Alpha_context.Level.t tzresult Lwt.t val level : Chain_services.chain * Block_services.block -> Alpha_context.Level.t tzresult Lwt.t
(** Calls the rpc service raw_context using the right rpc context *) (** Calls the rpc service raw_context using the right rpc context *)
val rpc_raw_context : Block_services.block -> string list -> int -> val rpc_raw_context : Block_services.block -> string list -> int ->
Block_services.raw_context_result tzresult Lwt.t Block_services.raw_context tzresult Lwt.t
module Account : sig module Account : sig
@ -103,7 +103,7 @@ module Baking : sig
val bake: val bake:
Block_services.block -> Block_services.block ->
Account.t -> Account.t ->
Operation.raw list -> Operation.t list ->
Block_hash.t tzresult Lwt.t Block_hash.t tzresult Lwt.t
end end
@ -114,7 +114,7 @@ module Endorse : sig
?slot:int -> ?slot:int ->
Account.t -> Account.t ->
Block_services.block -> Block_services.block ->
Operation.raw tzresult Lwt.t Operation.t tzresult Lwt.t
val endorsers_list : val endorsers_list :
Block_services.block -> Block_services.block ->
@ -134,14 +134,14 @@ module Protocol : sig
?block:Block_services.block -> ?block:Block_services.block ->
src:Account.t -> src:Account.t ->
Protocol_hash.t list -> Protocol_hash.t list ->
Operation.raw tzresult Lwt.t Operation.t tzresult Lwt.t
val ballot : val ballot :
?block:Block_services.block -> ?block:Block_services.block ->
src:Account.t -> src:Account.t ->
proposal:Protocol_hash.t -> proposal:Protocol_hash.t ->
Vote.ballot -> Vote.ballot ->
Operation.raw tzresult Lwt.t Operation.t tzresult Lwt.t
end end
@ -166,7 +166,7 @@ module Assert : sig
val failed_to_preapply: val failed_to_preapply:
msg:string -> msg:string ->
?op:Tezos_base.Operation.t -> ?op:Operation.t ->
(Alpha_environment.Error_monad.error -> (Alpha_environment.Error_monad.error ->
bool) -> bool) ->
'a tzresult -> unit 'a tzresult -> unit

View File

@ -14,13 +14,13 @@ module Assert = Helpers.Assert
A similar test is bin_client/test/test_basic.sh A similar test is bin_client/test/test_basic.sh
*) *)
let run blkid = let run blkid =
let open Block_services in
let open Block_services in
let is_equal a = function let is_equal a = function
| Ok b -> a = b | Ok b -> a = b
| _ -> false | _ -> false
in in
let is_not_found : raw_context_result tzresult -> bool = function let is_not_found : raw_context tzresult -> bool = function
| Error [RPC_context.Not_found _] -> true | Error [RPC_context.Not_found _] -> true
| _ -> false | _ -> false
in in
@ -38,15 +38,24 @@ let run blkid =
let tests = [((["version"],1), is_equal version); let tests = [((["version"],1), is_equal version);
(([""],0), is_equal dir_depth0); (([""],0), is_equal dir_depth0);
((["delegates";"ed25519"],2), is_equal dir_depth2); ((["delegates";"ed25519"],2), is_equal dir_depth2);
(([""],-1), is_not_found); (* (([""],-1), is_not_found); *)
((["not-existent"],1), is_not_found); ((["not-existent"],1), is_not_found);
((["not-existent"],0), is_not_found); ((["not-existent"],0), is_not_found);
((["not-existent"],-1), is_not_found); (* ((["not-existent"],-1), is_not_found); *)
] in ] in
let success = ref true in
iter_s (fun ((path,depth),predicate) -> iter_s (fun ((path,depth),predicate) ->
Helpers.rpc_raw_context blkid path depth >>= fun result -> Helpers.rpc_raw_context blkid path depth >>= fun result ->
return (assert (predicate result)) let res = predicate result in
) tests Format.eprintf "/%s (%d) -> %B@." (String.concat "/" path) depth res ;
success := !success && res ;
return ()
) tests >>=? fun () ->
if !success then
return ()
else
failwith "Error!"
let exe = try Sys.argv.(1) with _ -> "tezos-node" let exe = try Sys.argv.(1) with _ -> "tezos-node"
let rpc_port = try int_of_string Sys.argv.(2) with _ -> 18500 let rpc_port = try int_of_string Sys.argv.(2) with _ -> 18500

View File

@ -16,7 +16,7 @@ let demo_protocol =
"ProtoDemoDemoDemoDemoDemoDemoDemoDemoDemoDemoD3c8k9" "ProtoDemoDemoDemoDemoDemoDemoDemoDemoDemoDemoD3c8k9"
let print_level head = let print_level head =
level (`Hash (head, 0)) >>=? fun lvl -> level (`Main, `Hash (head, 0)) >>=? fun lvl ->
return @@ Format.eprintf "voting_period = %a.%ld@." return @@ Format.eprintf "voting_period = %a.%ld@."
Voting_period.pp lvl.voting_period lvl.voting_period_position Voting_period.pp lvl.voting_period lvl.voting_period_position

View File

@ -13,11 +13,11 @@ open Tezos_micheline
open Client_proto_contracts open Client_proto_contracts
open Client_keys open Client_keys
let get_balance (rpc : #Proto_alpha.rpc_context) block contract = let get_balance (rpc : #Proto_alpha.rpc_context) ~chain ~block contract =
Alpha_services.Contract.balance rpc block contract Alpha_services.Contract.balance rpc (chain, block) contract
let get_storage (rpc : #Proto_alpha.rpc_context) block contract = let get_storage (rpc : #Proto_alpha.rpc_context) ~chain ~block contract =
Alpha_services.Contract.storage_opt rpc block contract Alpha_services.Contract.storage_opt rpc (chain, block) contract
let parse_expression arg = let parse_expression arg =
Lwt.return Lwt.return
@ -25,9 +25,10 @@ let parse_expression arg =
(Michelson_v1_parser.parse_expression arg)) (Michelson_v1_parser.parse_expression arg))
let append_reveal let append_reveal
cctxt block cctxt ~chain ~block
~source ~src_pk ops = ~source ~src_pk ops =
Alpha_services.Contract.manager_key cctxt block source >>=? fun (_pkh, pk) -> Alpha_services.Contract.manager_key
cctxt (chain, block) source >>=? fun (_pkh, pk) ->
let is_reveal = function let is_reveal = function
| Reveal _ -> true | Reveal _ -> true
| _ -> false in | _ -> false in
@ -37,7 +38,7 @@ let append_reveal
| _ -> return ops | _ -> return ops
let transfer (cctxt : #Proto_alpha.full) let transfer (cctxt : #Proto_alpha.full)
block ?confirmations ~chain ~block ?confirmations
?branch ~source ~src_pk ~src_sk ~destination ?arg ?branch ~source ~src_pk ~src_sk ~destination ?arg
~amount ~fee ?(gas_limit = Z.minus_one) ?(storage_limit = -1L) () = ~amount ~fee ?(gas_limit = Z.minus_one) ?(storage_limit = -1L) () =
begin match arg with begin match arg with
@ -47,26 +48,28 @@ let transfer (cctxt : #Proto_alpha.full)
| None -> return None | None -> return None
end >>=? fun parameters -> end >>=? fun parameters ->
Alpha_services.Contract.counter Alpha_services.Contract.counter
cctxt block source >>=? fun pcounter -> cctxt (chain, block) source >>=? fun pcounter ->
let counter = Int32.succ pcounter in let counter = Int32.succ pcounter in
let parameters = Option.map ~f:Script.lazy_expr parameters in let parameters = Option.map ~f:Script.lazy_expr parameters in
let operations = [Transaction { amount ; parameters ; destination }] in let operations = [Transaction { amount ; parameters ; destination }] in
append_reveal cctxt block ~source ~src_pk operations >>=? fun operations -> append_reveal cctxt ~chain ~block
~source ~src_pk operations >>=? fun operations ->
let contents = let contents =
Sourced_operation Sourced_operation
(Manager_operations { source ; fee ; counter ; (Manager_operations { source ; fee ; counter ;
gas_limit ; storage_limit ; operations }) in gas_limit ; storage_limit ; operations }) in
Injection.inject_operation cctxt block ?confirmations Injection.inject_operation cctxt ~chain ~block ?confirmations
?branch ~src_sk contents >>=? fun (_oph, _op, result as res) -> ?branch ~src_sk contents >>=? fun (_oph, _op, result as res) ->
Lwt.return (Injection.originated_contracts result) >>=? fun contracts -> Lwt.return (Injection.originated_contracts result) >>=? fun contracts ->
return (res, contracts) return (res, contracts)
let reveal cctxt let reveal cctxt
block ?confirmations ~chain ~block ?confirmations
?branch ~source ~src_pk ~src_sk ~fee () = ?branch ~source ~src_pk ~src_sk ~fee () =
Alpha_services.Contract.counter cctxt block source >>=? fun pcounter -> Alpha_services.Contract.counter
cctxt (chain, block) source >>=? fun pcounter ->
let counter = Int32.succ pcounter in let counter = Int32.succ pcounter in
append_reveal cctxt block ~source ~src_pk [] >>=? fun operations -> append_reveal cctxt ~chain ~block ~source ~src_pk [] >>=? fun operations ->
match operations with match operations with
| [] -> | [] ->
failwith "The manager key was previously revealed." failwith "The manager key was previously revealed."
@ -76,24 +79,25 @@ let reveal cctxt
(Manager_operations { source ; fee ; counter ; (Manager_operations { source ; fee ; counter ;
gas_limit = Z.zero ; storage_limit = 0L ; gas_limit = Z.zero ; storage_limit = 0L ;
operations }) in operations }) in
Injection.inject_operation cctxt block ?confirmations Injection.inject_operation cctxt ~chain ~block ?confirmations
?branch ~src_sk contents >>=? fun res -> ?branch ~src_sk contents >>=? fun res ->
return res return res
let originate let originate
cctxt block ?confirmations cctxt ~chain ~block ?confirmations
?branch ~source ~src_pk ~src_sk ~fee ?branch ~source ~src_pk ~src_sk ~fee
?(gas_limit = Z.minus_one) ?(storage_limit = -1L) origination = ?(gas_limit = Z.minus_one) ?(storage_limit = -1L) origination =
Alpha_services.Contract.counter cctxt block source >>=? fun pcounter -> Alpha_services.Contract.counter
cctxt (chain, block) source >>=? fun pcounter ->
let counter = Int32.succ pcounter in let counter = Int32.succ pcounter in
let operations = [origination] in let operations = [origination] in
append_reveal append_reveal
cctxt block ~source ~src_pk operations >>=? fun operations -> cctxt ~chain ~block ~source ~src_pk operations >>=? fun operations ->
let contents = let contents =
Sourced_operation Sourced_operation
(Manager_operations { source ; fee ; counter ; (Manager_operations { source ; fee ; counter ;
gas_limit ; storage_limit ; operations }) in gas_limit ; storage_limit ; operations }) in
Injection.inject_operation cctxt block ?confirmations Injection.inject_operation cctxt ~chain ~block ?confirmations
?branch ~src_sk contents >>=? fun (_oph, _op, result as res) -> ?branch ~src_sk contents >>=? fun (_oph, _op, result as res) ->
Lwt.return (Injection.originated_contracts result) >>=? function Lwt.return (Injection.originated_contracts result) >>=? function
| [ contract ] -> return (res, contract) | [ contract ] -> return (res, contract)
@ -103,7 +107,7 @@ let originate
(List.length contracts) (List.length contracts)
let originate_account let originate_account
cctxt block ?confirmations cctxt ~chain ~block ?confirmations
?branch ~source ~src_pk ~src_sk ~manager_pkh ?branch ~source ~src_pk ~src_sk ~manager_pkh
?(delegatable = false) ?delegate ~balance ~fee () = ?(delegatable = false) ?delegate ~balance ~fee () =
let origination = let origination =
@ -115,32 +119,32 @@ let originate_account
credit = balance ; credit = balance ;
preorigination = None } in preorigination = None } in
originate originate
cctxt block ?confirmations cctxt ~chain ~block ?confirmations
?branch ~source ~gas_limit:Z.zero~src_pk ~src_sk ~fee origination ?branch ~source ~gas_limit:Z.zero~src_pk ~src_sk ~fee origination
let delegate_contract cctxt let delegate_contract cctxt
block ?branch ?confirmations ~chain ~block ?branch ?confirmations
~source ~src_pk ~src_sk ~source ~src_pk ~src_sk
~fee delegate_opt = ~fee delegate_opt =
Alpha_services.Contract.counter Alpha_services.Contract.counter
cctxt block source >>=? fun pcounter -> cctxt (chain, block) source >>=? fun pcounter ->
let counter = Int32.succ pcounter in let counter = Int32.succ pcounter in
let operations = [Delegation delegate_opt] in let operations = [Delegation delegate_opt] in
append_reveal append_reveal
cctxt block ~source ~src_pk operations >>=? fun operations -> cctxt ~chain ~block ~source ~src_pk operations >>=? fun operations ->
let contents = let contents =
Sourced_operation Sourced_operation
(Manager_operations { source ; fee ; counter ; (Manager_operations { source ; fee ; counter ;
gas_limit = Z.zero ; storage_limit = 0L ; gas_limit = Z.zero ; storage_limit = 0L ;
operations }) in operations }) in
Injection.inject_operation cctxt block ?confirmations Injection.inject_operation cctxt ~chain ~block ?confirmations
?branch ~src_sk contents >>=? fun res -> ?branch ~src_sk contents >>=? fun res ->
return res return res
let list_contract_labels let list_contract_labels
(cctxt : #Proto_alpha.full) (cctxt : #Proto_alpha.full)
block = ~chain ~block =
Alpha_services.Contract.list cctxt block >>=? fun contracts -> Alpha_services.Contract.list cctxt (chain, block) >>=? fun contracts ->
map_s (fun h -> map_s (fun h ->
begin match Contract.is_implicit h with begin match Contract.is_implicit h with
| Some m -> begin | Some m -> begin
@ -169,32 +173,39 @@ let message_added_contract (cctxt : #Proto_alpha.full) name =
let get_manager let get_manager
(cctxt : #Proto_alpha.full) (cctxt : #Proto_alpha.full)
block source = ~chain ~block source =
Client_proto_contracts.get_manager Client_proto_contracts.get_manager
cctxt block source >>=? fun src_pkh -> cctxt ~chain ~block source >>=? fun src_pkh ->
Client_keys.get_key cctxt src_pkh >>=? fun (src_name, src_pk, src_sk) -> Client_keys.get_key cctxt src_pkh >>=? fun (src_name, src_pk, src_sk) ->
return (src_name, src_pkh, src_pk, src_sk) return (src_name, src_pkh, src_pk, src_sk)
let dictate rpc_config block ?confirmations command src_sk = let dictate rpc_config ~chain ~block ?confirmations command src_sk =
let contents = Sourced_operation (Dictator_operation command) in let contents = Sourced_operation (Dictator_operation command) in
Injection.inject_operation Injection.inject_operation
rpc_config block ?confirmations rpc_config ~chain ~block ?confirmations
~src_sk contents >>=? fun res -> ~src_sk contents >>=? fun res ->
return res return res
let set_delegate cctxt block ?confirmations ~fee contract ~src_pk ~manager_sk opt_delegate = let set_delegate
cctxt ~chain ~block ?confirmations
~fee contract ~src_pk ~manager_sk opt_delegate =
delegate_contract delegate_contract
cctxt block ?confirmations ~source:contract ~src_pk ~src_sk:manager_sk ~fee opt_delegate cctxt ~chain ~block ?confirmations
~source:contract ~src_pk ~src_sk:manager_sk ~fee opt_delegate
let register_as_delegate cctxt block ?confirmations ~fee ~manager_sk src_pk = let register_as_delegate
cctxt ~chain ~block ?confirmations
~fee ~manager_sk src_pk =
let source = Signature.Public_key.hash src_pk in let source = Signature.Public_key.hash src_pk in
delegate_contract delegate_contract
cctxt block ?confirmations cctxt ~chain ~block ?confirmations
~source:(Contract.implicit_contract source) ~src_pk ~src_sk:manager_sk ~fee ~source:(Contract.implicit_contract source) ~src_pk ~src_sk:manager_sk ~fee
(Some source) (Some source)
let source_to_keys (wallet : #Proto_alpha.full) block source = let source_to_keys (wallet : #Proto_alpha.full) ~chain ~block source =
get_manager wallet block source >>=? fun (_src_name, _src_pkh, src_pk, src_sk) -> get_manager
wallet ~chain ~block
source >>=? fun (_src_name, _src_pkh, src_pk, src_sk) ->
return (src_pk, src_sk) return (src_pk, src_sk)
let save_contract ~force cctxt alias_name contract = let save_contract ~force cctxt alias_name contract =
@ -204,7 +215,7 @@ let save_contract ~force cctxt alias_name contract =
let originate_contract let originate_contract
(cctxt : #Proto_alpha.full) (cctxt : #Proto_alpha.full)
block ?confirmations ?branch ~chain ~block ?confirmations ?branch
~fee ~fee
?gas_limit ?gas_limit
?storage_limit ?storage_limit
@ -231,7 +242,7 @@ let originate_contract
delegatable ; delegatable ;
credit = balance ; credit = balance ;
preorigination = None } in preorigination = None } in
originate cctxt block ?confirmations originate cctxt ~chain ~block ?confirmations
?branch ~source ~src_pk ~src_sk ~fee ?gas_limit ?storage_limit origination ?branch ~source ~src_pk ~src_sk ~fee ?gas_limit ?storage_limit origination
type activation_key = type activation_key =
@ -295,8 +306,10 @@ let read_key key =
let pkh = Signature.Public_key.hash pk in let pkh = Signature.Public_key.hash pk in
return (pkh, pk, sk) return (pkh, pk, sk)
let claim_commitment (cctxt : #Proto_alpha.full) let claim_commitment
?(encrypted = false) ?confirmations ?force block key name = (cctxt : #Proto_alpha.full)
~chain ~block ?confirmations
?(encrypted = false) ?force key name =
read_key key >>=? fun (pkh, pk, sk) -> read_key key >>=? fun (pkh, pk, sk) ->
fail_unless (Signature.Public_key_hash.equal pkh (Ed25519 key.pkh)) fail_unless (Signature.Public_key_hash.equal pkh (Ed25519 key.pkh))
(failure "@[<v 2>Inconsistent activation key:@ \ (failure "@[<v 2>Inconsistent activation key:@ \
@ -307,7 +320,9 @@ let claim_commitment (cctxt : #Proto_alpha.full)
let contents = let contents =
Anonymous_operations Anonymous_operations
[ Activation { id = key.pkh ; activation_code = key.activation_code } ] in [ Activation { id = key.pkh ; activation_code = key.activation_code } ] in
Injection.inject_operation cctxt ?confirmations block contents >>=? fun (_oph, _op, _result as res) -> Injection.inject_operation
cctxt ?confirmations ~chain ~block
contents >>=? fun (_oph, _op, _result as res) ->
let pk_uri = Tezos_signer_backends.Unencrypted.make_pk pk in let pk_uri = Tezos_signer_backends.Unencrypted.make_pk pk in
begin begin
if encrypted then if encrypted then
@ -322,7 +337,7 @@ let claim_commitment (cctxt : #Proto_alpha.full)
return () return ()
| Some _confirmations -> | Some _confirmations ->
Alpha_services.Contract.balance Alpha_services.Contract.balance
cctxt (`Head 0) cctxt (`Main, `Head 0)
(Contract.implicit_contract pkh) >>=? fun balance -> (Contract.implicit_contract pkh) >>=? fun balance ->
cctxt#message "Account %s (%a) created with %s%a." cctxt#message "Account %s (%a) created with %s%a."
name name

View File

@ -12,31 +12,36 @@ open Alpha_context
val list_contract_labels : val list_contract_labels :
#Proto_alpha.full -> #Proto_alpha.full ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
(string * string * string) list tzresult Lwt.t (string * string * string) list tzresult Lwt.t
val get_storage : val get_storage :
#Proto_alpha.rpc_context -> #Proto_alpha.rpc_context ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
Contract.t -> Contract.t ->
Script.expr option tzresult Lwt.t Script.expr option tzresult Lwt.t
val get_manager : val get_manager :
#Proto_alpha.full -> #Proto_alpha.full ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
Contract.t -> Contract.t ->
(string * public_key_hash * (string * public_key_hash *
public_key * Client_keys.sk_uri) tzresult Lwt.t public_key * Client_keys.sk_uri) tzresult Lwt.t
val get_balance: val get_balance:
#Proto_alpha.rpc_context -> #Proto_alpha.rpc_context ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
Contract.t -> Contract.t ->
Tez.t tzresult Lwt.t Tez.t tzresult Lwt.t
val set_delegate : val set_delegate :
#Proto_alpha.full -> #Proto_alpha.full ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
?confirmations:int -> ?confirmations:int ->
fee:Tez.tez -> fee:Tez.tez ->
Contract.t -> Contract.t ->
@ -47,7 +52,8 @@ val set_delegate :
val register_as_delegate: val register_as_delegate:
#Proto_alpha.full -> #Proto_alpha.full ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
?confirmations:int -> ?confirmations:int ->
fee:Tez.tez -> fee:Tez.tez ->
manager_sk:Client_keys.sk_uri -> manager_sk:Client_keys.sk_uri ->
@ -56,13 +62,15 @@ val register_as_delegate:
val source_to_keys: val source_to_keys:
#Proto_alpha.full -> #Proto_alpha.full ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
Contract.t -> Contract.t ->
(public_key * Client_keys.sk_uri) tzresult Lwt.t (public_key * Client_keys.sk_uri) tzresult Lwt.t
val originate_account : val originate_account :
#Proto_alpha.full -> #Proto_alpha.full ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
?confirmations:int -> ?confirmations:int ->
?branch:int -> ?branch:int ->
source:Contract.t -> source:Contract.t ->
@ -84,7 +92,8 @@ val save_contract :
val originate_contract: val originate_contract:
#Proto_alpha.full -> #Proto_alpha.full ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
?confirmations:int -> ?confirmations:int ->
?branch:int -> ?branch:int ->
fee:Tez.t -> fee:Tez.t ->
@ -104,7 +113,8 @@ val originate_contract:
val transfer : val transfer :
#Proto_alpha.full -> #Proto_alpha.full ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
?confirmations:int -> ?confirmations:int ->
?branch:int -> ?branch:int ->
source:Contract.t -> source:Contract.t ->
@ -121,7 +131,8 @@ val transfer :
val reveal : val reveal :
#Proto_alpha.full -> #Proto_alpha.full ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
?confirmations:int -> ?confirmations:int ->
?branch:int -> ?branch:int ->
source:Contract.t -> source:Contract.t ->
@ -132,7 +143,8 @@ val reveal :
val dictate : val dictate :
#Proto_alpha.full -> #Proto_alpha.full ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
?confirmations:int -> ?confirmations:int ->
dictator_operation -> dictator_operation ->
Client_keys.sk_uri -> Client_keys.sk_uri ->
@ -151,10 +163,11 @@ val activation_key_encoding: activation_key Data_encoding.t
val claim_commitment: val claim_commitment:
#Proto_alpha.full -> #Proto_alpha.full ->
?encrypted:bool -> chain:Chain_services.chain ->
block:Block_services.block ->
?confirmations:int -> ?confirmations:int ->
?encrypted:bool ->
?force:bool -> ?force:bool ->
Block_services.block ->
activation_key -> activation_key ->
string -> string ->
Injection.result tzresult Lwt.t Injection.result tzresult Lwt.t

View File

@ -129,13 +129,13 @@ let list_contracts cctxt =
keys >>=? fun accounts -> keys >>=? fun accounts ->
return (contracts @ accounts) return (contracts @ accounts)
let get_manager cctxt block source = let get_manager cctxt ~chain ~block source =
match Contract.is_implicit source with match Contract.is_implicit source with
| Some hash -> return hash | Some hash -> return hash
| None -> Alpha_services.Contract.manager cctxt block source | None -> Alpha_services.Contract.manager cctxt (chain, block) source
let get_delegate cctxt block source = let get_delegate cctxt ~chain ~block source =
Alpha_services.Contract.delegate_opt cctxt block source Alpha_services.Contract.delegate_opt cctxt (chain, block) source
let may_check_key sourcePubKey sourcePubKeyHash = let may_check_key sourcePubKey sourcePubKeyHash =
match sourcePubKey with match sourcePubKey with

View File

@ -43,13 +43,15 @@ val list_contracts:
val get_manager: val get_manager:
#Proto_alpha.rpc_context -> #Proto_alpha.rpc_context ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
Contract.t -> Contract.t ->
public_key_hash tzresult Lwt.t public_key_hash tzresult Lwt.t
val get_delegate: val get_delegate:
#Proto_alpha.rpc_context -> #Proto_alpha.rpc_context ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
Contract.t -> Contract.t ->
public_key_hash option tzresult Lwt.t public_key_hash option tzresult Lwt.t

View File

@ -86,51 +86,75 @@ let print_trace_result (cctxt : #Client_context.printer) ~show_source ~parsed =
| Error errs -> | Error errs ->
print_errors cctxt errs ~show_source ~parsed print_errors cctxt errs ~show_source ~parsed
let get_contract cctxt block contract = let get_contract cctxt ?(chain = `Main) block contract =
match contract with match contract with
| Some contract -> return contract | Some contract -> return contract
| None -> | None ->
(* TODO use local contract by default *) (* TODO use local contract by default *)
Alpha_services.Contract.list cctxt block >>|? List.hd Alpha_services.Contract.list cctxt (chain, block) >>|? List.hd
let run let run
(cctxt : #Proto_alpha.rpc_context)
?(chain = `Main)
block
?contract ?contract
?(amount = Tez.fifty_cents) ?(amount = Tez.fifty_cents)
~(program : Michelson_v1_parser.parsed) ~(program : Michelson_v1_parser.parsed)
~(storage : Michelson_v1_parser.parsed) ~(storage : Michelson_v1_parser.parsed)
~(input : Michelson_v1_parser.parsed) ~(input : Michelson_v1_parser.parsed)
block () =
(cctxt : #RPC_context.simple) = get_contract cctxt ~chain block contract >>=? fun contract ->
get_contract cctxt block contract >>=? fun contract ->
Alpha_services.Helpers.run_code cctxt Alpha_services.Helpers.run_code cctxt
block program.expanded (storage.expanded, input.expanded, amount, contract) (chain, block)
program.expanded (storage.expanded, input.expanded, amount, contract)
let trace let trace
(cctxt : #Proto_alpha.rpc_context)
?(chain = `Main)
block
?contract ?contract
?(amount = Tez.fifty_cents) ?(amount = Tez.fifty_cents)
~(program : Michelson_v1_parser.parsed) ~(program : Michelson_v1_parser.parsed)
~(storage : Michelson_v1_parser.parsed) ~(storage : Michelson_v1_parser.parsed)
~(input : Michelson_v1_parser.parsed) ~(input : Michelson_v1_parser.parsed)
block () =
(cctxt : #RPC_context.simple) = get_contract cctxt ~chain block contract >>=? fun contract ->
get_contract cctxt block contract >>=? fun contract ->
Alpha_services.Helpers.trace_code cctxt Alpha_services.Helpers.trace_code cctxt
block program.expanded (storage.expanded, input.expanded, amount, contract) (chain, block)
program.expanded (storage.expanded, input.expanded, amount, contract)
let hash_and_sign ?gas (data : Michelson_v1_parser.parsed) (typ : Michelson_v1_parser.parsed) sk block cctxt = let hash_and_sign
Alpha_services.Helpers.hash_data cctxt block (data.expanded, typ.expanded, gas) >>=? fun (hash, gas) -> cctxt
?(chain = `Main)
block
?gas
(data : Michelson_v1_parser.parsed)
(typ : Michelson_v1_parser.parsed)
sk =
Alpha_services.Helpers.hash_data
cctxt (chain, block) (data.expanded, typ.expanded, gas) >>=? fun (hash, gas) ->
Client_keys.sign sk (MBytes.of_string hash) >>=? fun signature -> Client_keys.sign sk (MBytes.of_string hash) >>=? fun signature ->
return (hash, Signature.to_b58check signature, gas) return (hash, Signature.to_b58check signature, gas)
let typecheck_data let typecheck_data
cctxt
?(chain = `Main)
block
?gas ?gas
~(data : Michelson_v1_parser.parsed) ~(data : Michelson_v1_parser.parsed)
~(ty : Michelson_v1_parser.parsed) ~(ty : Michelson_v1_parser.parsed)
block cctxt = () =
Alpha_services.Helpers.typecheck_data cctxt block (data.expanded, ty.expanded, gas) Alpha_services.Helpers.typecheck_data
cctxt (chain, block)
(data.expanded, ty.expanded, gas)
let typecheck_program ?gas (program : Michelson_v1_parser.parsed) block cctxt = let typecheck_program
Alpha_services.Helpers.typecheck_code cctxt block (program.expanded, gas) cctxt
?(chain = `Main)
block
?gas
(program : Michelson_v1_parser.parsed) =
Alpha_services.Helpers.typecheck_code cctxt (chain, block) (program.expanded, gas)
let print_typecheck_result let print_typecheck_result
~emacs ~show_types ~print_source_on_error ~emacs ~show_types ~print_source_on_error

View File

@ -15,25 +15,29 @@ module Program : Client_aliases.Alias
with type t = Michelson_v1_parser.parsed Micheline_parser.parsing_result with type t = Michelson_v1_parser.parsed Micheline_parser.parsing_result
val run : val run :
#Proto_alpha.rpc_context ->
?chain:Chain_services.chain ->
Block_services.block ->
?contract:Contract.t -> ?contract:Contract.t ->
?amount:Tez.t -> ?amount:Tez.t ->
program:Michelson_v1_parser.parsed -> program:Michelson_v1_parser.parsed ->
storage:Michelson_v1_parser.parsed -> storage:Michelson_v1_parser.parsed ->
input:Michelson_v1_parser.parsed -> input:Michelson_v1_parser.parsed ->
Block_services.block -> unit ->
#Proto_alpha.rpc_context ->
(Script.expr * (Script.expr *
internal_operation list * internal_operation list *
Contract.big_map_diff option) tzresult Lwt.t Contract.big_map_diff option) tzresult Lwt.t
val trace : val trace :
#Proto_alpha.rpc_context ->
?chain:Chain_services.chain ->
Block_services.block ->
?contract:Contract.t -> ?contract:Contract.t ->
?amount:Tez.t -> ?amount:Tez.t ->
program:Michelson_v1_parser.parsed -> program:Michelson_v1_parser.parsed ->
storage:Michelson_v1_parser.parsed -> storage:Michelson_v1_parser.parsed ->
input:Michelson_v1_parser.parsed -> input:Michelson_v1_parser.parsed ->
Block_services.block -> unit ->
#Proto_alpha.rpc_context ->
(Script.expr * (Script.expr *
internal_operation list * internal_operation list *
Script_interpreter.execution_trace * Script_interpreter.execution_trace *
@ -58,27 +62,31 @@ val print_trace_result :
tzresult -> unit tzresult Lwt.t tzresult -> unit tzresult Lwt.t
val hash_and_sign : val hash_and_sign :
#Proto_alpha.full ->
?chain:Chain_services.chain ->
Block_services.block ->
?gas:Z.t -> ?gas:Z.t ->
Michelson_v1_parser.parsed -> Michelson_v1_parser.parsed ->
Michelson_v1_parser.parsed -> Michelson_v1_parser.parsed ->
Client_keys.sk_uri -> Client_keys.sk_uri ->
Block_services.block ->
#Proto_alpha.full ->
(string * string * Gas.t) tzresult Lwt.t (string * string * Gas.t) tzresult Lwt.t
val typecheck_data : val typecheck_data :
#Proto_alpha.rpc_context ->
?chain:Chain_services.chain ->
Block_services.block ->
?gas:Z.t -> ?gas:Z.t ->
data:Michelson_v1_parser.parsed -> data:Michelson_v1_parser.parsed ->
ty:Michelson_v1_parser.parsed -> ty:Michelson_v1_parser.parsed ->
'a -> unit ->
'a #Proto_alpha.Alpha_environment.RPC_context.simple ->
Gas.t tzresult Lwt.t Gas.t tzresult Lwt.t
val typecheck_program : val typecheck_program :
#Proto_alpha.rpc_context ->
?chain:Chain_services.chain ->
Block_services.block ->
?gas:Z.t -> ?gas:Z.t ->
Michelson_v1_parser.parsed -> Michelson_v1_parser.parsed ->
Block_services.block ->
#Proto_alpha.rpc_context ->
(Script_tc_errors.type_map * Gas.t) tzresult Lwt.t (Script_tc_errors.type_map * Gas.t) tzresult Lwt.t
val print_typecheck_result : val print_typecheck_result :

View File

@ -11,24 +11,24 @@ open Proto_alpha
open Alpha_context open Alpha_context
open Apply_operation_result open Apply_operation_result
let get_branch rpc_config (block : Block_services.block) branch = let get_branch (rpc_config: #Proto_alpha.full)
~chain ~(block : Block_services.block) branch =
let branch = Option.unopt ~default:0 branch in (* TODO export parameter *) let branch = Option.unopt ~default:0 branch in (* TODO export parameter *)
begin begin
match block with match block with
| `Head n -> return (`Head (n+branch)) | `Head n -> return (`Head (n+branch))
| `Test_head n -> return (`Test_head (n+branch))
| `Hash (h,n) -> return (`Hash (h,n+branch)) | `Hash (h,n) -> return (`Hash (h,n+branch))
| `Genesis -> return `Genesis | `Genesis -> return `Genesis
end >>=? fun block -> end >>=? fun block ->
Block_services.hash rpc_config block >>=? fun hash -> Block_services.hash rpc_config ~chain ~block () >>=? fun hash ->
return hash return hash
type result = Operation_hash.t * operation * operation_result type result = Operation_hash.t * operation * operation_result
let preapply let preapply
cctxt block (cctxt: #Proto_alpha.full) ~chain ~block
?branch ?src_sk contents = ?branch ?src_sk contents =
get_branch cctxt block branch >>=? fun branch -> get_branch cctxt ~chain ~block branch >>=? fun branch ->
let bytes = let bytes =
Data_encoding.Binary.to_bytes_exn Data_encoding.Binary.to_bytes_exn
Operation.unsigned_encoding Operation.unsigned_encoding
@ -51,9 +51,9 @@ let preapply
{ shell = { branch } ; { shell = { branch } ;
protocol_data = { contents ; signature } } in protocol_data = { contents ; signature } } in
let oph = Operation.hash op in let oph = Operation.hash op in
Block_services.hash cctxt block >>=? fun bh -> Block_services.hash cctxt ~chain ~block () >>=? fun bh ->
Alpha_services.Helpers.apply_operation cctxt Alpha_services.Helpers.apply_operation cctxt
block bh oph bytes signature >>=? fun result -> (chain, block) bh oph bytes signature >>=? fun result ->
return (oph, op, result) return (oph, op, result)
let estimated_gas = function let estimated_gas = function
@ -117,17 +117,18 @@ let detect_script_failure = function
| _ -> Ok () | _ -> Ok ()
let may_patch_limits let may_patch_limits
(cctxt : #Proto_alpha.full) block ?branch (cctxt : #Proto_alpha.full) ~chain ~block ?branch
?src_sk contents = ?src_sk contents =
Alpha_services.Constants.hard_gas_limits cctxt block >>=? fun (_, gas_limit) -> Alpha_services.Constants.hard_gas_limits cctxt (chain, block) >>=? fun (_, gas_limit) ->
Alpha_services.Constants.hard_storage_limits cctxt block >>=? fun (_, storage_limit) -> Alpha_services.Constants.hard_storage_limits cctxt (chain, block) >>=? fun (_, storage_limit) ->
match contents with match contents with
| Sourced_operation (Manager_operations c) | Sourced_operation (Manager_operations c)
when c.gas_limit < Z.zero || gas_limit < c.gas_limit when c.gas_limit < Z.zero || gas_limit < c.gas_limit
|| c.storage_limit < 0L || storage_limit < c.storage_limit -> || c.storage_limit < 0L || storage_limit < c.storage_limit ->
let contents = let contents =
Sourced_operation (Manager_operations { c with gas_limit ; storage_limit }) in Sourced_operation (Manager_operations { c with gas_limit ; storage_limit }) in
preapply cctxt block ?branch ?src_sk contents >>=? fun (_, _, result) -> preapply cctxt ~chain ~block ?branch ?src_sk contents >>=? fun (_, _, result) ->
begin if c.gas_limit < Z.zero || gas_limit < c.gas_limit then begin if c.gas_limit < Z.zero || gas_limit < c.gas_limit then
Lwt.return (estimated_gas result) >>=? fun gas -> Lwt.return (estimated_gas result) >>=? fun gas ->
begin begin
@ -160,11 +161,11 @@ let may_patch_limits
| op -> return op | op -> return op
let inject_operation let inject_operation
cctxt block cctxt ~chain ~block
?confirmations ?branch ?src_sk contents = ?confirmations ?branch ?src_sk contents =
may_patch_limits may_patch_limits
cctxt block ?branch ?src_sk contents >>=? fun contents -> cctxt ~chain ~block ?branch ?src_sk contents >>=? fun contents ->
preapply cctxt block preapply cctxt ~chain ~block
?branch ?src_sk contents >>=? fun (_oph, op, result) -> ?branch ?src_sk contents >>=? fun (_oph, op, result) ->
begin match detect_script_failure result with begin match detect_script_failure result with
| Ok () -> return () | Ok () -> return ()
@ -175,7 +176,7 @@ let inject_operation
Lwt.return res Lwt.return res
end >>=? fun () -> end >>=? fun () ->
let bytes = Data_encoding.Binary.to_bytes_exn Operation.encoding op in let bytes = Data_encoding.Binary.to_bytes_exn Operation.encoding op in
Block_services.chain_id cctxt block >>=? fun chain_id -> Chain_services.chain_id cctxt ~chain () >>=? fun chain_id ->
Shell_services.inject_operation cctxt ~chain_id bytes >>=? fun oph -> Shell_services.inject_operation cctxt ~chain_id bytes >>=? fun oph ->
cctxt#message "Operation successfully injected in the node." >>= fun () -> cctxt#message "Operation successfully injected in the node." >>= fun () ->
cctxt#message "Operation hash is '%a'." Operation_hash.pp oph >>= fun () -> cctxt#message "Operation hash is '%a'." Operation_hash.pp oph >>= fun () ->
@ -185,7 +186,7 @@ let inject_operation
| Some confirmations -> | Some confirmations ->
cctxt#message "Waiting for the operation to be included..." >>= fun () -> cctxt#message "Waiting for the operation to be included..." >>= fun () ->
Client_confirmations.wait_for_operation_inclusion Client_confirmations.wait_for_operation_inclusion
~confirmations cctxt oph >>=? fun () -> ~confirmations cctxt ~chain oph >>=? fun () ->
return () return ()
end >>=? fun () -> end >>=? fun () ->
cctxt#message cctxt#message

View File

@ -15,7 +15,8 @@ type result = Operation_hash.t * operation * operation_result
val preapply: val preapply:
#Proto_alpha.full -> #Proto_alpha.full ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
?branch:int -> ?branch:int ->
?src_sk:Client_keys.sk_uri -> ?src_sk:Client_keys.sk_uri ->
Operation.contents -> Operation.contents ->
@ -23,7 +24,8 @@ val preapply:
val inject_operation: val inject_operation:
#Proto_alpha.full -> #Proto_alpha.full ->
Block_services.block -> chain:Chain_services.chain ->
block:Block_services.block ->
?confirmations:int -> ?confirmations:int ->
?branch:int -> ?branch:int ->
?src_sk:Client_keys.sk_uri -> ?src_sk:Client_keys.sk_uri ->

View File

@ -9,11 +9,16 @@
module Name = struct let name = "alpha" end module Name = struct let name = "alpha" end
module Alpha_environment = Tezos_protocol_environment_faked.MakeV1(Name)() module Alpha_environment = Tezos_protocol_environment_faked.MakeV1(Name)()
include Tezos_protocol_alpha.Functor.Make(Alpha_environment) module Proto = Tezos_protocol_alpha.Functor.Make(Alpha_environment)
module Block_services = struct
include Block_services
include Block_services.Make(Proto)(Proto)
end
include Proto
class type rpc_context = object class type rpc_context = object
inherit RPC_context.json inherit RPC_context.json
inherit [Block_services.block] Alpha_environment.RPC_context.simple inherit [Chain_services.chain * Block_services.block] Alpha_environment.RPC_context.simple
end end
class wrap_proto_context (t : RPC_context.json) : rpc_context = object class wrap_proto_context (t : RPC_context.json) : rpc_context = object
@ -27,17 +32,20 @@ class wrap_proto_context (t : RPC_context.json) : rpc_context = object
on_chunk: ('o -> unit) -> on_chunk: ('o -> unit) ->
on_close: (unit -> unit) -> on_close: (unit -> unit) ->
'p -> 'q -> 'i -> (unit -> unit) tzresult Lwt.t = t#call_streamed_service 'p -> 'q -> 'i -> (unit -> unit) tzresult Lwt.t = t#call_streamed_service
inherit [Block_services.block] Alpha_environment.proto_rpc_context inherit [Chain_services.chain,
(t :> RPC_context.t) (Block_services.S.proto_path ()) Block_services.block] Alpha_environment.proto_rpc_context
(t :> RPC_context.t)
Block_services.path
end end
class type full = object class type full = object
inherit Client_context.full inherit Client_context.full
inherit [Block_services.block] Alpha_environment.RPC_context.simple inherit [Chain_services.chain * Block_services.block] Alpha_environment.RPC_context.simple
end end
class wrap_full (t : Client_context.full) : full = object class wrap_full (t : Client_context.full) : full = object
inherit Client_context.proxy_context t inherit Client_context.proxy_context t
inherit [Block_services.block] Alpha_environment.proto_rpc_context inherit [Chain_services.chain, Block_services.block] Alpha_environment.proto_rpc_context
(t :> RPC_context.t) (Block_services.S.proto_path ()) (t :> RPC_context.t)
Block_services.path
end end

View File

@ -56,8 +56,8 @@ let commands () =
(switch ~doc:"output time in seconds" ~short:'s' ~long:"seconds" ())) (switch ~doc:"output time in seconds" ~short:'s' ~long:"seconds" ()))
(fixed [ "get" ; "timestamp" ]) (fixed [ "get" ; "timestamp" ])
begin fun seconds (cctxt : Proto_alpha.full) -> begin fun seconds (cctxt : Proto_alpha.full) ->
Block_services.timestamp Block_services.Header.Shell.timestamp
cctxt cctxt#block >>=? fun v -> cctxt ~block:cctxt#block () >>=? fun v ->
begin begin
if seconds if seconds
then cctxt#message "%Ld" (Time.to_seconds v) then cctxt#message "%Ld" (Time.to_seconds v)
@ -70,7 +70,8 @@ let commands () =
no_options no_options
(fixed [ "list" ; "contracts" ]) (fixed [ "list" ; "contracts" ])
begin fun () (cctxt : Proto_alpha.full) -> begin fun () (cctxt : Proto_alpha.full) ->
list_contract_labels cctxt cctxt#block >>=? fun contracts -> list_contract_labels cctxt
~chain:`Main ~block:cctxt#block >>=? fun contracts ->
Lwt_list.iter_s Lwt_list.iter_s
(fun (alias, hash, kind) -> cctxt#message "%s%s%s" hash kind alias) (fun (alias, hash, kind) -> cctxt#message "%s%s%s" hash kind alias)
contracts >>= fun () -> contracts >>= fun () ->
@ -83,7 +84,9 @@ let commands () =
@@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract"
@@ stop) @@ stop)
begin fun () (_, contract) (cctxt : Proto_alpha.full) -> begin fun () (_, contract) (cctxt : Proto_alpha.full) ->
get_balance cctxt cctxt#block contract >>=? fun amount -> get_balance cctxt
~chain:`Main ~block:cctxt#block
contract >>=? fun amount ->
cctxt#answer "%a %s" Tez.pp amount Client_proto_args.tez_sym >>= fun () -> cctxt#answer "%a %s" Tez.pp amount Client_proto_args.tez_sym >>= fun () ->
return () return ()
end ; end ;
@ -94,7 +97,9 @@ let commands () =
@@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract"
@@ stop) @@ stop)
begin fun () (_, contract) (cctxt : Proto_alpha.full) -> begin fun () (_, contract) (cctxt : Proto_alpha.full) ->
get_storage cctxt cctxt#block contract >>=? function get_storage cctxt
~chain:`Main ~block:cctxt#block
contract >>=? function
| None -> | None ->
cctxt#error "This is not a smart contract." cctxt#error "This is not a smart contract."
| Some storage -> | Some storage ->
@ -108,8 +113,9 @@ let commands () =
@@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract"
@@ stop) @@ stop)
begin fun () (_, contract) (cctxt : Proto_alpha.full) -> begin fun () (_, contract) (cctxt : Proto_alpha.full) ->
Client_proto_contracts.get_manager Client_proto_contracts.get_manager cctxt
cctxt cctxt#block contract >>=? fun manager -> ~chain:`Main ~block:cctxt#block
contract >>=? fun manager ->
Public_key_hash.rev_find cctxt manager >>=? fun mn -> Public_key_hash.rev_find cctxt manager >>=? fun mn ->
Public_key_hash.to_source manager >>=? fun m -> Public_key_hash.to_source manager >>=? fun m ->
cctxt#message "%s (%s)" m cctxt#message "%s (%s)" m
@ -123,8 +129,9 @@ let commands () =
@@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract"
@@ stop) @@ stop)
begin fun () (_, contract) (cctxt : Proto_alpha.full) -> begin fun () (_, contract) (cctxt : Proto_alpha.full) ->
Client_proto_contracts.get_delegate Client_proto_contracts.get_delegate cctxt
cctxt cctxt#block contract >>=? function ~chain:`Main ~block:cctxt#block
contract >>=? function
| None -> | None ->
cctxt#message "none" >>= fun () -> cctxt#message "none" >>= fun () ->
return () return ()
@ -145,9 +152,11 @@ let commands () =
~name: "mgr" ~desc: "new delegate of the contract" ~name: "mgr" ~desc: "new delegate of the contract"
@@ stop) @@ stop)
begin fun fee (_, contract) (_, delegate) (cctxt : Proto_alpha.full) -> begin fun fee (_, contract) (_, delegate) (cctxt : Proto_alpha.full) ->
source_to_keys cctxt cctxt#block contract >>=? fun (src_pk, manager_sk) -> source_to_keys cctxt
set_delegate ~chain:`Main ~block:cctxt#block
cctxt cctxt#block ?confirmations:cctxt#confirmations contract >>=? fun (src_pk, manager_sk) ->
set_delegate cctxt
~chain:`Main ~block:cctxt#block ?confirmations:cctxt#confirmations
contract (Some delegate) ~fee ~src_pk ~manager_sk >>=? fun _ -> contract (Some delegate) ~fee ~src_pk ~manager_sk >>=? fun _ ->
return () return ()
end ; end ;
@ -158,9 +167,11 @@ let commands () =
@@ ContractAlias.destination_param ~name:"src" ~desc:"source contract" @@ ContractAlias.destination_param ~name:"src" ~desc:"source contract"
@@ stop) @@ stop)
begin fun fee (_, contract) (cctxt : Proto_alpha.full) -> begin fun fee (_, contract) (cctxt : Proto_alpha.full) ->
source_to_keys cctxt cctxt#block contract >>=? fun (src_pk, manager_sk) -> source_to_keys cctxt
set_delegate ~chain:`Main ~block:cctxt#block
cctxt cctxt#block ?confirmations:cctxt#confirmations contract >>=? fun (src_pk, manager_sk) ->
set_delegate cctxt
~chain:`Main ~block:cctxt#block ?confirmations:cctxt#confirmations
contract None ~fee ~src_pk ~manager_sk >>=? fun _ -> contract None ~fee ~src_pk ~manager_sk >>=? fun _ ->
return () return ()
end ; end ;
@ -183,20 +194,13 @@ let commands () =
begin fun (fee, delegate, delegatable, force) begin fun (fee, delegate, delegatable, force)
new_contract manager_pkh balance (_, source) (cctxt : Proto_alpha.full) -> new_contract manager_pkh balance (_, source) (cctxt : Proto_alpha.full) ->
RawContractAlias.of_fresh cctxt force new_contract >>=? fun alias_name -> RawContractAlias.of_fresh cctxt force new_contract >>=? fun alias_name ->
source_to_keys cctxt cctxt#block source >>=? fun (src_pk, src_sk) -> source_to_keys cctxt
originate_account ~chain:`Main ~block:cctxt#block
cctxt source >>=? fun (src_pk, src_sk) ->
cctxt#block originate_account cctxt
?confirmations:cctxt#confirmations ~chain:`Main ~block:cctxt#block ?confirmations:cctxt#confirmations
~fee ~fee ?delegate ~delegatable ~manager_pkh ~balance
?delegate ~source ~src_pk ~src_sk () >>=? fun (_res, contract) ->
~delegatable
~manager_pkh
~balance
~source
~src_pk
~src_sk
() >>=? fun (_res, contract) ->
save_contract ~force cctxt alias_name contract >>=? fun () -> save_contract ~force cctxt alias_name contract >>=? fun () ->
return () return ()
end ; end ;
@ -226,8 +230,11 @@ let commands () =
alias_name manager balance (_, source) program (cctxt : Proto_alpha.full) -> alias_name manager balance (_, source) program (cctxt : Proto_alpha.full) ->
RawContractAlias.of_fresh cctxt force alias_name >>=? fun alias_name -> RawContractAlias.of_fresh cctxt force alias_name >>=? fun alias_name ->
Lwt.return (Micheline_parser.no_parsing_error program) >>=? fun { expanded = code } -> Lwt.return (Micheline_parser.no_parsing_error program) >>=? fun { expanded = code } ->
source_to_keys cctxt cctxt#block source >>=? fun (src_pk, src_sk) -> source_to_keys cctxt
originate_contract cctxt cctxt#block ?confirmations:cctxt#confirmations ~chain:`Main ~block:cctxt#block
source >>=? fun (src_pk, src_sk) ->
originate_contract cctxt
~chain:`Main ~block:cctxt#block ?confirmations:cctxt#confirmations
~fee ?gas_limit ?storage_limit ~delegate ~delegatable ~spendable ~initial_storage ~fee ?gas_limit ?storage_limit ~delegate ~delegatable ~spendable ~initial_storage
~manager ~balance ~source ~src_pk ~src_sk ~code () >>= fun errors -> ~manager ~balance ~source ~src_pk ~src_sk ~code () >>= fun errors ->
report_michelson_errors ~no_print_source ~msg:"origination simulation failed" cctxt errors >>= function report_michelson_errors ~no_print_source ~msg:"origination simulation failed" cctxt errors >>= function
@ -250,8 +257,11 @@ let commands () =
~name: "dst" ~desc: "name/literal of the destination contract" ~name: "dst" ~desc: "name/literal of the destination contract"
@@ stop) @@ stop)
begin fun (fee, gas_limit, storage_limit, arg, no_print_source) amount (_, source) (_, destination) cctxt -> begin fun (fee, gas_limit, storage_limit, arg, no_print_source) amount (_, source) (_, destination) cctxt ->
source_to_keys cctxt cctxt#block source >>=? fun (src_pk, src_sk) -> source_to_keys cctxt
transfer cctxt cctxt#block ?confirmations:cctxt#confirmations ~chain:`Main ~block:cctxt#block
source >>=? fun (src_pk, src_sk) ->
transfer cctxt
~chain:`Main ~block:cctxt#block ?confirmations:cctxt#confirmations
~source ~fee ~src_pk ~src_sk ~destination ~arg ~amount ?gas_limit ?storage_limit () >>= ~source ~fee ~src_pk ~src_sk ~destination ~arg ~amount ?gas_limit ?storage_limit () >>=
report_michelson_errors ~no_print_source ~msg:"transfer simulation failed" cctxt >>= function report_michelson_errors ~no_print_source ~msg:"transfer simulation failed" cctxt >>= function
| None -> return () | None -> return ()
@ -266,8 +276,11 @@ let commands () =
~name: "src" ~desc: "name of the source contract" ~name: "src" ~desc: "name of the source contract"
@@ stop) @@ stop)
begin fun fee (_, source) cctxt -> begin fun fee (_, source) cctxt ->
source_to_keys cctxt cctxt#block source >>=? fun (src_pk, src_sk) -> source_to_keys cctxt
reveal cctxt cctxt#block ?confirmations:cctxt#confirmations ~chain:`Main ~block:cctxt#block
source >>=? fun (src_pk, src_sk) ->
reveal cctxt
~chain:`Main ~block:cctxt#block ?confirmations:cctxt#confirmations
~source ~fee ~src_pk ~src_sk () >>=? fun _res -> ~source ~fee ~src_pk ~src_sk () >>=? fun _res ->
return () return ()
end; end;
@ -281,8 +294,9 @@ let commands () =
@@ stop) @@ stop)
begin fun fee src_pkh cctxt -> begin fun fee src_pkh cctxt ->
Client_keys.get_key cctxt src_pkh >>=? fun (_, src_pk, src_sk) -> Client_keys.get_key cctxt src_pkh >>=? fun (_, src_pk, src_sk) ->
register_as_delegate cctxt ?confirmations:cctxt#confirmations register_as_delegate cctxt
~fee cctxt#block ~manager_sk:src_sk src_pk >>=? fun _res -> ~chain:`Main ~block:cctxt#block ?confirmations:cctxt#confirmations
~fee ~manager_sk:src_sk src_pk >>=? fun _res ->
return () return ()
end; end;
@ -309,8 +323,8 @@ let commands () =
(fun ppf -> Data_encoding.Json.print_error ppf) exn (fun ppf -> Data_encoding.Json.print_error ppf) exn
Data_encoding.Json.pp json Data_encoding.Json.pp json
| key -> | key ->
claim_commitment claim_commitment cctxt
cctxt cctxt#block ?confirmations:cctxt#confirmations ~chain:`Main ~block:cctxt#block ?confirmations:cctxt#confirmations
~encrypted ~force key name >>=? fun _res -> ~encrypted ~force key name >>=? fun _res ->
return () return ()
); );
@ -325,7 +339,8 @@ let commands () =
~name:"password" ~desc:"dictator's key" ~name:"password" ~desc:"dictator's key"
@@ stop) @@ stop)
begin fun () hash seckey cctxt -> begin fun () hash seckey cctxt ->
dictate cctxt cctxt#block dictate cctxt
~chain:`Main ~block:cctxt#block
(Activate hash) seckey >>=? fun _ -> (Activate hash) seckey >>=? fun _ ->
return () return ()
end ; end ;
@ -366,7 +381,7 @@ let commands () =
fail_when (predecessors < 0) fail_when (predecessors < 0)
(failure "check-previous cannot be negative") >>=? fun () -> (failure "check-previous cannot be negative") >>=? fun () ->
Client_confirmations.wait_for_operation_inclusion ctxt Client_confirmations.wait_for_operation_inclusion ctxt
~confirmations ~predecessors operation_hash >>=? fun _ -> ~chain:`Main ~confirmations ~predecessors operation_hash >>=? fun _ ->
return () return ()
end ; end ;
@ -380,7 +395,8 @@ let commands () =
~name:"password" ~desc:"dictator's key" ~name:"password" ~desc:"dictator's key"
@@ stop) @@ stop)
begin fun () hash seckey cctxt -> begin fun () hash seckey cctxt ->
dictate cctxt cctxt#block dictate cctxt
~chain:`Main ~block:cctxt#block
(Activate_testchain hash) seckey >>=? fun _res -> (Activate_testchain hash) seckey >>=? fun _res ->
return () return ()
end ; end ;

View File

@ -55,7 +55,7 @@ let commands () =
with _ -> failwith "invalid gas limit (must be a positive number)")) in with _ -> failwith "invalid gas limit (must be a positive number)")) in
let resolve_max_gas cctxt block = function let resolve_max_gas cctxt block = function
| None -> | None ->
Alpha_services.Constants.hard_gas_limits cctxt block >>=? fun (_, gas) -> Alpha_services.Constants.hard_gas_limits cctxt (`Main, block) >>=? fun (_, gas) ->
return gas return gas
| Some gas -> return gas in | Some gas -> return gas in
let data_parameter = let data_parameter =
@ -123,10 +123,10 @@ let commands () =
Lwt.return @@ Micheline_parser.no_parsing_error program >>=? fun program -> Lwt.return @@ Micheline_parser.no_parsing_error program >>=? fun program ->
let show_source = not no_print_source in let show_source = not no_print_source in
(if trace_exec then (if trace_exec then
trace ~amount ~program ~storage ~input cctxt#block cctxt >>= fun res -> trace cctxt cctxt#block ~amount ~program ~storage ~input () >>= fun res ->
print_trace_result cctxt ~show_source ~parsed:program res print_trace_result cctxt ~show_source ~parsed:program res
else else
run ~amount ~program ~storage ~input cctxt#block cctxt >>= fun res -> run cctxt cctxt#block ~amount ~program ~storage ~input () >>= fun res ->
print_run_result cctxt ~show_source ~parsed:program res)) ; print_run_result cctxt ~show_source ~parsed:program res)) ;
command ~group ~desc: "Ask the node to typecheck a program." command ~group ~desc: "Ask the node to typecheck a program."
(args4 show_types_switch emacs_mode_switch no_print_source_flag custom_gas_flag) (args4 show_types_switch emacs_mode_switch no_print_source_flag custom_gas_flag)
@ -137,7 +137,7 @@ let commands () =
match program with match program with
| program, [] -> | program, [] ->
resolve_max_gas cctxt cctxt#block original_gas >>=? fun original_gas -> resolve_max_gas cctxt cctxt#block original_gas >>=? fun original_gas ->
typecheck_program ~gas:original_gas program cctxt#block cctxt >>= fun res -> typecheck_program cctxt cctxt#block ~gas:original_gas program >>= fun res ->
print_typecheck_result print_typecheck_result
~emacs:emacs_mode ~emacs:emacs_mode
~show_types ~show_types
@ -171,7 +171,8 @@ let commands () =
@@ stop) @@ stop)
(fun (no_print_source, custom_gas) data ty cctxt -> (fun (no_print_source, custom_gas) data ty cctxt ->
resolve_max_gas cctxt cctxt#block custom_gas >>=? fun original_gas -> resolve_max_gas cctxt cctxt#block custom_gas >>=? fun original_gas ->
Client_proto_programs.typecheck_data ~gas:original_gas ~data ~ty cctxt#block cctxt >>= function Client_proto_programs.typecheck_data cctxt cctxt#block
~gas:original_gas ~data ~ty () >>= function
| Ok gas -> | Ok gas ->
cctxt#message "@[<v 0>Well typed@,Gas remaining: %a@]" cctxt#message "@[<v 0>Well typed@,Gas remaining: %a@]"
Proto_alpha.Alpha_context.Gas.pp gas >>= fun () -> Proto_alpha.Alpha_context.Gas.pp gas >>= fun () ->
@ -198,8 +199,8 @@ let commands () =
@@ stop) @@ stop)
(fun custom_gas data typ cctxt -> (fun custom_gas data typ cctxt ->
resolve_max_gas cctxt cctxt#block custom_gas >>=? fun original_gas -> resolve_max_gas cctxt cctxt#block custom_gas >>=? fun original_gas ->
Alpha_services.Helpers.hash_data cctxt Alpha_services.Helpers.hash_data cctxt (`Main, cctxt#block)
cctxt#block (data.expanded, typ.expanded, Some original_gas) >>= function (data.expanded, typ.expanded, Some original_gas) >>= function
| Ok (hash, remaining_gas) -> | Ok (hash, remaining_gas) ->
cctxt#message "%S@,Gas remaining: %a" hash cctxt#message "%S@,Gas remaining: %a" hash
Proto_alpha.Alpha_context.Gas.pp remaining_gas >>= fun () -> Proto_alpha.Alpha_context.Gas.pp remaining_gas >>= fun () ->
@ -231,7 +232,8 @@ let commands () =
@@ stop) @@ stop)
(fun gas data typ sk cctxt -> (fun gas data typ sk cctxt ->
resolve_max_gas cctxt cctxt#block gas >>=? fun gas -> resolve_max_gas cctxt cctxt#block gas >>=? fun gas ->
Client_proto_programs.hash_and_sign ~gas data typ sk cctxt#block cctxt >>= begin function Client_proto_programs.hash_and_sign cctxt cctxt#block
~gas data typ sk >>= begin function
| Ok (hash, signature, current_gas) -> | Ok (hash, signature, current_gas) ->
cctxt#message "@[<v 0>Hash: %S@,Signature: %S@,Remaining gas: %a@]" cctxt#message "@[<v 0>Hash: %S@,Signature: %S@,Remaining gas: %a@]"
hash signature hash signature

View File

@ -11,98 +11,6 @@ open Alpha_context
let custom_root = RPC_path.open_root let custom_root = RPC_path.open_root
module S = struct
open Data_encoding
let operations =
RPC_service.post_service
~description: "All the operations of the block (fully decoded)."
~query: RPC_query.empty
~input: empty
~output: (list (list (merge_objs
(obj1 (req "hash" Operation_hash.encoding))
(dynamic_size Operation.encoding))))
RPC_path.(custom_root / "operations")
let header =
RPC_service.post_service
~description: "The header of the block (fully decoded)."
~query: RPC_query.empty
~input: empty
~output: Block_header.encoding
RPC_path.(custom_root / "header")
let priority =
RPC_service.post_service
~description: "Baking priority of the block."
~query: RPC_query.empty
~input: empty
~output: (obj1 (req "priority" uint16))
RPC_path.(custom_root / "header" / "priority")
let seed_nonce_hash =
RPC_service.post_service
~description: "Hash of the seed nonce of the block."
~query: RPC_query.empty
~input: empty
~output: Nonce_hash.encoding
RPC_path.(custom_root / "header" / "seed_nonce_hash")
end
let parse_operation (op: Operation.raw) =
match Data_encoding.Binary.of_bytes
Operation.protocol_data_encoding
op.proto with
| Some protocol_data ->
ok { shell = op.shell ; protocol_data }
| None -> error Helpers_services.Cannot_parse_operation
let parse_block_header
({ shell ; protocol_data } : Block_header.raw) : Block_header.t tzresult =
match
Data_encoding.Binary.of_bytes
Block_header.protocol_data_encoding
protocol_data
with
| None -> Error [Helpers_services.Cant_parse_block_header]
| Some protocol_data -> Ok { shell ; protocol_data }
let () =
let open Services_registration in
register0_fullctxt S.operations begin fun ctxt () () ->
ctxt.operation_hashes () >>= fun operation_hashes ->
ctxt.operations () >>= fun operations ->
map2_s
(map2_s (fun h op ->
Lwt.return (parse_operation op) >>=? fun op ->
return (h, op)))
operation_hashes operations
end ;
register0_fullctxt S.header begin fun { block_header ; _ } () () ->
Lwt.return (parse_block_header block_header) >>=? fun block_header ->
return block_header
end ;
register0_fullctxt S.priority begin fun { block_header ; _ } () () ->
Lwt.return (parse_block_header block_header) >>=? fun block_header ->
return block_header.protocol_data.contents.priority
end ;
opt_register0_fullctxt S.seed_nonce_hash begin fun { block_header ; _ } () ( )->
Lwt.return (parse_block_header block_header) >>=? fun block_header ->
return block_header.protocol_data.contents.seed_nonce_hash
end
let operations ctxt block =
RPC_context.make_call0 S.operations ctxt block () ()
let header ctxt block =
RPC_context.make_call0 S.header ctxt block () ()
let priority ctxt block =
RPC_context.make_call0 S.priority ctxt block () ()
let seed_nonce_hash ctxt block =
RPC_context.make_call0 S.seed_nonce_hash ctxt block () ()
module Context = struct module Context = struct
module S = struct module S = struct

View File

@ -9,15 +9,6 @@
open Alpha_context open Alpha_context
val operations:
'a #RPC_context.simple -> 'a -> (Operation_hash.t * Operation.t) list list shell_tzresult Lwt.t
val header:
'a #RPC_context.simple -> 'a -> Block_header.t shell_tzresult Lwt.t
val priority:
'a #RPC_context.simple -> 'a -> int shell_tzresult Lwt.t
val seed_nonce_hash:
'a #RPC_context.simple -> 'a -> Nonce_hash.t shell_tzresult Lwt.t
module Context : sig module Context : sig
val level: val level:

View File

@ -99,13 +99,30 @@ let metadata_encoding =
(** Constants *) (** Constants *)
let max_header_length = let max_header_length =
let fake = { priority = 0 ; let fake_shell = {
Block_header.level = 0l ;
proto_level = 0 ;
predecessor = Block_hash.zero ;
timestamp = Time.of_seconds 0L ;
validation_passes = 0 ;
operations_hash = Operation_list_list_hash.zero ;
fitness = Fitness_repr.from_int64 0L ;
context = Context_hash.zero ;
}
and fake_contents =
{ priority = 0 ;
proof_of_work_nonce = proof_of_work_nonce =
MBytes.create Constants_repr.proof_of_work_nonce_size ; MBytes.create Constants_repr.proof_of_work_nonce_size ;
seed_nonce_hash = Some Nonce_hash.zero } in seed_nonce_hash = Some Nonce_hash.zero
} in
Data_encoding.Binary.length Data_encoding.Binary.length
protocol_data_encoding encoding
{ contents = fake ; signature = Signature.zero} { shell = fake_shell ;
protocol_data = {
contents = fake_contents ;
signature = Signature.zero ;
}
}
(** Header parsing entry point *) (** Header parsing entry point *)

View File

@ -11,20 +11,17 @@ open Alpha_context
type rpc_context = { type rpc_context = {
block_hash: Block_hash.t ; block_hash: Block_hash.t ;
block_header: Block_header.raw ; block_header: Block_header.shell_header ;
operation_hashes: unit -> Operation_hash.t list list Lwt.t ;
operations: unit -> Operation.raw list list Lwt.t ;
context: Alpha_context.t ; context: Alpha_context.t ;
} }
let rpc_init (rpc_context : Updater.rpc_context Lwt.t) = let rpc_init (rpc_context : Updater.rpc_context Lwt.t) =
rpc_context >>= fun { block_hash ; block_header ; rpc_context >>= fun { block_hash ; block_header ; context } ->
operation_hashes ; operations ; context } -> let level = block_header.level in
let level = block_header.shell.level in let timestamp = block_header.timestamp in
let timestamp = block_header.shell.timestamp in let fitness = block_header.fitness in
let fitness = block_header.shell.fitness in
Alpha_context.prepare ~level ~timestamp ~fitness context >>=? fun context -> Alpha_context.prepare ~level ~timestamp ~fitness context >>=? fun context ->
return { block_hash ; block_header ; operation_hashes ; operations ; context } return { block_hash ; block_header ; context }
let rpc_services = ref (RPC_directory.empty : Updater.rpc_context Lwt.t RPC_directory.t) let rpc_services = ref (RPC_directory.empty : Updater.rpc_context Lwt.t RPC_directory.t)

View File

@ -21,13 +21,9 @@ type t = {
type block = t type block = t
let rpc_context block = let rpc_context block =
let operations_hashes =
lazy [ List.map Operation.hash block.operations ] in
Lwt.return { Lwt.return {
Alpha_environment.Updater.block_hash = block.hash ; Alpha_environment.Updater.block_hash = block.hash ;
block_header = (Block_header.raw block.header) ; block_header = block.header.shell ;
operation_hashes = (fun () -> Lwt.return (Lazy.force operations_hashes)) ;
operations = (fun () -> Lwt.return [ List.map Operation.raw block.operations ]) ;
context = block.context ; context = block.context ;
} }

View File

@ -24,19 +24,10 @@ let predecessor { predecessor ; _ } = predecessor
let level st = st.header.shell.level let level st = st.header.shell.level
let rpc_context st = let rpc_context st =
let operations = lazy (List.rev st.rev_operations) in
let operations_hashes =
lazy (List.map Operation.hash (Lazy.force operations)) in
let result = Alpha_context.finalize st.state.ctxt in let result = Alpha_context.finalize st.state.ctxt in
Lwt.return { Lwt.return {
Alpha_environment.Updater.block_hash = Block_hash.zero ; Alpha_environment.Updater.block_hash = Block_hash.zero ;
block_header = block_header = { st.header.shell with fitness = result.fitness } ;
Block_header.raw
{ st.header with
shell = { st.header.shell with fitness = result.fitness }} ;
operation_hashes = (fun () -> Lwt.return [Lazy.force operations_hashes]) ;
operations = (fun () ->
Lwt.return [List.map Operation.raw (Lazy.force operations)]) ;
context = result.context ; context = result.context ;
} }

View File

@ -14,13 +14,10 @@ let protocol =
"ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im" "ProtoGenesisGenesisGenesisGenesisGenesisGenesk612im"
let bake cctxt ?(timestamp = Time.now ()) block command sk = let bake cctxt ?(timestamp = Time.now ()) block command sk =
let protocol_data = let protocol_data = { command ; signature = Signature.zero } in
Data_encoding.Binary.to_bytes_exn Block_services.Helpers.preapply
Proto_genesis.block_header_data_encoding cctxt ~block ~timestamp ~protocol_data
{ command ; signature = Signature.zero } in [] >>=? fun (shell_header, _) ->
Block_services.preapply
cctxt block ~timestamp ~protocol_data
[] >>=? fun { shell_header } ->
let blk = Data.Command.forge shell_header command in let blk = Data.Command.forge shell_header command in
Client_keys.append sk blk >>=? fun signed_blk -> Client_keys.append sk blk >>=? fun signed_blk ->
Shell_services.inject_block cctxt signed_blk [] Shell_services.inject_block cctxt signed_blk []

View File

@ -9,4 +9,9 @@
module Name = struct let name = "genesis" end module Name = struct let name = "genesis" end
module Genesis_environment = Tezos_protocol_environment_faked.MakeV1(Name)() module Genesis_environment = Tezos_protocol_environment_faked.MakeV1(Name)()
include Tezos_protocol_genesis.Functor.Make(Genesis_environment) module Proto = Tezos_protocol_genesis.Functor.Make(Genesis_environment)
module Block_services = struct
include Block_services
include Block_services.Make(Proto)(Proto)
end
include Proto