/
info.go
127 lines (108 loc) · 3.98 KB
/
info.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
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package ttx
import (
"github.com/hyperledger-labs/fabric-smart-client/platform/view"
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/kvs"
"github.com/hyperledger-labs/fabric-token-sdk/token"
"github.com/hyperledger-labs/fabric-token-sdk/token/services/network"
"github.com/hyperledger-labs/fabric-token-sdk/token/services/owner"
"github.com/hyperledger-labs/fabric-token-sdk/token/services/vault/keys"
"github.com/pkg/errors"
)
const (
// EndorsementAckPrefix is the prefix for the endorsement ACKs.
EndorsementAckPrefix = "ttx.endorse.ack"
)
type TokenTransactionDB interface {
GetTokenRequest(txID string) ([]byte, error)
}
// TransactionInfo contains the transaction info.
type TransactionInfo struct {
// EndorsementAcks contains the endorsement ACKs received at time of dissemination.
EndorsementAcks map[string][]byte
// ApplicationMetadata contains the application metadata
ApplicationMetadata map[string][]byte
TokenRequest []byte
}
// TransactionInfoProvider allows the retrieval of the transaction info
type TransactionInfoProvider struct {
sp view.ServiceProvider
tms *token.ManagementService
ttxDB TokenTransactionDB
}
func NewTransactionInfoProvider(sp view.ServiceProvider, tms *token.ManagementService) *TransactionInfoProvider {
return &TransactionInfoProvider{sp: sp, tms: tms, ttxDB: owner.Get(sp, tms)}
}
func NewTransactionInfoProviderFor(sp view.ServiceProvider, tms *token.ManagementService, ttxDB TokenTransactionDB) *TransactionInfoProvider {
return &TransactionInfoProvider{sp: sp, tms: tms, ttxDB: ttxDB}
}
// TransactionInfo returns the transaction info for the given transaction ID.
func (a *TransactionInfoProvider) TransactionInfo(txID string) (*TransactionInfo, error) {
endorsementAcks, err := a.loadEndorsementAcks(txID)
if err != nil {
return nil, errors.WithMessagef(err, "failed to load endorsement acks for [%s]", txID)
}
applicationMetadata, err := a.loadTransient(txID)
if err != nil {
return nil, errors.WithMessagef(err, "failed to load transient for [%s]", txID)
}
tr, err := a.ttxDB.GetTokenRequest(txID)
if err != nil {
return nil, errors.WithMessagef(err, "failed to load token request for [%s]", txID)
}
return &TransactionInfo{
EndorsementAcks: endorsementAcks,
ApplicationMetadata: applicationMetadata,
TokenRequest: tr,
}, nil
}
func (a *TransactionInfoProvider) loadEndorsementAcks(txID string) (map[string][]byte, error) {
// Load transaction endorsement ACKs
k := kvs.GetService(a.sp)
acks := make(map[string][]byte)
it, err := k.GetByPartialCompositeID(EndorsementAckPrefix, []string{txID})
if err != nil {
return nil, errors.WithMessagef(err, "failed loading ack for [%s]", txID)
}
defer it.Close()
for {
if !it.HasNext() {
break
}
var ack []byte
key, err := it.Next(&ack)
if err != nil {
return nil, errors.WithMessagef(err, "failed loading ack for [%s]", txID)
}
objectType, attrs, err := kvs.SplitCompositeKey(key)
if err != nil {
return nil, errors.WithMessagef(err, "failed splitting composite key for [%s]", txID)
}
if objectType != EndorsementAckPrefix {
return nil, errors.Errorf("unexpected object type [%s]", objectType)
}
if len(attrs) != 2 {
return nil, errors.Errorf("unexpected number of attributes [%d]", len(attrs))
}
acks[attrs[1]] = ack
}
return acks, nil
}
func (a *TransactionInfoProvider) loadTransient(txID string) (map[string][]byte, error) {
tm, err := network.GetInstance(a.sp, a.tms.Network(), a.tms.Channel()).GetTransient(txID)
if err != nil {
return nil, errors.WithMessagef(err, "failed to load transient for [%s]", txID)
}
if !tm.Exists(keys.TokenRequestMetadata) {
return nil, nil
}
raw := tm.Get(keys.TokenRequestMetadata)
metadata, err := a.tms.NewMetadataFromBytes(raw)
if err != nil {
return nil, errors.WithMessagef(err, "failed to unmarshal transient for [%s]", txID)
}
return metadata.TokenRequestMetadata.Application, nil
}