我可以通过在Hyperledger Fabric中使用fabric-python-sdk一次将tx提案发送给3个背书的对等方吗?

问题描述

  • 环境
    • 超级账本结构v1.4.7 / fabric-python-sdk
    • Node1-Org1(10.10.0.1),Node2-Org2(10.10.0.2),Node3-Org3(10.10.0.3)
    • 认可政策:AND ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')
  • network.json
{
    "name": "net_fabric","version": "1.0.0","client": {
        "organization": "Org1","credentialStore": {
            "path": "/tmp/hfc-kvs","cryptoStore": {
                "path": "/tmp/hfc-cvs"
            },"wallet": "wallet-name"
        },"connection": {
            "timeout": {
                "peer": {
                    "endorser": "60000","eventHub": "60000","eventReg": "60000"
                },"orderer": "60000"
            }
        }
    },"channels": {
        "mychannel": {
            "orderers": [
                "orderer.example.com"
            ],"peers": {
                "peer0.org1.example.com": {
                "endorsingPeer": true,"chaincodeQuery": true,"eventSource": true
        },"peer1.org1.example.com": {
                "endorsingPeer": true,"peer0.org2.example.com": {
                "endorsingPeer": true,"peer1.org2.example.com": {
                "endorsingPeer": true,"peer0.org3.example.com": {
                "endorsingPeer": true,"peer1.org3.example.com": {
                "endorsingPeer": true,"eventSource": true
        }
            }
        }
    },"organizations": {
        "orderer.example.com": {
            "mspid": "OrdererMSP","orderers": [
                "orderer.example.com"
            ],"users": {
                "Admin": {
                    "cert": "crypto-config/ordererOrganizations/example.com/users/[email protected]/msp/signcerts/[email protected]","private_key": "crypto-config/ordererOrganizations/example.com/users/[email protected]/msp/keystore/bb970e6666e63f00039c25c15f82ac39860027ea3a353fa9152dedf508a68541_sk"
                }
            }
        },"org1.example.com": {
            "mspid": "Org1MSP","peers": [
                "peer0.org1.example.com","peer1.org1.example.com"
            ],"certificateAuthorities": [
                "ca.org1.example.com"
            ],"users": {
                "Admin": {
                    "cert": "crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp/signcerts/[email protected]","private_key": "crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp/keystore/9ed12a80062621bc68bcf6d73309cb216b6d72b8b4e4ae2aea5751d69bbead35_sk"
                },"User1": {
                    "cert": "crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp/signcerts/[email protected]","private_key": "crypto-config/peerOrganizations/org1.example.com/users/[email protected]/msp/keystore/1a476c5cc5874ae5a9b5c313e6fbd4cf4717d2730d4e0349668bc53ef4e05b93_sk"
                }
            }
        },"org2.example.com": {
            "mspid": "Org2MSP","peers": [
                "peer0.org2.example.com","peer1.org2.example.com"
            ],"certificateAuthorities": [
                "ca.org2.example.com"
            ],"users": {
                "Admin": {
                    "cert": "crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/signcerts/[email protected]","private_key": "crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/keystore/5d3223ea7355959ffe90185e149395ee972902bd6f4ac4ec240c855a2d61ed4a_sk"
                },"User1": {
                    "cert": "crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/signcerts/[email protected]","private_key": "crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/keystore/57b1ca82356ba68fdf93aa208da3c25f8055310dffacd61373946f2673bc4e96_sk"
                }
            }
        },"org3.example.com": {
            "mspid": "Org3MSP","peers": [
                "peer0.org3.example.com","peer1.org3.example.com"
            ],"certificateAuthorities": [
                "ca.org3.example.com"
            ],"users": {
                "Admin": {
                    "cert": "crypto-config/peerOrganizations/org3.example.com/users/[email protected]/msp/signcerts/[email protected]","private_key": "crypto-config/peerOrganizations/org3.example.com/users/[email protected]/msp/keystore/570a370bfd2cea9ced433be8955c6676a6208d3ec5953df267781cf5ba6bf831_sk"
                },"User1": {
                    "cert": "crypto-config/peerOrganizations/org3.example.com/users/[email protected]/msp/signcerts/[email protected]","private_key": "crypto-config/peerOrganizations/org3.example.com/users/[email protected]/msp/keystore/e24c3bde2038a04bab26453083fd07433070e3cffccad5205ae319ce4d64fc47_sk"
                }
            }
        }
    },"orderers": {
        "orderer.example.com": {
            "url": "10.10.0.1:7050","grpcoptions": {
                "grpc.ssl_target_name_override": "orderer.example.com","grpc-max-send-message-length": 15
            }
        }
    },"peers": {
        "peer0.org1.example.com": {
            "url": "grpc://peer0.org1.example.com:7051","grpcoptions": {
                "grpc.ssl_target_name_override": "peer0.org1.example.com","grpc-max-send-message-length": 15
            }
        },"peer1.org1.example.com": {
            "url": "grpc://peer1.org1.example.com:7051","grpcoptions": {
                "grpc.ssl_target_name_override": "peer1.org1.example.com","peer0.org2.example.com": {
            "url": "grpc://peer0.org2.example.com:7051","grpcoptions": {
                "grpc.ssl_target_name_override": "peer0.org2.example.com","peer1.org2.example.com": {
            "url": "grpc://peer1.org2.example.com:7051","grpcoptions": {
                "grpc.ssl_target_name_override": "peer1.org2.example.com","peer0.org3.example.com": {
            "url": "grpc://peer0.org3.example.com:7051","grpcoptions": {
                "grpc.ssl_target_name_override": "peer0.org3.example.com","peer1.org3.example.com": {
            "url": "grpc://peer1.org3.example.com:7051","grpcoptions": {
                "grpc.ssl_target_name_override": "peer1.org3.example.com","certificateAuthorities": {
        "ca.org1.example.com": {
            "url": "http://ca.org1.example.com:7054","caName": "ca.org1.example.com"
        },"ca.org2.example.com": {
            "url": "http://ca.org2.example.com:7054","caName": "ca.org2.example.com"
        },"ca.org3.example.com": {
            "url": "http://ca.org3.example.com:7054","caName": "ca.org3.example.com"
        }
    }
}

我想一次向3个认可的同行发送提案。

我正在使用fabric-sdk-pygrpc发送这样的交易:

class GrpclbServicer(grpclb_pb2_grpc.GrpclbServicer):
    def Execute(self,request,context):
        org1_admin = cli.get_user(org_name='org1.example.com',name='Admin')
        # The response should be true if succeed
        response = loop.run_until_complete(cli.chaincode_invoke(
                            requestor=org1_admin,channel_name=request.channelName,peers=['peer0.org1.example.com','peer0.org2.example.com','peer0.org3.example.com'],fcn=request.functionName,# createCar
                            args=request.args,cc_name=request.chaincodeName,# fabcar  
                            transient_map=None,# optional,for private data
                            wait_for_event=True,# for being sure chaincode invocation has been commited in the ledger,default is on tx event
                            ))
        return grpclb_pb2.TxResponse(
            response = response
        )

执行chaincode_invoke时,只能选择一个请求(org1_admin),这样我得到了这样的错误消息。 (org1_admin仅包含Org1MSP)

2020-09-02 07:13:25.782 UTC [endorser] SimulateProposal -> ERRO 095 [mychannel][4bd53729] Failed to invoke chaincode name:"fabcar",error: txid: 4bd53729be43a4de95d5d6383fc9f6e2f610f05ea486815f75799839d1a8186c(mychannel) exists

所以我将代码更改如下:

    def Execute(self,context):
        orgs = ['org1.example.com','org2.example.com','org3.example.com']

        # The response should be true if succeed
        for org in orgs:
            org_admin = cli.get_user(org_name=org,name='Admin')
            response = loop.run_until_complete(cli.chaincode_invoke(
                                requestor=org_admin,peers=['peer0.'+org],args=request.args,transient_map=None,for private data
                                wait_for_event=True,default is on tx event
                                ))

但是我得到了这个错误。我认为...发生此错误的原因是,由于tx是一个一个地发送的,因此不符合认可政策。

2020-09-02 07:29:09.205 UTC [vscc] Validate -> ERRO 06a VSCC error: stateBasedValidator.Validate Failed,err validation of endorsement policy for chaincode fabcar in tx 6:0 Failed: signature set did not satisfy policy
2020-09-02 07:29:09.205 UTC [committer.txvalidator] validateTx -> ERRO 06b VSCCValidateTx for transaction txId = 3ac7c00db44090924edb8bc88c543430e3b77e69856a8a7c22b7c9062eb2b4d8 returned error: validation of endorsement policy for chaincode fabcar in tx 6:0 Failed: signature set did not satisfy policy

是否有一种方法可以通过使用fabric-sdk-py将Tx提议立即发送给认可的对等方(peer0.org1,peer0.org2,peer0.org3)?

或者我该如何满足认可政策?

解决方法

这是Fabric(Golang)的一种内部方法,但是您可以看到它们的方法,同时向背书人source

提出建议。
// processProposals sends a signed proposal to a set of peers,and gathers all the responses.
func processProposals(endorserClients []pb.EndorserClient,signedProposal *pb.SignedProposal) ([]*pb.ProposalResponse,error) {
    responsesCh := make(chan *pb.ProposalResponse,len(endorserClients))
    errorCh := make(chan error,len(endorserClients))
    wg := sync.WaitGroup{}
    for _,endorser := range endorserClients {
        wg.Add(1)
        go func(endorser pb.EndorserClient) {       <=== This line creates a new thread for each endorser call
            defer wg.Done()
            proposalResp,err := endorser.ProcessProposal(context.Background(),signedProposal)
            if err != nil {
                errorCh <- err
                return
            }
            responsesCh <- proposalResp
        }(endorser)
    }
    wg.Wait()                              <=== And then wait until receiving all the responses
    close(responsesCh)
    close(errorCh)
    for err := range errorCh {
        return nil,err
    }
    var responses []*pb.ProposalResponse
    for response := range responsesCh {
        responses = append(responses,response)
    }
    return responses,nil
}

我个人认为您也可以使用Python做到这一点