mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
364 lines
8.9 KiB
Go
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
|
||
|
|
}
|