fabric-samples/test-network/snippet.go

118 lines
No EOL
4.2 KiB
Go

// CreateAsset creates a new asset by placing the main asset details in the assetCollection
// that can be read by both organizations. The appraisal value is stored in the owners org specific collection.
func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface) error {
// Get new asset from transient map
transientMap, err := ctx.GetStub().GetTransient()
if err != nil {
return fmt.Errorf("error getting transient: %v", err)
}
// Asset properties are private, therefore they get passed in transient field, instead of func args
transientAssetJSON, ok := transientMap["asset_properties"]
if !ok {
//log error to stdout
return fmt.Errorf("asset not found in the transient map input")
}
type assetTransientInput struct {
Type string `json:"objectType"` //Type is used to distinguish the various types of objects in state database
ID string `json:"assetID"`
Color string `json:"color"`
Size int `json:"size"`
AppraisedValue int `json:"appraisedValue"`
}
var assetInput assetTransientInput
err = json.Unmarshal(transientAssetJSON, &assetInput)
if err != nil {
return fmt.Errorf("failed to unmarshal JSON: %v", err)
}
if len(assetInput.Type) == 0 {
return fmt.Errorf("objectType field must be a non-empty string")
}
if len(assetInput.ID) == 0 {
return fmt.Errorf("assetID field must be a non-empty string")
}
if len(assetInput.Color) == 0 {
return fmt.Errorf("color field must be a non-empty string")
}
if assetInput.Size <= 0 {
return fmt.Errorf("size field must be a positive integer")
}
if assetInput.AppraisedValue <= 0 {
return fmt.Errorf("appraisedValue field must be a positive integer")
}
// Check if asset already exists
assetAsBytes, err := ctx.GetStub().GetPrivateData(assetCollection, assetInput.ID)
if err != nil {
return fmt.Errorf("failed to get asset: %v", err)
} else if assetAsBytes != nil {
fmt.Println("Asset already exists: " + assetInput.ID)
return fmt.Errorf("this asset already exists: " + assetInput.ID)
}
// Get ID of submitting client identity
clientID, err := submittingClientIdentity(ctx)
if err != nil {
return err
}
// Verify that the client is submitting request to peer in their organization
// This is to ensure that a client from another org doesn't attempt to read or
// write private data from this peer.
err = verifyClientOrgMatchesPeerOrg(ctx)
if err != nil {
return fmt.Errorf("CreateAsset cannot be performed: Error %v", err)
}
// Make submitting client the owner
asset := Asset{
Type: assetInput.Type,
ID: assetInput.ID,
Color: assetInput.Color,
Size: assetInput.Size,
Owner: clientID,
}
assetJSONasBytes, err := json.Marshal(asset)
if err != nil {
return fmt.Errorf("failed to marshal asset into JSON: %v", err)
}
// Save asset to private data collection
// Typical logger, logs to stdout/file in the fabric managed docker container, running this chaincode
// Look for container name like dev-peer0.org1.example.com-{chaincodename_version}-xyz
log.Printf("CreateAsset Put: collection %v, ID %v, owner %v", assetCollection, assetInput.ID, clientID)
err = ctx.GetStub().PutPrivateData(assetCollection, assetInput.ID, assetJSONasBytes)
if err != nil {
return fmt.Errorf("failed to put asset into private data collection: %v", err)
}
// Save asset details to collection visible to owning organization
assetPrivateDetails := AssetPrivateDetails{
ID: assetInput.ID,
AppraisedValue: assetInput.AppraisedValue,
}
assetPrivateDetailsAsBytes, err := json.Marshal(assetPrivateDetails) // marshal asset details to JSON
if err != nil {
return fmt.Errorf("failed to marshal into JSON: %v", err)
}
// Get collection name for this organization.
orgCollection, err := getCollectionName(ctx)
if err != nil {
return fmt.Errorf("failed to infer private collection name for the org: %v", err)
}
// Put asset appraised value into owners org specific private data collection
log.Printf("Put: collection %v, ID %v", orgCollection, assetInput.ID)
err = ctx.GetStub().PutPrivateData(orgCollection, assetInput.ID, assetPrivateDetailsAsBytes)
if err != nil {
return fmt.Errorf("failed to put asset private details: %v", err)
}
return nil
}