diff --git a/token/core/common/interop/htlc/validator_htlc.go b/token/core/common/interop/htlc/validator_htlc.go index f86097e88..b067a304b 100644 --- a/token/core/common/interop/htlc/validator_htlc.go +++ b/token/core/common/interop/htlc/validator_htlc.go @@ -18,7 +18,7 @@ import ( ) // TransferHTLCValidate checks the validity of the HTLC scripts, if any -func TransferHTLCValidate[P driver.PublicParameters, T driver.Output, TA driver.TransferAction, IA driver.IssueAction](ctx *common.Context[P, T, TA, IA]) error { +func TransferHTLCValidate[P driver.PublicParameters, T driver.Output, TA driver.TransferAction, IA driver.IssueAction, DS driver.Deserializer](ctx *common.Context[P, T, TA, IA, DS]) error { now := time.Now() for i, in := range ctx.InputTokens { diff --git a/token/core/common/interop/pledge/validator_pledge.go b/token/core/common/interop/pledge/validator_pledge.go index 5854a5f20..ff0c5eba3 100644 --- a/token/core/common/interop/pledge/validator_pledge.go +++ b/token/core/common/interop/pledge/validator_pledge.go @@ -19,14 +19,14 @@ import ( "github.com/pkg/errors" ) -func IssuePledgeValidate[P driver.PublicParameters, T driver.Output, TA driver.TransferAction, IA driver.IssueAction](ctx *common.Context[P, T, TA, IA]) error { +func IssuePledgeValidate[P driver.PublicParameters, T driver.Output, TA driver.TransferAction, IA driver.IssueAction, DS driver.Deserializer](ctx *common.Context[P, T, TA, IA, DS]) error { for k := range ctx.IssueAction.GetMetadata() { ctx.CountMetadataKey(k) } return nil } -func TransferPledgeValidate[P driver.PublicParameters, T driver.Output, TA driver.TransferAction, IA driver.IssueAction](ctx *common.Context[P, T, TA, IA]) error { +func TransferPledgeValidate[P driver.PublicParameters, T driver.Output, TA driver.TransferAction, IA driver.IssueAction, DS driver.Deserializer](ctx *common.Context[P, T, TA, IA, DS]) error { for _, in := range ctx.InputTokens { id, err := identity.UnmarshalTypedIdentity(in.GetOwner()) if err != nil { diff --git a/token/core/fabtoken/driver/interop/state/fabric/state.go b/token/core/fabtoken/driver/interop/state/fabric/state.go index ec838319e..eee64577f 100644 --- a/token/core/fabtoken/driver/interop/state/fabric/state.go +++ b/token/core/fabtoken/driver/interop/state/fabric/state.go @@ -7,10 +7,7 @@ SPDX-License-Identifier: Apache-2.0 package fabric import ( - "encoding/base64" "encoding/json" - "strings" - "time" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric" "github.com/hyperledger-labs/fabric-token-sdk/token/core/common" @@ -18,241 +15,21 @@ import ( "github.com/hyperledger-labs/fabric-token-sdk/token/core/fabtoken" "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity" "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/pledge" - "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/state" - "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/state/driver" fabric3 "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/state/fabric" - "github.com/hyperledger-labs/fabric-token-sdk/token/services/network/common/rws/keys" - "github.com/hyperledger-labs/fabric-token-sdk/token/services/network/common/rws/translator" - "github.com/hyperledger-labs/fabric-token-sdk/token/services/network/fabric/tcc" + "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/state/fabric/core" "github.com/hyperledger-labs/fabric-token-sdk/token/token" "github.com/pkg/errors" "go.uber.org/dig" ) -type PledgeVault interface { - PledgeByTokenID(tokenID *token.ID) ([]*pledge.Info, error) -} - -type GetFabricNetworkServiceFunc = func(string) (*fabric.NetworkService, error) - -type StateQueryExecutor struct { - Logger logging.Logger - RelayProvider fabric3.RelayProvider - TargetNetworkURL string - RelaySelector *fabric.NetworkService -} - -func NewStateQueryExecutor( - Logger logging.Logger, - RelayProvider fabric3.RelayProvider, - targetNetworkURL string, - relaySelector *fabric.NetworkService, -) (*StateQueryExecutor, error) { - if err := fabric3.CheckFabricScheme(targetNetworkURL); err != nil { - return nil, err - } - return &StateQueryExecutor{ - Logger: Logger, - RelayProvider: RelayProvider, - TargetNetworkURL: targetNetworkURL, - RelaySelector: relaySelector, - }, nil -} - -func (p *StateQueryExecutor) Exist(tokenID *token.ID) ([]byte, error) { - raw, err := json.Marshal(tokenID) - if err != nil { - return nil, errors.Wrapf(err, "failed marshalling tokenID") - } +type Validator struct{} - // get local relay - relay := p.RelayProvider.Relay(p.RelaySelector) - - // Query - p.Logger.Debugf("Query [%s] for proof of existence of token [%s], input [%s]", p.TargetNetworkURL, tokenID.String(), base64.StdEncoding.EncodeToString(raw)) - query, err := relay.ToFabric().Query( - p.TargetNetworkURL, - tcc.ProofOfTokenExistenceQuery, - base64.StdEncoding.EncodeToString(raw), - ) - if err != nil { - return nil, errors.Wrapf(err, "failed querying token") - } - res, err := query.Call() - if err != nil { - // todo: move this to the query executor - errMsg := err.Error() - switch { - case strings.Contains(errMsg, "failed to confirm if token with ID"): - return nil, errors.WithMessagef(state.TokenDoesNotExistError, "%s", err) - default: - return nil, err - } - } - - return res.Proof() -} - -func (p *StateQueryExecutor) DoesNotExist(tokenID *token.ID, origin string, deadline time.Time) ([]byte, error) { - req := &tcc.ProofOfTokenNonExistenceRequest{ - Deadline: deadline, - OriginNetwork: origin, - TokenID: tokenID, - } - raw, err := json.Marshal(req) - if err != nil { - return nil, errors.Wrapf(err, "failed marshalling tokenID") - } - - // get local relay - relay := p.RelayProvider.Relay(p.RelaySelector) - - // Query - p.Logger.Debugf("Query [%s] for proof of non-existence of token [%s], input [%s]", p.TargetNetworkURL, tokenID.String(), base64.StdEncoding.EncodeToString(raw)) - query, err := relay.ToFabric().Query( - p.TargetNetworkURL, - tcc.ProofOfTokenNonExistenceQuery, - base64.StdEncoding.EncodeToString(raw), - ) - if err != nil { - return nil, errors.Wrapf(err, "failed querying token") - } - res, err := query.Call() - if err != nil { - errMsg := err.Error() - switch { - case strings.Contains(errMsg, "failed to confirm if token from network"): - return nil, errors.WithMessagef(state.TokenExistsError, "%s", err) - default: - return nil, err - } - } - - return res.Proof() -} - -// ExistsWithMetadata returns a proof that a token with metadata including the passed token ID and origin network exists -// in the network this query executor targets -func (p *StateQueryExecutor) ExistsWithMetadata(tokenID *token.ID, origin string) ([]byte, error) { - req := &tcc.ProofOfTokenMetadataExistenceRequest{ - OriginNetwork: origin, - TokenID: tokenID, - } - raw, err := json.Marshal(req) - if err != nil { - return nil, errors.Wrapf(err, "failed to marshal proof of token metadata [%s]", req) - } - - // Get local relay - relay := p.RelayProvider.Relay(p.RelaySelector) - - // Query - p.Logger.Debugf("Query [%s] for proof of existence of metadata with token [%s], input [%s]", p.TargetNetworkURL, tokenID.String(), base64.StdEncoding.EncodeToString(raw)) - query, err := relay.ToFabric().Query( - p.TargetNetworkURL, - tcc.ProofOfTokenMetadataExistenceQuery, - base64.StdEncoding.EncodeToString(raw), - ) - if err != nil { - return nil, errors.Wrapf(err, "failed to query proof of metadata [%s]", req) - } - res, err := query.Call() - if err != nil { - errMsg := err.Error() - switch { - case strings.Contains(errMsg, "failed to confirm if token from network"): - return nil, errors.WithMessagef(state.TokenExistsError, "%s", err) - default: - return nil, err - } - } - - return res.Proof() -} - -type StateVerifier struct { - Logger logging.Logger - RelayProvider fabric3.RelayProvider - NetworkURL string - RelaySelector *fabric.NetworkService - PledgeVault PledgeVault - GetFabricNetworkService GetFabricNetworkServiceFunc -} - -func NewStateVerifier( - Logger logging.Logger, - relayProvider fabric3.RelayProvider, - PledgeVault PledgeVault, - GetFabricNetworkService GetFabricNetworkServiceFunc, - networkURL string, - relaySelector *fabric.NetworkService, -) (*StateVerifier, error) { - if err := fabric3.CheckFabricScheme(networkURL); err != nil { - return nil, err - } - return &StateVerifier{ - Logger: Logger, - RelayProvider: relayProvider, - NetworkURL: networkURL, - RelaySelector: relaySelector, - PledgeVault: PledgeVault, - GetFabricNetworkService: GetFabricNetworkService, - }, nil -} - -func (v *StateVerifier) VerifyProofExistence(proofRaw []byte, tokenID *token.ID, metadata []byte) error { - // Get local relay - relay := v.RelayProvider.Relay(v.RelaySelector) - - // Parse proof - proof, err := relay.ToFabric().ProofFromBytes(proofRaw) - if err != nil { - return errors.Wrapf(err, "failed to unmarshal claim proof") - } - if err := proof.Verify(); err != nil { - return errors.Wrapf(err, "failed to verify pledge proof") - } - - // todo check that address in proof matches source network - - rwset, err := proof.RWSet() - if err != nil { - return errors.Wrapf(err, "failed to unmarshal claim proof") - } - - key, err := keys.CreateProofOfExistenceKey(tokenID) - if err != nil { - return errors.Wrapf(err, "failed to create proof of existence key from token [%s]", tokenID) - } - tmsID, err := fabric3.FabricURLToTMSID(v.NetworkURL) - if err != nil { - return errors.Wrapf(err, "failed to extract tms id from [%s]", v.NetworkURL) - } - raw, err := rwset.GetState(tmsID.Namespace, key) - if err != nil { - return errors.Wrapf(err, "failed to get state for token [%s:%s]", tmsID.Namespace, key) - } - if len(raw) == 0 { - return errors.Errorf("token [%s:%s] does not contain proof", tmsID.Namespace, key) - } +func (v *Validator) Validate(tokRaw []byte, info *pledge.Info) error { tok := &token.Token{} - err = json.Unmarshal(raw, tok) - if err != nil { - return errors.Wrapf(err, "failed to unmarshal token [%s]", common.Hashable(raw)) - } - // Validate against pledge - v.Logger.Debugf("verify proof of existence for token id [%s]", tokenID) - pledges, err := v.PledgeVault.PledgeByTokenID(tokenID) + err := json.Unmarshal(tokRaw, tok) if err != nil { - v.Logger.Errorf("failed retrieving pledge info for token id [%s]: [%s]", tokenID, err) - return errors.WithMessagef(err, "failed getting pledge for [%s]", tokenID) - } - if len(pledges) != 1 { - v.Logger.Errorf("failed retrieving pledge info for token id [%s]: no info found", tokenID) - return errors.Errorf("expected one pledge, got [%d]", len(pledges)) + return errors.Wrapf(err, "failed to unmarshal token [%s]", common.Hashable(tokRaw)) } - info := pledges[0] - v.Logger.Debugf("found pledge info for token id [%s]: [%s]", tokenID, info.Source) if tok.Type != info.TokenType { return errors.Errorf("type of pledge token does not match type in claim request") @@ -267,7 +44,7 @@ func (v *StateVerifier) VerifyProofExistence(proofRaw []byte, tokenID *token.ID, } owner, err := identity.UnmarshalTypedIdentity(tok.Owner.Raw) if err != nil { - return errors.Wrapf(err, "failed to unmarshal owner of token [%s]", tokenID) + return errors.Wrapf(err, "failed to unmarshal owner of token [%s]", common.Hashable(tokRaw)) } if owner.Type != pledge.ScriptType { return err @@ -275,7 +52,7 @@ func (v *StateVerifier) VerifyProofExistence(proofRaw []byte, tokenID *token.ID, script := &pledge.Script{} err = json.Unmarshal(owner.Identity, script) if err != nil { - return errors.Wrapf(err, "failed to unmarshal pledge script [%s]", tokenID) + return errors.Wrapf(err, "failed to unmarshal pledge script [%s]", common.Hashable(tokRaw)) } if script.Recipient == nil { return errors.Errorf("script in proof encodes invalid recipient") @@ -293,143 +70,6 @@ func (v *StateVerifier) VerifyProofExistence(proofRaw []byte, tokenID *token.ID, return nil } -func (v *StateVerifier) VerifyProofNonExistence(proofRaw []byte, tokenID *token.ID, origin string, deadline time.Time) error { - // v.NetworkURL is the network from which the proof comes from - tokenOriginNetworkTMSID, err := fabric3.FabricURLToTMSID(origin) - if err != nil { - return errors.Wrapf(err, "failed to parse network url") - } - // get local relay - fns, err := v.GetFabricNetworkService(tokenOriginNetworkTMSID.Network) - if err != nil { - return errors.Wrapf(err, "failed to get fabric network service for network [%s]", tokenOriginNetworkTMSID.Network) - } - relay := v.RelayProvider.Relay(fns) - - // parse proof - proof, err := relay.ToFabric().ProofFromBytes(proofRaw) - if err != nil { - return errors.Wrapf(err, "failed to umarshal proof") - } - - rwset, err := proof.RWSet() - if err != nil { - return errors.Wrapf(err, "failed to retrieve RWset") - } - - key, err := keys.CreateProofOfNonExistenceKey(tokenID, origin) - if err != nil { - return errors.Wrapf(err, "failed creating key for proof of non-existence") - } - - proofSourceNetworkTMSID, err := fabric3.FabricURLToTMSID(v.NetworkURL) - if err != nil { - return err - } - raw, err := rwset.GetState(proofSourceNetworkTMSID.Namespace, key) - if err != nil { - return errors.Wrapf(err, "failed to check proof of non-existence") - } - p := &translator.ProofOfTokenMetadataNonExistence{} - if raw == nil { - return errors.Errorf("could not find proof of non-existence") - } - err = json.Unmarshal(raw, p) - if err != nil { - return errors.Wrapf(err, "failed to unmarshal proof of non-existence") - } - if p.Deadline != deadline { - return errors.Errorf("deadline in reclaim request does not match deadline in proof of non-existence") - } - if p.TokenID.String() != tokenID.String() { - return errors.Errorf("token ID in reclaim request does not match token ID in proof of non-existence") - } - if p.Origin != fabric3.FabricURL(tokenOriginNetworkTMSID) { - return errors.Errorf("origin in reclaim request does not match origin in proof of non-existence") - } - - // todo check that address in proof is the destination network - - err = proof.Verify() - if err != nil { - return errors.Wrapf(err, "invalid proof of non-existence") - } - - return nil -} - -// VerifyProofTokenWithMetadataExistence verifies that a proof of existence of a token -// with metadata including the given token ID and origin network, in the target network is valid -func (v *StateVerifier) VerifyProofTokenWithMetadataExistence(proofRaw []byte, tokenID *token.ID, origin string) error { - // v.NetworkURL is the network from which the proof comes from - tokenOriginNetworkTMSID, err := fabric3.FabricURLToTMSID(origin) - if err != nil { - return errors.Wrapf(err, "failed to parse network url") - } - - // get local relay - fns, err := v.GetFabricNetworkService(tokenOriginNetworkTMSID.Network) - if err != nil { - return errors.Wrapf(err, "failed to get fabric network service for network [%s]", tokenOriginNetworkTMSID.Network) - } - relay := v.RelayProvider.Relay(fns) - - // parse proof - proof, err := relay.ToFabric().ProofFromBytes(proofRaw) - if err != nil { - return errors.Wrapf(err, "failed to umarshal proof") - } - - rwset, err := proof.RWSet() - if err != nil { - return errors.Wrapf(err, "failed to retrieve RWset") - } - - key, err := keys.CreateProofOfMetadataExistenceKey(tokenID, origin) - if err != nil { - return errors.Wrapf(err, "failed creating key for proof of token existence") - } - - proofSourceNetworkTMSID, err := fabric3.FabricURLToTMSID(v.NetworkURL) - if err != nil { - return err - } - raw, err := rwset.GetState(proofSourceNetworkTMSID.Namespace, key) - if err != nil { - return errors.Wrapf(err, "failed to check proof of token existence") - } - p := &translator.ProofOfTokenMetadataExistence{} - if raw == nil { - return errors.Errorf("could not find proof of token existence") - } - err = json.Unmarshal(raw, p) - if err != nil { - return errors.Wrapf(err, "failed to unmarshal proof of token existence") - } - if p.TokenID.String() != tokenID.String() { - return errors.Errorf("token ID in redeem request does not match token ID in proof of token existence") - } - if p.Origin != fabric3.FabricURL(tokenOriginNetworkTMSID) { - return errors.Errorf("origin in redeem request does not match origin in proof of token existence") - } - - // todo check that address in proof is the destination network - - err = proof.Verify() - if err != nil { - return errors.Wrapf(err, "invalid proof of token existence") - } - - return nil -} - -type StateDriver struct { - Logger logging.Logger - FNSProvider *fabric.NetworkServiceProvider - RelayProvider fabric3.RelayProvider - VaultStore *pledge.VaultStore -} - func NewStateDriver(in struct { dig.In FNSProvider *fabric.NetworkServiceProvider @@ -438,37 +78,12 @@ func NewStateDriver(in struct { }) fabric3.NamedStateDriver { return fabric3.NamedStateDriver{ Name: fabtoken.PublicParameters, - Driver: &StateDriver{ - Logger: logging.MustGetLogger("token-sdk.core.fabtoken"), - FNSProvider: in.FNSProvider, - RelayProvider: in.RelayProvider, - VaultStore: in.VaultStore, - }, - } -} - -func (d *StateDriver) NewStateQueryExecutor(url string) (driver.StateQueryExecutor, error) { - fns, err := d.FNSProvider.FabricNetworkService("") - if err != nil { - return nil, errors.Wrapf(err, "failed to get default FNS") - } - - return NewStateQueryExecutor(d.Logger, d.RelayProvider, url, fns) -} - -func (d *StateDriver) NewStateVerifier(url string) (driver.StateVerifier, error) { - fns, err := d.FNSProvider.FabricNetworkService("") - if err != nil { - return nil, errors.Wrapf(err, "failed to get default FNS") + Driver: core.NewStateDriver( + logging.MustGetLogger("token-sdk.core.fabtoken"), + in.FNSProvider, + in.RelayProvider, + in.VaultStore, + &Validator{}, + ), } - return NewStateVerifier( - d.Logger, - d.RelayProvider, - d.VaultStore, - func(id string) (*fabric.NetworkService, error) { - return d.FNSProvider.FabricNetworkService(id) - }, - url, - fns, - ) } diff --git a/token/core/fabtoken/validator.go b/token/core/fabtoken/validator.go index 6cbfb0073..e439d9739 100644 --- a/token/core/fabtoken/validator.go +++ b/token/core/fabtoken/validator.go @@ -50,14 +50,14 @@ func NewValidator(logger logging.Logger, pp *PublicParams, deserializer driver.D transferValidators := []ValidateTransferFunc{ TransferSignatureValidate, TransferBalanceValidate, - htlc.TransferHTLCValidate[*PublicParams, *Output, *TransferAction, *IssueAction], - pledge.TransferPledgeValidate[*PublicParams, *Output, *TransferAction, *IssueAction], + htlc.TransferHTLCValidate[*PublicParams, *Output, *TransferAction, *IssueAction, driver.Deserializer], + pledge.TransferPledgeValidate[*PublicParams, *Output, *TransferAction, *IssueAction, driver.Deserializer], } transferValidators = append(transferValidators, extraValidators...) issueValidators := []ValidateIssueFunc{ IssueValidate, - pledge.IssuePledgeValidate[*PublicParams, *Output, *TransferAction, *IssueAction], + pledge.IssuePledgeValidate[*PublicParams, *Output, *TransferAction, *IssueAction, driver.Deserializer], } return common.NewValidator[*PublicParams, *Output, *TransferAction, *IssueAction, driver.Deserializer]( diff --git a/token/core/zkatdlog/crypto/validator/validator.go b/token/core/zkatdlog/crypto/validator/validator.go index 1ec1784e2..b5d6c2ddd 100644 --- a/token/core/zkatdlog/crypto/validator/validator.go +++ b/token/core/zkatdlog/crypto/validator/validator.go @@ -54,14 +54,14 @@ func New(logger logging.Logger, pp *crypto.PublicParams, deserializer driver.Des transferValidators := []ValidateTransferFunc{ TransferSignatureValidate, TransferZKProofValidate, - htlc.TransferHTLCValidate[*crypto.PublicParams, *token.Token, *transfer.Action, *issue.IssueAction], - pledge.TransferPledgeValidate[*crypto.PublicParams, *token.Token, *transfer.Action, *issue.IssueAction], + htlc.TransferHTLCValidate[*crypto.PublicParams, *token.Token, *transfer.Action, *issue.IssueAction, driver.Deserializer], + pledge.TransferPledgeValidate[*crypto.PublicParams, *token.Token, *transfer.Action, *issue.IssueAction, driver.Deserializer], } transferValidators = append(transferValidators, extraValidators...) issueValidators := []ValidateIssueFunc{ IssueValidate, - pledge.IssuePledgeValidate[*crypto.PublicParams, *token.Token, *transfer.Action, *issue.IssueAction], + pledge.IssuePledgeValidate[*crypto.PublicParams, *token.Token, *transfer.Action, *issue.IssueAction, driver.Deserializer], } return common.NewValidator[*crypto.PublicParams, *token.Token, *transfer.Action, *issue.IssueAction, driver.Deserializer]( diff --git a/token/core/zkatdlog/nogh/driver/interop/state/fabric/state.go b/token/core/zkatdlog/nogh/driver/interop/state/fabric/state.go index eea6b1d40..e76c949e8 100644 --- a/token/core/zkatdlog/nogh/driver/interop/state/fabric/state.go +++ b/token/core/zkatdlog/nogh/driver/interop/state/fabric/state.go @@ -7,389 +7,64 @@ SPDX-License-Identifier: Apache-2.0 package fabric import ( - "encoding/base64" - "encoding/json" - "strings" - "time" - "github.com/hyperledger-labs/fabric-smart-client/platform/fabric" "github.com/hyperledger-labs/fabric-token-sdk/token/core/common/logging" "github.com/hyperledger-labs/fabric-token-sdk/token/core/zkatdlog/crypto" "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/pledge" - "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/state" - "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/state/driver" fabric3 "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/state/fabric" - "github.com/hyperledger-labs/fabric-token-sdk/token/services/network/common/rws/keys" - "github.com/hyperledger-labs/fabric-token-sdk/token/services/network/common/rws/translator" - "github.com/hyperledger-labs/fabric-token-sdk/token/services/network/fabric/tcc" - "github.com/hyperledger-labs/fabric-token-sdk/token/token" - "github.com/pkg/errors" + "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/state/fabric/core" "go.uber.org/dig" ) -type PledgeVault interface { - PledgeByTokenID(tokenID *token.ID) ([]*pledge.Info, error) -} - -type GetFabricNetworkServiceFunc = func(string) (*fabric.NetworkService, error) - -type StateQueryExecutor struct { - Logger logging.Logger - RelayProvider fabric3.RelayProvider - TargetNetworkURL string - RelaySelector *fabric.NetworkService -} - -func NewStateQueryExecutor( - Logger logging.Logger, - RelayProvider fabric3.RelayProvider, - targetNetworkURL string, - relaySelector *fabric.NetworkService, -) (*StateQueryExecutor, error) { - if err := fabric3.CheckFabricScheme(targetNetworkURL); err != nil { - return nil, err - } - return &StateQueryExecutor{ - Logger: Logger, - RelayProvider: RelayProvider, - TargetNetworkURL: targetNetworkURL, - RelaySelector: relaySelector, - }, nil -} - -func (p *StateQueryExecutor) Exist(tokenID *token.ID) ([]byte, error) { - raw, err := json.Marshal(tokenID) - if err != nil { - return nil, errors.Wrapf(err, "failed marshalling tokenID") - } - - // get local relay - relay := p.RelayProvider.Relay(p.RelaySelector) - - // Query - p.Logger.Debugf("Query [%s] for proof of existence of token [%s], input [%s]", p.TargetNetworkURL, tokenID.String(), base64.StdEncoding.EncodeToString(raw)) - query, err := relay.ToFabric().Query( - p.TargetNetworkURL, - tcc.ProofOfTokenExistenceQuery, - base64.StdEncoding.EncodeToString(raw), - ) - if err != nil { - return nil, errors.Wrapf(err, "failed querying token") - } - res, err := query.Call() - if err != nil { - // todo: move this to the query executor - errMsg := err.Error() - switch { - case strings.Contains(errMsg, "failed to confirm if token with ID"): - return nil, errors.WithMessagef(state.TokenDoesNotExistError, "%s", err) - default: - return nil, err - } - } - - return res.Proof() -} - -func (p *StateQueryExecutor) DoesNotExist(tokenID *token.ID, origin string, deadline time.Time) ([]byte, error) { - req := &tcc.ProofOfTokenNonExistenceRequest{ - Deadline: deadline, - OriginNetwork: origin, - TokenID: tokenID, - } - raw, err := json.Marshal(req) - if err != nil { - return nil, errors.Wrapf(err, "failed marshalling tokenID") - } - - // get local relay - relay := p.RelayProvider.Relay(p.RelaySelector) - - // Query - p.Logger.Debugf("Query [%s] for proof of non-existence of token [%s], input [%s]", p.TargetNetworkURL, tokenID.String(), base64.StdEncoding.EncodeToString(raw)) - query, err := relay.ToFabric().Query( - p.TargetNetworkURL, - tcc.ProofOfTokenNonExistenceQuery, - base64.StdEncoding.EncodeToString(raw), - ) - if err != nil { - return nil, errors.Wrapf(err, "failed querying token") - } - res, err := query.Call() - if err != nil { - errMsg := err.Error() - switch { - case strings.Contains(errMsg, "failed to confirm if token from network"): - return nil, errors.WithMessagef(state.TokenExistsError, "%s", err) - default: - return nil, err - } - } - - return res.Proof() -} - -// ExistsWithMetadata returns a proof that a token with metadata including the passed token ID and origin network exists -// in the network this query executor targets -func (p *StateQueryExecutor) ExistsWithMetadata(tokenID *token.ID, origin string) ([]byte, error) { - req := &tcc.ProofOfTokenMetadataExistenceRequest{ - OriginNetwork: origin, - TokenID: tokenID, - } - raw, err := json.Marshal(req) - if err != nil { - return nil, errors.Wrapf(err, "failed to marshal proof of token metadata [%s]", req) - } - - // Get local relay - relay := p.RelayProvider.Relay(p.RelaySelector) - - // Query - p.Logger.Debugf("Query [%s] for proof of existence of metadata with token [%s], input [%s]", p.TargetNetworkURL, tokenID.String(), base64.StdEncoding.EncodeToString(raw)) - query, err := relay.ToFabric().Query( - p.TargetNetworkURL, - tcc.ProofOfTokenMetadataExistenceQuery, - base64.StdEncoding.EncodeToString(raw), - ) - if err != nil { - return nil, errors.Wrapf(err, "failed to query proof of metadata [%s]", req) - } - res, err := query.Call() - if err != nil { - errMsg := err.Error() - switch { - case strings.Contains(errMsg, "failed to confirm if token from network"): - return nil, errors.WithMessagef(state.TokenExistsError, "%s", err) - default: - return nil, err - } - } - - return res.Proof() -} - -type StateVerifier struct { - Logger logging.Logger - RelayProvider fabric3.RelayProvider - NetworkURL string - RelaySelector *fabric.NetworkService - PledgeVault PledgeVault - GetFabricNetworkService GetFabricNetworkServiceFunc -} - -func NewStateVerifier( - Logger logging.Logger, - relayProvider fabric3.RelayProvider, - PledgeVault PledgeVault, - GetFabricNetworkService GetFabricNetworkServiceFunc, - networkURL string, - relaySelector *fabric.NetworkService, -) (*StateVerifier, error) { - if err := fabric3.CheckFabricScheme(networkURL); err != nil { - return nil, err - } - return &StateVerifier{ - Logger: Logger, - RelayProvider: relayProvider, - NetworkURL: networkURL, - RelaySelector: relaySelector, - PledgeVault: PledgeVault, - GetFabricNetworkService: GetFabricNetworkService, - }, nil -} - -func (v *StateVerifier) VerifyProofExistence(proofRaw []byte, tokenID *token.ID, metadata []byte) error { - // Get local relay - relay := v.RelayProvider.Relay(v.RelaySelector) - - // Parse proof - proof, err := relay.ToFabric().ProofFromBytes(proofRaw) - if err != nil { - return errors.Wrapf(err, "failed to unmarshal claim proof") - } - if err := proof.Verify(); err != nil { - return errors.Wrapf(err, "failed to verify pledge proof") - } - - // todo check that address in proof matches source network - - rwset, err := proof.RWSet() - if err != nil { - return errors.Wrapf(err, "failed to unmarshal claim proof") - } - - key, err := keys.CreateProofOfExistenceKey(tokenID) - if err != nil { - return errors.Wrapf(err, "failed to create proof of existence key from token [%s]", tokenID) - } - tmsID, err := fabric3.FabricURLToTMSID(v.NetworkURL) - if err != nil { - return errors.Wrapf(err, "failed to extract tms id from [%s]", v.NetworkURL) - } - raw, err := rwset.GetState(tmsID.Namespace, key) - if err != nil { - return errors.Wrapf(err, "failed to get state for token [%s:%s]", tmsID.Namespace, key) - } - if len(raw) == 0 { - return errors.Errorf("token [%s:%s] does not contain proof", tmsID.Namespace, key) - } - - // Validate against pledge - v.Logger.Debugf("verify proof of existence for token id [%s]", tokenID) - pledges, err := v.PledgeVault.PledgeByTokenID(tokenID) - if err != nil { - v.Logger.Errorf("failed retrieving pledge info for token id [%s]: [%s]", tokenID, err) - return errors.WithMessagef(err, "failed getting pledge for [%s]", tokenID) - } - if len(pledges) != 1 { - v.Logger.Errorf("failed retrieving pledge info for token id [%s]: no info found", tokenID) - return errors.Errorf("expected one pledge, got [%d]", len(pledges)) - } - info := pledges[0] - v.Logger.Debugf("found pledge info for token id [%s]: [%s]", tokenID, info.Source) - - // TODO compare token type and quantity and script, as done in fabtoken driver +type Validator struct{} + +func (v *Validator) Validate(tokRaw []byte, info *pledge.Info) error { + // TODO: complete this + // tok := &token.Token{} + // err := json.Unmarshal(tokRaw, tok) + // if err != nil { + // return errors.Wrapf(err, "failed to unmarshal token [%s]", common.Hashable(tokRaw)) + // } + // + // if tok.Type != info.TokenType { + // return errors.Errorf("type of pledge token does not match type in claim request") + // } + // q, err := token.ToQuantity(tok.Quantity, 64) + // if err != nil { + // return errors.Wrapf(err, "failed converting token quantity [%s]", tok.Quantity) + // } + // expectedQ := token.NewQuantityFromUInt64(info.Amount) + // if expectedQ.Cmp(q) != 0 { + // return errors.Errorf("quantity in pledged token is different from quantity in claim request") + // } + // owner, err := identity.UnmarshalTypedIdentity(tok.Owner.Raw) + // if err != nil { + // return errors.Wrapf(err, "failed to unmarshal owner of token [%s]", common.Hashable(tokRaw)) + // } + // if owner.Type != pledge.ScriptType { + // return err + // } + // script := &pledge.Script{} + // err = json.Unmarshal(owner.Identity, script) + // if err != nil { + // return errors.Wrapf(err, "failed to unmarshal pledge script [%s]", common.Hashable(tokRaw)) + // } + // if script.Recipient == nil { + // return errors.Errorf("script in proof encodes invalid recipient") + // } + // if !script.Recipient.Equal(info.Script.Recipient) { + // return errors.Errorf("recipient in claim request does not match recipient in proof") + // } + // if script.Deadline != info.Script.Deadline { + // return errors.Errorf("deadline in claim request does not match deadline in proof") + // } + // if script.DestinationNetwork != info.Script.DestinationNetwork { + // return errors.Errorf("destination network in claim request does not match destination network in proof [%s vs.%s]", info.Script.DestinationNetwork, script.DestinationNetwork) + // } return nil } -func (v *StateVerifier) VerifyProofNonExistence(proofRaw []byte, tokenID *token.ID, origin string, deadline time.Time) error { - // v.NetworkURL is the network from which the proof comes from - tokenOriginNetworkTMSID, err := fabric3.FabricURLToTMSID(origin) - if err != nil { - return errors.Wrapf(err, "failed to parse network url") - } - // get local relay - fns, err := v.GetFabricNetworkService(tokenOriginNetworkTMSID.Network) - if err != nil { - return errors.Wrapf(err, "failed to get fabric network service for network [%s]", tokenOriginNetworkTMSID.Network) - } - relay := v.RelayProvider.Relay(fns) - - // parse proof - proof, err := relay.ToFabric().ProofFromBytes(proofRaw) - if err != nil { - return errors.Wrapf(err, "failed to umarshal proof") - } - - rwset, err := proof.RWSet() - if err != nil { - return errors.Wrapf(err, "failed to retrieve RWset") - } - - key, err := keys.CreateProofOfNonExistenceKey(tokenID, origin) - if err != nil { - return errors.Wrapf(err, "failed creating key for proof of non-existence") - } - - proofSourceNetworkTMSID, err := fabric3.FabricURLToTMSID(v.NetworkURL) - if err != nil { - return err - } - raw, err := rwset.GetState(proofSourceNetworkTMSID.Namespace, key) - if err != nil { - return errors.Wrapf(err, "failed to check proof of non-existence") - } - p := &translator.ProofOfTokenMetadataNonExistence{} - if raw == nil { - return errors.Errorf("could not find proof of non-existence") - } - err = json.Unmarshal(raw, p) - if err != nil { - return errors.Wrapf(err, "failed to unmarshal proof of non-existence") - } - if p.Deadline != deadline { - return errors.Errorf("deadline in reclaim request does not match deadline in proof of non-existence") - } - if p.TokenID.String() != tokenID.String() { - return errors.Errorf("token ID in reclaim request does not match token ID in proof of non-existence") - } - if p.Origin != fabric3.FabricURL(tokenOriginNetworkTMSID) { - return errors.Errorf("origin in reclaim request does not match origin in proof of non-existence") - } - - // todo check that address in proof is the destination network - - err = proof.Verify() - if err != nil { - return errors.Wrapf(err, "invalid proof of non-existence") - } - - return nil -} - -// VerifyProofTokenWithMetadataExistence verifies that a proof of existence of a token -// with metadata including the given token ID and origin network, in the target network is valid -func (v *StateVerifier) VerifyProofTokenWithMetadataExistence(proofRaw []byte, tokenID *token.ID, origin string) error { - // v.NetworkURL is the network from which the proof comes from - tokenOriginNetworkTMSID, err := fabric3.FabricURLToTMSID(origin) - if err != nil { - return errors.Wrapf(err, "failed to parse network url") - } - - // get local relay - fns, err := v.GetFabricNetworkService(tokenOriginNetworkTMSID.Network) - if err != nil { - return errors.Wrapf(err, "failed to get fabric network service for network [%s]", tokenOriginNetworkTMSID.Network) - } - relay := v.RelayProvider.Relay(fns) - - // parse proof - proof, err := relay.ToFabric().ProofFromBytes(proofRaw) - if err != nil { - return errors.Wrapf(err, "failed to umarshal proof") - } - - rwset, err := proof.RWSet() - if err != nil { - return errors.Wrapf(err, "failed to retrieve RWset") - } - - key, err := keys.CreateProofOfMetadataExistenceKey(tokenID, origin) - if err != nil { - return errors.Wrapf(err, "failed creating key for proof of token existence") - } - - proofSourceNetworkTMSID, err := fabric3.FabricURLToTMSID(v.NetworkURL) - if err != nil { - return err - } - raw, err := rwset.GetState(proofSourceNetworkTMSID.Namespace, key) - if err != nil { - return errors.Wrapf(err, "failed to check proof of token existence") - } - p := &translator.ProofOfTokenMetadataExistence{} - if raw == nil { - return errors.Errorf("could not find proof of token existence") - } - err = json.Unmarshal(raw, p) - if err != nil { - return errors.Wrapf(err, "failed to unmarshal proof of token existence") - } - if p.TokenID.String() != tokenID.String() { - return errors.Errorf("token ID in redeem request does not match token ID in proof of token existence") - } - if p.Origin != fabric3.FabricURL(tokenOriginNetworkTMSID) { - return errors.Errorf("origin in redeem request does not match origin in proof of token existence") - } - - // todo check that address in proof is the destination network - - err = proof.Verify() - if err != nil { - return errors.Wrapf(err, "invalid proof of token existence") - } - - return nil -} - -type StateDriver struct { - Logger logging.Logger - FNSProvider *fabric.NetworkServiceProvider - RelayProvider fabric3.RelayProvider - VaultStore *pledge.VaultStore -} - func NewStateDriver(in struct { dig.In FNSProvider *fabric.NetworkServiceProvider @@ -398,37 +73,12 @@ func NewStateDriver(in struct { }) fabric3.NamedStateDriver { return fabric3.NamedStateDriver{ Name: crypto.DLogPublicParameters, - Driver: &StateDriver{ - Logger: logging.MustGetLogger("token-sdk.core.zkatdlog"), - FNSProvider: in.FNSProvider, - RelayProvider: in.RelayProvider, - VaultStore: in.VaultStore, - }, - } -} - -func (d *StateDriver) NewStateQueryExecutor(url string) (driver.StateQueryExecutor, error) { - fns, err := d.FNSProvider.FabricNetworkService("") - if err != nil { - return nil, errors.Wrapf(err, "failed to get default FNS") - } - - return NewStateQueryExecutor(d.Logger, d.RelayProvider, url, fns) -} - -func (d *StateDriver) NewStateVerifier(url string) (driver.StateVerifier, error) { - fns, err := d.FNSProvider.FabricNetworkService("") - if err != nil { - return nil, errors.Wrapf(err, "failed to get default FNS") + Driver: core.NewStateDriver( + logging.MustGetLogger("token-sdk.core.zkatdlog"), + in.FNSProvider, + in.RelayProvider, + in.VaultStore, + &Validator{}, + ), } - return NewStateVerifier( - d.Logger, - d.RelayProvider, - d.VaultStore, - func(id string) (*fabric.NetworkService, error) { - return d.FNSProvider.FabricNetworkService(id) - }, - url, - fns, - ) } diff --git a/token/services/interop/state/fabric/core/state.go b/token/services/interop/state/fabric/core/state.go index 30fa9f0c1..83b0d4aeb 100644 --- a/token/services/interop/state/fabric/core/state.go +++ b/token/services/interop/state/fabric/core/state.go @@ -13,8 +13,6 @@ import ( "time" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric" - driver2 "github.com/hyperledger-labs/fabric-token-sdk/token/driver" - "github.com/hyperledger-labs/fabric-token-sdk/token/services/identity" "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/pledge" "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/state" "github.com/hyperledger-labs/fabric-token-sdk/token/services/interop/state/driver" @@ -28,7 +26,7 @@ import ( ) type Validator interface { - Validate(tok []byte, info *pledge.Info) (driver2.Output, error) + Validate(tok []byte, info *pledge.Info) error } type PledgeVault interface { @@ -254,38 +252,11 @@ func (v *StateVerifier) VerifyProofExistence(proofRaw []byte, tokenID *token.ID, info := pledges[0] v.Logger.Debugf("found pledge info for token id [%s]: [%s]", tokenID, info.Source) - // check token - output, err := v.validator.Validate(raw, info) - if err != nil { + // validate + if err := v.validator.Validate(raw, info); err != nil { return errors.Wrapf(err, "failed to check token") } - // check script - owner, err := identity.UnmarshalTypedIdentity(output.GetOwner()) - if err != nil { - return errors.Wrapf(err, "failed to unmarshal owner of token [%s]", tokenID) - } - if owner.Type != pledge.ScriptType { - return errors.Errorf("invalid owner type, expected [%s], got [%s]", pledge.ScriptType, owner.Type) - } - script := &pledge.Script{} - err = json.Unmarshal(owner.Identity, script) - if err != nil { - return errors.Wrapf(err, "failed to unmarshal pledge script [%s]", tokenID) - } - if script.Recipient == nil { - return errors.Errorf("script in proof encodes invalid recipient") - } - if !script.Recipient.Equal(info.Script.Recipient) { - return errors.Errorf("recipient in claim request does not match recipient in proof") - } - if script.Deadline != info.Script.Deadline { - return errors.Errorf("deadline in claim request does not match deadline in proof") - } - if script.DestinationNetwork != info.Script.DestinationNetwork { - return errors.Errorf("destination network in claim request does not match destination network in proof [%s vs.%s]", info.Script.DestinationNetwork, script.DestinationNetwork) - } - return nil } @@ -424,23 +395,22 @@ type StateDriver struct { FNSProvider *fabric.NetworkServiceProvider RelayProvider fabric3.RelayProvider VaultStore *pledge.VaultStore + Validator Validator } func NewStateDriver( - name fabric3.StateDriverName, logger logging.Logger, FNSProvider *fabric.NetworkServiceProvider, - RelayProvider fabric3.RelayProvider, - VaultStore *pledge.VaultStore, -) fabric3.NamedStateDriver { - return fabric3.NamedStateDriver{ - Name: name, - Driver: &StateDriver{ - Logger: logger, - FNSProvider: FNSProvider, - RelayProvider: RelayProvider, - VaultStore: VaultStore, - }, + relayProvider fabric3.RelayProvider, + vaultStore *pledge.VaultStore, + validator Validator, +) *StateDriver { + return &StateDriver{ + Logger: logger, + FNSProvider: FNSProvider, + RelayProvider: relayProvider, + VaultStore: vaultStore, + Validator: validator, } } @@ -467,6 +437,6 @@ func (d *StateDriver) NewStateVerifier(url string) (driver.StateVerifier, error) }, url, fns, - nil, + d.Validator, ) }