Skip to content

Commit 5f9b3ea

Browse files
committed
C2C invocation for confidential contracts.
This PR addresses chaincode to chaincode invocation for confidential contracts (https://jira.hyperledger.org/browse/FAB-67). In order to achieve the goal the chaincode handler has been modified to contruct proper ephemeral transactions and security contexts. Let us consider the following scenario to describe the modification apported by this PR. Let us say that we have two chaincodes: A and B where A invokes B at some point of its computation. When a user invoke a chaincode A, using transaction tx, the certificate that the user has put in tx is passed to B when A invokes it. In this way, for example, chaincode B can perfom attribute-based access control. In addition, each chaincode can access it is own encrypted state and modify it in a proper way without affecting other chaincodes' state. This PR has been tested by adding a unit test in exectransaction_test.go. The unit tests, verify that C2C invocation can be perfomed when security is enabled. What will come next: 1. Chaincode to chaincode query. 2. Additional fields transfered to the invoked chaincode to support access control based on signature. Change-Id: I649d1953ac76e8af32d917a089a454fc0bba9fc1 Signed-off-by: Angelo De Caro <[email protected]>
1 parent 02a123c commit 5f9b3ea

File tree

2 files changed

+113
-18
lines changed

2 files changed

+113
-18
lines changed

core/chaincode/exectransaction_test.go

+71-8
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,18 @@ func TestChaincodeInvokeChaincode(t *testing.T) {
827827

828828
go grpcServer.Serve(lis)
829829

830+
err = chaincodeInvokeChaincode(t, "")
831+
if err != nil {
832+
t.Fail()
833+
t.Logf("Failed chaincode invoke chaincode : %s", err)
834+
closeListenerAndSleep(lis)
835+
return
836+
}
837+
838+
closeListenerAndSleep(lis)
839+
}
840+
841+
func chaincodeInvokeChaincode(t *testing.T, user string) (err error) {
830842
var ctxt = context.Background()
831843

832844
// Deploy first chaincode
@@ -836,15 +848,14 @@ func TestChaincodeInvokeChaincode(t *testing.T) {
836848
f := "init"
837849
args := util.ToChaincodeArgs(f, "a", "100", "b", "200")
838850

839-
spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Args: args}}
851+
spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Args: args}, SecureContext: user}
840852

841853
_, err = deploy(ctxt, spec1)
842854
chaincodeID1 := spec1.ChaincodeID.Name
843855
if err != nil {
844856
t.Fail()
845857
t.Logf("Error initializing chaincode %s(%s)", chaincodeID1, err)
846858
GetChain(DefaultChain).Stop(ctxt, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec1})
847-
closeListenerAndSleep(lis)
848859
return
849860
}
850861

@@ -859,7 +870,7 @@ func TestChaincodeInvokeChaincode(t *testing.T) {
859870
f = "init"
860871
args = util.ToChaincodeArgs(f, "e", "0")
861872

862-
spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}}
873+
spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}, SecureContext: user}
863874

864875
_, err = deploy(ctxt, spec2)
865876
chaincodeID2 := spec2.ChaincodeID.Name
@@ -868,7 +879,6 @@ func TestChaincodeInvokeChaincode(t *testing.T) {
868879
t.Logf("Error initializing chaincode %s(%s)", chaincodeID2, err)
869880
GetChain(DefaultChain).Stop(ctxt, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec1})
870881
GetChain(DefaultChain).Stop(ctxt, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec2})
871-
closeListenerAndSleep(lis)
872882
return
873883
}
874884

@@ -878,7 +888,7 @@ func TestChaincodeInvokeChaincode(t *testing.T) {
878888
f = "invoke"
879889
args = util.ToChaincodeArgs(f, "e", "1")
880890

881-
spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}}
891+
spec2 = &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}, SecureContext: user}
882892
// Invoke chaincode
883893
var uuid string
884894
_, uuid, _, err = invoke(ctxt, spec2, pb.Transaction_CHAINCODE_INVOKE)
@@ -888,7 +898,6 @@ func TestChaincodeInvokeChaincode(t *testing.T) {
888898
t.Logf("Error invoking <%s>: %s", chaincodeID2, err)
889899
GetChain(DefaultChain).Stop(ctxt, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec1})
890900
GetChain(DefaultChain).Stop(ctxt, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec2})
891-
closeListenerAndSleep(lis)
892901
return
893902
}
894903

@@ -899,13 +908,67 @@ func TestChaincodeInvokeChaincode(t *testing.T) {
899908
t.Logf("Incorrect final state after transaction for <%s>: %s", chaincodeID1, err)
900909
GetChain(DefaultChain).Stop(ctxt, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec1})
901910
GetChain(DefaultChain).Stop(ctxt, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec2})
902-
closeListenerAndSleep(lis)
903911
return
904912
}
905913

906914
GetChain(DefaultChain).Stop(ctxt, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec1})
907915
GetChain(DefaultChain).Stop(ctxt, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec2})
908-
closeListenerAndSleep(lis)
916+
917+
return
918+
}
919+
920+
func TestChaincodeInvokeChaincodeWithSec(t *testing.T) {
921+
testDBWrapper.CleanDB(t)
922+
viper.Set("security.enabled", "true")
923+
924+
//Initialize crypto
925+
if err := crypto.Init(); err != nil {
926+
panic(fmt.Errorf("Failed initializing the crypto layer [%s]", err))
927+
}
928+
929+
//set paths for memberservice to pick up
930+
viper.Set("peer.fileSystemPath", filepath.Join(os.TempDir(), "hyperledger", "production"))
931+
viper.Set("server.rootpath", filepath.Join(os.TempDir(), "ca"))
932+
933+
var err error
934+
var memSrvcLis net.Listener
935+
if memSrvcLis, err = initMemSrvc(); err != nil {
936+
t.Fail()
937+
t.Logf("Error registering user %s", err)
938+
return
939+
}
940+
941+
time.Sleep(2 * time.Second)
942+
943+
var peerLis net.Listener
944+
if peerLis, err = initPeer(); err != nil {
945+
finitMemSrvc(memSrvcLis)
946+
t.Fail()
947+
t.Logf("Error registering user %s", err)
948+
return
949+
}
950+
951+
if err = crypto.RegisterClient("jim", nil, "jim", "6avZQLwcUe9b"); err != nil {
952+
finitMemSrvc(memSrvcLis)
953+
finitPeer(peerLis)
954+
t.Fail()
955+
t.Logf("Error registering user %s", err)
956+
return
957+
}
958+
959+
//login as jim and test chaincode-chaincode interaction with security
960+
if err = chaincodeInvokeChaincode(t, "jim"); err != nil {
961+
finitMemSrvc(memSrvcLis)
962+
finitPeer(peerLis)
963+
t.Fail()
964+
t.Logf("Error executing test %s", err)
965+
return
966+
}
967+
968+
//cleanup
969+
finitMemSrvc(memSrvcLis)
970+
finitPeer(peerLis)
971+
909972
}
910973

911974
// Test the execution of a chaincode that invokes another chaincode with wrong parameters. Should receive error from

core/chaincode/handler.go

+42-10
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,9 @@ func (handler *Handler) deleteRangeQueryIterator(txContext *transactionContext,
161161
delete(txContext.rangeQueryIteratorMap, txid)
162162
}
163163

164-
//THIS CAN BE REMOVED ONCE WE SUPPORT CONFIDENTIALITY WITH CC-CALLING-CC
165-
//we dissallow chaincode-chaincode interactions till confidentiality implications are understood
166-
func (handler *Handler) canCallChaincode(txid string) *pb.ChaincodeMessage {
164+
//THIS CAN BE REMOVED ONCE WE FULL SUPPORT (Invoke and Query) CONFIDENTIALITY WITH CC-CALLING-CC
165+
//Only invocation are allowed, not queries
166+
func (handler *Handler) canCallChaincode(txid string, isQuery bool) *pb.ChaincodeMessage {
167167
secHelper := handler.chaincodeSupport.getSecHelper()
168168
if secHelper == nil {
169169
return nil
@@ -176,7 +176,9 @@ func (handler *Handler) canCallChaincode(txid string) *pb.ChaincodeMessage {
176176
} else if txctx.transactionSecContext == nil {
177177
errMsg = fmt.Sprintf("[%s]Error transaction context is nil while checking for confidentiality. Sending %s", shorttxid(txid), pb.ChaincodeMessage_ERROR)
178178
} else if txctx.transactionSecContext.ConfidentialityLevel != pb.ConfidentialityLevel_PUBLIC {
179-
errMsg = fmt.Sprintf("[%s]Error chaincode-chaincode interactions not supported for with privacy enabled. Sending %s", shorttxid(txid), pb.ChaincodeMessage_ERROR)
179+
if isQuery {
180+
errMsg = fmt.Sprintf("[%s]Error chaincode-chaincode interactions not supported for with privacy enabled. Sending %s", shorttxid(txid), pb.ChaincodeMessage_ERROR)
181+
}
180182
}
181183

182184
if errMsg != "" {
@@ -209,10 +211,12 @@ func (handler *Handler) encryptOrDecrypt(encrypt bool, txid string, payload []by
209211
var err error
210212
if txctx.transactionSecContext.Type == pb.Transaction_CHAINCODE_DEPLOY {
211213
if enc, err = secHelper.GetStateEncryptor(handler.deployTXSecContext, handler.deployTXSecContext); err != nil {
214+
chaincodeLogger.Errorf("error getting crypto encryptor for deploy tx :%s", err)
212215
return nil, fmt.Errorf("error getting crypto encryptor for deploy tx :%s", err)
213216
}
214217
} else if txctx.transactionSecContext.Type == pb.Transaction_CHAINCODE_INVOKE || txctx.transactionSecContext.Type == pb.Transaction_CHAINCODE_QUERY {
215218
if enc, err = secHelper.GetStateEncryptor(handler.deployTXSecContext, txctx.transactionSecContext); err != nil {
219+
chaincodeLogger.Errorf("error getting crypto encryptor %s", err)
216220
return nil, fmt.Errorf("error getting crypto encryptor %s", err)
217221
}
218222
} else {
@@ -1046,7 +1050,9 @@ func (handler *Handler) enterBusyState(e *fsm.Event, state string) {
10461050
err = ledgerObj.DeleteState(chaincodeID, key)
10471051
} else if msg.Type.String() == pb.ChaincodeMessage_INVOKE_CHAINCODE.String() {
10481052
//check and prohibit C-call-C for CONFIDENTIAL txs
1049-
if triggerNextStateMsg = handler.canCallChaincode(msg.Txid); triggerNextStateMsg != nil {
1053+
chaincodeLogger.Debugf("[%s] C-call-C", shorttxid(msg.Txid))
1054+
1055+
if triggerNextStateMsg = handler.canCallChaincode(msg.Txid, false); triggerNextStateMsg != nil {
10501056
return
10511057
}
10521058
chaincodeSpec := &pb.ChaincodeSpec{}
@@ -1060,12 +1066,21 @@ func (handler *Handler) enterBusyState(e *fsm.Event, state string) {
10601066

10611067
// Get the chaincodeID to invoke
10621068
newChaincodeID := chaincodeSpec.ChaincodeID.Name
1069+
chaincodeLogger.Debugf("[%s] C-call-C %s", shorttxid(msg.Txid), newChaincodeID)
10631070

10641071
// Create the transaction object
10651072
chaincodeInvocationSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: chaincodeSpec}
10661073
transaction, _ := pb.NewChaincodeExecute(chaincodeInvocationSpec, msg.Txid, pb.Transaction_CHAINCODE_INVOKE)
10671074

1068-
// Launch the new chaincode if not already running
1075+
tsc := handler.getTxContext(msg.Txid).transactionSecContext
1076+
1077+
transaction.Nonce = tsc.Nonce
1078+
transaction.ConfidentialityLevel = tsc.ConfidentialityLevel
1079+
transaction.ConfidentialityProtocolVersion = tsc.ConfidentialityProtocolVersion
1080+
transaction.Metadata = tsc.Metadata
1081+
transaction.Cert = tsc.Cert
1082+
1083+
// cd the new chaincode if not already running
10691084
_, chaincodeInput, launchErr := handler.chaincodeSupport.Launch(context.Background(), transaction)
10701085
if launchErr != nil {
10711086
payload := []byte(launchErr.Error())
@@ -1217,7 +1232,7 @@ func (handler *Handler) initializeSecContext(tx, depTx *pb.Transaction) error {
12171232
return nil
12181233
}
12191234

1220-
func (handler *Handler) setChaincodeSecurityContext(tx *pb.Transaction, msg *pb.ChaincodeMessage) error {
1235+
func (handler *Handler) setChaincodeSecurityContext(tx, depTx *pb.Transaction, msg *pb.ChaincodeMessage) error {
12211236
chaincodeLogger.Debug("setting chaincode security context...")
12221237
if msg.SecurityContext == nil {
12231238
msg.SecurityContext = &pb.ChaincodeSecurityContext{}
@@ -1248,6 +1263,13 @@ func (handler *Handler) setChaincodeSecurityContext(tx *pb.Transaction, msg *pb.
12481263
return err
12491264
}
12501265

1266+
msg.SecurityContext.Payload = ctorMsgRaw
1267+
// TODO: add deploy metadata
1268+
if depTx != nil {
1269+
msg.SecurityContext.ParentMetadata = depTx.Metadata
1270+
} else {
1271+
msg.SecurityContext.ParentMetadata = handler.deployTXSecContext.Metadata
1272+
}
12511273
msg.SecurityContext.Payload = ctorMsgRaw
12521274
msg.SecurityContext.TxTimestamp = tx.Timestamp
12531275
}
@@ -1289,7 +1311,7 @@ func (handler *Handler) initOrReady(txid string, initArgs [][]byte, tx *pb.Trans
12891311
}
12901312

12911313
//if security is disabled the context elements will just be nil
1292-
if err := handler.setChaincodeSecurityContext(tx, ccMsg); err != nil {
1314+
if err := handler.setChaincodeSecurityContext(tx, depTx, ccMsg); err != nil {
12931315
return nil, err
12941316
}
12951317

@@ -1317,7 +1339,7 @@ func (handler *Handler) handleQueryChaincode(msg *pb.ChaincodeMessage) {
13171339
}()
13181340

13191341
//check and prohibit C-call-C for CONFIDENTIAL txs
1320-
if serialSendMsg = handler.canCallChaincode(msg.Txid); serialSendMsg != nil {
1342+
if serialSendMsg = handler.canCallChaincode(msg.Txid, true); serialSendMsg != nil {
13211343
return
13221344
}
13231345

@@ -1337,6 +1359,16 @@ func (handler *Handler) handleQueryChaincode(msg *pb.ChaincodeMessage) {
13371359
chaincodeInvocationSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: chaincodeSpec}
13381360
transaction, _ := pb.NewChaincodeExecute(chaincodeInvocationSpec, msg.Txid, pb.Transaction_CHAINCODE_QUERY)
13391361

1362+
tsc := handler.getTxContext(msg.Txid).transactionSecContext
1363+
1364+
transaction.Nonce = tsc.Nonce
1365+
transaction.ConfidentialityLevel = tsc.ConfidentialityLevel
1366+
transaction.ConfidentialityProtocolVersion = tsc.ConfidentialityProtocolVersion
1367+
transaction.Metadata = tsc.Metadata
1368+
transaction.Cert = tsc.Cert
1369+
1370+
chaincodeLogger.Debugf("[%s]Invoking another chaincode", shorttxid(msg.Txid))
1371+
13401372
// Launch the new chaincode if not already running
13411373
_, chaincodeInput, launchErr := handler.chaincodeSupport.Launch(context.Background(), transaction)
13421374
if launchErr != nil {
@@ -1466,7 +1498,7 @@ func (handler *Handler) sendExecuteMessage(msg *pb.ChaincodeMessage, tx *pb.Tran
14661498
}
14671499

14681500
//if security is disabled the context elements will just be nil
1469-
if err := handler.setChaincodeSecurityContext(tx, msg); err != nil {
1501+
if err := handler.setChaincodeSecurityContext(tx, nil, msg); err != nil {
14701502
return nil, err
14711503
}
14721504

0 commit comments

Comments
 (0)