Skip to content

Commit 909b517

Browse files
author
Srinivasan Muralidharan
committed
FAB-466 integrate ledgernext with chaincode framework
The ledgernext and kvledger packages provide APIs to simulate transactions by collecting read-write sets from invokes of chaincodes. This change set integrates this for the Endorser flows. The main purpose of this code is to enable read write sets to be propagated so end to end flow ending in a commit to the ledger can be tested. The chaincode unit tests continue to use the old ledger. This allows us to (1) incrementally integrate ledger and (2) show that the two packages can coexist from a build and runtime point of view. It is worth noting that the file kv_ledgers.go hosts a temporary container for ledgers. This simple approach is expected to be revised when (sub)ledgers are implemented. Change-Id: I6e0bf4b9795b83d2ae869244b212c02ef9b5214a Signed-off-by: Srinivasan Muralidharan <[email protected]>
1 parent ea9f840 commit 909b517

File tree

10 files changed

+382
-66
lines changed

10 files changed

+382
-66
lines changed

core/chaincode/chaincode_support.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ const (
4848
chaincodeStartupTimeoutDefault int = 5000
4949
chaincodeInstallPathDefault string = "/opt/gopath/bin/"
5050
peerAddressDefault string = "0.0.0.0:7051"
51+
52+
//TXSimulatorKey is used to attach ledger simulation context
53+
TXSimulatorKey string = "txsimulatorkey"
5154
)
5255

5356
// chains is a map between different blockchains and their ChaincodeSupport.
@@ -257,7 +260,7 @@ func (chaincodeSupport *ChaincodeSupport) sendInitOrReady(context context.Contex
257260

258261
var notfy chan *pb.ChaincodeMessage
259262
var err error
260-
if notfy, err = chrte.handler.initOrReady(txid, initArgs, tx, depTx); err != nil {
263+
if notfy, err = chrte.handler.initOrReady(context, txid, initArgs, tx, depTx); err != nil {
261264
return fmt.Errorf("Error sending %s: %s", pb.ChaincodeMessage_INIT, err)
262265
}
263266
if notfy != nil {
@@ -648,7 +651,7 @@ func (chaincodeSupport *ChaincodeSupport) Execute(ctxt context.Context, chaincod
648651

649652
var notfy chan *pb.ChaincodeMessage
650653
var err error
651-
if notfy, err = chrte.handler.sendExecuteMessage(msg, tx); err != nil {
654+
if notfy, err = chrte.handler.sendExecuteMessage(ctxt, msg, tx); err != nil {
652655
return nil, fmt.Errorf("Error sending %s: %s", msg.Type.String(), err)
653656
}
654657
var ccresp *pb.ChaincodeMessage

core/chaincode/chaincodeexec.go

+3-13
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121

2222
"fmt"
2323

24-
"github.com/hyperledger/fabric/core/ledger"
2524
"github.com/hyperledger/fabric/core/util"
2625
pb "github.com/hyperledger/fabric/protos"
2726
)
@@ -40,24 +39,15 @@ func createTx(typ pb.Transaction_Type, ccname string, args [][]byte) (*pb.Transa
4039
}
4140

4241
// ExecuteChaincode executes a given chaincode given chaincode name and arguments
43-
func ExecuteChaincode(typ pb.Transaction_Type, chainname string, ccname string, args [][]byte) ([]byte, error) {
42+
func ExecuteChaincode(ctxt context.Context, typ pb.Transaction_Type, chainname string, ccname string, args [][]byte) ([]byte, error) {
4443
var tx *pb.Transaction
4544
var err error
4645
var b []byte
47-
var lgr *ledger.Ledger
46+
4847
tx, err = createTx(typ, ccname, args)
49-
lgr, err = ledger.GetLedger()
50-
if err != nil {
51-
return nil, fmt.Errorf("Failed to get handle to ledger: %s ", err)
52-
}
53-
//TODO - new ledger access will change this call to take a context
54-
lgr.BeginTxBatch("1")
55-
b, _, err = Execute(context.Background(), GetChain(ChainName(chainname)), tx)
48+
b, _, err = Execute(ctxt, GetChain(ChainName(chainname)), tx)
5649
if err != nil {
5750
return nil, fmt.Errorf("Error deploying chaincode: %s", err)
5851
}
59-
//TODO - new ledger access will change this call to take a context
60-
lgr.CommitTxBatch("1", []*pb.Transaction{tx}, nil, nil)
61-
6252
return b, err
6353
}

core/chaincode/exectransaction.go

+32-19
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"golang.org/x/net/context"
2626

2727
"github.com/hyperledger/fabric/core/ledger"
28+
ledgernext "github.com/hyperledger/fabric/core/ledgernext"
2829
"github.com/hyperledger/fabric/events/producer"
2930
pb "github.com/hyperledger/fabric/protos"
3031
)
@@ -33,10 +34,16 @@ import (
3334
func Execute(ctxt context.Context, chain *ChaincodeSupport, t *pb.Transaction) ([]byte, *pb.ChaincodeEvent, error) {
3435
var err error
3536

36-
// get a handle to ledger to mark the begin/finish of a tx
37-
ledger, ledgerErr := ledger.GetLedger()
38-
if ledgerErr != nil {
39-
return nil, nil, fmt.Errorf("Failed to get handle to ledger (%s)", ledgerErr)
37+
//are we in V1 mode doing simulation ?
38+
txsim, _ := ctxt.Value(TXSimulatorKey).(ledgernext.TxSimulator)
39+
40+
var lgr *ledger.Ledger
41+
if txsim == nil {
42+
// get a handle to ledger to mark the begin/finish of a tx
43+
lgr, err = ledger.GetLedger()
44+
if err != nil {
45+
return nil, nil, fmt.Errorf("Failed to get handle to ledger (%s)", err)
46+
}
4047
}
4148

4249
if secHelper := chain.getSecHelper(); nil != secHelper {
@@ -55,13 +62,13 @@ func Execute(ctxt context.Context, chain *ChaincodeSupport, t *pb.Transaction) (
5562
}
5663

5764
//launch and wait for ready
58-
markTxBegin(ledger, t)
65+
markTxBegin(lgr, t)
5966
_, _, err = chain.Launch(ctxt, t)
6067
if err != nil {
61-
markTxFinish(ledger, t, false)
68+
markTxFinish(lgr, t, false)
6269
return nil, nil, fmt.Errorf("%s", err)
6370
}
64-
markTxFinish(ledger, t, true)
71+
markTxFinish(lgr, t, true)
6572
} else if t.Type == pb.Transaction_CHAINCODE_INVOKE || t.Type == pb.Transaction_CHAINCODE_QUERY {
6673
//will launch if necessary (and wait for ready)
6774
cID, cMsg, err := chain.Launch(ctxt, t)
@@ -97,15 +104,15 @@ func Execute(ctxt context.Context, chain *ChaincodeSupport, t *pb.Transaction) (
97104
}
98105
}
99106

100-
markTxBegin(ledger, t)
107+
markTxBegin(lgr, t)
101108
resp, err := chain.Execute(ctxt, chaincode, ccMsg, timeout, t)
102109
if err != nil {
103110
// Rollback transaction
104-
markTxFinish(ledger, t, false)
111+
markTxFinish(lgr, t, false)
105112
return nil, nil, fmt.Errorf("Failed to execute transaction or query(%s)", err)
106113
} else if resp == nil {
107114
// Rollback transaction
108-
markTxFinish(ledger, t, false)
115+
markTxFinish(lgr, t, false)
109116
return nil, nil, fmt.Errorf("Failed to receive a response for (%s)", t.Txid)
110117
} else {
111118
if resp.ChaincodeEvent != nil {
@@ -115,14 +122,14 @@ func Execute(ctxt context.Context, chain *ChaincodeSupport, t *pb.Transaction) (
115122

116123
if resp.Type == pb.ChaincodeMessage_COMPLETED || resp.Type == pb.ChaincodeMessage_QUERY_COMPLETED {
117124
// Success
118-
markTxFinish(ledger, t, true)
125+
markTxFinish(lgr, t, true)
119126
return resp.Payload, resp.ChaincodeEvent, nil
120127
} else if resp.Type == pb.ChaincodeMessage_ERROR || resp.Type == pb.ChaincodeMessage_QUERY_ERROR {
121128
// Rollback transaction
122-
markTxFinish(ledger, t, false)
129+
markTxFinish(lgr, t, false)
123130
return nil, resp.ChaincodeEvent, fmt.Errorf("Transaction or query returned with failure: %s", string(resp.Payload))
124131
}
125-
markTxFinish(ledger, t, false)
132+
markTxFinish(lgr, t, false)
126133
return resp.Payload, nil, fmt.Errorf("receive a response for (%s) but in invalid state(%d)", t.Txid, resp.Type)
127134
}
128135

@@ -201,17 +208,23 @@ func getTimeout(cID *pb.ChaincodeID) (time.Duration, error) {
201208
}
202209

203210
func markTxBegin(ledger *ledger.Ledger, t *pb.Transaction) {
204-
if t.Type == pb.Transaction_CHAINCODE_QUERY {
205-
return
211+
//ledger would be nil if are in simulation mode
212+
if ledger != nil {
213+
if t.Type == pb.Transaction_CHAINCODE_QUERY {
214+
return
215+
}
216+
ledger.TxBegin(t.Txid)
206217
}
207-
ledger.TxBegin(t.Txid)
208218
}
209219

210220
func markTxFinish(ledger *ledger.Ledger, t *pb.Transaction, successful bool) {
211-
if t.Type == pb.Transaction_CHAINCODE_QUERY {
212-
return
221+
//ledger would be nil if are in simulation mode
222+
if ledger != nil {
223+
if t.Type == pb.Transaction_CHAINCODE_QUERY {
224+
return
225+
}
226+
ledger.TxFinished(t.Txid, successful)
213227
}
214-
ledger.TxFinished(t.Txid, successful)
215228
}
216229

217230
func sendTxRejectedEvent(tx *pb.Transaction, errorMsg string) {

core/chaincode/handler.go

+35-8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
ccintf "github.com/hyperledger/fabric/core/container/ccintf"
2727
"github.com/hyperledger/fabric/core/crypto"
2828
"github.com/hyperledger/fabric/core/ledger/statemgmt"
29+
ledgernext "github.com/hyperledger/fabric/core/ledgernext"
2930
"github.com/hyperledger/fabric/core/util"
3031
pb "github.com/hyperledger/fabric/protos"
3132
"github.com/looplab/fsm"
@@ -61,6 +62,8 @@ type transactionContext struct {
6162

6263
// tracks open iterators used for range queries
6364
rangeQueryIteratorMap map[string]statemgmt.RangeScanIterator
65+
66+
txsimulator ledgernext.TxSimulator
6467
}
6568

6669
type nextStateInfo struct {
@@ -113,7 +116,7 @@ func (handler *Handler) serialSend(msg *pb.ChaincodeMessage) error {
113116
return nil
114117
}
115118

116-
func (handler *Handler) createTxContext(txid string, tx *pb.Transaction) (*transactionContext, error) {
119+
func (handler *Handler) createTxContext(ctxt context.Context, txid string, tx *pb.Transaction) (*transactionContext, error) {
117120
if handler.txCtxs == nil {
118121
return nil, fmt.Errorf("cannot create notifier for txid:%s", txid)
119122
}
@@ -125,6 +128,10 @@ func (handler *Handler) createTxContext(txid string, tx *pb.Transaction) (*trans
125128
txctx := &transactionContext{transactionSecContext: tx, responseNotifier: make(chan *pb.ChaincodeMessage, 1),
126129
rangeQueryIteratorMap: make(map[string]statemgmt.RangeScanIterator)}
127130
handler.txCtxs[txid] = txctx
131+
if txsim, ok := ctxt.Value(TXSimulatorKey).(ledgernext.TxSimulator); ok {
132+
txctx.txsimulator = txsim
133+
}
134+
128135
return txctx, nil
129136
}
130137

@@ -624,7 +631,16 @@ func (handler *Handler) handleGetState(msg *pb.ChaincodeMessage) {
624631
chaincodeID := handler.ChaincodeID.Name
625632

626633
readCommittedState := !handler.getIsTransaction(msg.Txid)
627-
res, err := ledgerObj.GetState(chaincodeID, key, readCommittedState)
634+
var res []byte
635+
var err error
636+
637+
txContext := handler.getTxContext(msg.Txid)
638+
if txContext.txsimulator != nil {
639+
res, err = txContext.txsimulator.GetState(chaincodeID, key)
640+
} else {
641+
res, err = ledgerObj.GetState(chaincodeID, key, readCommittedState)
642+
}
643+
628644
if err != nil {
629645
// Send error msg back to chaincode. GetState will not trigger event
630646
payload := []byte(err.Error())
@@ -1038,12 +1054,23 @@ func (handler *Handler) enterBusyState(e *fsm.Event, state string) {
10381054
// Encrypt the data if the confidential is enabled
10391055
if pVal, err = handler.encrypt(msg.Txid, putStateInfo.Value); err == nil {
10401056
// Invoke ledger to put state
1041-
err = ledgerObj.SetState(chaincodeID, putStateInfo.Key, pVal)
1057+
txContext := handler.getTxContext(msg.Txid)
1058+
if txContext.txsimulator != nil {
1059+
err = txContext.txsimulator.SetState(chaincodeID, putStateInfo.Key, pVal)
1060+
} else {
1061+
err = ledgerObj.SetState(chaincodeID, putStateInfo.Key, pVal)
1062+
}
1063+
10421064
}
10431065
} else if msg.Type.String() == pb.ChaincodeMessage_DEL_STATE.String() {
10441066
// Invoke ledger to delete state
10451067
key := string(msg.Payload)
1046-
err = ledgerObj.DeleteState(chaincodeID, key)
1068+
txContext := handler.getTxContext(msg.Txid)
1069+
if txContext.txsimulator != nil {
1070+
err = txContext.txsimulator.DeleteState(chaincodeID, key)
1071+
} else {
1072+
err = ledgerObj.DeleteState(chaincodeID, key)
1073+
}
10471074
} else if msg.Type.String() == pb.ChaincodeMessage_INVOKE_CHAINCODE.String() {
10481075
//check and prohibit C-call-C for CONFIDENTIAL txs
10491076
if triggerNextStateMsg = handler.canCallChaincode(msg.Txid); triggerNextStateMsg != nil {
@@ -1256,11 +1283,11 @@ func (handler *Handler) setChaincodeSecurityContext(tx *pb.Transaction, msg *pb.
12561283

12571284
//if initArgs is set (should be for "deploy" only) move to Init
12581285
//else move to ready
1259-
func (handler *Handler) initOrReady(txid string, initArgs [][]byte, tx *pb.Transaction, depTx *pb.Transaction) (chan *pb.ChaincodeMessage, error) {
1286+
func (handler *Handler) initOrReady(ctxt context.Context, txid string, initArgs [][]byte, tx *pb.Transaction, depTx *pb.Transaction) (chan *pb.ChaincodeMessage, error) {
12601287
var ccMsg *pb.ChaincodeMessage
12611288
var send bool
12621289

1263-
txctx, funcErr := handler.createTxContext(txid, tx)
1290+
txctx, funcErr := handler.createTxContext(ctxt, txid, tx)
12641291
if funcErr != nil {
12651292
return nil, funcErr
12661293
}
@@ -1451,8 +1478,8 @@ func filterError(errFromFSMEvent error) error {
14511478
return nil
14521479
}
14531480

1454-
func (handler *Handler) sendExecuteMessage(msg *pb.ChaincodeMessage, tx *pb.Transaction) (chan *pb.ChaincodeMessage, error) {
1455-
txctx, err := handler.createTxContext(msg.Txid, tx)
1481+
func (handler *Handler) sendExecuteMessage(ctxt context.Context, msg *pb.ChaincodeMessage, tx *pb.Transaction) (chan *pb.ChaincodeMessage, error) {
1482+
txctx, err := handler.createTxContext(ctxt, msg.Txid, tx)
14561483
if err != nil {
14571484
return nil, err
14581485
}

0 commit comments

Comments
 (0)