Skip to content

Commit

Permalink
[FAB-3329] set chaincode version in ProposalResponse
Browse files Browse the repository at this point in the history
When endorser endorse proposal, set ChaincodeID field
of ChaincodeAction with the ChaincodeID which was used
to execute chaincode, especially the chaincode version.
This CR add ChaincodeID to escc args and set it when
endorsing proposal. Another CR will implement checking
chaincode version of transaction matches latest chaincode
version in commiiter side.

Change-Id: I62d7a5d34e12ff9d3131aa52d1af428bb8d58f2e
Signed-off-by: jiangyaoguo <jiangyaoguo@gmail.com>
  • Loading branch information
jiangyaoguo committed Apr 26, 2017
1 parent 62aec85 commit fc95c06
Show file tree
Hide file tree
Showing 15 changed files with 165 additions and 73 deletions.
10 changes: 7 additions & 3 deletions common/ledger/testutil/test_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/hyperledger/fabric/common/util"
lutils "github.com/hyperledger/fabric/core/ledger/util"
"github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
ptestutils "github.com/hyperledger/fabric/protos/testutils"
"github.com/hyperledger/fabric/protos/utils"

Expand Down Expand Up @@ -75,15 +76,18 @@ func (bg *BlockGenerator) NextTestBlocks(numBlocks int) []*common.Block {

// ConstructTransaction constructs a transaction for testing
func ConstructTransaction(_ *testing.T, simulationResults []byte, sign bool) (*common.Envelope, string, error) {
ccName := "foo"
ccid := &pb.ChaincodeID{
Name: "foo",
Version: "v1",
}
//response := &pb.Response{Status: 200}
var txID string
var txEnv *common.Envelope
var err error
if sign {
txEnv, txID, err = ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GetTestChainID(), ccName, nil, simulationResults, nil, nil)
txEnv, txID, err = ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GetTestChainID(), ccid, nil, simulationResults, nil, nil)
} else {
txEnv, txID, err = ptestutils.ConstructUnsingedTxEnv(util.GetTestChainID(), ccName, nil, simulationResults, nil, nil)
txEnv, txID, err = ptestutils.ConstructUnsingedTxEnv(util.GetTestChainID(), ccid, nil, simulationResults, nil, nil)
}
return txEnv, txID, err
}
Expand Down
22 changes: 15 additions & 7 deletions core/chaincode/exectransaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,28 +171,36 @@ func endTxSimulationCDS(chainID string, _ string, txsim ledger.TxSimulator, payl
if err != nil {
return err
}

// get lscc ChaincodeID
lsccid := &pb.ChaincodeID{
Name: "lscc",
Version: util.GetSysCCVersion(),
}

// get a proposal - we need it to get a transaction
prop, _, err := putils.CreateDeployProposalFromCDS(chainID, cds, ss, nil, nil, nil)
if err != nil {
return err
}

return endTxSimulation(chainID, txsim, payload, commit, prop, blockNumber)
return endTxSimulation(chainID, lsccid, txsim, payload, commit, prop, blockNumber)
}

func endTxSimulationCIS(chainID string, _ string, txsim ledger.TxSimulator, payload []byte, commit bool, cis *pb.ChaincodeInvocationSpec, blockNumber uint64) error {
func endTxSimulationCIS(chainID string, ccid *pb.ChaincodeID, _ string, txsim ledger.TxSimulator, payload []byte, commit bool, cis *pb.ChaincodeInvocationSpec, blockNumber uint64) error {
// get serialized version of the signer
ss, err := signer.Serialize()
if err != nil {
return err
}

// get a proposal - we need it to get a transaction
prop, _, err := putils.CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, chainID, cis, ss)
if err != nil {
return err
}

return endTxSimulation(chainID, txsim, payload, commit, prop, blockNumber)
return endTxSimulation(chainID, ccid, txsim, payload, commit, prop, blockNumber)
}

//getting a crash from ledger.Commit when doing concurrent invokes
Expand All @@ -205,7 +213,7 @@ func endTxSimulationCIS(chainID string, _ string, txsim ledger.TxSimulator, payl
//concurrently (100 concurrent invokes followed by 100 concurrent queries)
var _commitLock_ sync.Mutex

func endTxSimulation(chainID string, txsim ledger.TxSimulator, _ []byte, commit bool, prop *pb.Proposal, blockNumber uint64) error {
func endTxSimulation(chainID string, ccid *pb.ChaincodeID, txsim ledger.TxSimulator, _ []byte, commit bool, prop *pb.Proposal, blockNumber uint64) error {
txsim.Done()
if lgr := peer.GetLedger(chainID); lgr != nil {
if commit {
Expand All @@ -218,7 +226,7 @@ func endTxSimulation(chainID string, txsim ledger.TxSimulator, _ []byte, commit
}

// assemble a (signed) proposal response message
resp, err := putils.CreateProposalResponse(prop.Header, prop.Payload, &pb.Response{Status: 200}, txSimulationResults, nil, nil, signer)
resp, err := putils.CreateProposalResponse(prop.Header, prop.Payload, &pb.Response{Status: 200}, txSimulationResults, nil, ccid, nil, signer)
if err != nil {
return err
}
Expand Down Expand Up @@ -355,10 +363,10 @@ func invokeWithVersion(ctx context.Context, chainID string, version string, spec
//no error, lets try commit
if err == nil {
//capture returned error from commit
err = endTxSimulationCIS(chainID, uuid, txsim, []byte("invoke"), true, cdInvocationSpec, blockNumber)
err = endTxSimulationCIS(chainID, spec.ChaincodeId, uuid, txsim, []byte("invoke"), true, cdInvocationSpec, blockNumber)
} else {
//there was an error, just close simulation and return that
endTxSimulationCIS(chainID, uuid, txsim, []byte("invoke"), false, cdInvocationSpec, blockNumber)
endTxSimulationCIS(chainID, spec.ChaincodeId, uuid, txsim, []byte("invoke"), false, cdInvocationSpec, blockNumber)
}
}()

Expand Down
18 changes: 11 additions & 7 deletions core/common/validation/fullflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,17 @@ import (
func getProposal() (*peer.Proposal, error) {
cis := &peer.ChaincodeInvocationSpec{
ChaincodeSpec: &peer.ChaincodeSpec{
ChaincodeId: &peer.ChaincodeID{Name: "foo"},
ChaincodeId: getChaincodeID(),
Type: peer.ChaincodeSpec_GOLANG}}

proposal, _, err := utils.CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), cis, signerSerialized)
return proposal, err
}

func getChaincodeID() *peer.ChaincodeID {
return &peer.ChaincodeID{Name: "foo", Version: "v1"}
}

func TestGoodPath(t *testing.T) {
// get a toy proposal
prop, err := getProposal()
Expand All @@ -68,7 +72,7 @@ func TestGoodPath(t *testing.T) {
simRes := []byte("simulation_result")

// endorse it to get a proposal response
presp, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response, simRes, nil, nil, signer)
presp, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response, simRes, nil, getChaincodeID(), nil, signer)
if err != nil {
t.Fatalf("CreateProposalResponse failed, err %s", err)
return
Expand Down Expand Up @@ -202,7 +206,7 @@ func TestBadTx(t *testing.T) {
simRes := []byte("simulation_result")

// endorse it to get a proposal response
presp, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response, simRes, nil, nil, signer)
presp, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response, simRes, nil, getChaincodeID(), nil, signer)
if err != nil {
t.Fatalf("CreateProposalResponse failed, err %s", err)
return
Expand Down Expand Up @@ -255,7 +259,7 @@ func Test2EndorsersAgree(t *testing.T) {
simRes1 := []byte("simulation_result")

// endorse it to get a proposal response
presp1, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response1, simRes1, nil, nil, signer)
presp1, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response1, simRes1, nil, getChaincodeID(), nil, signer)
if err != nil {
t.Fatalf("CreateProposalResponse failed, err %s", err)
return
Expand All @@ -265,7 +269,7 @@ func Test2EndorsersAgree(t *testing.T) {
simRes2 := []byte("simulation_result")

// endorse it to get a proposal response
presp2, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response2, simRes2, nil, nil, signer)
presp2, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response2, simRes2, nil, getChaincodeID(), nil, signer)
if err != nil {
t.Fatalf("CreateProposalResponse failed, err %s", err)
return
Expand Down Expand Up @@ -298,7 +302,7 @@ func Test2EndorsersDisagree(t *testing.T) {
simRes1 := []byte("simulation_result1")

// endorse it to get a proposal response
presp1, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response1, simRes1, nil, nil, signer)
presp1, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response1, simRes1, nil, getChaincodeID(), nil, signer)
if err != nil {
t.Fatalf("CreateProposalResponse failed, err %s", err)
return
Expand All @@ -308,7 +312,7 @@ func Test2EndorsersDisagree(t *testing.T) {
simRes2 := []byte("simulation_result2")

// endorse it to get a proposal response
presp2, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response2, simRes2, nil, nil, signer)
presp2, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response2, simRes2, nil, getChaincodeID(), nil, signer)
if err != nil {
t.Fatalf("CreateProposalResponse failed, err %s", err)
return
Expand Down
36 changes: 26 additions & 10 deletions core/endorser/endorser.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,18 +210,19 @@ func (e *Endorser) getCDSFromLSCC(ctx context.Context, chainID string, txid stri
func (e *Endorser) endorseProposal(ctx context.Context, chainID string, txid string, signedProp *pb.SignedProposal, proposal *pb.Proposal, response *pb.Response, simRes []byte, event *pb.ChaincodeEvent, visibility []byte, ccid *pb.ChaincodeID, txsim ledger.TxSimulator, cd *ccprovider.ChaincodeData) (*pb.ProposalResponse, error) {
endorserLogger.Debugf("endorseProposal starts for chainID %s, ccid %s", chainID, ccid)

isSysCC := cd == nil
// 1) extract the name of the escc that is requested to endorse this chaincode
var escc string
//ie, not "lscc" or system chaincodes
if cd != nil {
if isSysCC {
// FIXME: getCDSFromLSCC seems to fail for lscc - not sure this is expected?
// TODO: who should endorse a call to LSCC?
escc = "escc"
} else {
escc = cd.Escc
if escc == "" { // this should never happen, LSCC always fills this field
panic("No ESCC specified in ChaincodeData")
}
} else {
// FIXME: getCDSFromLSCC seems to fail for lscc - not sure this is expected?
// TODO: who should endorse a call to LSCC?
escc = "escc"
}

endorserLogger.Debugf("endorseProposal info: escc for cid %s is %s", ccid, escc)
Expand All @@ -241,16 +242,31 @@ func (e *Endorser) endorseProposal(ctx context.Context, chainID string, txid str
return nil, fmt.Errorf("failed to marshal response bytes - %s", err)
}

// set version of executing chaincode
if isSysCC {
// if we want to allow mixed fabric levels we should
// set syscc version to ""
ccid.Version = util.GetSysCCVersion()
} else {
ccid.Version = cd.Version
}

ccidBytes, err := putils.Marshal(ccid)
if err != nil {
return nil, fmt.Errorf("failed to marshal ChaincodeID - %s", err)
}

// 3) call the ESCC we've identified
// arguments:
// args[0] - function name (not used now)
// args[1] - serialized Header object
// args[2] - serialized ChaincodeProposalPayload object
// args[3] - result of executing chaincode
// args[4] - binary blob of simulation results
// args[5] - serialized events
// args[6] - payloadVisibility
args := [][]byte{[]byte(""), proposal.Header, proposal.Payload, resBytes, simRes, eventBytes, visibility}
// args[3] - ChaincodeID of executing chaincode
// args[4] - result of executing chaincode
// args[5] - binary blob of simulation results
// args[6] - serialized events
// args[7] - payloadVisibility
args := [][]byte{[]byte(""), proposal.Header, proposal.Payload, ccidBytes, resBytes, simRes, eventBytes, visibility}
version := util.GetSysCCVersion()
ecccis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeId: &pb.ChaincodeID{Name: escc}, Input: &pb.ChaincodeInput{Args: args}}}
res, _, err := e.callChaincode(ctx, chainID, version, txid, signedProp, proposal, ecccis, &pb.ChaincodeID{Name: escc}, txsim)
Expand Down
6 changes: 5 additions & 1 deletion core/ledger/kvledger/example/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,12 @@ func (app *App) QueryBalances(accounts []string) ([]int, error) {
}

func constructTransaction(simulationResults []byte) *common.Envelope {
ccid := &pb.ChaincodeID{
Name: "foo",
Version: "v1",
}
response := &pb.Response{Status: 200}
txEnv, _, _ := ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GetTestChainID(), "foo", response, simulationResults, nil, nil)
txEnv, _, _ := ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GetTestChainID(), ccid, response, simulationResults, nil, nil)
return txEnv
}

Expand Down
42 changes: 27 additions & 15 deletions core/scc/escc/endorser_onevalidsignature.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,12 @@ func (e *EndorserOneValidSignature) Init(stub shim.ChaincodeStubInterface) pb.Re
// args[0] - function name (not used now)
// args[1] - serialized Header object
// args[2] - serialized ChaincodeProposalPayload object
// args[3] - result of executing chaincode
// args[4] - binary blob of simulation results
// args[5] - serialized events
// args[6] - payloadVisibility
// args[3] - ChaincodeID of executing chaincode
// args[4] - result of executing chaincode
// args[5] - binary blob of simulation results
// args[6] - serialized events
// args[7] - payloadVisibility

//
// NOTE: this chaincode is meant to sign another chaincode's simulation
// results. It should not manipulate state as any state change will be
Expand All @@ -64,9 +66,9 @@ func (e *EndorserOneValidSignature) Init(stub shim.ChaincodeStubInterface) pb.Re
// definition can't be a state change of our own.
func (e *EndorserOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
args := stub.GetArgs()
if len(args) < 5 {
if len(args) < 6 {
return shim.Error(fmt.Sprintf("Incorrect number of arguments (expected a minimum of 5, provided %d)", len(args)))
} else if len(args) > 7 {
} else if len(args) > 8 {
return shim.Error(fmt.Sprintf("Incorrect number of arguments (expected a maximum of 7, provided %d)", len(args)))
}

Expand All @@ -88,13 +90,23 @@ func (e *EndorserOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) pb.

payl = args[2]

// handle ChaincodeID
if args[3] == nil {
return shim.Error("ChaincodeID is null")
}

ccid, err := putils.UnmarshalChaincodeID(args[3])
if err != nil {
return shim.Error(err.Error())
}

// handle executing chaincode result
// Status code < 500 can be endorsed
if args[3] == nil {
if args[4] == nil {
return shim.Error("Response of chaincode executing is null")
}

response, err := putils.GetResponse(args[3])
response, err := putils.GetResponse(args[4])
if err != nil {
return shim.Error(fmt.Sprintf("Failed to get Response of executing chaincode: %s", err.Error()))
}
Expand All @@ -105,18 +117,18 @@ func (e *EndorserOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) pb.

// handle simulation results
var results []byte
if args[4] == nil {
if args[5] == nil {
return shim.Error("simulation results are null")
}

results = args[4]
results = args[5]

// Handle serialized events if they have been provided
// they might be nil in case there's no events but there
// is a visibility field specified as the next arg
events := []byte("")
if len(args) > 5 && args[5] != nil {
events = args[5]
if len(args) > 6 && args[6] != nil {
events = args[6]
}

// Handle payload visibility (it's an optional argument)
Expand All @@ -128,8 +140,8 @@ func (e *EndorserOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) pb.
// mechanisms that shall be encoded in this field (and handled
// appropriately by the peer)
var visibility []byte
if len(args) > 6 {
visibility = args[6]
if len(args) > 7 {
visibility = args[7]
}

// obtain the default signing identity for this peer; it will be used to sign this proposal response
Expand All @@ -144,7 +156,7 @@ func (e *EndorserOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) pb.
}

// obtain a proposal response
presp, err := utils.CreateProposalResponse(hdr, payl, response, results, events, visibility, signingEndorser)
presp, err := utils.CreateProposalResponse(hdr, payl, response, results, events, ccid, visibility, signingEndorser)
if err != nil {
return shim.Error(err.Error())
}
Expand Down
Loading

0 comments on commit fc95c06

Please sign in to comment.