Commit 32668825 authored by Angelo De Caro's avatar Angelo De Caro
Browse files

Replay attack protection

This change-set enforces the field TxID of a
proposal/transaction to be computed as the result
of an hash function computed on nonce and creator.
This is to be able to uniquely identity a proposal/transaction.

In addition, the endorsers verify that a TxID is not duplicated
by looking up the ledger as done by the committers.

Before merging this change-set, the client-sdk
needs to be modified to generate the TxID in the
new expected way.

This change-set comes in the context of
https://jira.hyperledger.org/browse/FAB-583



Change-Id: Icc5892976aeec1d4fdca736234355833d04bd4c8
Signed-off-by: default avatarAngelo De Caro <adc@zurich.ibm.com>
parent 60ecaf1c
......@@ -35,10 +35,6 @@ func createChaincodeSpec(ccType string, path string, args [][]byte) *pb.Chaincod
}
func createProposalID() string {
return util.GenerateUUID()
}
// createChaincodeDeploymentSpec Returns a deployment proposal of chaincode type
func createProposalForChaincode(ccChaincodeDeploymentSpec *pb.ChaincodeDeploymentSpec, creator []byte) (proposal *pb.Proposal, err error) {
var ccDeploymentSpecBytes []byte
......@@ -50,8 +46,8 @@ func createProposalForChaincode(ccChaincodeDeploymentSpec *pb.ChaincodeDeploymen
Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("deploy"), []byte("default"), ccDeploymentSpecBytes}}}
lcChaincodeInvocationSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: lcChaincodeSpec}
uuid := createProposalID()
// make proposal
return putils.CreateChaincodeProposal(uuid, common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), lcChaincodeInvocationSpec, creator)
proposal, _, err = putils.CreateChaincodeProposal(common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), lcChaincodeInvocationSpec, creator)
return
}
......@@ -221,6 +221,7 @@ func MakeChainCreationTransaction(creationPolicy string, chainID string, signer
payloadChannelHeader := utils.MakeChannelHeader(cb.HeaderType_CONFIG, msgVersion, chainID, epoch)
payloadSignatureHeader := utils.MakeSignatureHeader(sSigner, utils.CreateNonceOrPanic())
utils.SetTxID(payloadChannelHeader, payloadSignatureHeader)
payloadHeader := utils.MakePayloadHeader(payloadChannelHeader, payloadSignatureHeader)
payload := &cb.Payload{Header: payloadHeader, Data: utils.MarshalOrPanic(newConfigEnv)}
paylBytes := utils.MarshalOrPanic(payload)
......
......@@ -34,7 +34,6 @@ func TestBlockSerialization(t *testing.T) {
}
func TestExtractTxid(t *testing.T) {
txid := "txID"
txEnv, txid, _ := testutil.ConstructTransaction(t, testutil.ConstructRandomBytes(t, 50), false)
txEnvBytes, _ := putils.GetBytesEnvelope(txEnv)
extractedTxid, err := extractTxID(txEnvBytes)
......
......@@ -93,13 +93,13 @@ func ConstructTestBlocks(t *testing.T, numBlocks int) []*common.Block {
func ConstructTransaction(t *testing.T, simulationResults []byte, sign bool) (*common.Envelope, string, error) {
ccName := "foo"
//response := &pb.Response{Status: 200}
txID := util.GenerateUUID()
var txID string
var txEnv *common.Envelope
var err error
if sign {
txEnv, err = ptestutils.ConstructSingedTxEnvWithDefaultSigner(txID, util.GetTestChainID(), ccName, nil, simulationResults, nil, nil)
txEnv, txID, err = ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GetTestChainID(), ccName, nil, simulationResults, nil, nil)
} else {
txEnv, err = ptestutils.ConstructUnsingedTxEnv(txID, util.GetTestChainID(), ccName, nil, simulationResults, nil, nil)
txEnv, txID, err = ptestutils.ConstructUnsingedTxEnv(util.GetTestChainID(), ccName, nil, simulationResults, nil, nil)
}
return txEnv, txID, err
}
......
......@@ -142,7 +142,7 @@ func endTxSimulationCDS(chainID string, txid string, txsim ledger.TxSimulator, p
return err
}
// get a proposal - we need it to get a transaction
prop, err := putils.CreateDeployProposalFromCDS(txid, chainID, cds, ss, nil, nil, nil)
prop, _, err := putils.CreateDeployProposalFromCDS(chainID, cds, ss, nil, nil, nil)
if err != nil {
return err
}
......@@ -157,7 +157,7 @@ func endTxSimulationCIS(chainID string, txid string, txsim ledger.TxSimulator, p
return err
}
// get a proposal - we need it to get a transaction
prop, err := putils.CreateProposalFromCIS(txid, common.HeaderType_ENDORSER_TRANSACTION, chainID, cis, ss)
prop, _, err := putils.CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, chainID, cis, ss)
if err != nil {
return err
}
......
......@@ -39,9 +39,8 @@ func getProposal() (*peer.Proposal, error) {
ChaincodeId: &peer.ChaincodeID{Name: "foo"},
Type: peer.ChaincodeSpec_GOLANG}}
uuid := util.GenerateUUID()
return utils.CreateProposalFromCIS(uuid, common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), cis, signerSerialized)
proposal, _, err := utils.CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), cis, signerSerialized)
return proposal, err
}
func TestGoodPath(t *testing.T) {
......
......@@ -92,7 +92,16 @@ func ValidateProposalMessage(signedProp *pb.SignedProposal) (*pb.Proposal, *comm
// TODO: ensure that creator can transact with us (some ACLs?) which set of APIs is supposed to give us this info?
// TODO: perform a check against replay attacks
// Verify that the transaction ID has been computed properly.
// This check is needed to ensure that the lookup into the ledger
// for the same TxID catches duplicates.
err = utils.CheckProposalTxID(
hdr.ChannelHeader.TxId,
hdr.SignatureHeader.Nonce,
hdr.SignatureHeader.Creator)
if err != nil {
return nil, nil, nil, err
}
// continue the validation in a way that depends on the type specified in the header
switch common.HeaderType(hdr.ChannelHeader.Type) {
......@@ -197,9 +206,15 @@ func validateChannelHeader(cHdr *common.ChannelHeader) error {
// TODO: validate chainID in cHdr.ChainID
// TODO: validate epoch in cHdr.Epoch
// Validate epoch in cHdr.Epoch
// Currently we enforce that Epoch is 0.
// TODO: This check will be modified once the Epoch management
// will be in place.
if cHdr.Epoch != 0 {
return fmt.Errorf("Invalid Epoch in ChannelHeader. It must be 0. It was [%d]", cHdr.Epoch)
}
// TODO: validate version in cHdr.Version
// TODO: Validate version in cHdr.Version
return nil
}
......@@ -356,7 +371,16 @@ func ValidateTransaction(e *common.Envelope) (*common.Payload, error) {
// TODO: ensure that creator can transact with us (some ACLs?) which set of APIs is supposed to give us this info?
// TODO: perform a check against replay attacks
// Verify that the transaction ID has been computed properly.
// This check is needed to ensure that the lookup into the ledger
// for the same TxID catches duplicates.
err = utils.CheckProposalTxID(
payload.Header.ChannelHeader.TxId,
payload.Header.SignatureHeader.Nonce,
payload.Header.SignatureHeader.Creator)
if err != nil {
return nil, err
}
// continue the validation in a way that depends on the type specified in the header
switch common.HeaderType(payload.Header.ChannelHeader.Type) {
......
......@@ -23,6 +23,8 @@ import (
"github.com/op/go-logging"
"golang.org/x/net/context"
"errors"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/chaincode"
"github.com/hyperledger/fabric/core/chaincode/shim"
......@@ -285,14 +287,23 @@ func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedPro
ischainless = true
}
//TODO check for uniqueness of prop.TxID with ledger
// Check for uniqueness of prop.TxID with ledger
// Notice that ValidateProposalMessage has already verified
// that TxID is computed propertly
txid := hdr.ChannelHeader.TxId
if txid == "" {
err = fmt.Errorf("Invalid txID")
err = errors.New("Invalid txID. It must be different from the empty string.")
return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
}
lgr := peer.GetLedger(chainID)
if lgr == nil {
return nil, errors.New("Failure while looking up the ledger")
}
if _, err := lgr.GetTransactionByID(txid); err == nil {
return nil, fmt.Errorf("Duplicate transaction found [%s]. Creator [%x]. [%s]", txid, hdr.SignatureHeader.Creator, err)
}
// obtaining once the tx simulator for this proposal. This will be nil
// for chainless proposals
// Also obtain a history query executor for history queries, since tx simulator does not cover history
......
......@@ -112,8 +112,9 @@ func closeListenerAndSleep(l net.Listener) {
//getProposal gets the proposal for the chaincode invocation
//Currently supported only for Invokes (Queries still go through devops client)
func getInvokeProposal(cis *pb.ChaincodeInvocationSpec, chainID string, creator []byte) (*pb.Proposal, error) {
uuid := util.GenerateUUID()
return pbutils.CreateChaincodeProposal(uuid, common.HeaderType_ENDORSER_TRANSACTION, chainID, cis, creator)
proposal, _, err := pbutils.CreateChaincodeProposal(common.HeaderType_ENDORSER_TRANSACTION, chainID, cis, creator)
return proposal, err
}
func getDeployProposal(cds *pb.ChaincodeDeploymentSpec, chainID string, creator []byte) (*pb.Proposal, error) {
......
......@@ -116,7 +116,7 @@ func (app *App) QueryBalances(accounts []string) ([]int, error) {
func constructTransaction(simulationResults []byte) *common.Envelope {
response := &pb.Response{Status: 200}
txEnv, _ := ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GenerateUUID(), util.GetTestChainID(), "foo", response, simulationResults, nil, nil)
txEnv, _, _ := ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GetTestChainID(), "foo", response, simulationResults, nil, nil)
return txEnv
}
......
......@@ -140,9 +140,7 @@ func TestInvoke(t *testing.T) {
return
}
uuid := util.GenerateUUID()
proposal, err := putils.CreateChaincodeProposal(uuid, common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), cis, sIdBytes)
proposal, _, err := putils.CreateChaincodeProposal(common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), cis, sIdBytes)
if err != nil {
t.Fail()
t.Fatalf("couldn't generate chaincode proposal: err %s", err)
......
......@@ -35,9 +35,7 @@ import (
func createTx() (*common.Envelope, error) {
cis := &peer.ChaincodeInvocationSpec{ChaincodeSpec: &peer.ChaincodeSpec{ChaincodeId: &peer.ChaincodeID{Name: "foo"}}}
uuid := util.GenerateUUID()
prop, err := utils.CreateProposalFromCIS(uuid, common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), cis, sid)
prop, _, err := utils.CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), cis, sid)
if err != nil {
return nil, err
}
......
......@@ -24,7 +24,6 @@ import (
"strings"
"github.com/hyperledger/fabric/common/cauthdsl"
cutil "github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/chaincode"
"github.com/hyperledger/fabric/core/chaincode/platforms"
"github.com/hyperledger/fabric/core/container"
......@@ -263,15 +262,13 @@ func ChaincodeInvokeOrQuery(spec *pb.ChaincodeSpec, cID string, invoke bool, sig
return nil, fmt.Errorf("Error serializing identity for %s: %s", signer.GetIdentifier(), err)
}
uuid := cutil.GenerateUUID()
funcName := "invoke"
if !invoke {
funcName = "query"
}
var prop *pb.Proposal
prop, err = putils.CreateProposalFromCIS(uuid, pcommon.HeaderType_ENDORSER_TRANSACTION, cID, invocation, creator)
prop, _, err = putils.CreateProposalFromCIS(pcommon.HeaderType_ENDORSER_TRANSACTION, cID, invocation, creator)
if err != nil {
return nil, fmt.Errorf("Error creating proposal %s: %s", funcName, err)
}
......
......@@ -21,7 +21,6 @@ import (
"golang.org/x/net/context"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/common/ccprovider"
"github.com/hyperledger/fabric/peer/common"
pb "github.com/hyperledger/fabric/protos/peer"
......@@ -56,9 +55,7 @@ func install(chaincodeName string, chaincodeVersion string, cds *pb.ChaincodeDep
return fmt.Errorf("Error serializing identity for %s: %s\n", cf.Signer.GetIdentifier(), err)
}
uuid := util.GenerateUUID()
prop, err := utils.CreateInstallProposalFromCDS(uuid, cds, creator)
prop, _, err := utils.CreateInstallProposalFromCDS(cds, creator)
if err != nil {
return fmt.Errorf("Error creating proposal %s: %s\n", chainFuncName, err)
}
......
......@@ -21,7 +21,6 @@ import (
"golang.org/x/net/context"
"github.com/hyperledger/fabric/common/util"
protcommon "github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/hyperledger/fabric/protos/utils"
......@@ -64,9 +63,7 @@ func instantiate(cmd *cobra.Command, cf *ChaincodeCmdFactory) (*protcommon.Envel
return nil, fmt.Errorf("Error serializing identity for %s: %s\n", cf.Signer.GetIdentifier(), err)
}
uuid := util.GenerateUUID()
prop, err := utils.CreateDeployProposalFromCDS(uuid, chainID, cds, creator, policyMarhsalled, []byte(escc), []byte(vscc))
prop, _, err := utils.CreateDeployProposalFromCDS(chainID, cds, creator, policyMarhsalled, []byte(escc), []byte(vscc))
if err != nil {
return nil, fmt.Errorf("Error creating proposal %s: %s\n", chainFuncName, err)
}
......
......@@ -21,7 +21,6 @@ import (
"golang.org/x/net/context"
"github.com/hyperledger/fabric/common/util"
protcommon "github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
"github.com/hyperledger/fabric/protos/utils"
......@@ -64,9 +63,7 @@ func upgrade(cmd *cobra.Command, cf *ChaincodeCmdFactory) (*protcommon.Envelope,
return nil, fmt.Errorf("Error serializing identity for %s: %s\n", cf.Signer.GetIdentifier(), err)
}
uuid := util.GenerateUUID()
prop, err := utils.CreateUpgradeProposalFromCDS(uuid, chainID, cds, creator, policyMarhsalled, []byte(escc), []byte(vscc))
prop, _, err := utils.CreateUpgradeProposalFromCDS(chainID, cds, creator, policyMarhsalled, []byte(escc), []byte(vscc))
if err != nil {
return nil, fmt.Errorf("Error creating proposal %s: %s\n", chainFuncName, err)
}
......
......@@ -20,7 +20,6 @@ import (
"fmt"
"io/ioutil"
cutil "github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/peer/common"
pcommon "github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
......@@ -97,10 +96,8 @@ func executeJoin(cf *ChannelCmdFactory) (err error) {
return fmt.Errorf("Error serializing identity for %s: %s\n", cf.Signer.GetIdentifier(), err)
}
uuid := cutil.GenerateUUID()
var prop *pb.Proposal
prop, err = putils.CreateProposalFromCIS(uuid, pcommon.HeaderType_CONFIG, "", invocation, creator)
prop, _, err = putils.CreateProposalFromCIS(pcommon.HeaderType_CONFIG, "", invocation, creator)
if err != nil {
return fmt.Errorf("Error creating proposal for join %s\n", err)
}
......
......@@ -80,43 +80,43 @@ func getMSPMgrConfigDir() (string, error) {
// ConstructSingedTxEnvWithDefaultSigner constructs a transaction envelop for tests with a default signer.
// This method helps other modules to construct a transaction with supplied parameters
func ConstructSingedTxEnvWithDefaultSigner(txid string, chainID, ccName string, response *pb.Response, simulationResults []byte, events []byte, visibility []byte) (*common.Envelope, error) {
return ConstructSingedTxEnv(txid, chainID, ccName, response, simulationResults, events, visibility, signer)
func ConstructSingedTxEnvWithDefaultSigner(chainID, ccName string, response *pb.Response, simulationResults []byte, events []byte, visibility []byte) (*common.Envelope, string, error) {
return ConstructSingedTxEnv(chainID, ccName, response, simulationResults, events, visibility, signer)
}
// ConstructSingedTxEnv constructs a transaction envelop for tests
func ConstructSingedTxEnv(txid string, chainID string, ccName string, pResponse *pb.Response, simulationResults []byte, events []byte, visibility []byte, signer msp.SigningIdentity) (*common.Envelope, error) {
func ConstructSingedTxEnv(chainID string, ccName string, pResponse *pb.Response, simulationResults []byte, events []byte, visibility []byte, signer msp.SigningIdentity) (*common.Envelope, string, error) {
ss, err := signer.Serialize()
if err != nil {
return nil, err
return nil, "", err
}
prop, err := putils.CreateChaincodeProposal(txid, common.HeaderType_ENDORSER_TRANSACTION, chainID, &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: ccName}}}, ss)
prop, txid, err := putils.CreateChaincodeProposal(common.HeaderType_ENDORSER_TRANSACTION, chainID, &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: ccName}}}, ss)
if err != nil {
return nil, err
return nil, "", err
}
presp, err := putils.CreateProposalResponse(prop.Header, prop.Payload, pResponse, simulationResults, nil, nil, signer)
if err != nil {
return nil, err
return nil, "", err
}
env, err := putils.CreateSignedTx(prop, signer, presp)
if err != nil {
return nil, err
return nil, "", err
}
return env, nil
return env, txid, nil
}
var mspLcl msp.MSP
var sigId msp.SigningIdentity
// ConstructUnsingedTxEnv creates a Transaction envelope from given inputs
func ConstructUnsingedTxEnv(txid string, chainID string, ccName string, response *pb.Response, simulationResults []byte, events []byte, visibility []byte) (*common.Envelope, error) {
func ConstructUnsingedTxEnv(chainID string, ccName string, response *pb.Response, simulationResults []byte, events []byte, visibility []byte) (*common.Envelope, string, error) {
if mspLcl == nil {
mspLcl = msp.NewNoopMsp()
sigId, _ = mspLcl.GetDefaultSigningIdentity()
}
return ConstructSingedTxEnv(txid, chainID, ccName, response, simulationResults, events, visibility, sigId)
return ConstructSingedTxEnv(chainID, ccName, response, simulationResults, events, visibility, sigId)
}
......@@ -164,6 +164,18 @@ func MakeSignatureHeader(serializedCreatorCertChain []byte, nonce []byte) *cb.Si
}
}
func SetTxID(channelHeader *cb.ChannelHeader, signatureHeader *cb.SignatureHeader) error {
txid, err := ComputeProposalTxID(
signatureHeader.Nonce,
signatureHeader.Creator,
)
if err != nil {
return err
}
channelHeader.TxId = txid
return nil
}
// MakePayloadHeader creates a Payload Header.
func MakePayloadHeader(ch *cb.ChannelHeader, sh *cb.SignatureHeader) *cb.Header {
return &cb.Header{
......
......@@ -21,7 +21,11 @@ import (
"errors"
"encoding/base64"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/bccsp/factory"
"github.com/hyperledger/fabric/core/chaincode/platforms"
"github.com/hyperledger/fabric/core/crypto/primitives"
"github.com/hyperledger/fabric/protos/common"
......@@ -253,47 +257,60 @@ func GetSignaturePolicyEnvelope(bytes []byte) (*common.SignaturePolicyEnvelope,
}
// CreateChaincodeProposal creates a proposal from given input
func CreateChaincodeProposal(txid string, typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, error) {
return CreateChaincodeProposalWithTransient(txid, typ, chainID, cis, creator, nil)
func CreateChaincodeProposal(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) {
return CreateChaincodeProposalWithTransient(typ, chainID, cis, creator, nil)
}
// CreateChaincodeProposalWithTransient creates a proposal from given input
func CreateChaincodeProposalWithTransient(txid string, typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte, transient []byte) (*peer.Proposal, error) {
func CreateChaincodeProposalWithTransient(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte, transient []byte) (*peer.Proposal, string, error) {
ccHdrExt := &peer.ChaincodeHeaderExtension{ChaincodeId: cis.ChaincodeSpec.ChaincodeId}
ccHdrExtBytes, err := proto.Marshal(ccHdrExt)
if err != nil {
return nil, err
return nil, "", err
}
cisBytes, err := proto.Marshal(cis)
if err != nil {
return nil, err
return nil, "", err
}
ccPropPayload := &peer.ChaincodeProposalPayload{Input: cisBytes, Transient: transient}
ccPropPayloadBytes, err := proto.Marshal(ccPropPayload)
if err != nil {
return nil, err
return nil, "", err
}
// generate a random nonce
nonce, err := primitives.GetRandomNonce()
if err != nil {
return nil, err
return nil, "", err
}
hdr := &common.Header{ChannelHeader: &common.ChannelHeader{Type: int32(typ),
// epoch
// TODO: it is now set to zero. This must be changed once we
// get a more appropriate mechanism to handle it in.
var epoch uint64 = 0
// compute txid
txid, err := ComputeProposalTxID(nonce, creator)
if err != nil {
return nil, "", err
}
hdr := &common.Header{ChannelHeader: &common.ChannelHeader{
Type: int32(typ),
TxId: txid,
ChannelId: chainID,
Extension: ccHdrExtBytes},
Extension: ccHdrExtBytes,
Epoch: epoch},
SignatureHeader: &common.SignatureHeader{Nonce: nonce, Creator: creator}}
hdrBytes, err := proto.Marshal(hdr)
if err != nil {
return nil, err
return nil, "", err
}
return &peer.Proposal{Header: hdrBytes, Payload: ccPropPayloadBytes}, nil
return &peer.Proposal{Header: hdrBytes, Payload: ccPropPayloadBytes}, txid, nil
}
// GetBytesProposalResponsePayload gets proposal response payload
......@@ -445,27 +462,27 @@ func GetActionFromEnvelope(envBytes []byte) (*peer.ChaincodeAction, error) {
}
// CreateProposalFromCIS returns a proposal given a serialized identity and a ChaincodeInvocationSpec
func CreateProposalFromCIS(txid string, typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, error) {
return CreateChaincodeProposal(txid, typ, chainID, cis, creator)
func CreateProposalFromCIS(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) {
return CreateChaincodeProposal(typ, chainID, cis, creator)
}
// CreateInstallProposalFromCDS returns a install proposal given a serialized identity and a ChaincodeDeploymentSpec
func CreateInstallProposalFromCDS(txid string, cds *peer.ChaincodeDeploymentSpec, creator []byte) (*peer.Proposal, error) {
return createProposalFromCDS(txid, "", cds, creator, nil, nil, nil, "install")
func CreateInstallProposalFromCDS(cds *peer.ChaincodeDeploymentSpec, creator []byte) (*peer.Proposal, string, error) {
return createProposalFromCDS("", cds, creator, nil, nil, nil, "install")
}
// CreateDeployProposalFromCDS returns a deploy proposal given a serialized identity and a ChaincodeDeploymentSpec
func CreateDeployProposalFromCDS(txid string, chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, error) {
return createProposalFromCDS(txid, chainID, cds, creator, policy, escc, vscc, "deploy")
func CreateDeployProposalFromCDS(chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, string, error) {
return createProposalFromCDS(chainID, cds, creator, policy, escc, vscc, "deploy")
}
// CreateUpgradeProposalFromCDS returns a upgrade proposal given a serialized identity and a ChaincodeDeploymentSpec
func CreateUpgradeProposalFromCDS(txid string, chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, error) {
return createProposalFromCDS(txid, chainID, cds, creator, policy, escc, vscc, "upgrade")
func CreateUpgradeProposalFromCDS(chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, string, error) {
return createProposalFromCDS(chainID, cds, creator, policy, escc, vscc, "upgrade")
}
// createProposalFromCDS returns a deploy or upgrade proposal given a serialized identity and a ChaincodeDeploymentSpec
func createProposalFromCDS(txid string, chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte, propType string) (*peer.Proposal, error) {
func createProposalFromCDS(chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte, propType string) (*peer.Proposal, string, error) {
//in the new mode, cds will be nil, "deploy" and "upgrade" are instantiates.
var ccinp *peer.ChaincodeInput
var b []byte
......@@ -473,7 +490,7 @@ func createProposalFromCDS(txid string, chainID string, cds *peer.ChaincodeDeplo
if cds != nil {
b, err = proto.Marshal(cds)
if err != nil {
return nil, err
return nil, "", err
}
}
switch propType {
......@@ -493,5 +510,30 @@ func createProposalFromCDS(txid string, chainID string, cds *peer.ChaincodeDeplo
Input: ccinp}}
//...and get the proposal for it
return CreateProposalFromCIS(txid, common.HeaderType_ENDORSER_TRANSACTION, chainID, lcccSpec, creator)
return CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, chainID, lcccSpec, creator)
}
func ComputeProposalTxID(nonce, creator []byte) (string, error) {
// TODO: Get the Hash function to be used from
// channel configuration
digest, err := factory.GetDefaultOrPanic().Hash(
append(nonce, creator...),
&bccsp.SHA256Opts{})
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(digest), nil
}
func CheckProposalTxID(txid string, nonce, creator []byte) error {
computedTxID, err := ComputeProposalTxID(nonce, creator)
if err != nil {
return fmt.Errorf("Failed computing target TXID for comparison [%s]", err)
}
if txid != computedTxID {
return fmt.Errorf("Transaction is not valid. Got [%s], expected [%s]", txid, computedTxID)
}
return nil
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment