Пример #1
0
//simulate the proposal by calling the chaincode
func (e *Endorser) simulateProposal(ctx context.Context, chainID string, txid string, prop *pb.Proposal, cid *pb.ChaincodeID, txsim ledger.TxSimulator) ([]byte, []byte, *pb.ChaincodeEvent, error) {
	//we do expect the payload to be a ChaincodeInvocationSpec
	//if we are supporting other payloads in future, this be glaringly point
	//as something that should change
	cis, err := putils.GetChaincodeInvocationSpec(prop)
	if err != nil {
		return nil, nil, nil, err
	}
	//---1. check ACL
	if err = e.checkACL(prop); err != nil {
		return nil, nil, nil, err
	}

	//---2. check ESCC and VSCC for the chaincode
	if err = e.checkEsccAndVscc(prop); err != nil {
		return nil, nil, nil, err
	}

	//---3. execute the proposal and get simulation results
	var simResult []byte
	var resp []byte
	var ccevent *pb.ChaincodeEvent
	resp, ccevent, err = e.callChaincode(ctx, chainID, txid, prop, cis, cid, txsim)
	if err != nil {
		return nil, nil, nil, err
	}

	if txsim != nil {
		if simResult, err = txsim.GetTxSimulationResults(); err != nil {
			return nil, nil, nil, err
		}
	}

	return resp, simResult, ccevent, nil
}
Пример #2
0
// deploySysCC deploys the given system chaincode on a chain
func deploySysCC(chainID string, syscc *SystemChaincode) error {
	if !syscc.Enabled || !isWhitelisted(syscc) {
		sysccLogger.Info(fmt.Sprintf("system chaincode (%s,%s) disabled", syscc.Name, syscc.Path))
		return nil
	}

	if chainID == "" && !syscc.ChainlessCC {
		return fmt.Errorf("cannot deploy system chaincode %s without chain id", syscc.Name)
	} else if chainID != "" && syscc.ChainlessCC {
		return fmt.Errorf("cannot deploy chainless system chaincode %s with chain id %s", syscc.Name, chainID)
	}

	var err error

	ctxt := context.Background()
	if !syscc.ChainlessCC {
		lgr := peer.GetLedger(chainID)
		var txsim ledger.TxSimulator
		if txsim, err = lgr.NewTxSimulator(); err != nil {
			return err
		}

		ctxt = context.WithValue(ctxt, TXSimulatorKey, txsim)

		defer txsim.Done()
	}

	chaincodeID := &pb.ChaincodeID{Path: syscc.Path, Name: syscc.Name}
	spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeID: chaincodeID, CtorMsg: &pb.ChaincodeInput{Args: syscc.InitArgs}}

	// First build and get the deployment spec
	chaincodeDeploymentSpec, err := buildSysCC(ctxt, spec)

	if err != nil {
		sysccLogger.Error(fmt.Sprintf("Error deploying chaincode spec: %v\n\n error: %s", spec, err))
		return err
	}

	txid := util.GenerateUUID()

	cccid := NewCCContext(chainID, chaincodeDeploymentSpec.ChaincodeSpec.ChaincodeID.Name, "", txid, true, nil)

	_, _, err = Execute(ctxt, cccid, chaincodeDeploymentSpec)

	sysccLogger.Infof("system chaincode %s/%s(%s) deployed", syscc.Name, chainID, syscc.Path)

	return err
}
Пример #3
0
func isTxValidForVscc(payload *common.Payload, envBytes []byte) error {
	// TODO: Extract the VSCC/policy from LCCC as soon as this is ready
	vscc := "vscc"

	chainName := payload.Header.ChainHeader.ChainID
	if chainName == "" {
		err := fmt.Errorf("transaction header does not contain an chain ID")
		logger.Errorf("%s", err)
		return err
	}

	txid := "N/A" // FIXME: is that appropriate?

	// build arguments for VSCC invocation
	// args[0] - function name (not used now)
	// args[1] - serialized Envelope
	args := [][]byte{[]byte(""), envBytes}

	// create VSCC invocation proposal
	vsccCis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeID: &pb.ChaincodeID{Name: vscc}, CtorMsg: &pb.ChaincodeInput{Args: args}}}
	prop, err := putils.CreateProposalFromCIS(txid, chainName, vsccCis, []byte(""))
	if err != nil {
		logger.Errorf("Cannot create a proposal to invoke VSCC, err %s\n", err)
		return err
	}

	// get context for the chaincode execution
	var txsim ledger.TxSimulator
	lgr := peer.GetLedger(chainName)
	txsim, err = lgr.NewTxSimulator()
	if err != nil {
		logger.Errorf("Cannot obtain tx simulator, err %s\n", err)
		return err
	}
	defer txsim.Done()
	ctxt := context.WithValue(context.Background(), chaincode.TXSimulatorKey, txsim)

	cccid := chaincode.NewCCContext(chainName, vscc, "", txid, true, prop)

	// invoke VSCC
	_, _, err = chaincode.ExecuteChaincode(ctxt, cccid, args)
	if err != nil {
		logger.Errorf("VSCC check failed for transaction, error %s", err)
		return err
	}

	return nil
}
Пример #4
0
// TransferMarble simulates transfer transaction
func (marbleApp *MarbleApp) TransferMarble(args []string) (*common.Envelope, error) {
	//   0       1
	// "name", "bob"
	if len(args) < 2 {
		return nil, errors.New("Incorrect number of arguments. Expecting 2")
	}
	marbleName := args[0]
	marbleNewOwner := args[1]

	logger.Debugf("===COUCHDB=== Entering ----------TransferMarble----------")
	var txSimulator ledger.TxSimulator
	var err error
	if txSimulator, err = marbleApp.ledger.NewTxSimulator(); err != nil {
		return nil, err
	}
	defer txSimulator.Done()

	marbleBytes, err := txSimulator.GetState(marbleApp.name, marbleName)
	logger.Debugf("===COUCHDB=== marbleBytes is: %v", marbleBytes)
	if marbleBytes != nil {
		jsonString := string(marbleBytes[:])
		logger.Debugf("===COUCHDB=== TransferMarble() Retrieved jsonString: \n   %s", jsonString)
	}

	theMarble := Marble{}
	json.Unmarshal(marbleBytes, &theMarble) //Unmarshal JSON bytes into a Marble struct

	logger.Debugf("===COUCHDB===  theMarble after unmarshal: %v", theMarble)

	logger.Debugf("===COUCHDB===  Setting the owner to: %s", marbleNewOwner)
	theMarble.User = marbleNewOwner      //change the user
	theMarble.Txid = "tx000000000000002" // COUCHDB hardcode a txid for now for demo purpose

	updatedMarbleBytes, _ := json.Marshal(theMarble)
	if updatedMarbleBytes != nil {
		updatedJsonString := string(updatedMarbleBytes[:])
		logger.Debugf("===COUCHDB=== updatedJsonString:\n   %s", updatedJsonString)
	}
	err = txSimulator.SetState(marbleApp.name, marbleName, updatedMarbleBytes)
	if err != nil {
		return nil, err
	}

	var txSimulationResults []byte
	if txSimulationResults, err = txSimulator.GetTxSimulationResults(); err != nil {
		return nil, err
	}
	logger.Debugf("===COUCHDB=== TransferMarble() simulation done, packaging into a transaction...")
	tx := constructTransaction(txSimulationResults)
	return tx, nil
}
Пример #5
0
// CreateMarble simulates init transaction
func (marbleApp *MarbleApp) CreateMarble(args []string) (*common.Envelope, error) {
	//   0       1       2     3
	// "asdf", "blue", "35", "bob"
	logger.Debugf("===COUCHDB=== Entering ----------CreateMarble()----------")
	marbleName := args[0]
	marbleJsonBytes, err := init_marble(args)
	if err != nil {
		return nil, err
	}

	var txSimulator ledger.TxSimulator
	if txSimulator, err = marbleApp.ledger.NewTxSimulator(); err != nil {
		return nil, err
	}
	defer txSimulator.Done()

	txSimulator.SetState(marbleApp.name, marbleName, marbleJsonBytes)

	var txSimulationResults []byte
	if txSimulationResults, err = txSimulator.GetTxSimulationResults(); err != nil {
		return nil, err
	}
	logger.Debugf("===COUCHDB=== CreateMarble() simulation done, packaging into a transaction...")
	tx := constructTransaction(txSimulationResults)
	logger.Debugf("===COUCHDB=== Exiting CreateMarble()")
	return tx, nil
}
Пример #6
0
func endTxSimulation(chainID string, txsim ledger.TxSimulator, payload []byte, commit bool, prop *pb.Proposal) error {
	txsim.Done()
	if lgr := peer.GetLedger(chainID); lgr != nil {
		if commit {
			var txSimulationResults []byte
			var err error

			//get simulation results
			if txSimulationResults, err = txsim.GetTxSimulationResults(); err != nil {
				return err
			}

			// assemble a (signed) proposal response message
			resp, err := putils.CreateProposalResponse(prop.Header, prop.Payload, txSimulationResults, nil, nil, signer)
			if err != nil {
				return err
			}

			// get the envelope
			env, err := putils.CreateSignedTx(prop, signer, resp)
			if err != nil {
				return err
			}

			envBytes, err := putils.GetBytesEnvelope(env)
			if err != nil {
				return err
			}

			//create the block with 1 transaction
			block := common.NewBlock(1, []byte{})
			block.Data.Data = [][]byte{envBytes}
			//commit the block
			if err := lgr.Commit(block); err != nil {
				return err
			}
		}
	}

	return nil
}
Пример #7
0
// Init simulates init transaction
func (app *App) Init(initialBalances map[string]int) (*common.Envelope, error) {
	var txSimulator ledger.TxSimulator
	var err error
	if txSimulator, err = app.ledger.NewTxSimulator(); err != nil {
		return nil, err
	}
	defer txSimulator.Done()
	for accountID, bal := range initialBalances {
		txSimulator.SetState(app.name, accountID, toBytes(bal))
	}
	var txSimulationResults []byte
	if txSimulationResults, err = txSimulator.GetTxSimulationResults(); err != nil {
		return nil, err
	}
	tx := constructTransaction(txSimulationResults)
	return tx, nil
}
Пример #8
0
// ProcessProposal process the Proposal
func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedProposal) (*pb.ProposalResponse, error) {
	// at first, we check whether the message is valid
	prop, _, hdrExt, err := peer.ValidateProposalMessage(signedProp)
	if err != nil {
		return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
	}

	hdr, err := putils.GetHeader(prop.Header)
	if err != nil {
		return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
	}

	chainID := hdr.ChainHeader.ChainID

	//chainless MSPs have "" chain name
	ischainless := chaincode.IsChainlessSysCC(hdrExt.ChaincodeID.Name)

	//chainID should be empty for chainless SysCC (such as CSCC for Join proposal) and for
	//nothing else
	if chainID == "" && !ischainless {
		err = fmt.Errorf("chainID not provided for chaincode %s", hdrExt.ChaincodeID.Name)
		return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
	} else if chainID != "" && ischainless {
		err = fmt.Errorf("chainID %s provided for a chainless syscc", hdrExt.ChaincodeID.Name)
		return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
	}

	//TODO check for uniqueness of prop.TxID with ledger

	txid := hdr.ChainHeader.TxID
	if txid == "" {
		err = fmt.Errorf("Invalid txID")
		return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
	}

	// obtaining once the tx simulator for this proposal. This will be nil
	// for chainless proposals
	var txsim ledger.TxSimulator
	if chainID != "" {
		if txsim, err = e.getTxSimulator(chainID); err != nil {
			return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
		}
		defer txsim.Done()
	}
	//this could be a request to a chainless SysCC

	// TODO: if the proposal has an extension, it will be of type ChaincodeAction;
	//       if it's present it means that no simulation is to be performed because
	//       we're trying to emulate a submitting peer. On the other hand, we need
	//       to validate the supplied action before endorsing it

	//1 -- simulate
	//TODO what do we do with response ? We need it for Invoke responses for sure
	//Which field in PayloadResponse will carry return value ?
	result, simulationResult, ccevent, err := e.simulateProposal(ctx, chainID, txid, prop, hdrExt.ChaincodeID, txsim)
	if err != nil {
		return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
	}

	//2 -- endorse and get a marshalled ProposalResponse message
	var pResp *pb.ProposalResponse

	//TODO till we implement global ESCC, CSCC for system chaincodes
	//chainless proposals (such as CSCC) don't have to be endorsed
	if ischainless {
		pResp = &pb.ProposalResponse{Response: &pb.Response{}}
	} else {
		pResp, err = e.endorseProposal(ctx, chainID, txid, prop, simulationResult, ccevent, hdrExt.PayloadVisibility, hdrExt.ChaincodeID, txsim)
		if err != nil {
			return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err
		}
	}

	//TODO what do we do with response ? We need it for Invoke responses for sure
	// Set the proposal response payload - it
	// contains the "return value" from the
	// chaincode invocation
	pResp.Response.Payload = result

	return pResp, nil
}
Пример #9
0
// TransferFunds simulates a transaction for transferring fund from fromAccount to toAccount
func (app *App) TransferFunds(fromAccount string, toAccount string, transferAmt int) (*common.Envelope, error) {
	// act as endorsing peer shim code to simulate a transaction on behalf of chaincode
	var txSimulator ledger.TxSimulator
	var err error
	if txSimulator, err = app.ledger.NewTxSimulator(); err != nil {
		return nil, err
	}
	defer txSimulator.Done()
	var balFromBytes []byte
	if balFromBytes, err = txSimulator.GetState(app.name, fromAccount); err != nil {
		return nil, err
	}
	balFrom := toInt(balFromBytes)
	if balFrom-transferAmt < 0 {
		return nil, fmt.Errorf("Not enough balance in account [%s]. Balance = [%d], transfer request = [%d]",
			fromAccount, balFrom, transferAmt)
	}

	var balToBytes []byte
	if balToBytes, err = txSimulator.GetState(app.name, toAccount); err != nil {
		return nil, err
	}
	balTo := toInt(balToBytes)
	txSimulator.SetState(app.name, fromAccount, toBytes(balFrom-transferAmt))
	txSimulator.SetState(app.name, toAccount, toBytes(balTo+transferAmt))
	var txSimulationResults []byte
	if txSimulationResults, err = txSimulator.GetTxSimulationResults(); err != nil {
		return nil, err
	}

	// act as endorsing peer to create an Action with the SimulationResults
	// then act as SDK to create a Transaction with the EndorsedAction
	tx := constructTransaction(txSimulationResults)
	return tx, nil
}