prysm-pulse/validator/slashing-protection/local/standard-protection-format/export.go
Raul Jordan af0977b8d0
Implement Export Block Proposals (#7964)
* export funcs for proposals

* add failing test

* round trip test passes

* progress

* deepsource

* Update validator/slashing-protection/local/standard-protection-format/export.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* Update validator/slashing-protection/local/standard-protection-format/import.go

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* revert

* empty root

* deep source

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
2020-11-26 04:09:35 +00:00

89 lines
2.5 KiB
Go

package interchangeformat
import (
"context"
"fmt"
"github.com/prysmaticlabs/prysm/validator/db"
)
// ExportStandardProtectionJSON extracts all slashing protection data from a validator database
// and packages it into an EIP-3076 compliant, standard
func ExportStandardProtectionJSON(ctx context.Context, validatorDB db.Database) (*EIPSlashingProtectionFormat, error) {
interchangeJSON := &EIPSlashingProtectionFormat{}
genesisValidatorsRoot, err := validatorDB.GenesisValidatorsRoot(ctx)
if err != nil {
return nil, err
}
genesisRootHex, err := rootToHexString(genesisValidatorsRoot)
if err != nil {
return nil, err
}
interchangeJSON.Metadata.GenesisValidatorsRoot = genesisRootHex
interchangeJSON.Metadata.InterchangeFormatVersion = INTERCHANGE_FORMAT_VERSION
// Extract the existing public keys in our database.
proposedPublicKeys, err := validatorDB.ProposedPublicKeys(ctx)
if err != nil {
return nil, err
}
dataByPubKey := make(map[[48]byte]*ProtectionData)
// Extract the signed proposals by public keys.
for _, pubKey := range proposedPublicKeys {
pubKeyHex, err := pubKeyToHexString(pubKey[:])
if err != nil {
return nil, err
}
signedBlocks, err := getSignedBlocksByPubKey(ctx, validatorDB, pubKey)
if err != nil {
return nil, err
}
dataByPubKey[pubKey] = &ProtectionData{
Pubkey: pubKeyHex,
SignedBlocks: signedBlocks,
SignedAttestations: nil,
}
}
// Next we turn our map into a slice as expected by the EIP-3076 JSON standard.
dataList := make([]*ProtectionData, 0)
for _, item := range dataByPubKey {
dataList = append(dataList, item)
}
interchangeJSON.Data = dataList
return interchangeJSON, nil
}
func getSignedBlocksByPubKey(ctx context.Context, validatorDB db.Database, pubKey [48]byte) ([]*SignedBlock, error) {
lowestSignedSlot, err := validatorDB.LowestSignedProposal(ctx, pubKey)
if err != nil {
return nil, err
}
highestSignedSlot, err := validatorDB.HighestSignedProposal(ctx, pubKey)
if err != nil {
return nil, err
}
signedBlocks := make([]*SignedBlock, 0)
for i := lowestSignedSlot; i <= highestSignedSlot; i++ {
if ctx.Err() != nil {
return nil, ctx.Err()
}
signingRoot, exists, err := validatorDB.ProposalHistoryForSlot(ctx, pubKey, i)
if err != nil {
return nil, err
}
if exists {
signingRootHex, err := rootToHexString(signingRoot[:])
if err != nil {
return nil, err
}
signedBlocks = append(signedBlocks, &SignedBlock{
Slot: fmt.Sprintf("%d", i),
SigningRoot: signingRootHex,
})
}
}
return signedBlocks, nil
}