@@ -143,6 +143,18 @@ type
143143 ioHandle* : IoLockHandle
144144 opened* : bool
145145
146+ RemoteSignerType * {.pure .} = enum
147+ Web3Signer , VerifyingWeb3Signer
148+
149+ ProvenProperty * = object
150+ path* : string
151+ description* : Option [string ]
152+ phase0Index* : Option [GeneralizedIndex ]
153+ altairIndex* : Option [GeneralizedIndex ]
154+ bellatrixIndex* : Option [GeneralizedIndex ]
155+ capellaIndex* : Option [GeneralizedIndex ]
156+ denebIndex* : Option [GeneralizedIndex ]
157+
146158 KeystoreData * = object
147159 version* : uint64
148160 pubkey* : ValidatorPubKey
@@ -157,7 +169,11 @@ type
157169 flags* : set [RemoteKeystoreFlag ]
158170 remotes* : seq [RemoteSignerInfo ]
159171 threshold* : uint32
160- remoteType* : RemoteSignerType
172+ case remoteType* : RemoteSignerType
173+ of RemoteSignerType .Web3Signer :
174+ discard
175+ of RemoteSignerType .VerifyingWeb3Signer :
176+ provenBlockProperties* : seq [ProvenProperty ]
161177
162178 NetKeystore * = object
163179 crypto* : Crypto
@@ -166,13 +182,14 @@ type
166182 uuid* : string
167183 version* : int
168184
169- RemoteSignerType * {.pure .} = enum
170- Web3Signer , Web3SignerDiva
171-
172185 RemoteKeystore * = object
173186 version* : uint64
174187 description* : Option [string ]
175- remoteType* : RemoteSignerType
188+ case remoteType* : RemoteSignerType
189+ of RemoteSignerType .Web3Signer :
190+ discard
191+ of RemoteSignerType .VerifyingWeb3Signer :
192+ provenBlockProperties* : seq [ProvenProperty ]
176193 pubkey* : ValidatorPubKey
177194 flags* : set [RemoteKeystoreFlag ]
178195 remotes* : seq [RemoteSignerInfo ]
@@ -599,8 +616,9 @@ proc writeValue*(writer: var JsonWriter, value: RemoteKeystore)
599616 case value.remoteType
600617 of RemoteSignerType .Web3Signer :
601618 writer.writeField (" type" , " web3signer" )
602- of RemoteSignerType .Web3SignerDiva :
603- writer.writeField (" type" , " web3signer-diva" )
619+ of RemoteSignerType .VerifyingWeb3Signer :
620+ writer.writeField (" type" , " verifying-web3signer" )
621+ writer.writeField (" proven_block_properties" , value.provenBlockProperties)
604622 if value.description.isSome ():
605623 writer.writeField (" description" , value.description.get ())
606624 if RemoteKeystoreFlag .IgnoreSSLVerification in value.flags:
@@ -618,77 +636,139 @@ proc readValue*(reader: var JsonReader, value: var RemoteKeystore)
618636 description: Option [string ]
619637 remote: Option [HttpHostUri ]
620638 remotes: Option [seq [RemoteSignerInfo ]]
621- remoteType: Option [string ]
639+ remoteType: Option [RemoteSignerType ]
640+ provenBlockProperties: Option [seq [ProvenProperty ]]
622641 ignoreSslVerification: Option [bool ]
623642 pubkey: Option [ValidatorPubKey ]
624643 threshold: Option [uint32 ]
625- implicitVersion1 = false
626644
627645 # TODO : implementing deserializers for versioned objects
628646 # manually is extremely error-prone. This should use
629647 # the auto-generated deserializer from nim-json-serialization
630648 for fieldName in readObjectFields (reader):
631649 case fieldName:
632650 of " pubkey" :
633- if pubkey.isSome () :
651+ if pubkey.isSome:
634652 reader.raiseUnexpectedField (" Multiple `pubkey` fields found" ,
635653 " RemoteKeystore" )
636654 pubkey = some (reader.readValue (ValidatorPubKey ))
637655 of " remote" :
638- if version.isSome and version.get > 1 :
639- reader.raiseUnexpectedField (
640- " The `remote` field is valid only in version 1 of the remote keystore format" ,
641- " RemoteKeystore" )
642-
643- if remote.isSome ():
656+ if remote.isSome:
644657 reader.raiseUnexpectedField (" Multiple `remote` fields found" ,
645658 " RemoteKeystore" )
659+ if remotes.isSome:
660+ reader.raiseUnexpectedField (" The `remote` field cannot be specified together with `remotes`" ,
661+ " RemoteKeystore" )
646662 remote = some (reader.readValue (HttpHostUri ))
647- implicitVersion1 = true
648663 of " remotes" :
649- if remotes.isSome () :
664+ if remotes.isSome:
650665 reader.raiseUnexpectedField (" Multiple `remote` fields found" ,
651666 " RemoteKeystore" )
667+ if remote.isSome:
668+ reader.raiseUnexpectedField (" The `remotes` field cannot be specified together with `remote`" ,
669+ " RemoteKeystore" )
670+ if version.isNone:
671+ reader.raiseUnexpectedField (
672+ " The `remotes` field should be specified after the `version` field of the keystore" ,
673+ " RemoteKeystore" )
674+ if version.get < 2 :
675+ reader.raiseUnexpectedField (
676+ " The `remotes` field is valid only past version 2 of the remote keystore format" ,
677+ " RemoteKeystore" )
652678 remotes = some (reader.readValue (seq [RemoteSignerInfo ]))
653679 of " version" :
654- if version.isSome () :
680+ if version.isSome:
655681 reader.raiseUnexpectedField (" Multiple `version` fields found" ,
656682 " RemoteKeystore" )
657683 version = some (reader.readValue (uint64 ))
658- if implicitVersion1 and version.get > 1 'u64 :
659- reader.raiseUnexpectedValue (
660- " Remote keystore format doesn't match the specified version number" )
661- if version.get > 2 'u64 :
684+ if version.get > 3 'u64 :
662685 reader.raiseUnexpectedValue (
663686 " Remote keystore version " & $ version.get &
664687 " requires a more recent version of Nimbus" )
665688 of " description" :
666- let res = reader.readValue (string )
667- if description.isSome ():
668- description = some (description.get () & " \n " & res)
669- else :
670- description = some (res)
689+ if description.isSome:
690+ reader.raiseUnexpectedField (" Multiple `description` fields found" ,
691+ " RemoteKeystore" )
692+ description = some (reader.readValue (string ))
671693 of " ignore_ssl_verification" :
672- if ignoreSslVerification.isSome () :
694+ if ignoreSslVerification.isSome:
673695 reader.raiseUnexpectedField (" Multiple conflicting options found" ,
674696 " RemoteKeystore" )
675697 ignoreSslVerification = some (reader.readValue (bool ))
676698 of " type" :
677- if remoteType.isSome () :
699+ if remoteType.isSome:
678700 reader.raiseUnexpectedField (" Multiple `type` fields found" ,
679701 " RemoteKeystore" )
680- remoteType = some (reader.readValue (string ))
702+ if version.isNone:
703+ reader.raiseUnexpectedField (
704+ " The `type` field should be specified after the `version` field of the keystore" ,
705+ " RemoteKeystore" )
706+ if version.get < 2 :
707+ reader.raiseUnexpectedField (
708+ " The `type` field is valid only past version 2 of the remote keystore format" ,
709+ " RemoteKeystore" )
710+ let remoteTypeValue = case reader.readValue (string ).toLowerAscii ()
711+ of " web3signer" :
712+ RemoteSignerType .Web3Signer
713+ of " verifying-web3signer" :
714+ RemoteSignerType .VerifyingWeb3Signer
715+ else :
716+ reader.raiseUnexpectedValue (" Unsupported remote signer `type` value" )
717+ remoteType = some remoteTypeValue
718+ of " proven_block_properties" :
719+ if provenBlockProperties.isSome:
720+ reader.raiseUnexpectedField (" Multiple `proven_block_properties` fields found" ,
721+ " RemoteKeystore" )
722+ if version.isNone:
723+ reader.raiseUnexpectedField (
724+ " The `proven_block_properties` field should be specified after the `version` field of the keystore" ,
725+ " RemoteKeystore" )
726+ if version.get < 3 :
727+ reader.raiseUnexpectedField (
728+ " The `proven_block_properties` field is valid only past version 3 of the remote keystore format" ,
729+ " RemoteKeystore" )
730+ if remoteType.isNone:
731+ reader.raiseUnexpectedField (
732+ " The `proven_block_properties` field should be specified after the `type` field of the keystore" ,
733+ " RemoteKeystore" )
734+ if remoteType.get != RemoteSignerType .VerifyingWeb3Signer :
735+ reader.raiseUnexpectedField (
736+ " The `proven_block_properties` field can be specified only when the remote signer type is 'verifying-web3signer'" ,
737+ " RemoteKeystore" )
738+ var provenProperties = reader.readValue (seq [ProvenProperty ])
739+ for prop in provenProperties.mitems:
740+ if prop.path == " .execution_payload.fee_recipient" :
741+ prop.bellatrixIndex = some GeneralizedIndex (401 )
742+ prop.capellaIndex = some GeneralizedIndex (401 )
743+ prop.denebIndex = some GeneralizedIndex (401 )
744+ elif prop.path == " .graffiti" :
745+ prop.bellatrixIndex = some GeneralizedIndex (18 )
746+ prop.capellaIndex = some GeneralizedIndex (18 )
747+ prop.denebIndex = some GeneralizedIndex (18 )
748+ else :
749+ reader.raiseUnexpectedValue (" Keystores with proven properties different than " &
750+ " `.execution_payload.fee_recipient` and `.graffiti` " &
751+ " require a more recent version of Nimbus" )
752+ provenBlockProperties = some provenProperties
681753 of " threshold" :
682- if threshold.isSome () :
754+ if threshold.isSome:
683755 reader.raiseUnexpectedField (" Multiple `threshold` fields found" ,
684756 " RemoteKeystore" )
757+ if version.isNone:
758+ reader.raiseUnexpectedField (
759+ " The `threshold` field should be specified after the `version` field of the keystore" ,
760+ " RemoteKeystore" )
761+ if version.get < 2 :
762+ reader.raiseUnexpectedField (
763+ " The `threshold` field is valid only past version 2 of the remote keystore format" ,
764+ " RemoteKeystore" )
685765 threshold = some (reader.readValue (uint32 ))
686766 else :
687767 # Ignore unknown field names.
688768 discard
689769
690770 if version.isNone ():
691- reader.raiseUnexpectedValue (" Field `version` is missing" )
771+ reader.raiseUnexpectedValue (" The required field `version` is missing" )
692772 if remotes.isNone ():
693773 if remote.isSome and pubkey.isSome:
694774 remotes = some @ [RemoteSignerInfo (
@@ -697,22 +777,27 @@ proc readValue*(reader: var JsonReader, value: var RemoteKeystore)
697777 url: remote.get
698778 )]
699779 else :
700- reader.raiseUnexpectedValue (" Field `remotes` is missing" )
780+ reader.raiseUnexpectedValue (" The required field `remotes` is missing" )
781+
782+ if threshold.isNone:
783+ if remotes.get.len > 1 :
784+ reader.raiseUnexpectedValue (" The `threshold` field must be specified when using distributed keystores" )
785+ else :
786+ if threshold.get.uint64 > remotes.get.lenu64:
787+ reader.raiseUnexpectedValue (" The specified `threshold` must be lower than the number of remote signers" )
788+
701789 if pubkey.isNone ():
702790 reader.raiseUnexpectedValue (" Field `pubkey` is missing" )
703791
704- let keystoreType =
705- if remoteType.isSome ():
706- let res = remoteType.get ()
707- case res.toLowerAscii ()
708- of " web3signer" :
709- RemoteSignerType .Web3Signer
710- of " web3signer-diva" :
711- RemoteSignerType .Web3SignerDiva
712- else :
713- reader.raiseUnexpectedValue (" Unsupported remote signer `type` value" )
714- else :
715- RemoteSignerType .Web3Signer
792+ if version.get >= 3 :
793+ if remoteType.isNone:
794+ reader.raiseUnexpectedValue (" The required field `type` is missing" )
795+ case remoteType.get
796+ of RemoteSignerType .Web3Signer :
797+ discard
798+ of RemoteSignerType .VerifyingWeb3Signer :
799+ if provenBlockProperties.isNone:
800+ reader.raiseUnexpectedValue (" The required field `proven_block_properties` is missing" )
716801
717802 let keystoreFlags =
718803 block :
@@ -721,14 +806,24 @@ proc readValue*(reader: var JsonReader, value: var RemoteKeystore)
721806 res.incl (RemoteKeystoreFlag .IgnoreSSLVerification )
722807 res
723808
724- value = RemoteKeystore (
725- version: 2 'u64 ,
726- pubkey: pubkey.get,
727- description: description,
728- remoteType: keystoreType,
729- remotes: remotes.get,
730- threshold: threshold.get (1 ),
731- )
809+ value = case remoteType.get (RemoteSignerType .Web3Signer )
810+ of RemoteSignerType .Web3Signer :
811+ RemoteKeystore (
812+ version: 2 'u64 ,
813+ pubkey: pubkey.get,
814+ description: description,
815+ remoteType: RemoteSignerType .Web3Signer ,
816+ remotes: remotes.get,
817+ threshold: threshold.get (1 ))
818+ of RemoteSignerType .VerifyingWeb3Signer :
819+ RemoteKeystore (
820+ version: 2 'u64 ,
821+ pubkey: pubkey.get,
822+ description: description,
823+ remoteType: RemoteSignerType .VerifyingWeb3Signer ,
824+ provenBlockProperties: provenBlockProperties.get,
825+ remotes: remotes.get,
826+ threshold: threshold.get (1 ))
732827
733828template writeValue * (w: var JsonWriter ,
734829 value: Pbkdf2Salt | SimpleHexEncodedTypes | Aes128CtrIv ) =
0 commit comments