Skip to content

Commit 7b8dbdf

Browse files
committed
Invoke VSCC from committer
This change-set adds the call to VSCC to the committer's code path. There are still a few missing pieces that we can only address once LCCC is finalized (e.g. identify the right VSCC, extract policies). The change-set also contains a minor refactoring of the tx-assembly code as discussed with Manish. Change-Id: Ibf8807dbb2934dcf4929c3e1a3edd4e5ec9f40ea Signed-off-by: Alessandro Sorniotti <[email protected]>
1 parent de00eaa commit 7b8dbdf

File tree

4 files changed

+110
-72
lines changed

4 files changed

+110
-72
lines changed

core/committer/noopssinglechain/client.go

+54-1
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@ import (
3535

3636
"fmt"
3737

38+
"github.com/hyperledger/fabric/core/ledger"
3839
"github.com/hyperledger/fabric/core/peer"
3940
"github.com/hyperledger/fabric/gossip/gossip"
4041
"github.com/hyperledger/fabric/gossip/integration"
4142
gossip_proto "github.com/hyperledger/fabric/gossip/proto"
4243
"github.com/hyperledger/fabric/gossip/state"
44+
pb "github.com/hyperledger/fabric/protos/peer"
4345
)
4446

4547
var logger *logging.Logger // package-level logger
@@ -224,6 +226,49 @@ func (d *DeliverService) isDone() bool {
224226
return atomic.LoadInt32(&d.stopFlag) == 1
225227
}
226228

229+
func isTxValidForVscc(envBytes []byte) error {
230+
// TODO: Extract the VSCC/policy from LCCC as soon as this is ready
231+
vscc := "vscc"
232+
233+
// TODO - get chainname from the envelope
234+
chainName := string(chaincode.DefaultChain)
235+
236+
txid := "N/A" // FIXME: is that appropriate?
237+
238+
// build arguments for VSCC invocation
239+
// args[0] - function name (not used now)
240+
// args[1] - serialized Envelope
241+
args := [][]byte{[]byte(""), envBytes}
242+
243+
// create VSCC invocation proposal
244+
vsccCis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeID: &pb.ChaincodeID{Name: vscc}, CtorMsg: &pb.ChaincodeInput{Args: args}}}
245+
prop, err := putils.CreateProposalFromCIS(txid, util.GetTestChainID(), vsccCis, []byte(""))
246+
if err != nil {
247+
logger.Errorf("Cannot create a proposal to invoke VSCC, err %s\n", err)
248+
return err
249+
}
250+
251+
// get context for the chaincode execution
252+
var txsim ledger.TxSimulator
253+
lgr := kvledger.GetLedger(chainName)
254+
txsim, err = lgr.NewTxSimulator()
255+
if err != nil {
256+
logger.Errorf("Cannot obtain tx simulator, err %s\n", err)
257+
return err
258+
}
259+
defer txsim.Done()
260+
ctxt := context.WithValue(context.Background(), chaincode.TXSimulatorKey, txsim)
261+
262+
// invoke VSCC
263+
_, _, err = chaincode.ExecuteChaincode(ctxt, txid, prop, chainName, vscc, args)
264+
if err != nil {
265+
logger.Errorf("VSCC check failed for transaction, error %s", err)
266+
return err
267+
}
268+
269+
return nil
270+
}
271+
227272
func (d *DeliverService) readUntilClose() {
228273
for {
229274
msg, err := d.client.Recv()
@@ -264,7 +309,15 @@ func (d *DeliverService) readUntilClose() {
264309
// in validation is just dropped on the floor
265310
logger.Errorf("Invalid transaction, error %s", err)
266311
} else {
267-
// TODO: call VSCC now
312+
err = isTxValidForVscc(d)
313+
if err != nil {
314+
// TODO: this code needs to receive a bit more attention and discussion:
315+
// it's not clear what it means if a transaction which causes a failure
316+
// in validation is just dropped on the floor
317+
logger.Errorf("isTxValidForVscc returned error %s", err)
318+
continue
319+
}
320+
268321
if t, err := proto.Marshal(env); err == nil {
269322
block.Data.Data = append(block.Data.Data, t)
270323
} else {

core/system_chaincode/vscc/validator_onevalidsignature.go

+15
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ import (
2424
"github.com/hyperledger/fabric/msp"
2525
"github.com/hyperledger/fabric/protos/common"
2626
"github.com/hyperledger/fabric/protos/utils"
27+
"github.com/op/go-logging"
2728
)
2829

30+
var logger = logging.MustGetLogger("vscc")
31+
2932
// ValidatorOneValidSignature implements the default transaction validation policy,
3033
// which is to check the correctness of the read-write set and the endorsement
3134
// signatures
@@ -59,33 +62,40 @@ func (vscc *ValidatorOneValidSignature) Invoke(stub shim.ChaincodeStubInterface)
5962
return nil, errors.New("No block to validate")
6063
}
6164

65+
logger.Infof("VSCC invoked")
66+
6267
// get the envelope...
6368
env, err := utils.GetEnvelope(args[1])
6469
if err != nil {
70+
logger.Errorf("VSCC error: GetEnvelope failed, err %s", err)
6571
return nil, err
6672
}
6773

6874
// ...and the payload...
6975
payl, err := utils.GetPayload(env)
7076
if err != nil {
77+
logger.Errorf("VSCC error: GetPayload failed, err %s", err)
7178
return nil, err
7279
}
7380

7481
// validate the payload type
7582
if common.HeaderType(payl.Header.ChainHeader.Type) != common.HeaderType_ENDORSER_TRANSACTION {
83+
logger.Errorf("Only Endorser Transactions are supported, provided type %d", payl.Header.ChainHeader.Type)
7684
return nil, fmt.Errorf("Only Endorser Transactions are supported, provided type %d", payl.Header.ChainHeader.Type)
7785
}
7886

7987
// ...and the transaction...
8088
tx, err := utils.GetTransaction(payl.Data)
8189
if err != nil {
90+
logger.Errorf("VSCC error: GetTransaction failed, err %s", err)
8291
return nil, err
8392
}
8493

8594
// loop through each of the actions within
8695
for _, act := range tx.Actions {
8796
cap, err := utils.GetChaincodeActionPayload(act.Payload)
8897
if err != nil {
98+
logger.Errorf("VSCC error: GetChaincodeActionPayload failed, err %s", err)
8999
return nil, err
90100
}
91101

@@ -97,23 +107,28 @@ func (vscc *ValidatorOneValidSignature) Invoke(stub shim.ChaincodeStubInterface)
97107
// extract the identity of the signer
98108
end, err := msp.GetManager().DeserializeIdentity(endorsement.Endorser)
99109
if err != nil {
110+
logger.Errorf("VSCC error: DeserializeIdentity failed, err %s", err)
100111
return nil, err
101112
}
102113

103114
// validate it
104115
valid, err := end.Validate()
105116
if err != nil || !valid {
117+
logger.Errorf("Invalid endorser, err %s, valid %t", err, valid)
106118
return nil, fmt.Errorf("Invalid endorser, err %s, valid %t", err, valid)
107119
}
108120

109121
// verify the signature
110122
valid, err = end.Verify(append(prespBytes, endorsement.Endorser...), endorsement.Signature)
111123
if err != nil || !valid {
124+
logger.Errorf("Invalid signature, err %s, valid %t", err, valid)
112125
return nil, fmt.Errorf("Invalid signature, err %s, valid %t", err, valid)
113126
}
114127
}
115128
}
116129

130+
logger.Infof("VSCC exists successfully")
131+
117132
return nil, nil
118133
}
119134

protos/testutils/txtestutils.go

+7-14
Original file line numberDiff line numberDiff line change
@@ -107,22 +107,15 @@ func ConstructSingedTxEnv(txid string, chainID string, ccName string, simulation
107107
return env, nil
108108
}
109109

110+
var mspLcl msp.PeerMSP
111+
var sigId msp.SigningIdentity
112+
110113
// ConstructUnsingedTxEnv creates a Transaction envelope from given inputs
111114
func ConstructUnsingedTxEnv(txid string, chainID string, ccName string, simulationResults []byte, events []byte, visibility []byte) (*common.Envelope, error) {
112-
prop, err := putils.CreateChaincodeProposal(txid, chainID, &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeID: &pb.ChaincodeID{Name: ccName}}}, nil)
113-
if err != nil {
114-
return nil, err
115-
}
116-
117-
presp, err := putils.ConstructUnsignedProposalResponse(prop.Header, prop.Payload, simulationResults, nil, nil)
118-
if err != nil {
119-
return nil, err
120-
}
121-
122-
env, err := putils.ConstructUnsignedTxEnvelope(prop, presp)
123-
if err != nil {
124-
return nil, err
115+
if mspLcl == nil {
116+
mspLcl = msp.NewNoopMsp()
117+
sigId, _ = mspLcl.GetSigningIdentity(nil)
125118
}
126-
return env, nil
127119

120+
return ConstructSingedTxEnv(txid, chainID, ccName, simulationResults, events, visibility, sigId)
128121
}

protos/utils/txutils.go

+34-57
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func GetPayloads(txActions *peer.TransactionAction) (*peer.ChaincodeActionPayloa
5959
return ccPayload, respPayload, nil
6060
}
6161

62-
// GetEndorserTxFromBlock gets Transaction2 from Block.Data.Data
62+
// GetEndorserTxFromBlock gets Transaction from Block.Data.Data
6363
func GetEnvelopeFromBlock(data []byte) (*common.Envelope, error) {
6464
//Block always begins with an envelope
6565
var err error
@@ -71,42 +71,10 @@ func GetEnvelopeFromBlock(data []byte) (*common.Envelope, error) {
7171
return env, nil
7272
}
7373

74-
// CreateSignedTx assembles an Envelope message from proposal, endorsements and a signer.
74+
// assemble an Envelope message from proposal, endorsements and a signer.
7575
// This function should be called by a client when it has collected enough endorsements
7676
// for a proposal to create a transaction and submit it to peers for ordering
7777
func CreateSignedTx(proposal *peer.Proposal, signer msp.SigningIdentity, resps ...*peer.ProposalResponse) (*common.Envelope, error) {
78-
// the original header
79-
hdr, err := GetHeader(proposal.Header)
80-
if err != nil {
81-
return nil, fmt.Errorf("Could not unmarshal the proposal header")
82-
}
83-
// check that the signer is the same that is referenced in the header
84-
// TODO: maybe worth removing?
85-
signerBytes, err := signer.Serialize()
86-
if err != nil {
87-
return nil, err
88-
}
89-
90-
if bytes.Compare(signerBytes, hdr.SignatureHeader.Creator) != 0 {
91-
return nil, fmt.Errorf("The signer needs to be the same as the one referenced in the header")
92-
}
93-
94-
// create the payload
95-
txEnvelope, err := ConstructUnsignedTxEnvelope(proposal, resps...)
96-
if err != nil {
97-
return nil, err
98-
}
99-
// sign the payload
100-
sig, err := signer.Sign(txEnvelope.Payload)
101-
if err != nil {
102-
return nil, err
103-
}
104-
txEnvelope.Signature = sig
105-
return txEnvelope, nil
106-
}
107-
108-
// ConstructUnsignedTxEnvelope constructs payload for the transaction from proposal and endorsements.
109-
func ConstructUnsignedTxEnvelope(proposal *peer.Proposal, resps ...*peer.ProposalResponse) (*common.Envelope, error) {
11078
if len(resps) == 0 {
11179
return nil, fmt.Errorf("At least one proposal response is necessary")
11280
}
@@ -123,6 +91,17 @@ func ConstructUnsignedTxEnvelope(proposal *peer.Proposal, resps ...*peer.Proposa
12391
return nil, fmt.Errorf("Could not unmarshal the proposal payload")
12492
}
12593

94+
// check that the signer is the same that is referenced in the header
95+
// TODO: maybe worth removing?
96+
signerBytes, err := signer.Serialize()
97+
if err != nil {
98+
return nil, err
99+
}
100+
101+
if bytes.Compare(signerBytes, hdr.SignatureHeader.Creator) != 0 {
102+
return nil, fmt.Errorf("The signer needs to be the same as the one referenced in the header")
103+
}
104+
126105
// get header extensions so we have the visibility field
127106
hdrExt, err := GetChaincodeHeaderExtension(hdr)
128107
if err != nil {
@@ -184,40 +163,25 @@ func ConstructUnsignedTxEnvelope(proposal *peer.Proposal, resps ...*peer.Proposa
184163
if err != nil {
185164
return nil, err
186165
}
166+
167+
// create the payload
187168
payl := &common.Payload{Header: hdr, Data: txBytes}
188169
paylBytes, err := GetBytesPayload(payl)
189170
if err != nil {
190171
return nil, err
191172
}
192173

193-
// here's the envelope
194-
return &common.Envelope{Payload: paylBytes, Signature: nil}, nil
195-
}
196-
197-
// CreateProposalResponse creates the proposal response and endorses the payload
198-
func CreateProposalResponse(hdr []byte, payl []byte, results []byte, events []byte, visibility []byte, signingEndorser msp.SigningIdentity) (*peer.ProposalResponse, error) {
199-
resp, err := ConstructUnsignedProposalResponse(hdr, payl, results, events, visibility)
174+
// sign the payload
175+
sig, err := signer.Sign(paylBytes)
200176
if err != nil {
201177
return nil, err
202178
}
203-
// serialize the signing identity
204-
endorser, err := signingEndorser.Serialize()
205-
if err != nil {
206-
return nil, fmt.Errorf("Could not serialize the signing identity for %s, err %s", signingEndorser.Identifier(), err)
207-
}
208179

209-
// sign the concatenation of the proposal response and the serialized endorser identity with this endorser's key
210-
signature, err := signingEndorser.Sign(append(resp.Payload, endorser...))
211-
if err != nil {
212-
return nil, fmt.Errorf("Could not sign the proposal response payload, err %s", err)
213-
}
214-
resp.Endorsement.Endorser = endorser
215-
resp.Endorsement.Signature = signature
216-
return resp, nil
180+
// here's the envelope
181+
return &common.Envelope{Payload: paylBytes, Signature: sig}, nil
217182
}
218183

219-
// ConstructUnsignedProposalResponse constructs the proposal response structure only
220-
func ConstructUnsignedProposalResponse(hdr []byte, payl []byte, results []byte, events []byte, visibility []byte) (*peer.ProposalResponse, error) {
184+
func CreateProposalResponse(hdr []byte, payl []byte, results []byte, events []byte, visibility []byte, signingEndorser msp.SigningIdentity) (*peer.ProposalResponse, error) {
221185
// obtain the proposal hash given proposal header, payload and the requested visibility
222186
pHashBytes, err := GetProposalHash1(hdr, payl, visibility)
223187
if err != nil {
@@ -229,10 +193,23 @@ func ConstructUnsignedProposalResponse(hdr []byte, payl []byte, results []byte,
229193
if err != nil {
230194
return nil, errors.New("Failure while unmarshalling the ProposalResponsePayload")
231195
}
196+
197+
// serialize the signing identity
198+
endorser, err := signingEndorser.Serialize()
199+
if err != nil {
200+
return nil, fmt.Errorf("Could not serialize the signing identity for %s, err %s", signingEndorser.Identifier(), err)
201+
}
202+
203+
// sign the concatenation of the proposal response and the serialized endorser identity with this endorser's key
204+
signature, err := signingEndorser.Sign(append(prpBytes, endorser...))
205+
if err != nil {
206+
return nil, fmt.Errorf("Could not sign the proposal response payload, err %s", err)
207+
}
208+
232209
resp := &peer.ProposalResponse{
233210
// Timestamp: TODO!
234211
Version: 1, // TODO: pick right version number
235-
Endorsement: &peer.Endorsement{Signature: nil, Endorser: nil},
212+
Endorsement: &peer.Endorsement{Signature: signature, Endorser: endorser},
236213
Payload: prpBytes,
237214
Response: &peer.Response{Status: 200, Message: "OK"}}
238215

0 commit comments

Comments
 (0)