Signer: better high watermarking

This commit is contained in:
Benjamin Canou 2018-10-21 23:22:28 +02:00
parent 3f04501c0d
commit 89372a8e28
No known key found for this signature in database
GPG Key ID: 73607948459DC5F8

View File

@ -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.to_b58check pkh, mark))
(List.map (fun (pkh, mark) -> Signature.Public_key_hash.of_b58check_exn pkh, mark)) @@ (List.map (fun (pkh, mark) -> Signature.Public_key_hash.of_b58check_exn pkh, mark)) @@
assoc @@ assoc @@
obj2 obj3
(req "level" int32) (req "level" int32)
(req "hash" raw_hash) (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 mark art name get_level =
let file = name ^ "_high_watermark" in let file = name ^ "_high_watermark" in
cctxt#with_lock @@ fun () -> 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 chain_id = Chain_id.of_bytes_exn (MBytes.sub bytes 1 4) in
let level = get_level () in let level = get_level () in
begin match List.assoc_opt chain_id all with begin match List.assoc_opt chain_id all with
| None -> return () | None -> return None
| Some marks -> | Some marks ->
match List.assoc_opt pkh marks with match List.assoc_opt pkh marks with
| None -> return () | None -> return None
| Some (previous_level, previous_hash) -> | 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 if previous_level > level then
failwith "%s level %ld below high watermark %ld" name level previous_level failwith "%s level %ld below high watermark %ld" name level previous_level
else if previous_level = level && previous_hash <> hash then 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 else
return () return (Some signature)
end >>=? fun () -> end >>=? function
| Some signature -> return signature
| None ->
sign bytes >>=? fun signature ->
let rec update = function let rec update = function
| [] -> [ chain_id, [ pkh, (level, hash) ] ] | [] -> [ chain_id, [ pkh, (level, hash, Some signature) ] ]
| (e_chain_id, marks) :: rest -> | (e_chain_id, marks) :: rest ->
if chain_id = e_chain_id then if chain_id = e_chain_id then
let marks = (pkh, (level, hash)) :: List.filter (fun (pkh', _) -> pkh <> pkh') marks in let marks = (pkh, (level, hash, Some signature)) :: List.filter (fun (pkh', _) -> pkh <> pkh') marks in
(e_chain_id, marks) :: rest (e_chain_id, marks) :: rest
else else
(e_chain_id, marks) :: update rest in (e_chain_id, marks) :: update rest in
cctxt#write file (update all) encoding in cctxt#write file (update all) encoding >>=? fun () ->
return signature in
if MBytes.length bytes > 0 && MBytes.get_uint8 bytes 0 = 0x01 then if MBytes.length bytes > 0 && MBytes.get_uint8 bytes 0 = 0x01 then
mark "a" "block" (fun () -> MBytes.get_int32 bytes 5) mark "a" "block" (fun () -> MBytes.get_int32 bytes 5)
else if MBytes.length bytes > 0 && MBytes.get_uint8 bytes 0 = 0x02 then 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)) mark "an" "endorsement" (fun () -> MBytes.get_int32 bytes (MBytes.length bytes - 4))
else return () else sign bytes
end end
@ -134,12 +144,11 @@ let sign
f "Signing data for key %s" f "Signing data for key %s"
-% t event "signing_data" -% t event "signing_data"
-% s Client_keys.Logging.tag name) >>= fun () -> -% s Client_keys.Logging.tag name) >>= fun () ->
begin if check_high_watermark then let sign = Client_keys.sign cctxt sk_uri in
High_watermark.mark_if_block_or_endorsement cctxt pkh data if check_high_watermark then
else return () High_watermark.mark_if_block_or_endorsement cctxt pkh data sign
end >>=? fun () -> else
Client_keys.sign cctxt sk_uri data >>=? fun signature -> sign data
return signature
let public_key (cctxt : #Client_context.wallet) pkh = let public_key (cctxt : #Client_context.wallet) pkh =
log Tag.DSL.(fun f -> log Tag.DSL.(fun f ->