/
sender.go
142 lines (126 loc) · 4.72 KB
/
sender.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package fabtoken
import (
"github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
"github.com/hyperledger-labs/fabric-token-sdk/token/core/common"
"github.com/hyperledger-labs/fabric-token-sdk/token/core/identity"
"github.com/hyperledger-labs/fabric-token-sdk/token/core/interop/htlc"
"github.com/hyperledger-labs/fabric-token-sdk/token/driver"
token2 "github.com/hyperledger-labs/fabric-token-sdk/token/token"
"github.com/pkg/errors"
)
// Transfer returns a TransferAction as a function of the passed arguments
// It also returns the corresponding TransferMetadata
func (s *Service) Transfer(txID string, wallet driver.OwnerWallet, ids []*token2.ID, Outputs []*token2.Token, opts *driver.TransferOptions) (driver.TransferAction, *driver.TransferMetadata, error) {
// select inputs
inputIDs, inputTokens, err := s.TokenLoader.GetTokens(ids)
if err != nil {
return nil, nil, errors.WithMessagef(err, "failed loading input tokens")
}
var signerIds []view.Identity
for _, tok := range inputTokens {
logger.Debugf("Selected output [%s,%s,%s]", tok.Type, tok.Quantity, view.Identity(tok.Owner.Raw))
signerIds = append(signerIds, tok.Owner.Raw)
}
// prepare outputs
var outs []*Output
var metas [][]byte
for _, output := range Outputs {
outs = append(outs, &Output{
Output: output,
})
meta := &OutputMetadata{}
metaRaw, err := meta.Serialize()
if err != nil {
return nil, nil, errors.Wrapf(err, "failed serializing token information")
}
metas = append(metas, metaRaw)
}
// assemble transfer action
transfer := &TransferAction{
Inputs: inputIDs,
Outputs: outs,
Metadata: map[string][]byte{},
}
// add transfer action's metadata
common.SetTransferActionMetadata(opts.Attributes, transfer.Metadata)
// assemble transfer metadata
var receivers []view.Identity
for i, output := range outs {
if output.Output == nil || output.Output.Owner == nil {
return nil, nil, errors.Errorf("failed to transfer: invalid output at index %d", i)
}
if len(output.Output.Owner.Raw) == 0 { // redeem
receivers = append(receivers, output.Output.Owner.Raw)
continue
}
owner, err := identity.UnmarshallRawOwner(output.Output.Owner.Raw)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to unmarshal owner of input token")
}
if owner.Type == identity.SerializedIdentityType {
receivers = append(receivers, output.Output.Owner.Raw)
continue
}
_, recipient, err := htlc.GetScriptSenderAndRecipient(owner)
if err != nil {
return nil, nil, errors.Wrap(err, "failed getting script sender and recipient")
}
receivers = append(receivers, recipient)
}
var senderAuditInfos [][]byte
for _, t := range inputTokens {
auditInfo, err := htlc.GetOwnerAuditInfo(t.Owner.Raw, s)
if err != nil {
return nil, nil, errors.Wrapf(err, "failed getting audit info for sender identity [%s]", view.Identity(t.Owner.Raw).String())
}
senderAuditInfos = append(senderAuditInfos, auditInfo)
}
var receiverAuditInfos [][]byte
for _, output := range outs {
auditInfo, err := htlc.GetOwnerAuditInfo(output.Output.Owner.Raw, s)
if err != nil {
return nil, nil, errors.Wrapf(err, "failed getting audit info for recipient identity [%s]", view.Identity(output.Output.Owner.Raw).String())
}
receiverAuditInfos = append(receiverAuditInfos, auditInfo)
}
outputs, err := transfer.GetSerializedOutputs()
if err != nil {
return nil, nil, errors.Wrapf(err, "failed getting serialized outputs")
}
receiverIsSender := make([]bool, len(receivers))
for i, receiver := range receivers {
_, err = s.OwnerWalletByID(receiver)
receiverIsSender[i] = err == nil
}
metadata := &driver.TransferMetadata{
Outputs: outputs,
Senders: signerIds,
SenderAuditInfos: senderAuditInfos,
TokenIDs: ids,
OutputsMetadata: metas,
Receivers: receivers,
ReceiverIsSender: receiverIsSender,
ReceiverAuditInfos: receiverAuditInfos,
}
logger.Debugf("Transfer metadata: [out:%d, rec:%d]", len(metadata.Outputs), len(metadata.Receivers))
// done
return transfer, metadata, nil
}
// VerifyTransfer checks the outputs in the TransferAction against the passed tokenInfos
func (s *Service) VerifyTransfer(tr driver.TransferAction, outputsMetadata [][]byte) error {
// TODO:
return nil
}
// DeserializeTransferAction un-marshals a TransferAction from the passed array of bytes.
// DeserializeTransferAction returns an error, if the un-marshalling fails.
func (s *Service) DeserializeTransferAction(raw []byte) (driver.TransferAction, error) {
t := &TransferAction{}
if err := t.Deserialize(raw); err != nil {
return nil, errors.Wrap(err, "failed deserializing transfer action")
}
return t, nil
}