diff --git a/Makefile b/Makefile index 32db1d044..0cecf0562 100644 --- a/Makefile +++ b/Makefile @@ -140,6 +140,10 @@ clean-fabric-peer-images: docker images -a | grep "_peer.org" | awk '{print $3}' | xargs docker rmi docker images -a | grep "_peer_" | awk '{print $3}' | xargs docker rmi +.PHONY: clean-all-containers +clean-all-containers: + @if [ -n "$$(docker ps -aq)" ]; then docker rm -f $$(docker ps -aq); else echo "No containers to remove"; fi + .PHONY: tokengen tokengen: @go install ./cmd/tokengen diff --git a/integration/token/fungible/dlog/dlog_test.go b/integration/token/fungible/dlog/dlog_test.go index 17519db4c..f2a0984e1 100644 --- a/integration/token/fungible/dlog/dlog_test.go +++ b/integration/token/fungible/dlog/dlog_test.go @@ -107,6 +107,13 @@ var _ = Describe("EndToEnd", func() { AfterEach(ts.TearDown) It("succeeded", Label("T12"), func() { fungible.TestMultiSig(ts.II, selector) }) }) + + Describe("Redeem flow", t.Label, func() { + ts, selector := newTestSuite(t.CommType, Aries, t.ReplicationFactor, "", "alice", "bob", "charlie") + BeforeEach(ts.Setup) + AfterEach(ts.TearDown) + It("succeeded", Label("T13"), func() { fungible.TestRedeem(ts.II, selector, "default") }) + }) } for _, tokenSelector := range integration2.TokenSelectors { diff --git a/integration/token/fungible/fabtoken/fabtoken_test.go b/integration/token/fungible/fabtoken/fabtoken_test.go index 5e11aea21..2c9a27e17 100644 --- a/integration/token/fungible/fabtoken/fabtoken_test.go +++ b/integration/token/fungible/fabtoken/fabtoken_test.go @@ -35,6 +35,7 @@ var _ = Describe("EndToEnd", func() { It("Test Identity Revocation", Label("T3"), func() { fungible.TestRevokeIdentity(ts.II, "auditor", selector) }) It("Test Remote Wallet (GRPC)", Label("T4"), func() { fungible.TestRemoteOwnerWallet(ts.II, "auditor", selector, false) }) It("Test Remote Wallet (WebSocket)", Label("T5"), func() { fungible.TestRemoteOwnerWallet(ts.II, "auditor", selector, true) }) + It("Test redeem flow", Label("T6"), func() { fungible.TestRedeem(ts.II, selector, "default") }) }) } }) diff --git a/integration/token/fungible/odlog/dlog_test.go b/integration/token/fungible/odlog/dlog_test.go index ee169582c..0a84abdae 100644 --- a/integration/token/fungible/odlog/dlog_test.go +++ b/integration/token/fungible/odlog/dlog_test.go @@ -25,6 +25,7 @@ var _ = Describe("Orion EndToEnd", func() { BeforeEach(ts.Setup) AfterEach(ts.TearDown) It("succeeded", func() { fungible.TestAll(ts.II, "auditor", nil, true, selector) }) + It("Test redeem flow", Label("T1"), func() { fungible.TestRedeem(ts.II, selector, "orion") }) }) } }) diff --git a/integration/token/fungible/ofabtoken/fabtoken_test.go b/integration/token/fungible/ofabtoken/fabtoken_test.go index 48f4a8aa8..fd63e0a5f 100644 --- a/integration/token/fungible/ofabtoken/fabtoken_test.go +++ b/integration/token/fungible/ofabtoken/fabtoken_test.go @@ -25,6 +25,7 @@ var _ = Describe("Orion EndToEnd", func() { BeforeEach(ts.Setup) AfterEach(ts.TearDown) It("succeeded", func() { fungible.TestAll(ts.II, "auditor", nil, true, selector) }) + It("Test redeem flow", Label("T1"), func() { fungible.TestRedeem(ts.II, selector, "orion") }) }) } }) diff --git a/integration/token/fungible/sdk/auditor/sdk.go b/integration/token/fungible/sdk/auditor/sdk.go index 295a6a37e..f5e328d9c 100644 --- a/integration/token/fungible/sdk/auditor/sdk.go +++ b/integration/token/fungible/sdk/auditor/sdk.go @@ -48,6 +48,7 @@ func (p *SDK) Install() error { registry.RegisterFactory("DoesWalletExist", &views.DoesWalletExistViewFactory{}), registry.RegisterFactory("TxFinality", &views1.TxFinalityViewFactory{}), registry.RegisterFactory("GetPublicParams", &views.GetPublicParamsViewFactory{}), + registry.RegisterFactory("SetBinding", &views.SetBindingViewFactory{}), ) }); err != nil { return errors.WithMessage(err, "failed to install auditor's views") diff --git a/integration/token/fungible/sdk/issuer/sdk.go b/integration/token/fungible/sdk/issuer/sdk.go index 713d450bc..91c8634d5 100644 --- a/integration/token/fungible/sdk/issuer/sdk.go +++ b/integration/token/fungible/sdk/issuer/sdk.go @@ -52,8 +52,10 @@ func (p *SDK) Install() error { registry.RegisterFactory("DoesWalletExist", &views.DoesWalletExistViewFactory{}), registry.RegisterFactory("TxFinality", &views1.TxFinalityViewFactory{}), registry.RegisterFactory("issue", &views.IssueCashViewFactory{}), + registry.RegisterFactory("SetBinding", &views.SetBindingViewFactory{}), registry.RegisterResponder(&views.WithdrawalResponderView{}, &views.WithdrawalInitiatorView{}), registry.RegisterResponder(&views.TokensUpgradeResponderView{}, &views.TokensUpgradeInitiatorView{}), + registry.RegisterResponder(&views.IssuerRedeemAcceptView{}, &views.RedeemView{}), ) }); err != nil { return errors.WithMessage(err, "failed to install issuer's views") diff --git a/integration/token/fungible/sdk/party/sdk.go b/integration/token/fungible/sdk/party/sdk.go index 0cab828cc..495bc3b19 100644 --- a/integration/token/fungible/sdk/party/sdk.go +++ b/integration/token/fungible/sdk/party/sdk.go @@ -66,6 +66,7 @@ func (p *SDK) Install() error { registry.RegisterFactory("TokenSelectorUnlock", &views.TokenSelectorUnlockViewFactory{}), registry.RegisterFactory("FinalityWithTimeout", &views.FinalityWithTimeoutViewFactory{}), registry.RegisterFactory("GetRevocationHandle", &views.GetRevocationHandleViewFactory{}), + registry.RegisterFactory("SetBinding", &views.SetBindingViewFactory{}), registry.RegisterResponder(&views.AcceptCashView{}, &views.IssueCashView{}), registry.RegisterResponder(&views.AcceptCashView{}, &views.TransferView{}), registry.RegisterResponder(&views.AcceptCashView{}, &views.TransferWithSelectorView{}), diff --git a/integration/token/fungible/support.go b/integration/token/fungible/support.go index c9ccf804f..4e1b97a10 100644 --- a/integration/token/fungible/support.go +++ b/integration/token/fungible/support.go @@ -806,17 +806,18 @@ func TransferCashWithSelector(network *integration.Infrastructure, sender *token } } -func RedeemCash(network *integration.Infrastructure, id *token3.NodeReference, wallet string, typ token.Type, amount uint64, auditor *token3.NodeReference) { - RedeemCashForTMSID(network, id, wallet, typ, amount, auditor, nil) +func RedeemCash(network *integration.Infrastructure, id *token3.NodeReference, wallet string, typ token.Type, amount uint64, auditor *token3.NodeReference, issuerPublicKey []byte) { + RedeemCashForTMSID(network, id, wallet, typ, amount, auditor, issuerPublicKey, nil) } -func RedeemCashForTMSID(network *integration.Infrastructure, id *token3.NodeReference, wallet string, typ token.Type, amount uint64, auditor *token3.NodeReference, tmsID *token2.TMSID) { +func RedeemCashForTMSID(network *integration.Infrastructure, id *token3.NodeReference, wallet string, typ token.Type, amount uint64, auditor *token3.NodeReference, issuerPublicKey []byte, tmsID *token2.TMSID) { txid, err := network.Client(id.ReplicaName()).CallView("redeem", common.JSONMarshall(&views.Redeem{ - Auditor: auditor.Id(), - Wallet: wallet, - Type: typ, - Amount: amount, - TMSID: tmsID, + Auditor: auditor.Id(), + IssuerPublicKey: issuerPublicKey, + Wallet: wallet, + Type: typ, + Amount: amount, + TMSID: tmsID, })) Expect(err).NotTo(HaveOccurred()) common2.CheckFinality(network, auditor, common.JSONUnmarshalString(txid), tmsID, false) @@ -1346,3 +1347,18 @@ func MultiSigSpendCashForTMSID(network *integration.Infrastructure, sender *toke return txID } + +func SetBinding(network *integration.Infrastructure, issuer *token3.NodeReference, issuerPublicKey []byte, onNodes ...*token3.NodeReference) { + for _, node := range onNodes { + for _, nodeReplica := range node.AllNames() { + for _, issuerName := range issuer.AllNames() { + _, err := network.Client(nodeReplica).CallView("SetBinding", common.JSONMarshall(&views.Binding{ + FSCNodeIdentity: network.Identity(issuerName), // issuer's network node identity. + Alias: issuerPublicKey, // issuer's public key for the token issuance + })) + Expect(err).NotTo(HaveOccurred()) + + } + } + } +} diff --git a/integration/token/fungible/tests.go b/integration/token/fungible/tests.go index 7b4ec855e..f58e4c938 100644 --- a/integration/token/fungible/tests.go +++ b/integration/token/fungible/tests.go @@ -405,7 +405,7 @@ func TestAll(network *integration.Infrastructure, auditorId string, onRestart On Expect(ut.Sum(64).ToBigInt().Cmp(big.NewInt(111))).To(BeEquivalentTo(0), "got [%d], expected 111", ut.Sum(64).ToBigInt()) Expect(ut.ByType("USD").Count()).To(BeEquivalentTo(ut.Count())) - RedeemCash(network, bob, "", "USD", 11, auditor) + RedeemCash(network, bob, "", "USD", 11, auditor, nil) t10 := time.Now() CheckAcceptedTransactions(network, bob, "", BobAcceptedTransactions[:6], nil, nil, nil) CheckAcceptedTransactions(network, bob, "", BobAcceptedTransactions[5:6], nil, nil, nil, ttxdb.Redeem) @@ -456,7 +456,7 @@ func TestAll(network *integration.Infrastructure, auditorId string, onRestart On CheckSpending(network, alice, "", "USD", auditor, 121) CheckSpending(network, bob, "", "EUR", auditor, 10) - RedeemCash(network, bob, "", "USD", 10, auditor) + RedeemCash(network, bob, "", "USD", 10, auditor, nil) CheckBalanceAndHolding(network, bob, "", "USD", 110, auditor) CheckSpending(network, bob, "", "USD", auditor, 21) @@ -952,7 +952,7 @@ func TestMixed(network *integration.Infrastructure, onRestart OnRestartFunc, sel TransferCashForTMSID(network, alice, "", "USD", 20, bob, auditor1, dlogId) TransferCashForTMSID(network, alice, "", "USD", 30, bob, auditor2, fabTokenId) - RedeemCashForTMSID(network, bob, "", "USD", 11, auditor1, dlogId) + RedeemCashForTMSID(network, bob, "", "USD", 11, auditor1, nil, dlogId) CheckSpendingForTMSID(network, bob, "", "USD", auditor1, 11, dlogId) CheckBalanceAndHoldingForTMSID(network, alice, "", "USD", 90, auditor1, dlogId) @@ -1430,3 +1430,27 @@ func TestMultiSig(network *integration.Infrastructure, sel *token3.ReplicaSelect CheckCoOwnedBalance(network, charlie, "", "USD", 0) CheckCoOwnedBalance(network, manager, "", "USD", 0) } + +func TestRedeem(network *integration.Infrastructure, sel *token3.ReplicaSelector, networkName string) { + tms := GetTMSByNetworkName(network, networkName) + auditor := sel.Get("auditor") + issuer := sel.Get("issuer") + alice := sel.Get("alice") + RegisterAuditor(network, auditor) + + // give some time to the nodes to get the public parameters + time.Sleep(10 * time.Second) + + SetKVSEntry(network, issuer, "auditor", auditor.Id()) + var issuerPublicKey []byte = GetIssuerIdentity(tms, issuer.Id()) + SetBinding(network, issuer, issuerPublicKey, alice) + CheckPublicParams(network, issuer, auditor, alice) + + IssueCash(network, "", "USD", 110, alice, auditor, true, issuer) + CheckBalance(network, alice, "", "USD", 110) + CheckHolding(network, alice, "", "USD", 110, auditor) + + RedeemCash(network, alice, "", "USD", 10, auditor, issuerPublicKey) + CheckBalance(network, alice, "", "USD", 100) + CheckHolding(network, alice, "", "USD", 100, auditor) +} diff --git a/integration/token/fungible/topology/topology.go b/integration/token/fungible/topology/topology.go index 555bcab65..1d1481c08 100644 --- a/integration/token/fungible/topology/topology.go +++ b/integration/token/fungible/topology/topology.go @@ -235,6 +235,9 @@ func Topology(opts common.Opts) []api.Topology { } } + // Add the default issuer + tms.AddIssuer(issuer) + // any extra TMS for _, tmsOpts := range opts.ExtraTMSs { tms := tokenTopology.AddTMS(nodeList, backendNetwork, backendChannel, tmsOpts.TokenSDKDriver) diff --git a/integration/token/fungible/views/binding.go b/integration/token/fungible/views/binding.go new file mode 100644 index 000000000..4ba7c585a --- /dev/null +++ b/integration/token/fungible/views/binding.go @@ -0,0 +1,42 @@ +/* +Copyright IBM Corp. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package views + +import ( + "encoding/json" + + view2 "github.com/hyperledger-labs/fabric-smart-client/platform/view" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/assert" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" + "github.com/pkg/errors" +) + +type Binding struct { + FSCNodeIdentity view.Identity + Alias view.Identity +} + +type SetBindingView struct { + *Binding +} + +func (s *SetBindingView) Call(context view.Context) (interface{}, error) { + es := view2.GetEndpointService(context) + if err := es.Bind(s.FSCNodeIdentity, s.Alias); err != nil { + return nil, errors.Wrap(err, `failed to bind fsc node identity`) + } + return nil, nil +} + +type SetBindingViewFactory struct{} + +func (p *SetBindingViewFactory) NewView(in []byte) (view.View, error) { + f := &SetBindingView{Binding: &Binding{}} + err := json.Unmarshal(in, f.Binding) + assert.NoError(err, "failed unmarshalling input") + + return f, nil +} diff --git a/integration/token/fungible/views/redeem.go b/integration/token/fungible/views/redeem.go index 7cf80bbfe..36eecaf55 100644 --- a/integration/token/fungible/views/redeem.go +++ b/integration/token/fungible/views/redeem.go @@ -9,6 +9,8 @@ package views import ( "encoding/json" + "github.com/pkg/errors" + view2 "github.com/hyperledger-labs/fabric-smart-client/platform/view" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/assert" "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" @@ -21,6 +23,8 @@ import ( type Redeem struct { // Auditor is the name of the auditor that must be contacted to approve the operation Auditor string + // IssuerPublicKey is the (optional) PK of an issuer that would need to be contacted to approve the operation + IssuerPublicKey []byte // Wallet is the identifier of the wallet that owns the tokens to redeem Wallet string // TokenIDs contains a list of token ids to redeem. If empty, tokens are selected on the spot. @@ -64,6 +68,7 @@ func (t *RedeemView) Call(context view.Context) (interface{}, error) { senderWallet, t.Type, t.Amount, + t.IssuerPublicKey, token2.WithTokenIDs(t.TokenIDs...), ) assert.NoError(err, "failed adding new tokens") @@ -106,3 +111,22 @@ func (p *RedeemViewFactory) NewView(in []byte) (view.View, error) { assert.NoError(err, "failed unmarshalling input") return f, nil } + +type IssuerRedeemAcceptView struct{} + +func (a *IssuerRedeemAcceptView) Call(context view.Context) (interface{}, error) { + // Verify Token Request against Metadata + tx, err := ttx.ReceiveTransaction(context) + if err != nil { + return nil, errors.Wrap(err, "failed getting transaction") + } + + // Sign the transaction + // EndorserView generates the signature and send in back on the same communication session + _, err = context.RunView(ttx.NewEndorseView(tx)) + if err != nil { + return nil, errors.Wrap(err, "issuer failed endorsing transaction") + } + + return nil, nil +} diff --git a/token/core/fabtoken/v1/core/actions.go b/token/core/fabtoken/v1/core/actions.go index 5c6709b1d..0393ee0d8 100644 --- a/token/core/fabtoken/v1/core/actions.go +++ b/token/core/fabtoken/v1/core/actions.go @@ -183,6 +183,8 @@ type TransferAction struct { Outputs []*Output // Metadata contains the transfer action's metadata Metadata map[string][]byte + // ExtraSigners contains the identities that need to sign the transfer action + ESigners []driver.Identity } func (t *TransferAction) NumInputs() int { @@ -282,5 +284,5 @@ func (t *TransferAction) Validate() error { } func (t *TransferAction) ExtraSigners() []driver.Identity { - return nil + return t.ESigners } diff --git a/token/core/fabtoken/v1/transfer.go b/token/core/fabtoken/v1/transfer.go index 7e08cd8e0..ddf167c9c 100644 --- a/token/core/fabtoken/v1/transfer.go +++ b/token/core/fabtoken/v1/transfer.go @@ -44,7 +44,8 @@ func NewTransferService( // Transfer returns a TransferAction as a function of the passed arguments // It also returns the corresponding TransferMetadata -func (s *TransferService) Transfer(ctx context.Context, _ string, _ driver.OwnerWallet, tokenIDs []*token.ID, Outputs []*token.Token, opts *driver.TransferOptions) (driver.TransferAction, *driver.TransferMetadata, error) { +func (s *TransferService) Transfer(ctx context.Context, _ string, _ driver.OwnerWallet, tokenIDs []*token.ID, Outputs []*token.Token, issuerPublicKey []byte, opts *driver.TransferOptions) (driver.TransferAction, *driver.TransferMetadata, error) { + var isRedeem bool // select inputs inputTokens, err := s.TokenLoader.GetTokens(tokenIDs) if err != nil { @@ -66,6 +67,10 @@ func (s *TransferService) Transfer(ctx context.Context, _ string, _ driver.Owner Type: output.Type, Quantity: output.Quantity, }) + + if len(output.Owner) == 0 { + isRedeem = true + } } // assemble transfer transferMetadata @@ -146,6 +151,7 @@ func (s *TransferService) Transfer(ctx context.Context, _ string, _ driver.Owner InputTokens: inputs, Outputs: outs, Metadata: meta.TransferActionMetadata(opts.Attributes), + ESigners: nil, } transferMetadata := &driver.TransferMetadata{ Inputs: transferInputsMetadata, @@ -153,6 +159,23 @@ func (s *TransferService) Transfer(ctx context.Context, _ string, _ driver.Owner ExtraSigners: nil, } + // add redeem signer + if isRedeem { + var issuer driver.Identity + if issuerPublicKey != nil { + issuer = issuerPublicKey + } else { + issuers := s.PublicParametersManager.PublicParameters().Issuers() + if len(issuers) < 1 { + return nil, nil, errors.New("no issuer found") + } + issuer = issuers[0] + } + + transfer.ESigners = []driver.Identity{issuer} + transferMetadata.ExtraSigners = []driver.Identity{issuer} + } + return transfer, transferMetadata, nil } diff --git a/token/core/fabtoken/v1/validator/validator_transfer.go b/token/core/fabtoken/v1/validator/validator_transfer.go index 93efcba82..5c603aeff 100644 --- a/token/core/fabtoken/v1/validator/validator_transfer.go +++ b/token/core/fabtoken/v1/validator/validator_transfer.go @@ -41,6 +41,36 @@ func TransferSignatureValidate(ctx *Context) error { } ctx.Signatures = append(ctx.Signatures, sigma) } + + // If transfer action is a redeem, verify the signature of the issuer + isRedeem := func() bool { + for _, output := range ctx.TransferAction.Outputs { + if output.Owner == nil { + return true + } + } + return false + } + + if isRedeem() { + ctx.Logger.Debugf("at redeem action validation") + extraSigners := ctx.TransferAction.ESigners + if len(extraSigners) < 1 { + return errors.New("no extra signers provided for redeem action") + } + issuer := ctx.TransferAction.ESigners[0] // issuer is the first extra signer + + verifier, err := ctx.Deserializer.GetIssuerVerifier(issuer) + if err != nil { + return errors.Wrapf(err, "failed deserializing issuer [%s]", issuer.UniqueID()) + } + + sigma, err := ctx.SignatureProvider.HasBeenSignedBy(issuer, verifier) + if err != nil { + return errors.Wrapf(err, "failed signature verification [%s]", issuer.UniqueID()) + } + ctx.Signatures = append(ctx.Signatures, sigma) + } return nil } diff --git a/token/core/zkatdlog/nogh/protos-go/actions/noghactions.pb.go b/token/core/zkatdlog/nogh/protos-go/actions/noghactions.pb.go index a419237ba..1c2cd7fd2 100644 --- a/token/core/zkatdlog/nogh/protos-go/actions/noghactions.pb.go +++ b/token/core/zkatdlog/nogh/protos-go/actions/noghactions.pb.go @@ -5,8 +5,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 -// protoc v5.28.1 +// protoc-gen-go v1.34.2 +// protoc v5.26.1 // source: noghactions.proto package actions @@ -431,6 +431,7 @@ type TransferAction struct { Outputs []*TransferActionOutput `protobuf:"bytes,2,rep,name=outputs,proto3" json:"outputs,omitempty"` // outputs Proof *Proof `protobuf:"bytes,3,opt,name=proof,proto3" json:"proof,omitempty"` // ZK Proof that shows that the transfer is correct Metadata map[string][]byte `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // Metadata contains the transfer action's metadata + ESigners []*pp.Identity `protobuf:"bytes,5,rep,name=e_signers,json=eSigners,proto3" json:"e_signers,omitempty"` // ESigners is the list of extra signer of the transfer action } func (x *TransferAction) Reset() { @@ -493,6 +494,13 @@ func (x *TransferAction) GetMetadata() map[string][]byte { return nil } +func (x *TransferAction) GetESigners() []*pp.Identity { + if x != nil { + return x.ESigners + } + return nil +} + type IssueActionInput struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -723,7 +731,7 @@ var file_noghactions_proto_rawDesc = []byte{ 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x1d, 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x99, 0x02, 0x0a, 0x0e, 0x54, 0x72, + 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0xc6, 0x02, 0x0a, 0x0e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, @@ -737,45 +745,47 @@ var file_noghactions_proto_rawDesc = []byte{ 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x47, 0x0a, 0x10, 0x49, 0x73, 0x73, 0x75, 0x65, 0x41, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x1d, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x36, - 0x0a, 0x11, 0x49, 0x73, 0x73, 0x75, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x12, 0x21, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, - 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xb5, 0x02, 0x0a, 0x0b, 0x49, 0x73, 0x73, 0x75, 0x65, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x12, 0x2e, - 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, - 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x31, - 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x17, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x41, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x73, 0x12, 0x21, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x0b, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x05, 0x70, - 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x49, 0x73, - 0x73, 0x75, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x59, - 0x5a, 0x57, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, - 0x65, 0x72, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x66, 0x61, - 0x62, 0x72, 0x69, 0x63, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x7a, 0x6b, 0x61, 0x74, 0x64, 0x6c, - 0x6f, 0x67, 0x2f, 0x6e, 0x6f, 0x67, 0x68, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, - 0x6f, 0x2f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x2b, 0x0a, 0x09, 0x65, 0x5f, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6e, 0x6f, + 0x67, 0x68, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x65, 0x53, 0x69, + 0x67, 0x6e, 0x65, 0x72, 0x73, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, + 0x38, 0x01, 0x22, 0x47, 0x0a, 0x10, 0x49, 0x73, 0x73, 0x75, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x1d, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x49, + 0x44, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x36, 0x0a, 0x11, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x12, 0x21, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0b, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x05, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x22, 0xb5, 0x02, 0x0a, 0x0b, 0x49, 0x73, 0x73, 0x75, 0x65, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x06, 0x69, + 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6e, 0x6f, + 0x67, 0x68, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x52, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x31, 0x0a, 0x07, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6e, + 0x6f, 0x67, 0x68, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x21, + 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, + 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, + 0x66, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x6e, 0x6f, 0x67, 0x68, 0x2e, 0x49, 0x73, 0x73, 0x75, 0x65, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, + 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x59, 0x5a, 0x57, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x79, 0x70, 0x65, 0x72, 0x6c, + 0x65, 0x64, 0x67, 0x65, 0x72, 0x2d, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x66, 0x61, 0x62, 0x72, 0x69, + 0x63, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x7a, 0x6b, 0x61, 0x74, 0x64, 0x6c, 0x6f, 0x67, 0x2f, + 0x6e, 0x6f, 0x67, 0x68, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2d, 0x67, 0x6f, 0x2f, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -791,7 +801,7 @@ func file_noghactions_proto_rawDescGZIP() []byte { } var file_noghactions_proto_msgTypes = make([]protoimpl.MessageInfo, 13) -var file_noghactions_proto_goTypes = []interface{}{ +var file_noghactions_proto_goTypes = []any{ (*Token)(nil), // 0: nogh.Token (*TokenMetadata)(nil), // 1: nogh.TokenMetadata (*TokenID)(nil), // 2: nogh.TokenID @@ -825,18 +835,19 @@ var file_noghactions_proto_depIdxs = []int32{ 5, // 11: nogh.TransferAction.outputs:type_name -> nogh.TransferActionOutput 6, // 12: nogh.TransferAction.proof:type_name -> nogh.Proof 11, // 13: nogh.TransferAction.metadata:type_name -> nogh.TransferAction.MetadataEntry - 2, // 14: nogh.IssueActionInput.id:type_name -> nogh.TokenID - 0, // 15: nogh.IssueActionOutput.token:type_name -> nogh.Token - 15, // 16: nogh.IssueAction.issuer:type_name -> nogh.Identity - 8, // 17: nogh.IssueAction.inputs:type_name -> nogh.IssueActionInput - 9, // 18: nogh.IssueAction.outputs:type_name -> nogh.IssueActionOutput - 6, // 19: nogh.IssueAction.proof:type_name -> nogh.Proof - 12, // 20: nogh.IssueAction.metadata:type_name -> nogh.IssueAction.MetadataEntry - 21, // [21:21] is the sub-list for method output_type - 21, // [21:21] is the sub-list for method input_type - 21, // [21:21] is the sub-list for extension type_name - 21, // [21:21] is the sub-list for extension extendee - 0, // [0:21] is the sub-list for field type_name + 15, // 14: nogh.TransferAction.e_signers:type_name -> nogh.Identity + 2, // 15: nogh.IssueActionInput.id:type_name -> nogh.TokenID + 0, // 16: nogh.IssueActionOutput.token:type_name -> nogh.Token + 15, // 17: nogh.IssueAction.issuer:type_name -> nogh.Identity + 8, // 18: nogh.IssueAction.inputs:type_name -> nogh.IssueActionInput + 9, // 19: nogh.IssueAction.outputs:type_name -> nogh.IssueActionOutput + 6, // 20: nogh.IssueAction.proof:type_name -> nogh.Proof + 12, // 21: nogh.IssueAction.metadata:type_name -> nogh.IssueAction.MetadataEntry + 22, // [22:22] is the sub-list for method output_type + 22, // [22:22] is the sub-list for method input_type + 22, // [22:22] is the sub-list for extension type_name + 22, // [22:22] is the sub-list for extension extendee + 0, // [0:22] is the sub-list for field type_name } func init() { file_noghactions_proto_init() } @@ -845,7 +856,7 @@ func file_noghactions_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_noghactions_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_noghactions_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Token); i { case 0: return &v.state @@ -857,7 +868,7 @@ func file_noghactions_proto_init() { return nil } } - file_noghactions_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_noghactions_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*TokenMetadata); i { case 0: return &v.state @@ -869,7 +880,7 @@ func file_noghactions_proto_init() { return nil } } - file_noghactions_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_noghactions_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*TokenID); i { case 0: return &v.state @@ -881,7 +892,7 @@ func file_noghactions_proto_init() { return nil } } - file_noghactions_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_noghactions_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*TransferActionInput); i { case 0: return &v.state @@ -893,7 +904,7 @@ func file_noghactions_proto_init() { return nil } } - file_noghactions_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_noghactions_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*TransferActionInputUpgradeWitness); i { case 0: return &v.state @@ -905,7 +916,7 @@ func file_noghactions_proto_init() { return nil } } - file_noghactions_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_noghactions_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*TransferActionOutput); i { case 0: return &v.state @@ -917,7 +928,7 @@ func file_noghactions_proto_init() { return nil } } - file_noghactions_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_noghactions_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*Proof); i { case 0: return &v.state @@ -929,7 +940,7 @@ func file_noghactions_proto_init() { return nil } } - file_noghactions_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_noghactions_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*TransferAction); i { case 0: return &v.state @@ -941,7 +952,7 @@ func file_noghactions_proto_init() { return nil } } - file_noghactions_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_noghactions_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*IssueActionInput); i { case 0: return &v.state @@ -953,7 +964,7 @@ func file_noghactions_proto_init() { return nil } } - file_noghactions_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_noghactions_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*IssueActionOutput); i { case 0: return &v.state @@ -965,7 +976,7 @@ func file_noghactions_proto_init() { return nil } } - file_noghactions_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_noghactions_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*IssueAction); i { case 0: return &v.state diff --git a/token/core/zkatdlog/nogh/protos/noghactions.proto b/token/core/zkatdlog/nogh/protos/noghactions.proto index 0aa11c3e3..7e3f686db 100644 --- a/token/core/zkatdlog/nogh/protos/noghactions.proto +++ b/token/core/zkatdlog/nogh/protos/noghactions.proto @@ -55,6 +55,7 @@ message TransferAction { repeated TransferActionOutput outputs = 2; // outputs Proof proof = 3; // ZK Proof that shows that the transfer is correct map metadata = 4; // Metadata contains the transfer action's metadata + repeated Identity e_signers = 5; // ESigners is the list of extra signer of the transfer action } message IssueActionInput { diff --git a/token/core/zkatdlog/nogh/v1/transfer.go b/token/core/zkatdlog/nogh/v1/transfer.go index 1fa31690b..3b52031d5 100644 --- a/token/core/zkatdlog/nogh/v1/transfer.go +++ b/token/core/zkatdlog/nogh/v1/transfer.go @@ -111,6 +111,7 @@ func (s *TransferService) Transfer( _ driver.OwnerWallet, tokenIDs []*token2.ID, outputTokens []*token2.Token, + issuerPublicKey []byte, opts *driver.TransferOptions, ) (driver.TransferAction, *driver.TransferMetadata, error) { span := trace.SpanFromContext(ctx) @@ -136,6 +137,8 @@ func (s *TransferService) Transfer( return nil, nil, errors.Wrapf(err, "failed to prepare inputs") } + var isRedeem bool + // get sender pp := s.PublicParametersManager.PublicParams() sender, err := transfer.NewSender(nil, prepareInputs.Tokens(), tokenIDs, prepareInputs.Metadata(), pp) @@ -153,6 +156,10 @@ func (s *TransferService) Transfer( } values = append(values, q.ToBigInt().Uint64()) owners = append(owners, output.Owner) + + if len(output.Owner) == 0 { + isRedeem = true + } } // produce zkatdlog transfer action // return for each output its information in the clear @@ -259,6 +266,22 @@ func (s *TransferService) Transfer( ExtraSigners: nil, } + if isRedeem { + var issuer driver.Identity + if issuerPublicKey != nil { + issuer = issuerPublicKey + } else { + issuers := s.PublicParametersManager.PublicParameters().Issuers() + if len(issuers) == 0 { + return nil, nil, errors.New("no issuers found") + } + issuer = issuers[0] + } + + transfer.ESigners = []driver.Identity{issuer} + transferMetadata.ExtraSigners = []driver.Identity{issuer} + } + return transfer, transferMetadata, nil } diff --git a/token/core/zkatdlog/nogh/v1/transfer/action.go b/token/core/zkatdlog/nogh/v1/transfer/action.go index dce4cdf46..cd13c4907 100644 --- a/token/core/zkatdlog/nogh/v1/transfer/action.go +++ b/token/core/zkatdlog/nogh/v1/transfer/action.go @@ -13,6 +13,7 @@ import ( factions "github.com/hyperledger-labs/fabric-token-sdk/token/core/fabtoken/protos-go/actions" fv1 "github.com/hyperledger-labs/fabric-token-sdk/token/core/fabtoken/v1/core" "github.com/hyperledger-labs/fabric-token-sdk/token/core/zkatdlog/nogh/protos-go/actions" + "github.com/hyperledger-labs/fabric-token-sdk/token/core/zkatdlog/nogh/protos-go/pp" "github.com/hyperledger-labs/fabric-token-sdk/token/core/zkatdlog/nogh/protos-go/utils" "github.com/hyperledger-labs/fabric-token-sdk/token/core/zkatdlog/nogh/v1/token" "github.com/hyperledger-labs/fabric-token-sdk/token/driver" @@ -121,6 +122,8 @@ type Action struct { Proof []byte // Metadata contains the transfer action's metadata Metadata map[string][]byte + // ExtraSigners contains the identities that need to sign the transfer action + ESigners []driver.Identity } // NewTransfer returns the Action that matches the passed arguments @@ -149,6 +152,7 @@ func NewTransfer(tokenIDs []*token2.ID, inputToken []*token.Token, commitments [ Outputs: tokens, Proof: proof, Metadata: map[string][]byte{}, + ESigners: nil, }, nil } @@ -283,7 +287,7 @@ func (t *Action) Validate() error { } func (t *Action) ExtraSigners() []driver.Identity { - return nil + return t.ESigners } // Serialize marshal TransferAction @@ -311,6 +315,14 @@ func (t *Action) Serialize() ([]byte, error) { return nil, errors.Wrap(err, "failed to serialize outputs") } + // extra signers + extraSigners := make([]*pp.Identity, len(t.ESigners)) + for i, s := range t.ESigners { + extraSigners[i] = &pp.Identity{ + Raw: s.Bytes(), + } + } + action := &actions.TransferAction{ Inputs: inputs, Outputs: outputs, @@ -318,6 +330,7 @@ func (t *Action) Serialize() ([]byte, error) { Proof: t.Proof, }, Metadata: t.Metadata, + ESigners: extraSigners, } return proto.Marshal(action) } @@ -358,6 +371,12 @@ func (t *Action) Deserialize(raw []byte) error { } t.Metadata = action.Metadata + // extra signers + t.ESigners = make([]driver.Identity, len(action.ESigners)) + for i, s := range action.ESigners { + t.ESigners[i] = driver.Identity(s.Raw) + } + return nil } diff --git a/token/core/zkatdlog/nogh/v1/transfer/action_test.go b/token/core/zkatdlog/nogh/v1/transfer/action_test.go index 204dd627d..7e8651834 100644 --- a/token/core/zkatdlog/nogh/v1/transfer/action_test.go +++ b/token/core/zkatdlog/nogh/v1/transfer/action_test.go @@ -16,6 +16,7 @@ import ( "github.com/hyperledger-labs/fabric-token-sdk/token/core/common/encoding/json" fabtokenv1 "github.com/hyperledger-labs/fabric-token-sdk/token/core/fabtoken/v1/core" token2 "github.com/hyperledger-labs/fabric-token-sdk/token/core/zkatdlog/nogh/v1/token" + "github.com/hyperledger-labs/fabric-token-sdk/token/driver" "github.com/hyperledger-labs/fabric-token-sdk/token/token" "github.com/stretchr/testify/assert" ) @@ -488,5 +489,6 @@ func randomAction(curve *math.Curve, rand io.Reader, b assert.TestingT) *Action "key1": getRandomBytes(b, 32), "key2": getRandomBytes(b, 32), } + action.ESigners = make([]driver.Identity, 0) return action } diff --git a/token/core/zkatdlog/nogh/v1/validator/validator_test.go b/token/core/zkatdlog/nogh/v1/validator/validator_test.go index 169417d66..a87b8594a 100644 --- a/token/core/zkatdlog/nogh/v1/validator/validator_test.go +++ b/token/core/zkatdlog/nogh/v1/validator/validator_test.go @@ -309,7 +309,15 @@ func prepareRedeemRequest(pp *v1.PublicParams, auditor *audit.Auditor) (*transfe owners := make([][]byte, 2) owners[0] = id - return prepareTransfer(pp, signer, auditor, auditInfo, id, owners) + issuerSigner, err := ecdsa.NewECDSASigner() + Expect(err).NotTo(HaveOccurred()) + + issuer := &issue2.Issuer{} + issuer.New("ABC", issuerSigner, pp) + issuerIdentity, err := issuerSigner.Serialize() + Expect(err).NotTo(HaveOccurred()) + + return prepareTransfer(pp, signer, auditor, auditInfo, id, owners, issuer, issuerIdentity) } func prepareTransferRequest(pp *v1.PublicParams, auditor *audit.Auditor) (*transfer.Sender, *driver.TokenRequest, *driver.TokenRequestMetadata, []*tokn.Token) { @@ -318,7 +326,7 @@ func prepareTransferRequest(pp *v1.PublicParams, auditor *audit.Auditor) (*trans owners[0] = id owners[1] = id - return prepareTransfer(pp, signer, auditor, auditInfo, id, owners) + return prepareTransfer(pp, signer, auditor, auditInfo, id, owners, nil, nil) } func prepareTokens(values, bf []*math.Zr, ttype string, pp []*math.G1, curve *math.Curve) []*math.G1 { @@ -479,7 +487,7 @@ func prepareIssue(auditor *audit.Auditor, issuer *issue2.Issuer, issuerIdentity return ir, issueMetadata } -func prepareTransfer(pp *v1.PublicParams, signer driver.SigningIdentity, auditor *audit.Auditor, auditInfo *crypto.AuditInfo, id []byte, owners [][]byte) (*transfer.Sender, *driver.TokenRequest, *driver.TokenRequestMetadata, []*tokn.Token) { +func prepareTransfer(pp *v1.PublicParams, signer driver.SigningIdentity, auditor *audit.Auditor, auditInfo *crypto.AuditInfo, id []byte, owners [][]byte, issuer *issue2.Issuer, issuerIdentity []byte) (*transfer.Sender, *driver.TokenRequest, *driver.TokenRequestMetadata, []*tokn.Token) { signers := make([]driver.Signer, 2) signers[0] = signer @@ -515,10 +523,14 @@ func prepareTransfer(pp *v1.PublicParams, signer driver.SigningIdentity, auditor sender, err := transfer.NewSender(signers, tokens, ids, inputInf, pp) Expect(err).NotTo(HaveOccurred()) - transfer, metas, err := sender.GenerateZKTransfer(context.TODO(), outvalues, owners) + transfer2, metas, err := sender.GenerateZKTransfer(context.TODO(), outvalues, owners) Expect(err).NotTo(HaveOccurred()) - transferRaw, err := transfer.Serialize() + if issuerIdentity != nil { + transfer2.ESigners = []driver.Identity{issuerIdentity} + } + + transferRaw, err := transfer2.Serialize() Expect(err).NotTo(HaveOccurred()) tr := &driver.TokenRequest{Transfers: [][]byte{transferRaw}} @@ -533,7 +545,7 @@ func prepareTransfer(pp *v1.PublicParams, signer driver.SigningIdentity, auditor auditInfoRaw, err := auditInfo.Bytes() Expect(err).NotTo(HaveOccurred()) metadata := &driver.TransferMetadata{} - for i := 0; i < len(transfer.Inputs); i++ { + for i := 0; i < len(transfer2.Inputs); i++ { metadata.Inputs = append(metadata.Inputs, &driver.TransferInputMetadata{ TokenID: nil, Senders: []*driver.AuditableIdentity{ @@ -546,7 +558,7 @@ func prepareTransfer(pp *v1.PublicParams, signer driver.SigningIdentity, auditor Expect(err).NotTo(HaveOccurred()) } - for i := 0; i < len(transfer.Outputs); i++ { + for i := 0; i < len(transfer2.Outputs); i++ { marshalledinf, err := metas[i].Serialize() Expect(err).NotTo(HaveOccurred()) metadata.Outputs = append(metadata.Outputs, &driver.TransferOutputMetadata{ @@ -565,8 +577,13 @@ func prepareTransfer(pp *v1.PublicParams, signer driver.SigningIdentity, auditor for i := 0; i < len(tokens); i++ { tokns[0] = append(tokns[0], tokens[i]) } - transferMetadata := &driver.TokenRequestMetadata{Transfers: []*driver.TransferMetadata{metadata}} - err = auditor.Check(context.Background(), tr, transferMetadata, tokns, "1") + + if issuerIdentity != nil { + metadata.ExtraSigners = []driver.Identity{issuerIdentity} + } + transfersMetadata := []*driver.TransferMetadata{metadata} + tokenRequestMetadata := &driver.TokenRequestMetadata{Transfers: transfersMetadata} + err = auditor.Check(context.Background(), tr, tokenRequestMetadata, tokns, "1") Expect(err).NotTo(HaveOccurred()) sigma, err := auditor.Endorse(tr, "1") @@ -575,9 +592,17 @@ func prepareTransfer(pp *v1.PublicParams, signer driver.SigningIdentity, auditor signatures, err := sender.SignTokenActions(raw) Expect(err).NotTo(HaveOccurred()) + tr.Signatures = append(tr.Signatures, signatures...) - return sender, tr, transferMetadata, tokens + // Add issuer signature for redeem case + if issuer != nil { + issuerSignature, err := issuer.Signer.Sign(raw) + Expect(err).NotTo(HaveOccurred()) + tr.Signatures = append(tr.Signatures, issuerSignature) + } + + return sender, tr, tokenRequestMetadata, tokens } func getState(id token2.ID) ([]byte, error) { diff --git a/token/core/zkatdlog/nogh/v1/validator/validator_transfer.go b/token/core/zkatdlog/nogh/v1/validator/validator_transfer.go index 98883c348..f6352621e 100644 --- a/token/core/zkatdlog/nogh/v1/validator/validator_transfer.go +++ b/token/core/zkatdlog/nogh/v1/validator/validator_transfer.go @@ -55,6 +55,36 @@ func TransferSignatureValidate(ctx *Context) error { signatures = append(signatures, sigma) } + // If transfer action is a redeem action, verify the signature of the issuer + isRedeem := func() bool { + for _, output := range ctx.TransferAction.Outputs { + if output.Owner == nil { + return true + } + } + return false + } + + if isRedeem() { + ctx.Logger.Infof("redeem action") + extraSigners := ctx.TransferAction.ESigners + if len(extraSigners) < 1 { + return errors.New("no extra signers provided for redeem action") + } + issuer := ctx.TransferAction.ESigners[0] // issuer is the first extra signer + + verifier, err := ctx.Deserializer.GetIssuerVerifier(issuer) + if err != nil { + return errors.Wrapf(err, "failed deserializing issuer [%s]", issuer.UniqueID()) + } + + sigma, err := ctx.SignatureProvider.HasBeenSignedBy(issuer, verifier) + if err != nil { + return errors.Wrapf(err, "failed signature verification [%s]", issuer.UniqueID()) + } + signatures = append(signatures, sigma) + } + ctx.InputTokens = inputToken ctx.Signatures = signatures diff --git a/token/driver/transfer.go b/token/driver/transfer.go index f0d2179fa..917d9f451 100644 --- a/token/driver/transfer.go +++ b/token/driver/transfer.go @@ -25,7 +25,7 @@ type TransferService interface { // Transfer generates a TransferAction that spend the passed token ids and created the passed outputs. // In addition, a set of options can be specified to further customize the transfer command. // The function returns an TransferAction and the associated metadata. - Transfer(ctx context.Context, txID string, wallet OwnerWallet, ids []*token2.ID, Outputs []*token2.Token, opts *TransferOptions) (TransferAction, *TransferMetadata, error) + Transfer(ctx context.Context, txID string, wallet OwnerWallet, ids []*token2.ID, Outputs []*token2.Token, issuerPublicKey []byte, opts *TransferOptions) (TransferAction, *TransferMetadata, error) // VerifyTransfer checks the well-formedness of the passed TransferAction with the respect to the passed output metadata VerifyTransfer(tr TransferAction, outputMetadata []*TransferOutputMetadata) error diff --git a/token/request.go b/token/request.go index f1aac32e7..8cd129c58 100644 --- a/token/request.go +++ b/token/request.go @@ -317,6 +317,7 @@ func (r *Request) Transfer(ctx context.Context, wallet *OwnerWallet, typ token.T wallet.w, tokenIDs, outputTokens, + nil, &driver.TransferOptions{ Attributes: opt.Attributes, }, @@ -345,7 +346,7 @@ func (r *Request) Transfer(ctx context.Context, wallet *OwnerWallet, typ token.T // Redeem appends a redeem action to the request. The action will be prepared using the provided owner wallet. // The action redeems tokens of the passed type for a total amount matching the passed value. // Additional options can be passed to customize the action. -func (r *Request) Redeem(ctx context.Context, wallet *OwnerWallet, typ token.Type, value uint64, opts ...TransferOption) error { +func (r *Request) Redeem(ctx context.Context, wallet *OwnerWallet, typ token.Type, value uint64, issuerPublicKey []byte, opts ...TransferOption) error { opt, err := compileTransferOptions(opts...) if err != nil { return errors.WithMessagef(err, "failed compiling options [%v]", opts) @@ -360,12 +361,14 @@ func (r *Request) Redeem(ctx context.Context, wallet *OwnerWallet, typ token.Typ ts := r.TokenService.tms.TransferService() // Compute redeem, it is a transfer with owner set to nil + logger.Infof("L1=", len(issuerPublicKey), issuerPublicKey[20], issuerPublicKey[21]) transfer, transferMetadata, err := ts.Transfer( ctx, r.Anchor, wallet.w, tokenIDs, outputTokens, + issuerPublicKey, &driver.TransferOptions{ Attributes: opt.Attributes, }, diff --git a/token/services/ttx/transaction.go b/token/services/ttx/transaction.go index ae91646dd..e157ffe0f 100644 --- a/token/services/ttx/transaction.go +++ b/token/services/ttx/transaction.go @@ -244,8 +244,8 @@ func (t *Transaction) Transfer(wallet *token.OwnerWallet, typ token2.Type, value return err } -func (t *Transaction) Redeem(wallet *token.OwnerWallet, typ token2.Type, value uint64, opts ...token.TransferOption) error { - return t.TokenRequest.Redeem(t.Context, wallet, typ, value, opts...) +func (t *Transaction) Redeem(wallet *token.OwnerWallet, typ token2.Type, value uint64, issuerPublicKey []byte, opts ...token.TransferOption) error { + return t.TokenRequest.Redeem(t.Context, wallet, typ, value, issuerPublicKey, opts...) } // Upgrade performs an upgrade operation of the passed ledger tokens.