Skip to content

Commit 458328b

Browse files
committedFeb 19, 2017
Chaincode API Enhancement
This change-set allows the chaincode to get the proposal's creator, transient field and binding. This is done by trasferring to the chiancode the proposal. This change-set comes in the context of https://jira.hyperledger.org/browse/FAB-1751 and https://jira.hyperledger.org/browse/FAB-1752 Change-Id: I8ac643a24008fbe7edf2779636dc0de1d1a0ddc1 Signed-off-by: Angelo De Caro <adc@zurich.ibm.com>
1 parent dd658bf commit 458328b

30 files changed

+796
-683
lines changed
 

‎accesscontrol/crypto/attr/attr_support.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import (
2828

2929
// chaincodeHolder is the struct that hold the certificate and the metadata. An implementation is ChaincodeStub
3030
type chaincodeHolder interface {
31-
// GetCallerCertificate returns caller certificate
32-
GetCallerCertificate() ([]byte, error)
31+
// GetCreator returns caller certificate
32+
GetCreator() ([]byte, error)
3333

3434
// GetCallerMetadata returns caller metadata
3535
/*
@@ -82,8 +82,8 @@ type chaincodeHolderImpl struct {
8282
Certificate []byte
8383
}
8484

85-
// GetCallerCertificate returns caller certificate
86-
func (holderImpl *chaincodeHolderImpl) GetCallerCertificate() ([]byte, error) {
85+
// GetCreator returns caller certificate
86+
func (holderImpl *chaincodeHolderImpl) GetCreator() ([]byte, error) {
8787
return holderImpl.Certificate, nil
8888
}
8989

@@ -99,7 +99,7 @@ func GetValueFrom(attributeName string, cert []byte) ([]byte, error) {
9999
//NewAttributesHandlerImpl creates a new AttributesHandlerImpl from a pb.ChaincodeSecurityContext object.
100100
func NewAttributesHandlerImpl(holder chaincodeHolder) (*AttributesHandlerImpl, error) {
101101
// Getting certificate
102-
certRaw, err := holder.GetCallerCertificate()
102+
certRaw, err := holder.GetCreator()
103103
if err != nil {
104104
return nil, err
105105
}

‎accesscontrol/crypto/attr/attr_support_test.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ type chaincodeStubMock struct {
4040
*/
4141
}
4242

43-
// GetCallerCertificate returns caller certificate
44-
func (shim *chaincodeStubMock) GetCallerCertificate() ([]byte, error) {
43+
// GetCreator returns caller certificate
44+
func (shim *chaincodeStubMock) GetCreator() ([]byte, error) {
4545
return shim.callerCert, nil
4646
}
4747

@@ -60,9 +60,9 @@ type certErrorMock struct {
6060
*/
6161
}
6262

63-
// GetCallerCertificate returns caller certificate
64-
func (shim *certErrorMock) GetCallerCertificate() ([]byte, error) {
65-
return nil, errors.New("GetCallerCertificate error")
63+
// GetCreator returns caller certificate
64+
func (shim *certErrorMock) GetCreator() ([]byte, error) {
65+
return nil, errors.New("GetCreator error")
6666
}
6767

6868
/*
@@ -76,16 +76,16 @@ type metadataErrorMock struct {
7676
callerCert []byte
7777
}
7878

79-
// GetCallerCertificate returns caller certificate
80-
func (shim *metadataErrorMock) GetCallerCertificate() ([]byte, error) {
79+
// GetCreator returns caller certificate
80+
func (shim *metadataErrorMock) GetCreator() ([]byte, error) {
8181
return shim.callerCert, nil
8282
}
8383

8484
/*
8585
TODO: ##attributes-keys-pending This code have be redefined to avoid use of metadata field.
8686
// GetCallerMetadata returns caller metadata
8787
func (shim *metadataErrorMock) GetCallerMetadata() ([]byte, error) {
88-
return nil, errors.New("GetCallerCertificate error")
88+
return nil, errors.New("GetCreator error")
8989
}*/
9090

9191
func TestVerifyAttribute(t *testing.T) {

‎core/chaincode/handler.go

+1-10
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import (
3131
"github.com/hyperledger/fabric/core/ledger"
3232
"github.com/hyperledger/fabric/core/peer"
3333
pb "github.com/hyperledger/fabric/protos/peer"
34-
"github.com/hyperledger/fabric/protos/utils"
3534
"github.com/looplab/fsm"
3635
logging "github.com/op/go-logging"
3736
"golang.org/x/net/context"
@@ -1379,13 +1378,7 @@ func (handler *Handler) setChaincodeProposal(prop *pb.Proposal, msg *pb.Chaincod
13791378
if prop != nil {
13801379
chaincodeLogger.Debug("Proposal different from nil. Creating chaincode proposal context...")
13811380

1382-
proposalContext, err := utils.GetChaincodeProposalContext(prop)
1383-
if err != nil {
1384-
chaincodeLogger.Debug("Failed getting proposal context from proposal [%s]", err)
1385-
return fmt.Errorf("Failed getting proposal context from proposal [%s]", err)
1386-
}
1387-
1388-
msg.ProposalContext = proposalContext
1381+
msg.Proposal = prop
13891382
}
13901383
return nil
13911384
}
@@ -1400,7 +1393,6 @@ func (handler *Handler) ready(ctxt context.Context, chainID string, txid string,
14001393
chaincodeLogger.Debug("sending READY")
14011394
ccMsg := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_READY, Txid: txid}
14021395

1403-
//if security is disabled the context elements will just be nil
14041396
if err := handler.setChaincodeProposal(prop, ccMsg); err != nil {
14051397
return nil, err
14061398
}
@@ -1465,7 +1457,6 @@ func (handler *Handler) sendExecuteMessage(ctxt context.Context, chainID string,
14651457
chaincodeLogger.Debugf("[%s]Inside sendExecuteMessage. Message %s", shorttxid(msg.Txid), msg.Type.String())
14661458
}
14671459

1468-
//if security is disabled the context elements will just be nil
14691460
if err = handler.setChaincodeProposal(prop, msg); err != nil {
14701461
return nil, err
14711462
}

‎core/chaincode/shim/chaincode.go

+53-35
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ import (
2929

3030
"github.com/golang/protobuf/proto"
3131
"github.com/golang/protobuf/ptypes/timestamp"
32-
"github.com/hyperledger/fabric/common/util"
3332
"github.com/hyperledger/fabric/core/comm"
3433
pb "github.com/hyperledger/fabric/protos/peer"
34+
"github.com/hyperledger/fabric/protos/utils"
3535
"github.com/op/go-logging"
3636
"github.com/spf13/viper"
3737
"golang.org/x/net/context"
@@ -49,11 +49,16 @@ const (
4949
// ChaincodeStub is an object passed to chaincode for shim side handling of
5050
// APIs.
5151
type ChaincodeStub struct {
52-
TxID string
53-
proposalContext *pb.ChaincodeProposalContext
54-
chaincodeEvent *pb.ChaincodeEvent
55-
args [][]byte
56-
handler *Handler
52+
TxID string
53+
chaincodeEvent *pb.ChaincodeEvent
54+
args [][]byte
55+
handler *Handler
56+
proposal *pb.Proposal
57+
58+
// Additional fields extracted from the proposal
59+
creator []byte
60+
transient map[string][]byte
61+
binding []byte
5762
}
5863

5964
// Peer address derived from command line or env var
@@ -270,20 +275,32 @@ func chatWithPeer(chaincodename string, stream PeerChaincodeStream, cc Chaincode
270275
// -- init stub ---
271276
// ChaincodeInvocation functionality
272277

273-
func (stub *ChaincodeStub) init(handler *Handler, txid string, input *pb.ChaincodeInput, proposalContext *pb.ChaincodeProposalContext) {
278+
func (stub *ChaincodeStub) init(handler *Handler, txid string, input *pb.ChaincodeInput, proposal *pb.Proposal) error {
274279
stub.TxID = txid
275280
stub.args = input.Args
276281
stub.handler = handler
277-
stub.proposalContext = proposalContext
278-
}
282+
stub.proposal = proposal
283+
284+
// TODO: sanity check: verify that every call to init with a nil
285+
// proposal is a legitimate one, meaning it is an internal call
286+
// to system chaincodes.
287+
if proposal != nil {
288+
// Extract creator, transient, binding...
289+
var err error
290+
stub.creator, stub.transient, err = utils.GetChaincodeProposalContext(proposal)
291+
if err != nil {
292+
return fmt.Errorf("Failed extracting proposal fields. [%s]", err)
293+
}
279294

280-
// InitTestStub initializes an appropriate stub for testing chaincode
281-
func InitTestStub(funargs ...string) *ChaincodeStub {
282-
stub := ChaincodeStub{}
283-
allargs := util.ToChaincodeArgs(funargs...)
284-
newCI := &pb.ChaincodeInput{Args: allargs}
285-
stub.init(&Handler{}, "TEST-txid", newCI, nil) // TODO: add msg.ProposalContext
286-
return &stub
295+
// TODO: txid must uniquely identity the transaction.
296+
// Remove this comment once replay attack protection will be in place
297+
stub.binding, err = utils.ComputeProposalBinding(proposal)
298+
if err != nil {
299+
return fmt.Errorf("Failed computing binding from proposal. [%s]", err)
300+
}
301+
}
302+
303+
return nil
287304
}
288305

289306
// GetTxID returns the transaction ID
@@ -505,33 +522,34 @@ func (stub *ChaincodeStub) GetFunctionAndParameters() (function string, params [
505522
return
506523
}
507524

508-
// GetCallerCertificate returns caller certificate
509-
func (stub *ChaincodeStub) GetCallerCertificate() ([]byte, error) {
510-
if stub.proposalContext != nil {
511-
return stub.proposalContext.Transient, nil
512-
}
513-
514-
return nil, errors.New("Creator field not set.")
525+
// GetCreator returns SignatureHeader.Creator of the proposal
526+
// this Stub refers to.
527+
func (stub *ChaincodeStub) GetCreator() ([]byte, error) {
528+
return stub.creator, nil
515529
}
516530

517-
// GetCallerMetadata returns caller metadata
518-
func (stub *ChaincodeStub) GetCallerMetadata() ([]byte, error) {
519-
if stub.proposalContext != nil {
520-
return stub.proposalContext.Transient, nil
521-
}
522-
523-
return nil, errors.New("Transient field not set.")
531+
// GetTransient returns the ChaincodeProposalPayload.transient field.
532+
// It is a map that contains data (e.g. cryptographic material)
533+
// that might be used to implement some form of application-level confidentiality. The contents
534+
// of this field, as prescribed by ChaincodeProposalPayload, are supposed to always
535+
// be omitted from the transaction and excluded from the ledger.
536+
func (stub *ChaincodeStub) GetTransient() (map[string][]byte, error) {
537+
return stub.transient, nil
524538
}
525539

526540
// GetBinding returns the transaction binding
527541
func (stub *ChaincodeStub) GetBinding() ([]byte, error) {
528-
return nil, nil
542+
return stub.binding, nil
529543
}
530544

531-
// GetPayload returns transaction payload, which is a `ChaincodeSpec` defined
532-
// in fabric/protos/chaincode.proto
533-
func (stub *ChaincodeStub) GetPayload() ([]byte, error) {
534-
return nil, nil
545+
// GetArgsSlice returns the arguments to the stub call as a byte array
546+
func (stub *ChaincodeStub) GetArgsSlice() ([]byte, error) {
547+
args := stub.GetArgs()
548+
res := []byte{}
549+
for _, barg := range args {
550+
res = append(res, barg...)
551+
}
552+
return res, nil
535553
}
536554

537555
// GetTxTimestamp returns transaction created timestamp, which is currently

‎core/chaincode/shim/handler.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,12 @@ func (handler *Handler) handleInit(msg *pb.ChaincodeMessage) {
227227
// Call chaincode's Run
228228
// Create the ChaincodeStub which the chaincode can use to callback
229229
stub := new(ChaincodeStub)
230-
stub.init(handler, msg.Txid, input, msg.ProposalContext)
230+
err := stub.init(handler, msg.Txid, input, msg.Proposal)
231+
if err != nil {
232+
chaincodeLogger.Errorf("[%s]Init get error response [%s]. Sending %s", shorttxid(msg.Txid), err.Error(), pb.ChaincodeMessage_ERROR)
233+
nextStateMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR, Payload: []byte(err.Error()), Txid: msg.Txid, ChaincodeEvent: stub.chaincodeEvent}
234+
return
235+
}
231236
res := handler.cc.Init(stub)
232237
chaincodeLogger.Debugf("[%s]Init get response status: %d", shorttxid(msg.Txid), res.Status)
233238

@@ -296,7 +301,14 @@ func (handler *Handler) handleTransaction(msg *pb.ChaincodeMessage) {
296301
// Call chaincode's Run
297302
// Create the ChaincodeStub which the chaincode can use to callback
298303
stub := new(ChaincodeStub)
299-
stub.init(handler, msg.Txid, input, msg.ProposalContext)
304+
err := stub.init(handler, msg.Txid, input, msg.Proposal)
305+
if err != nil {
306+
payload := []byte(err.Error())
307+
// Send ERROR message to chaincode support and change state
308+
chaincodeLogger.Errorf("[%s]Transaction execution failed. Sending %s", shorttxid(msg.Txid), pb.ChaincodeMessage_ERROR)
309+
nextStateMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR, Payload: payload, Txid: msg.Txid, ChaincodeEvent: stub.chaincodeEvent}
310+
return
311+
}
300312
res := handler.cc.Invoke(stub)
301313

302314
// Endorser will handle error contained in Response.

‎core/chaincode/shim/interfaces.go

+11-7
Original file line numberDiff line numberDiff line change
@@ -101,18 +101,22 @@ type ChaincodeStubInterface interface {
101101
// key values across time. GetHistoryForKey is intended to be used for read-only queries.
102102
GetHistoryForKey(key string) (StateQueryIteratorInterface, error)
103103

104-
// GetCallerCertificate returns caller certificate
105-
GetCallerCertificate() ([]byte, error)
104+
// GetCreator returns SignatureHeader.Creator of the proposal
105+
// this Stub refers to.
106+
GetCreator() ([]byte, error)
106107

107-
// GetCallerMetadata returns caller metadata
108-
GetCallerMetadata() ([]byte, error)
108+
// GetTransient returns the ChaincodeProposalPayload.transient field.
109+
// It is a map that contains data (e.g. cryptographic material)
110+
// that might be used to implement some form of application-level confidentiality. The contents
111+
// of this field, as prescribed by ChaincodeProposalPayload, are supposed to always
112+
// be omitted from the transaction and excluded from the ledger.
113+
GetTransient() (map[string][]byte, error)
109114

110115
// GetBinding returns the transaction binding
111116
GetBinding() ([]byte, error)
112117

113-
// GetPayload returns transaction payload, which is a `ChaincodeSpec` defined
114-
// in fabric/protos/chaincode.proto
115-
GetPayload() ([]byte, error)
118+
// GetArgsSlice returns the arguments to the stub call as a byte array
119+
GetArgsSlice() ([]byte, error)
116120

117121
// GetTxTimestamp returns transaction created timestamp, which is currently
118122
// taken from the peer receiving the transaction. Note that this timestamp

‎core/chaincode/shim/java/build.gradle

+3
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ task copyProtos(type:Copy){
9393
from ("${rootDir}/protos/peer"){
9494
include '**/chaincodeevent.proto'
9595
include '**/chaincode.proto'
96+
include '**/chaincodeshim.proto'
97+
include '**/proposal.proto'
98+
include '**/proposal_response.proto'
9699
}
97100
into "${projectDir}/src/main/proto/peer"
98101

‎core/chaincode/shim/java/src/main/java/org/hyperledger/java/shim/ChaincodeBase.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
import org.apache.commons.logging.Log;
3030
import org.apache.commons.logging.LogFactory;
3131
import org.hyperledger.protos.Chaincode.ChaincodeID;
32-
import org.hyperledger.protos.Chaincode.ChaincodeMessage;
33-
import org.hyperledger.protos.Chaincode.ChaincodeMessage.Type;
32+
import org.hyperledger.protos.Chaincodeshim.ChaincodeMessage;
33+
import org.hyperledger.protos.Chaincodeshim.ChaincodeMessage.Type;
3434
import org.hyperledger.protos.ChaincodeSupportGrpc;
3535
import org.hyperledger.protos.ChaincodeSupportGrpc.ChaincodeSupportStub;
3636

‎core/chaincode/shim/java/src/main/java/org/hyperledger/java/shim/ChaincodeStub.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import com.google.protobuf.InvalidProtocolBufferException;
2121
import org.apache.commons.logging.Log;
2222
import org.apache.commons.logging.LogFactory;
23-
import org.hyperledger.protos.Chaincode;
23+
import org.hyperledger.protos.Chaincodeshim;
2424

2525
import java.util.ArrayList;
2626
import java.util.HashMap;
@@ -102,7 +102,7 @@ public Map<String, String> getStateByRange(String startKey, String endKey) {
102102
*/
103103
public Map<String, ByteString> getStateByRangeRaw(String startKey, String endKey) {
104104
Map<String, ByteString> map = new HashMap<>();
105-
for (Chaincode.QueryStateKeyValue mapping : handler.handleGetStateByRange(
105+
for (Chaincodeshim.QueryStateKeyValue mapping : handler.handleGetStateByRange(
106106
startKey, endKey, uuid).getKeysAndValuesList()) {
107107
map.put(mapping.getKey(), mapping.getValue());
108108
}

‎core/chaincode/shim/java/src/main/java/org/hyperledger/java/shim/Handler.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@
2828
import org.hyperledger.java.fsm.exceptions.NoTransitionException;
2929
import org.hyperledger.java.helper.Channel;
3030
import org.hyperledger.protos.Chaincode.*;
31-
import org.hyperledger.protos.Chaincode.ChaincodeMessage.Builder;
31+
import org.hyperledger.protos.Chaincodeshim.*;
32+
import org.hyperledger.protos.Chaincodeshim.ChaincodeMessage.Builder;
3233

3334
import java.util.HashMap;
3435
import java.util.List;
3536
import java.util.Map;
3637

3738
import static org.hyperledger.java.fsm.CallbackType.*;
38-
import static org.hyperledger.protos.Chaincode.ChaincodeMessage.Type.*;
39+
import static org.hyperledger.protos.Chaincodeshim.ChaincodeMessage.Type.*;
3940

4041
public class Handler {
4142

‎core/chaincode/shim/java/src/main/java/org/hyperledger/java/shim/NextStateInfo.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package org.hyperledger.java.shim;
1818

19-
import org.hyperledger.protos.Chaincode.ChaincodeMessage;
19+
import org.hyperledger.protos.Chaincodeshim.ChaincodeMessage;
2020

2121
public class NextStateInfo {
2222

‎core/chaincode/shim/mockstub.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -251,12 +251,12 @@ func (stub *MockStub) InvokeChaincode(chaincodeName string, args [][]byte, chann
251251
}
252252

253253
// Not implemented
254-
func (stub *MockStub) GetCallerCertificate() ([]byte, error) {
254+
func (stub *MockStub) GetCreator() ([]byte, error) {
255255
return nil, nil
256256
}
257257

258258
// Not implemented
259-
func (stub *MockStub) GetCallerMetadata() ([]byte, error) {
259+
func (stub *MockStub) GetTransient() (map[string][]byte, error) {
260260
return nil, nil
261261
}
262262

@@ -266,7 +266,7 @@ func (stub *MockStub) GetBinding() ([]byte, error) {
266266
}
267267

268268
// Not implemented
269-
func (stub *MockStub) GetPayload() ([]byte, error) {
269+
func (stub *MockStub) GetArgsSlice() ([]byte, error) {
270270
return nil, nil
271271
}
272272

‎examples/chaincode/go/asset_management/asset_management.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func (t *AssetManagementChaincode) isCaller(stub shim.ChaincodeStubInterface, ce
173173
if err != nil {
174174
return false, errors.New("Failed getting metadata")
175175
}
176-
payload, err := stub.GetPayload()
176+
payload, err := stub.GetArgsSlice()
177177
if err != nil {
178178
return false, errors.New("Failed getting payload")
179179
}

‎examples/chaincode/go/asset_management_interactive/asset_management.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ func (t *AssetManagementChaincode) isCaller(stub shim.ChaincodeStubInterface, ce
210210
if err != nil {
211211
return false, errors.New("Failed getting metadata")
212212
}
213-
payload, err := stub.GetPayload()
213+
payload, err := stub.GetArgsSlice()
214214
if err != nil {
215215
return false, errors.New("Failed getting payload")
216216
}

‎examples/chaincode/go/rbac_tcerts_no_attrs/rbac.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ func (t *RBACChaincode) hasInvokerRole(stub shim.ChaincodeStubInterface, role st
242242
}
243243

244244
// Verify signature
245-
payload, err := stub.GetPayload()
245+
payload, err := stub.GetArgsSlice()
246246
if err != nil {
247247
return false, nil, errors.New("Failed getting payload")
248248
}

‎protos/peer/admin.pb.go

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎protos/peer/chaincode.pb.go

+38-407
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎protos/peer/chaincode.proto

+1-100
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ syntax = "proto3";
1919
package protos;
2020
option java_package = "org.hyperledger.protos";
2121
option go_package = "github.com/hyperledger/fabric/protos/peer";
22-
import "peer/chaincodeevent.proto";
2322
import "google/protobuf/timestamp.proto";
2423

2524

@@ -103,102 +102,4 @@ message ChaincodeInvocationSpec {
103102
// 2, a decoding used to decode user (string) input to bytes
104103
// Currently, SHA256 with BASE64 is supported (e.g. idGenerationAlg='sha256base64')
105104
string id_generation_alg = 2;
106-
}
107-
108-
// ChaincodeProposalContext contains proposal data that we send to the chaincode
109-
// container shim and allow the chaincode to access through the shim interface.
110-
message ChaincodeProposalContext {
111-
112-
// Creator corresponds to SignatureHeader.Creator
113-
bytes creator = 1;
114-
115-
// Transient corresponds to ChaincodeProposalPayload.Transient
116-
// TODO: The transient field is supposed to carry application-specific
117-
// data. They might be realted to access-control, encryption and so on.
118-
// To simply access to this data, replacing bytes with a map
119-
// is the next step to be carried.
120-
bytes transient = 2;
121-
}
122-
123-
message ChaincodeMessage {
124-
125-
enum Type {
126-
UNDEFINED = 0;
127-
REGISTER = 1;
128-
REGISTERED = 2;
129-
INIT = 3;
130-
READY = 4;
131-
TRANSACTION = 5;
132-
COMPLETED = 6;
133-
ERROR = 7;
134-
GET_STATE = 8;
135-
PUT_STATE = 9;
136-
DEL_STATE = 10;
137-
INVOKE_CHAINCODE = 11;
138-
RESPONSE = 13;
139-
GET_STATE_BY_RANGE = 14;
140-
GET_QUERY_RESULT = 15;
141-
QUERY_STATE_NEXT = 16;
142-
QUERY_STATE_CLOSE = 17;
143-
KEEPALIVE = 18;
144-
GET_HISTORY_FOR_KEY = 19;
145-
}
146-
147-
Type type = 1;
148-
google.protobuf.Timestamp timestamp = 2;
149-
bytes payload = 3;
150-
string txid = 4;
151-
152-
ChaincodeProposalContext proposal_context = 5;
153-
154-
//event emmited by chaincode. Used only with Init or Invoke.
155-
// This event is then stored (currently)
156-
//with Block.NonHashData.TransactionResult
157-
ChaincodeEvent chaincode_event = 6;
158-
}
159-
160-
message PutStateInfo {
161-
string key = 1;
162-
bytes value = 2;
163-
}
164-
165-
message GetStateByRange {
166-
string startKey = 1;
167-
string endKey = 2;
168-
}
169-
170-
message GetQueryResult {
171-
string query = 1;
172-
}
173-
174-
message GetHistoryForKey {
175-
string key = 1;
176-
}
177-
178-
message QueryStateNext {
179-
string id = 1;
180-
}
181-
182-
message QueryStateClose {
183-
string id = 1;
184-
}
185-
186-
message QueryStateKeyValue {
187-
string key = 1;
188-
bytes value = 2;
189-
}
190-
191-
message QueryStateResponse {
192-
repeated QueryStateKeyValue keys_and_values = 1;
193-
bool has_more = 2;
194-
string id = 3;
195-
}
196-
197-
// Interface that provides support to chaincode execution. ChaincodeContext
198-
// provides the context necessary for the server to respond appropriately.
199-
service ChaincodeSupport {
200-
201-
rpc Register(stream ChaincodeMessage) returns (stream ChaincodeMessage) {}
202-
203-
204-
}
105+
}

‎protos/peer/chaincodeshim.pb.go

+386
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎protos/peer/chaincodeshim.proto

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
Copyright IBM Corp. 2016 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
syntax = "proto3";
18+
19+
package protos;
20+
option java_package = "org.hyperledger.protos";
21+
option go_package = "github.com/hyperledger/fabric/protos/peer";
22+
import "peer/chaincodeevent.proto";
23+
import "peer/proposal.proto";
24+
import "google/protobuf/timestamp.proto";
25+
26+
27+
message ChaincodeMessage {
28+
29+
enum Type {
30+
UNDEFINED = 0;
31+
REGISTER = 1;
32+
REGISTERED = 2;
33+
INIT = 3;
34+
READY = 4;
35+
TRANSACTION = 5;
36+
COMPLETED = 6;
37+
ERROR = 7;
38+
GET_STATE = 8;
39+
PUT_STATE = 9;
40+
DEL_STATE = 10;
41+
INVOKE_CHAINCODE = 11;
42+
RESPONSE = 13;
43+
GET_STATE_BY_RANGE = 14;
44+
GET_QUERY_RESULT = 15;
45+
QUERY_STATE_NEXT = 16;
46+
QUERY_STATE_CLOSE = 17;
47+
KEEPALIVE = 18;
48+
GET_HISTORY_FOR_KEY = 19;
49+
}
50+
51+
Type type = 1;
52+
google.protobuf.Timestamp timestamp = 2;
53+
bytes payload = 3;
54+
string txid = 4;
55+
56+
Proposal proposal = 5;
57+
58+
//event emmited by chaincode. Used only with Init or Invoke.
59+
// This event is then stored (currently)
60+
//with Block.NonHashData.TransactionResult
61+
ChaincodeEvent chaincode_event = 6;
62+
}
63+
64+
message PutStateInfo {
65+
string key = 1;
66+
bytes value = 2;
67+
}
68+
69+
message GetStateByRange {
70+
string startKey = 1;
71+
string endKey = 2;
72+
}
73+
74+
message GetQueryResult {
75+
string query = 1;
76+
}
77+
78+
message GetHistoryForKey {
79+
string key = 1;
80+
}
81+
82+
message QueryStateNext {
83+
string id = 1;
84+
}
85+
86+
message QueryStateClose {
87+
string id = 1;
88+
}
89+
90+
message QueryStateKeyValue {
91+
string key = 1;
92+
bytes value = 2;
93+
}
94+
95+
message QueryStateResponse {
96+
repeated QueryStateKeyValue keys_and_values = 1;
97+
bool has_more = 2;
98+
string id = 3;
99+
}
100+
101+
// Interface that provides support to chaincode execution. ChaincodeContext
102+
// provides the context necessary for the server to respond appropriately.
103+
service ChaincodeSupport {
104+
105+
rpc Register(stream ChaincodeMessage) returns (stream ChaincodeMessage) {}
106+
107+
108+
}

‎protos/peer/configuration.pb.go

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎protos/peer/events.pb.go

+11-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎protos/peer/peer.pb.go

+5-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎protos/peer/proposal.pb.go

+47-36
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎protos/peer/proposal.proto

+4-4
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,8 @@ message ChaincodeHeaderExtension {
217217
// The PayloadVisibility field controls to what extent the Proposal's payload
218218
// (recall that for the type CHAINCODE, it is ChaincodeProposalPayload
219219
// message) field will be visible in the final transaction and in the ledger.
220-
// Ideally, it would be configurable, supporting at least 3 main visibility
221-
// modes:
220+
// Ideally, it would be configurable, supporting at least 3 main visibility
221+
// modes:
222222
// 1. all bytes of the payload are visible;
223223
// 2. only a hash of the payload is visible;
224224
// 3. nothing is visible.
@@ -240,11 +240,11 @@ message ChaincodeProposalPayload {
240240
// deploys a new chaincode, ESCC/VSCC are part of this field.
241241
bytes input = 1;
242242

243-
// Transient contains data (e.g. cryptographic material) that might be used
243+
// TransientMap contains data (e.g. cryptographic material) that might be used
244244
// to implement some form of application-level confidentiality. The contents
245245
// of this field are supposed to always be omitted from the transaction and
246246
// excluded from the ledger.
247-
bytes transient = 2;
247+
map<string, bytes> TransientMap = 2;
248248
}
249249

250250
// ChaincodeAction contains the actions the events generated by the execution

‎protos/peer/proposal_response.pb.go

+6-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎protos/peer/transaction.pb.go

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎protos/utils/proputils.go

+55-13
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"errors"
2323

2424
"encoding/base64"
25+
"encoding/binary"
2526

2627
"github.com/golang/protobuf/proto"
2728
"github.com/hyperledger/fabric/bccsp"
@@ -52,32 +53,42 @@ func GetChaincodeInvocationSpec(prop *peer.Proposal) (*peer.ChaincodeInvocationS
5253
return cis, nil
5354
}
5455

55-
// GetChaincodeProposalContext returns a ChaincodeProposalContext from a Proposal
56-
func GetChaincodeProposalContext(prop *peer.Proposal) (*peer.ChaincodeProposalContext, error) {
57-
// get back the header
56+
// GetChaincodeProposalContext returns creator and transient
57+
func GetChaincodeProposalContext(prop *peer.Proposal) ([]byte, map[string][]byte, error) {
58+
if prop == nil {
59+
return nil, nil, fmt.Errorf("Proposal is nil")
60+
}
61+
if len(prop.Header) == 0 {
62+
return nil, nil, fmt.Errorf("Proposal's header is nil")
63+
}
64+
if len(prop.Payload) == 0 {
65+
return nil, nil, fmt.Errorf("Proposal's payload is nil")
66+
}
67+
68+
//// get back the header
5869
hdr, err := GetHeader(prop.Header)
5970
if err != nil {
60-
return nil, fmt.Errorf("Could not extract the header from the proposal: %s", err)
71+
return nil, nil, fmt.Errorf("Could not extract the header from the proposal: %s", err)
72+
}
73+
if hdr == nil {
74+
return nil, nil, fmt.Errorf("Unmarshalled header is nil")
6175
}
6276
if common.HeaderType(hdr.ChannelHeader.Type) != common.HeaderType_ENDORSER_TRANSACTION &&
6377
common.HeaderType(hdr.ChannelHeader.Type) != common.HeaderType_CONFIG {
64-
return nil, fmt.Errorf("Invalid proposal type expected ENDORSER_TRANSACTION or CONFIG. Was: %d", hdr.ChannelHeader.Type)
78+
return nil, nil, fmt.Errorf("Invalid proposal type expected ENDORSER_TRANSACTION or CONFIG. Was: %d", hdr.ChannelHeader.Type)
6579
}
6680

6781
if hdr.SignatureHeader == nil {
68-
return nil, errors.New("Invalid signature header. It must be different from nil.")
82+
return nil, nil, errors.New("Invalid signature header. It must be different from nil.")
6983
}
7084

7185
ccPropPayload := &peer.ChaincodeProposalPayload{}
7286
err = proto.Unmarshal(prop.Payload, ccPropPayload)
7387
if err != nil {
74-
return nil, err
88+
return nil, nil, err
7589
}
7690

77-
return &peer.ChaincodeProposalContext{
78-
Creator: hdr.SignatureHeader.Creator,
79-
Transient: ccPropPayload.Transient,
80-
}, nil
91+
return hdr.SignatureHeader.Creator, ccPropPayload.TransientMap, nil
8192
}
8293

8394
// GetHeader Get Header from bytes
@@ -262,7 +273,7 @@ func CreateChaincodeProposal(typ common.HeaderType, chainID string, cis *peer.Ch
262273
}
263274

264275
// CreateChaincodeProposalWithTransient creates a proposal from given input
265-
func CreateChaincodeProposalWithTransient(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte, transient []byte) (*peer.Proposal, string, error) {
276+
func CreateChaincodeProposalWithTransient(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) {
266277
ccHdrExt := &peer.ChaincodeHeaderExtension{ChaincodeId: cis.ChaincodeSpec.ChaincodeId}
267278
ccHdrExtBytes, err := proto.Marshal(ccHdrExt)
268279
if err != nil {
@@ -274,7 +285,7 @@ func CreateChaincodeProposalWithTransient(typ common.HeaderType, chainID string,
274285
return nil, "", err
275286
}
276287

277-
ccPropPayload := &peer.ChaincodeProposalPayload{Input: cisBytes, Transient: transient}
288+
ccPropPayload := &peer.ChaincodeProposalPayload{Input: cisBytes, TransientMap: transientMap}
278289
ccPropPayloadBytes, err := proto.Marshal(ccPropPayload)
279290
if err != nil {
280291
return nil, "", err
@@ -537,3 +548,34 @@ func CheckProposalTxID(txid string, nonce, creator []byte) error {
537548

538549
return nil
539550
}
551+
552+
// ComputeProposalBinding computes the binding of a proposal
553+
func ComputeProposalBinding(proposal *peer.Proposal) ([]byte, error) {
554+
if proposal == nil {
555+
return nil, fmt.Errorf("Porposal is nil")
556+
}
557+
if len(proposal.Header) == 0 {
558+
return nil, fmt.Errorf("Proposal's Header is nil")
559+
}
560+
561+
h, err := GetHeader(proposal.Header)
562+
if err != nil {
563+
return nil, err
564+
}
565+
566+
return computeProposalBindingInternal(h.SignatureHeader.Nonce, h.SignatureHeader.Creator, h.ChannelHeader.Epoch)
567+
}
568+
569+
func computeProposalBindingInternal(nonce, creator []byte, epoch uint64) ([]byte, error) {
570+
epochBytes := make([]byte, 8)
571+
binary.LittleEndian.PutUint64(epochBytes, epoch)
572+
573+
// TODO: add to genesis block the hash function used for the binding computation.
574+
digest, err := factory.GetDefaultOrPanic().Hash(
575+
append(append(nonce, creator...), epochBytes...),
576+
&bccsp.SHA256Opts{})
577+
if err != nil {
578+
return nil, err
579+
}
580+
return digest, nil
581+
}

‎protos/utils/proputils_test.go

+11-6
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,11 @@ func createCIS() *pb.ChaincodeInvocationSpec {
4444

4545
func TestProposal(t *testing.T) {
4646
// create a proposal from a ChaincodeInvocationSpec
47-
prop, _, err := CreateChaincodeProposalWithTransient(common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), createCIS(), []byte("creator"), []byte("transient"))
47+
prop, _, err := CreateChaincodeProposalWithTransient(
48+
common.HeaderType_ENDORSER_TRANSACTION,
49+
util.GetTestChainID(), createCIS(),
50+
[]byte("creator"),
51+
map[string][]byte{"certx": []byte("transient")})
4852
if err != nil {
4953
t.Fatalf("Could not create chaincode proposal, err %s\n", err)
5054
return
@@ -122,16 +126,17 @@ func TestProposal(t *testing.T) {
122126
return
123127
}
124128

125-
porposalContexd, err := GetChaincodeProposalContext(prop)
129+
creator, transient, err := GetChaincodeProposalContext(prop)
126130
if err != nil {
127131
t.Fatalf("Failed getting chaincode proposal context [%s]", err)
128132
}
129-
if string(porposalContexd.Transient) != "transient" {
130-
t.Fatalf("Failed checking Transient field. Invalid value, expectext 'transient', got [%s]", string(porposalContexd.Transient))
133+
if string(creator) != "creator" {
134+
t.Fatalf("Failed checking Creator field. Invalid value, expectext 'creator', got [%s]", string(creator))
131135
return
132136
}
133-
if string(porposalContexd.Creator) != "creator" {
134-
t.Fatalf("Failed checking Creator field. Invalid value, expectext 'creator', got [%s]", string(porposalContexd.Creator))
137+
value, ok := transient["certx"]
138+
if !ok || string(value) != "transient" {
139+
t.Fatalf("Failed checking Transient field. Invalid value, expectext 'transient', got [%s]", string(value))
135140
return
136141
}
137142
}

‎protos/utils/txutils.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ func GetBytesProposalPayloadForTx(payload *peer.ChaincodeProposalPayload, visibi
247247
}
248248

249249
// strip the transient bytes off the payload - this needs to be done no matter the visibility mode
250-
cppNoTransient := &peer.ChaincodeProposalPayload{Input: payload.Input, Transient: nil}
250+
cppNoTransient := &peer.ChaincodeProposalPayload{Input: payload.Input, TransientMap: nil}
251251
cppBytes, err := GetBytesChaincodeProposalPayload(cppNoTransient)
252252
if err != nil {
253253
return nil, errors.New("Failure while marshalling the ChaincodeProposalPayload!")

0 commit comments

Comments
 (0)
Please sign in to comment.