-
Notifications
You must be signed in to change notification settings - Fork 0
/
scc.go
152 lines (124 loc) · 4.35 KB
/
scc.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
143
144
145
146
147
148
149
150
151
152
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package lifecycle
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
lb "github.com/hyperledger/fabric/protos/peer/lifecycle"
"github.com/pkg/errors"
)
const (
//InstalledChaincodeFuncName is the chaincode function name used to install a chaincode
InstallChaincodeFuncName = "InstallChaincode"
// QueryInstalledChaincodeFuncName is the chaincode function name used to query an installed chaincode
QueryInstalledChaincodeFuncName = "QueryInstalledChaincode"
)
// SCCFunctions provides a backing implementation with concrete arguments
// for each of the SCC functions
type SCCFunctions interface {
// InstallChaincode persists a chaincode definition to disk
InstallChaincode(name, version string, chaincodePackage []byte) (hash []byte, err error)
// QueryInstalledChaincode returns the hash for a given name and version of an installed chaincode
QueryInstalledChaincode(name, version string) (hash []byte, err error)
}
// SCC implements the required methods to satisfy the chaincode interface.
// It routes the invocation calls to the backing implementations.
type SCC struct {
Protobuf Protobuf
Functions SCCFunctions
}
// Name returns "+lifecycle"
func (scc *SCC) Name() string {
return "+lifecycle"
}
// Path returns "github.com/hyperledger/fabric/core/chaincode/lifecycle"
func (scc *SCC) Path() string {
return "github.com/hyperledger/fabric/core/chaincode/lifecycle"
}
// InitArgs returns nil
func (scc *SCC) InitArgs() [][]byte {
return nil
}
// Chaincode returns a reference to itself
func (scc *SCC) Chaincode() shim.Chaincode {
return scc
}
// InvokableExternal returns true
func (scc *SCC) InvokableExternal() bool {
return true
}
// InvokableCC2CC returns true
func (scc *SCC) InvokableCC2CC() bool {
return true
}
// Enabled returns true
func (scc *SCC) Enabled() bool {
return true
}
// Init is mostly useless for system chaincodes and always returns success
func (scc *SCC) Init(stub shim.ChaincodeStubInterface) pb.Response {
return shim.Success(nil)
}
// Invoke takes chaincode invocation arguments and routes them to the correct
// underlying lifecycle operation. All functions take a single argument of
// type marshaled lb.<FunctionName>Args and return a marshaled lb.<FunctionName>Result
func (scc *SCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
args := stub.GetArgs()
if len(args) == 0 {
return shim.Error("lifecycle scc must be invoked with arguments")
}
if len(args) != 2 {
return shim.Error(fmt.Sprintf("lifecycle scc operations require exactly two arguments but received %d", len(args)))
}
funcName := args[0]
inputBytes := args[1]
// TODO add ACLs
switch string(funcName) {
// Each lifecycle SCC function gets a case here
case InstallChaincodeFuncName:
input := &lb.InstallChaincodeArgs{}
err := scc.Protobuf.Unmarshal(inputBytes, input)
if err != nil {
err = errors.WithMessage(err, "failed to decode input arg to InstallChaincode")
return shim.Error(err.Error())
}
hash, err := scc.Functions.InstallChaincode(input.Name, input.Version, input.ChaincodeInstallPackage)
if err != nil {
err = errors.WithMessage(err, "failed to invoke backing InstallChaincode")
return shim.Error(err.Error())
}
resultBytes, err := scc.Protobuf.Marshal(&lb.InstallChaincodeResult{
Hash: hash,
})
if err != nil {
err = errors.WithMessage(err, "failed to marshal result")
return shim.Error(err.Error())
}
return shim.Success(resultBytes)
case QueryInstalledChaincodeFuncName:
input := &lb.QueryInstalledChaincodeArgs{}
err := scc.Protobuf.Unmarshal(inputBytes, input)
if err != nil {
err = errors.WithMessage(err, "failed to decode input arg to QueryInstalledChaincode")
return shim.Error(err.Error())
}
hash, err := scc.Functions.QueryInstalledChaincode(input.Name, input.Version)
if err != nil {
err = errors.WithMessage(err, "failed to invoke backing QueryInstalledChaincode")
return shim.Error(err.Error())
}
resultBytes, err := scc.Protobuf.Marshal(&lb.QueryInstalledChaincodeResult{
Hash: hash,
})
if err != nil {
err = errors.WithMessage(err, "failed to marshal result")
return shim.Error(err.Error())
}
return shim.Success(resultBytes)
default:
return shim.Error(fmt.Sprintf("unknown lifecycle function: %s", funcName))
}
}