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 }