Files
sonr/x/did/keeper/genesis_enhanced.go
T
Prad NukalaandGitHub 13e6c3e84d Master (#1262)
* clear

* feat: Add everything

* fix: Commenht
2025-10-03 14:45:52 -04:00

364 lines
8.9 KiB
Go

package keeper
import (
"context"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
apiv1 "github.com/sonr-io/sonr/api/did/v1"
"github.com/sonr-io/sonr/x/did/types"
)
// GenesisOrmData holds all ORM table data for genesis import/export
type GenesisOrmData struct {
DidDocuments []*apiv1.DIDDocument
Assertions []*apiv1.Assertion
Controllers []*apiv1.Controller
Authentications []*apiv1.Authentication
DidMetadata []*apiv1.DIDDocumentMetadata
Credentials []*apiv1.VerifiableCredential
Delegations []*apiv1.Delegation
Invocations []*apiv1.Invocation
DidControllers []*apiv1.DIDController
}
// InitGenesisWithORM initializes the module's state from genesis including all ORM tables
// This function handles the ORM data separately from the base GenesisState
func (k *Keeper) InitGenesisWithORM(ctx context.Context, data *types.GenesisState, ormData *GenesisOrmData) error {
// Initialize params first
if err := data.Params.Validate(); err != nil {
return fmt.Errorf("invalid params: %w", err)
}
if err := k.Params.Set(ctx, data.Params); err != nil {
return fmt.Errorf("failed to set params: %w", err)
}
// If no ORM data provided, return early
if ormData == nil {
return nil
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
// Import DID Documents
if ormData.DidDocuments != nil {
for _, doc := range ormData.DidDocuments {
if err := k.OrmDB.DIDDocumentTable().Insert(ctx, doc); err != nil {
sdkCtx.Logger().Error(
"Failed to import DID document",
"did", doc.Id,
"error", err,
)
}
}
}
// Import Assertions
if ormData.Assertions != nil {
for _, assertion := range ormData.Assertions {
if err := k.OrmDB.AssertionTable().Insert(ctx, assertion); err != nil {
sdkCtx.Logger().Error(
"Failed to import assertion",
"did", assertion.Did,
"error", err,
)
}
}
}
// Import Controllers
if ormData.Controllers != nil {
for _, controller := range ormData.Controllers {
if err := k.OrmDB.ControllerTable().Insert(ctx, controller); err != nil {
sdkCtx.Logger().Error(
"Failed to import controller",
"did", controller.Did,
"error", err,
)
}
}
}
// Import Authentications
if ormData.Authentications != nil {
for _, auth := range ormData.Authentications {
if err := k.OrmDB.AuthenticationTable().Insert(ctx, auth); err != nil {
sdkCtx.Logger().Error(
"Failed to import authentication",
"did", auth.Did,
"error", err,
)
}
}
}
// Import DID Document Metadata
if ormData.DidMetadata != nil {
for _, metadata := range ormData.DidMetadata {
if err := k.OrmDB.DIDDocumentMetadataTable().Insert(ctx, metadata); err != nil {
sdkCtx.Logger().Error(
"Failed to import DID metadata",
"did", metadata.Did,
"error", err,
)
}
}
}
// Import Verifiable Credentials
if ormData.Credentials != nil {
for _, cred := range ormData.Credentials {
if err := k.OrmDB.VerifiableCredentialTable().Insert(ctx, cred); err != nil {
sdkCtx.Logger().Error(
"Failed to import credential",
"id", cred.Id,
"error", err,
)
}
}
}
sdkCtx.Logger().Info(
"Genesis import completed",
"did_documents", len(ormData.DidDocuments),
"assertions", len(ormData.Assertions),
"controllers", len(ormData.Controllers),
"authentications", len(ormData.Authentications),
"credentials", len(ormData.Credentials),
)
return nil
}
// ExportGenesisWithORM exports the module's complete state to genesis
func (k *Keeper) ExportGenesisWithORM(ctx context.Context) (*types.GenesisState, *GenesisOrmData, error) {
params, err := k.Params.Get(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to get params: %w", err)
}
genesis := &types.GenesisState{
Params: params,
}
ormData := &GenesisOrmData{}
// Export DID Documents
didDocs, err := k.exportDIDDocuments(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to export DID documents: %w", err)
}
ormData.DidDocuments = didDocs
// Export Assertions
assertions, err := k.exportAssertions(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to export assertions: %w", err)
}
ormData.Assertions = assertions
// Export Controllers
controllers, err := k.exportControllers(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to export controllers: %w", err)
}
ormData.Controllers = controllers
// Export Authentications
auths, err := k.exportAuthentications(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to export authentications: %w", err)
}
ormData.Authentications = auths
// Export DID Metadata
metadata, err := k.exportDIDMetadata(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to export DID metadata: %w", err)
}
ormData.DidMetadata = metadata
// Export Verifiable Credentials
creds, err := k.exportCredentials(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to export credentials: %w", err)
}
ormData.Credentials = creds
return genesis, ormData, nil
}
// Helper functions for exporting each table
func (k *Keeper) exportDIDDocuments(ctx context.Context) ([]*apiv1.DIDDocument, error) {
var documents []*apiv1.DIDDocument
iter, err := k.OrmDB.DIDDocumentTable().List(ctx, apiv1.DIDDocumentPrimaryKey{})
if err != nil {
return nil, err
}
defer iter.Close()
for iter.Next() {
doc, err := iter.Value()
if err != nil {
return nil, err
}
documents = append(documents, doc)
}
return documents, nil
}
func (k *Keeper) exportAssertions(ctx context.Context) ([]*apiv1.Assertion, error) {
var assertions []*apiv1.Assertion
iter, err := k.OrmDB.AssertionTable().List(ctx, apiv1.AssertionPrimaryKey{})
if err != nil {
return nil, err
}
defer iter.Close()
for iter.Next() {
assertion, err := iter.Value()
if err != nil {
return nil, err
}
assertions = append(assertions, assertion)
}
return assertions, nil
}
func (k *Keeper) exportControllers(ctx context.Context) ([]*apiv1.Controller, error) {
var controllers []*apiv1.Controller
iter, err := k.OrmDB.ControllerTable().List(ctx, apiv1.ControllerPrimaryKey{})
if err != nil {
return nil, err
}
defer iter.Close()
for iter.Next() {
controller, err := iter.Value()
if err != nil {
return nil, err
}
controllers = append(controllers, controller)
}
return controllers, nil
}
func (k *Keeper) exportAuthentications(ctx context.Context) ([]*apiv1.Authentication, error) {
var auths []*apiv1.Authentication
iter, err := k.OrmDB.AuthenticationTable().List(ctx, apiv1.AuthenticationPrimaryKey{})
if err != nil {
return nil, err
}
defer iter.Close()
for iter.Next() {
auth, err := iter.Value()
if err != nil {
return nil, err
}
auths = append(auths, auth)
}
return auths, nil
}
func (k *Keeper) exportDIDMetadata(ctx context.Context) ([]*apiv1.DIDDocumentMetadata, error) {
var metadata []*apiv1.DIDDocumentMetadata
iter, err := k.OrmDB.DIDDocumentMetadataTable().List(ctx, apiv1.DIDDocumentMetadataPrimaryKey{})
if err != nil {
return nil, err
}
defer iter.Close()
for iter.Next() {
meta, err := iter.Value()
if err != nil {
return nil, err
}
metadata = append(metadata, meta)
}
return metadata, nil
}
func (k *Keeper) exportCredentials(ctx context.Context) ([]*apiv1.VerifiableCredential, error) {
var credentials []*apiv1.VerifiableCredential
iter, err := k.OrmDB.VerifiableCredentialTable().List(ctx, apiv1.VerifiableCredentialPrimaryKey{})
if err != nil {
return nil, err
}
defer iter.Close()
for iter.Next() {
cred, err := iter.Value()
if err != nil {
return nil, err
}
credentials = append(credentials, cred)
}
return credentials, nil
}
// ValidateGenesisOrmData validates the ORM data for consistency
func ValidateGenesisOrmData(ormData *GenesisOrmData) error {
if ormData == nil {
return nil
}
// Check for duplicate DIDs
didSet := make(map[string]bool)
for _, doc := range ormData.DidDocuments {
if didSet[doc.Id] {
return fmt.Errorf("duplicate DID document: %s", doc.Id)
}
didSet[doc.Id] = true
}
// Check for duplicate assertions (controller+subject must be unique)
assertionSet := make(map[string]bool)
for _, assertion := range ormData.Assertions {
key := fmt.Sprintf("%s:%s", assertion.Controller, assertion.Subject)
if assertionSet[key] {
return fmt.Errorf("duplicate assertion for controller=%s, subject=%s",
assertion.Controller, assertion.Subject)
}
assertionSet[key] = true
}
// Check for duplicate controllers (address must be unique)
addressSet := make(map[string]bool)
for _, controller := range ormData.Controllers {
if addressSet[controller.Address] {
return fmt.Errorf("duplicate controller address: %s", controller.Address)
}
addressSet[controller.Address] = true
}
return nil
}
// isValidDerivedDID checks if a DID is a valid derived DID (email/tel)
func isValidDerivedDID(did string) bool {
// Check for email or tel DIDs
if len(did) > 10 {
prefix := did[:10]
if prefix == "did:email:" || len(did) > 8 && did[:8] == "did:tel:" {
return true
}
}
return false
}