1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
| package chaincode
import ( "encoding/json" "fmt" "time"
"github.com/golang/protobuf/ptypes" "github.com/hyperledger/fabric-contract-api-go/contractapi" )
// SmartContract provides functions for managing an Asset type SmartContract struct { contractapi.Contract }
// Asset describes basic details of what makes up a simple asset type Asset struct { ID string `json:"ID"` Issuer string `json:"issuer"` Owner string `json:"owner"` Amount int64 `json:"amount"` CreateDate time.Time `json:"createDate"` EndDate time.Time `json:"endDate"` ContractHash string `json:"contractHash"` InvoiceHash string `json:"invoiceHash"` }
// IssueVoucher 发行凭证 func (s *SmartContract) IssueVoucher(ctx contractapi.TransactionContextInterface, assetID string, amount int64, owner string, contractHash string, invoiceHash string) error { // 创建资产 return s.CreateAssetAndSave(ctx, assetID, amount, "核心企业", owner, contractHash, invoiceHash) }
// CreateAssetAndSave 创建资产并保存 func (s *SmartContract) CreateAssetAndSave(ctx contractapi.TransactionContextInterface, id string, amount int64, issuerName string, owner string, contractHash string, invoiceHash string) error { asset, err := s.createAsset(ctx, id, amount, issuerName, owner, contractHash, invoiceHash) if err != nil { return err } return s.PutState(ctx, asset) }
// createAsset issues a new asset to the world state with given details. func (s *SmartContract) createAsset(ctx contractapi.TransactionContextInterface, id string, amount int64, issuerName string, owner string, contractHash string, invoiceHash string) (*Asset, error) { exists, err := s.AssetExists(ctx, id) if err != nil { return nil, err } if exists { return nil, fmt.Errorf("the asset %s already exists", id) } now, err := getNow(ctx) if err != nil { return nil, err } asset := Asset{ID: id, Issuer: issuerName, Amount: amount, Owner: owner, CreateDate: now, EndDate: now.AddDate(0, 6, 0), ContractHash: contractHash, InvoiceHash: invoiceHash} return &asset, nil }
// 获取当前时间 func getNow(ctx contractapi.TransactionContextInterface) (time.Time, error) { now, err := ctx.GetStub().GetTxTimestamp() if err != nil { return time.Now(), err } return ptypes.Timestamp(now) }
// ReadAsset returns the asset stored in the world state with given id. func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) { assetJSON, err := ctx.GetStub().GetState(id) if err != nil { return nil, fmt.Errorf("failed to read from world state: %v", err) } if assetJSON == nil { return nil, fmt.Errorf("the asset %s does not exist", id) }
var asset Asset err = json.Unmarshal(assetJSON, &asset) if err != nil { return nil, err }
return &asset, nil }
// AssetExists returns true when asset with given ID exists in world state func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) { assetJSON, err := ctx.GetStub().GetState(id) if err != nil { return false, fmt.Errorf("failed to read from world state: %v", err) }
return assetJSON != nil, nil }
// TransferAssetByID 根据资产ID转账 func (s *SmartContract) TransferAssetByID(ctx contractapi.TransactionContextInterface, id string, newID string, newOwner string, amount int64, contractHash string, invoiceHash string) error { asset, err := s.ReadAsset(ctx, id) if err != nil { return err } return s.TransferAsset(ctx, asset, newID, newOwner, amount, contractHash, invoiceHash) }
// TransferAsset updates the owner field of asset with given id in world state. func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, asset *Asset, newID string, newOwner string, amount int64, contractHash string, invoiceHash string) error { // 如果金额刚好等于凭证资产的金额,直接更新凭证资产的拥有者 if asset.Amount == amount { asset.Owner = newOwner return s.PutState(ctx, asset) } else if asset.Amount > amount { // 如果凭证资产的金额大于转账的金额,则创建一个新的资产 if newID == "" { return fmt.Errorf("转账金额小于资产的金额时,newID必须不能为空") } // 创建新的资产并保存 err := s.CreateAssetAndSave(ctx, newID, amount, asset.Issuer, newOwner, contractHash, invoiceHash) if err != nil { return err } // 更新旧资产的金额 asset.Amount = asset.Amount - amount return s.PutState(ctx, asset) } else if asset.Amount < amount { // 如果资产的额度小于要转账的金额,则直接报错 return fmt.Errorf("转账金额=%d,不能超过资产的金额=%d", amount, asset.Amount) } return nil }
// PutState 更新资产 func (s *SmartContract) PutState(ctx contractapi.TransactionContextInterface, asset *Asset) error { assetJSON, err := json.Marshal(asset) if err != nil { return err } return ctx.GetStub().PutState(asset.ID, assetJSON) }
// DelState 删除资产 func (s *SmartContract) DelState(ctx contractapi.TransactionContextInterface, assetID string) error { exists, err := s.AssetExists(ctx, assetID) if err != nil { return nil } if !exists { return fmt.Errorf("assetID=%s的资产不存在", assetID) } return ctx.GetStub().DelState(assetID) }
// GetAllAssets returns all assets found in world state func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) { // range query with empty string for startKey and endKey does an // open-ended query of all assets in the chaincode namespace. resultsIterator, err := ctx.GetStub().GetStateByRange("", "") if err != nil { return nil, err } defer resultsIterator.Close()
var assets []*Asset for resultsIterator.HasNext() { queryResponse, err := resultsIterator.Next() if err != nil { return nil, err }
var asset Asset err = json.Unmarshal(queryResponse.Value, &asset) if err != nil { return nil, err } assets = append(assets, &asset) }
return assets, nil }
|