Skip to content

Commit 458328b

Browse files
committed
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 <[email protected]>
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

0 commit comments

Comments
 (0)