diff --git a/src/bin_signer/handler.ml b/src/bin_signer/handler.ml index 0ebddb9fd..2cafadfe6 100644 --- a/src/bin_signer/handler.ml +++ b/src/bin_signer/handler.ml @@ -40,11 +40,12 @@ module High_watermark = struct (List.map (fun (pkh, mark) -> Signature.Public_key_hash.to_b58check pkh, mark)) (List.map (fun (pkh, mark) -> Signature.Public_key_hash.of_b58check_exn pkh, mark)) @@ assoc @@ - obj2 + obj3 (req "level" int32) (req "hash" raw_hash) + (opt "signature" Signature.encoding) - let mark_if_block_or_endorsement (cctxt : #Client_context.wallet) pkh bytes = + let mark_if_block_or_endorsement (cctxt : #Client_context.wallet) pkh bytes sign = let mark art name get_level = let file = name ^ "_high_watermark" in cctxt#with_lock @@ fun () -> @@ -56,32 +57,41 @@ module High_watermark = struct let chain_id = Chain_id.of_bytes_exn (MBytes.sub bytes 1 4) in let level = get_level () in begin match List.assoc_opt chain_id all with - | None -> return () + | None -> return None | Some marks -> match List.assoc_opt pkh marks with - | None -> return () - | Some (previous_level, previous_hash) -> + | None -> return None + | Some (previous_level, _, None) -> + if previous_level >= level then + failwith "%s level %ld not above high watermark %ld" name level previous_level + else + return None + | Some (previous_level, previous_hash, Some signature) -> if previous_level > level then failwith "%s level %ld below high watermark %ld" name level previous_level else if previous_level = level && previous_hash <> hash then - failwith "%s level %ld already signed with a different header" name level + failwith "%s level %ld already signed with different data" name level else - return () - end >>=? fun () -> - let rec update = function - | [] -> [ chain_id, [ pkh, (level, hash) ] ] - | (e_chain_id, marks) :: rest -> - if chain_id = e_chain_id then - let marks = (pkh, (level, hash)) :: List.filter (fun (pkh', _) -> pkh <> pkh') marks in - (e_chain_id, marks) :: rest - else - (e_chain_id, marks) :: update rest in - cctxt#write file (update all) encoding in + return (Some signature) + end >>=? function + | Some signature -> return signature + | None -> + sign bytes >>=? fun signature -> + let rec update = function + | [] -> [ chain_id, [ pkh, (level, hash, Some signature) ] ] + | (e_chain_id, marks) :: rest -> + if chain_id = e_chain_id then + let marks = (pkh, (level, hash, Some signature)) :: List.filter (fun (pkh', _) -> pkh <> pkh') marks in + (e_chain_id, marks) :: rest + else + (e_chain_id, marks) :: update rest in + cctxt#write file (update all) encoding >>=? fun () -> + return signature in if MBytes.length bytes > 0 && MBytes.get_uint8 bytes 0 = 0x01 then mark "a" "block" (fun () -> MBytes.get_int32 bytes 5) else if MBytes.length bytes > 0 && MBytes.get_uint8 bytes 0 = 0x02 then mark "an" "endorsement" (fun () -> MBytes.get_int32 bytes (MBytes.length bytes - 4)) - else return () + else sign bytes end @@ -134,12 +144,11 @@ let sign f "Signing data for key %s" -% t event "signing_data" -% s Client_keys.Logging.tag name) >>= fun () -> - begin if check_high_watermark then - High_watermark.mark_if_block_or_endorsement cctxt pkh data - else return () - end >>=? fun () -> - Client_keys.sign cctxt sk_uri data >>=? fun signature -> - return signature + let sign = Client_keys.sign cctxt sk_uri in + if check_high_watermark then + High_watermark.mark_if_block_or_endorsement cctxt pkh data sign + else + sign data let public_key (cctxt : #Client_context.wallet) pkh = log Tag.DSL.(fun f ->