-
Notifications
You must be signed in to change notification settings - Fork 111
split token driver in two #864 #1399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
3e221d1
split driver in two
adecaro df2d37d
split driver
adecaro 876eb07
more refactoring
adecaro 6c306d3
dlog driver refactoring
adecaro 0fdb8ab
additional refactoring
adecaro bd7f4ed
additional refactoring and example:wq
adecaro da63eca
minor
adecaro c40e2cf
test fix
adecaro File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| # Extending a Validator Driver | ||
|
|
||
| This guide explains how to extend an existing token validator driver with custom validation functions. | ||
| This is useful when you need to enforce additional business rules or compliance checks beyond the default logic provided by the token drivers (e.g., `FabToken` or `ZKAT-DLog`). | ||
|
|
||
| ## Overview | ||
|
|
||
| The Token SDK uses a `ValidatorDriverService` to manage factories for creating `driver.Validator` instances. | ||
| Each driver version is identified by a unique string (e.g., `zkatdlognogh.v1`). | ||
|
|
||
| To extend a validator, you typically: | ||
| 1. Implement a custom `driver.ValidatorDriver` that wraps an existing one. | ||
| 2. Override the `NewValidator` method to inject additional validation logic. | ||
| 3. Register your custom driver factory in the SDK's dependency injection container. | ||
|
|
||
| ## Architecture | ||
|
|
||
| The `ValidatorDriverService` (found in `token/core/service.go`) maintains a map of driver identifiers to `driver.ValidatorDriver` implementations. | ||
|
|
||
| ```go | ||
| type ValidatorDriverService struct { | ||
| *factoryDirectory[driver.ValidatorDriver] | ||
| } | ||
|
|
||
| func (s *ValidatorDriverService) NewValidator(pp driver.PublicParameters) (driver.Validator, error) { | ||
| if driver, ok := s.factories[DriverIdentifierFromPP(pp)]; ok { | ||
| return driver.NewValidator(pp) | ||
| } | ||
| return nil, errors.Errorf("no validator found for token driver [%s]", DriverIdentifierFromPP(pp)) | ||
| } | ||
| ``` | ||
|
|
||
| By providing a custom factory with the same identifier as an existing driver, you can effectively "hijack" the validator creation process. | ||
|
|
||
| ## Example: Extending the ZKAT-DLog Validator | ||
|
|
||
| Suppose you want to add a custom check to all transfer operations in a `ZKAT-DLog` system. | ||
|
|
||
| ### 1. Define your custom validation function | ||
|
|
||
| First, define a function that matches the signature expected by the validator. For `ZKAT-DLog` (NOGH v1), this is `ValidateTransferFunc`. | ||
|
|
||
| ```go | ||
| package myextension | ||
|
|
||
| import ( | ||
| v1 "github.com/hyperledger-labs/fabric-token-sdk/token/core/zkatdlog/nogh/v1/setup" | ||
| "github.com/hyperledger-labs/fabric-token-sdk/token/core/zkatdlog/nogh/v1/token" | ||
| "github.com/hyperledger-labs/fabric-token-sdk/token/core/zkatdlog/nogh/v1/transfer" | ||
| "github.com/hyperledger-labs/fabric-token-sdk/token/core/zkatdlog/nogh/v1/validator" | ||
| "github.com/hyperledger-labs/fabric-token-sdk/token/driver" | ||
| ) | ||
|
|
||
| func MyCustomTransferValidation(ctx validator.Context, tr *transfer.Action) error { | ||
| // Perform your custom validation logic here. | ||
| // For example, check if the transfer metadata contains a specific attribute. | ||
| if len(tr.Metadata) == 0 { | ||
| return errors.New("transfer metadata is missing") | ||
| } | ||
| return nil | ||
| } | ||
| ``` | ||
|
|
||
| ### 2. Create a custom Validator Driver | ||
|
|
||
| Implement the `driver.ValidatorDriver` interface by wrapping the standard one. | ||
|
|
||
| ```go | ||
| type MyValidatorDriver struct { | ||
| driver.ValidatorDriver // Wrap the existing driver | ||
| } | ||
|
|
||
| func (d *MyValidatorDriver) NewValidator(pp driver.PublicParameters) (driver.Validator, error) { | ||
| // We can't easily use the wrapped driver's NewValidator if we want to | ||
| // inject functions into its internal pipeline, so we replicate its logic. | ||
|
|
||
| ppp, ok := pp.(*v1.PublicParams) | ||
| if !ok { | ||
| return nil, errors.Errorf("invalid public parameters type [%T]", pp) | ||
| } | ||
|
|
||
| deserializer, err := driver.NewDeserializer(ppp) // Assume driver is the zkatdlog driver package | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| logger := logging.DriverLoggerFromPP("token-sdk.driver.myextension", string(pp.TokenDriverName())) | ||
|
|
||
| // Instantiate the validator with your custom function | ||
| return validator.New( | ||
| logger, | ||
| ppp, | ||
| deserializer, | ||
| []validator.ValidateTransferFunc{MyCustomTransferValidation}, // Extra transfer validators | ||
| nil, // Extra issuer validators | ||
| nil, // Extra auditor validators | ||
| ), nil | ||
| } | ||
| ``` | ||
|
|
||
| ### 3. Register the extension | ||
|
|
||
| Register your custom factory using the SDK's registration mechanism. If you are using the `dig` container (standard in FSC-based applications), you can provide it to the `token-validator-drivers` group. | ||
|
|
||
| ```go | ||
| func NewMyValidatorDriver() core.NamedFactory[driver.ValidatorDriver] { | ||
| return core.NamedFactory[driver.ValidatorDriver]{ | ||
| Name: core.DriverIdentifier(v1.DLogNoGHDriverName, v1.ProtocolV1), | ||
| Driver: &MyValidatorDriver{ | ||
| // You might need to initialize the wrapped driver here | ||
| }, | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| By using the same `Name` as the original driver, the `ValidatorDriverService` will use your factory instead of the default one. | ||
|
|
||
| ## Alternative: Generic Validator Wrapping | ||
|
|
||
| If you want to add validation that is independent of the driver's internal implementation, you can wrap the `driver.Validator` interface directly. | ||
|
|
||
| ```go | ||
| type WrappedValidator struct { | ||
| driver.Validator | ||
| } | ||
|
|
||
| func (v *WrappedValidator) VerifyTokenRequestFromRaw(ctx context.Context, getState driver.GetStateFnc, anchor driver.TokenRequestAnchor, raw []byte) ([]interface{}, driver.ValidationAttributes, error) { | ||
| // Call the original validator first | ||
| actions, attrs, err := v.Validator.VerifyTokenRequestFromRaw(ctx, getState, anchor, raw) | ||
| if err != nil { | ||
| return nil, nil, err | ||
| } | ||
|
|
||
| // Perform post-validation | ||
| for _, action := range actions { | ||
| if err := myGlobalCheck(action); err != nil { | ||
| return nil, nil, err | ||
| } | ||
| } | ||
|
|
||
| return actions, attrs, nil | ||
| } | ||
| ``` | ||
|
|
||
| This approach is highly portable and works across all token drivers. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.