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.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 ->