github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/core/ledger/kvledger/example/app.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package example
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/golang/protobuf/proto"
    23  	"github.com/hyperledger/fabric/core/ledger"
    24  
    25  	"github.com/hyperledger/fabric/common/util"
    26  	"github.com/hyperledger/fabric/protos/common"
    27  	pb "github.com/hyperledger/fabric/protos/peer"
    28  	ptestutils "github.com/hyperledger/fabric/protos/testutils"
    29  )
    30  
    31  // App - a sample fund transfer app
    32  type App struct {
    33  	name   string
    34  	ledger ledger.PeerLedger
    35  }
    36  
    37  // ConstructAppInstance constructs an instance of an app
    38  func ConstructAppInstance(ledger ledger.PeerLedger) *App {
    39  	return &App{"PaymentApp", ledger}
    40  }
    41  
    42  // Init simulates init transaction
    43  func (app *App) Init(initialBalances map[string]int) (*common.Envelope, error) {
    44  	var txSimulator ledger.TxSimulator
    45  	var err error
    46  	if txSimulator, err = app.ledger.NewTxSimulator(); err != nil {
    47  		return nil, err
    48  	}
    49  	defer txSimulator.Done()
    50  	for accountID, bal := range initialBalances {
    51  		txSimulator.SetState(app.name, accountID, toBytes(bal))
    52  	}
    53  	var txSimulationResults []byte
    54  	if txSimulationResults, err = txSimulator.GetTxSimulationResults(); err != nil {
    55  		return nil, err
    56  	}
    57  	tx := constructTransaction(txSimulationResults)
    58  	return tx, nil
    59  }
    60  
    61  // TransferFunds simulates a transaction for transferring fund from fromAccount to toAccount
    62  func (app *App) TransferFunds(fromAccount string, toAccount string, transferAmt int) (*common.Envelope, error) {
    63  	// act as endorsing peer shim code to simulate a transaction on behalf of chaincode
    64  	var txSimulator ledger.TxSimulator
    65  	var err error
    66  	if txSimulator, err = app.ledger.NewTxSimulator(); err != nil {
    67  		return nil, err
    68  	}
    69  	defer txSimulator.Done()
    70  	var balFromBytes []byte
    71  	if balFromBytes, err = txSimulator.GetState(app.name, fromAccount); err != nil {
    72  		return nil, err
    73  	}
    74  	balFrom := toInt(balFromBytes)
    75  	if balFrom-transferAmt < 0 {
    76  		return nil, fmt.Errorf("Not enough balance in account [%s]. Balance = [%d], transfer request = [%d]",
    77  			fromAccount, balFrom, transferAmt)
    78  	}
    79  
    80  	var balToBytes []byte
    81  	if balToBytes, err = txSimulator.GetState(app.name, toAccount); err != nil {
    82  		return nil, err
    83  	}
    84  	balTo := toInt(balToBytes)
    85  	txSimulator.SetState(app.name, fromAccount, toBytes(balFrom-transferAmt))
    86  	txSimulator.SetState(app.name, toAccount, toBytes(balTo+transferAmt))
    87  	var txSimulationResults []byte
    88  	if txSimulationResults, err = txSimulator.GetTxSimulationResults(); err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	// act as endorsing peer to create an Action with the SimulationResults
    93  	// then act as SDK to create a Transaction with the EndorsedAction
    94  	tx := constructTransaction(txSimulationResults)
    95  	return tx, nil
    96  }
    97  
    98  // QueryBalances queries the balance funds
    99  func (app *App) QueryBalances(accounts []string) ([]int, error) {
   100  	var queryExecutor ledger.QueryExecutor
   101  	var err error
   102  	if queryExecutor, err = app.ledger.NewQueryExecutor(); err != nil {
   103  		return nil, err
   104  	}
   105  	defer queryExecutor.Done()
   106  	balances := make([]int, len(accounts))
   107  	for i := 0; i < len(accounts); i++ {
   108  		var balBytes []byte
   109  		if balBytes, err = queryExecutor.GetState(app.name, accounts[i]); err != nil {
   110  			return nil, err
   111  		}
   112  		balances[i] = toInt(balBytes)
   113  	}
   114  	return balances, nil
   115  }
   116  
   117  func constructTransaction(simulationResults []byte) *common.Envelope {
   118  	ccid := &pb.ChaincodeID{
   119  		Name:    "foo",
   120  		Version: "v1",
   121  	}
   122  	response := &pb.Response{Status: 200}
   123  	txEnv, _, _ := ptestutils.ConstructSingedTxEnvWithDefaultSigner(util.GetTestChainID(), ccid, response, simulationResults, nil, nil)
   124  	return txEnv
   125  }
   126  
   127  func toBytes(balance int) []byte {
   128  	return proto.EncodeVarint(uint64(balance))
   129  }
   130  
   131  func toInt(balanceBytes []byte) int {
   132  	v, _ := proto.DecodeVarint(balanceBytes)
   133  	return int(v)
   134  }