From c66e5680aa1d596540a8235241363ab593fd6032 Mon Sep 17 00:00:00 2001 From: Fernando Garzon Date: Tue, 1 Nov 2022 16:02:13 -0700 Subject: [PATCH] Random Comment with little to no meaning --- .../chaincode-go/chaincode/smartcontract.go | 213 +++++--- .../chaincode/smartcontractBACKUP4.go.txt | 464 ++++++++++++++++++ 2 files changed, 607 insertions(+), 70 deletions(-) create mode 100644 asset-transfer-basic/chaincode-go/chaincode/smartcontractBACKUP4.go.txt diff --git a/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go b/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go index e122e91b..cc3874f4 100644 --- a/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go +++ b/asset-transfer-basic/chaincode-go/chaincode/smartcontract.go @@ -44,7 +44,7 @@ type SmartContract struct { // Insert struct field in alphabetic order => to achieve determinism across languages // golang keeps the order when marshal to json but doesn't order automatically -var schemas []Schema +var lastSchemaHash String type Data struct { Contributor string `json:"Contributor"` @@ -56,80 +56,118 @@ type Data struct { } type Schema struct { - Contributor string `json:"Contributor"` - ContributorId string `json:"ContributorId"` - ContentHash string `json:"ContentHash"` - Id string `json:"Id"` - Owners []string `json:"Owners"` - JsonFileContent map[string]interface{} + Version int `json:"Version"` + Hash string `json:"Hash"` + JsonSchemaContent map[string]interface{} } // InitLedger adds a base set of Data entries to the ledger -func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface, pathSchema string, pathFirstJsonFile string) error { +func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface, InitSchema string, InitData string) error { // We use the function jsonReader in order to read the content of the shcema Json File. The schema Json file is composed by us and inserted into // the docker container of the commited chaincode (For now) - schemaJsonFileContent, error_schema := s.JsonReader(ctx, pathSchema) - firstJsonFileContent, error_file := s.JsonReader(ctx, pathFirstJsonFile) + schemaJsonFileContent, error_schema := s.JsonReader(ctx, InitSchema) + firstJsonFileContent, error_file := s.JsonReader(ctx, InitData) if error_schema != nil { return fmt.Errorf("failed to read shcema.json file: %v", error_schema) } else if error_file != nil { return fmt.Errorf("failed to read 1st json files: %v", error_file) } else { - fmt.Printf("Schema Content: %v", schemaJsonFileContent) - fmt.Printf("Test Json file Content: %v", firstJsonFileContent) - dataEntries := []Data{ - {Contributor: "pepitoperes@email.com", ContributorId: "ABC123", ContentHash: "ZXCVBNM", Id: "00000", Owners: []string{"CIA", "DEA", "FBI"}, JsonFileContent: firstJsonFileContent}, + firstJsonFileHash = Hash(InitData) + schemaJsonFileHash = Hash(InitSchema) + lastSchemaHash = schemaJsonFileHash + + data := Data{ + Contributor: "pepitoperes@email.com", + ContributorId: "ABC123", + ContentHash: firstJsonFileHash, + Id: "00000", + Owners: []string{"CIA", "DEA", "FBI"}, + JsonFileContent: firstJsonFileContent, } //This is the definition of the Schema that we should use for validate all the JSON files from now on. - initSchema := Schema{Contributor: "pepitoperes@email.com", ContributorId: "ABC123", ContentHash: "ZXCVBNM", Id: "00000", Owners: []string{"CIA", "DEA", "FBI"}, JsonFileContent: schemaJsonFileContent} - schemas = append(schemas, initSchema) - - for _, data := range schemas { - assetJSON, err := json.Marshal(data) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(data.Id, assetJSON) - if err != nil { - return fmt.Errorf("failed to put to world state. %v", err) - } + + initSchema := Schema{ + Version: "1.0", + Hash: schemaJsonFileHash, + JsonSchemaContent: schemaJsonFileContent, } - for _, data := range dataEntries { - assetJSON, err := json.Marshal(data) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(data.Id, assetJSON) - if err != nil { - return fmt.Errorf("failed to put to world state. %v", err) - } + + assetJSON, err := json.Marshal(data) + if err != nil { + return err } + err = ctx.GetStub().PutState(data.ContentHash, assetJSON) + if err != nil { + return fmt.Errorf("failed to put to world state. %v", err) + } + + + + assetJSON, err := json.Marshal(initSchema) + if err != nil { + return err + } + + err = ctx.GetStub().PutState(initSchema.Hash, assetJSON) + if err != nil { + return fmt.Errorf("failed to put to world state. %v", err) + } + + } return nil } -func (s *SmartContract) JsonReader(ctx contractapi.TransactionContextInterface, path string) (map[string]interface{}, error) { +func (s *SmartContract) LastSchemaHash() (string) { + return lastSchemaHash +} - content, err := ioutil.ReadFile(path) - if err != nil { - log.Fatal("Error when opening file: ", err) +func (s *SmartContract) Hash(doc string) string, err { + result = isJSON(doc) + if !result{ + return "HASH CRASH", fmt.Errorf("String passed as parameter is not in JSON format") + } else{ + var v interface{} + err = json.Unmarshal([]byte(doc), &v) + if err != nil{ + return "HASH CRASH", fmt.Errorf("Unable to unmarshal Json String passed as parameter. No hash calculation can be completed: %v", err) + } else { + cdoc, err := json.Marshal(v) + if err != nil{ + return "HASH CRASH", fmt.Errorf("Unable to re-marshal interface into json format. No hash calculation can be completed: %v", err) + } else{ + sum := sha256.Sum256(cdoc) + return hex.EncodeToString(sum[0:]), nil + } } +} + +func (smct *SmartContract) isJSON(s string) bool { + var js interface{} + return json.Unmarshal([]byte(s), &js) == nil +} + +func (s *SmartContract) JsonReader(ctx contractapi.TransactionContextInterface, content string) (map[string]interface{}, error) { - // Now let's unmarshall the data into `payload` var payload map[string]interface{} - err = json.Unmarshal(content, &payload) - if err != nil { - log.Fatal("Error during Unmarshal(): ", err) + IsJson := isJSON(content) + + if !content { + return payload, log.Fatal("The String passed is not in JSON format. Check the string: %v", IsJson) + } else { + // Now let's unmarshall the data into `payload` + err = json.Unmarshal(IsJson, &payload) + if err != nil { + log.Fatal("Error during Unmarshal() of string into type Interface: %v", err) + } + return payload, nil } - return payload, nil } // GetAllAssets returns all assets found in world state @@ -160,8 +198,17 @@ func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface return dataSamples, nil } +func (s *SmartContract) SchemaExists(ctx contractapi.TransactionContextInterface, Hash string) (bool, error) { + assetJSON, err := ctx.GetStub().GetState(Hash) + if err != nil { + return false, fmt.Errorf("failed to read from world state: %v", err) + } + + return assetJSON != nil, nil +} + func (s *SmartContract) CreateNewSchema(ctx contractapi.TransactionContextInterface, - Contributor string, ContributorId string, ContentHash string, Id string, AbsolutePathToJsonFile string) error { + version string, newSchemaContent string) error { // We assume this new schema is different from what existed previously //exists, err := s.AssetExists(ctx, Id) @@ -172,21 +219,24 @@ func (s *SmartContract) CreateNewSchema(ctx contractapi.TransactionContextInterf // return fmt.Errorf("the asset %s already exists", Id) //} - jsonFileContent, err := s.JsonReader(ctx, AbsolutePathToJsonFile) + jsonFileContent, err := s.JsonReader(ctx, newSchemaContent) if err != nil { return err } else { - newSchema := Schema{ - Contributor: Contributor, - ContributorId: ContributorId, - ContentHash: ContentHash, - Id: Id, - Owners: []string{"DOE", "DOS", "DOJ"}, - JsonFileContent: jsonFileContent, + // Verify that an schema with exact same structure doesn't exist yet. + hashContent = Hash(newSchemaContent) + exists, err = SchemaExists(hashContent) + if exists{ + return fmt.Errorf("Schema already exists: %v", err) + } else { + lastSchemaHash = hashContent + newSchema := Schema{ + Version: version, + Hash: hashContent, + JsonSchemaContent: jsonFileContent, + } } - schemas = append(schemas, newSchema) - return nil } } @@ -194,7 +244,7 @@ func (s *SmartContract) CreateNewSchema(ctx contractapi.TransactionContextInterf // GetAllSchemas returns all schemas found in world state -func (s *SmartContract) GetAllSchemas(ctx contractapi.TransactionContextInterface) ([]Schema, error) { +//func (s *SmartContract) GetAllSchemas(ctx contractapi.TransactionContextInterface) ([]Schema, error) { // range query with empty string for startKey and endKey does an // open-ended query of all schemas in the chaincode namespace. //resultsIterator, err := ctx.GetStub().GetStateByRange("", "") @@ -218,8 +268,8 @@ func (s *SmartContract) GetAllSchemas(ctx contractapi.TransactionContextInterfac // schemaSamples = append(schemaSamples, &schm) //} - return schemas, nil -} + //return schemas, nil +//} // AssetExists returns true when asset with given ID exists in world state func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, Id string) (bool, error) { @@ -233,7 +283,7 @@ func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, // JSON Validation -func (s *SmartContract) ValidJson(ctx contractapi.TransactionContextInterface, AbsolutePathToJsonFile string) (bool, error) { +func (s *SmartContract) ValidJson(ctx contractapi.TransactionContextInterface, JsonContent string) (bool, error) { //schemaLoader := gojsonschema.NewReferenceLoader("file:///Users/fernando/Projects/OSC-IS/fabric-samples/test-network/JsonSchemaValidationTests/Schema.json") //documentLoader := gojsonschema.NewReferenceLoader("file:////Users/fernando/Projects/OSC-IS/fabric-samples/test-network/JsonSchemaValidationTests/testFile.json") @@ -243,9 +293,13 @@ func (s *SmartContract) ValidJson(ctx contractapi.TransactionContextInterface, A // PATH Needs to be absolute path (From root '/'). Add something that takes care of that. - m := schemas[len(schemas) - 1].JsonFileContent - schemaLoader := gojsonschema.NewGoLoader(m) - documentLoader := gojsonschema.NewReferenceLoader("file://" + AbsolutePathToJsonFile) + //m := schemas[len(schemas) - 1].JsonFileContent + + CurrentSchemaHash = LastSchemaHash() + schema = ReadSchema(CurrentSchemaHash) + + schemaLoader := gojsonschema.NewGoLoader(schema.JsonSchemaContent) + documentLoader := gojsonschema.NewStringLoader(JsonContent) result, err := gojsonschema.Validate(schemaLoader, documentLoader) @@ -266,9 +320,10 @@ func (s *SmartContract) ValidJson(ctx contractapi.TransactionContextInterface, A // CreateDataSample issues a new Data Sample to the world state with given details. func (s *SmartContract) CreateDataSample(ctx contractapi.TransactionContextInterface, - Contributor string, ContributorId string, ContentHash string, Id string, AbsolutePathToJsonFile string) error { - - exists, err := s.AssetExists(ctx, Id) + Contributor string, ContributorId string, Id string, JsonFileContent string) error { + + ContentHash = Hash(JsonFileContent) + exists, err := s.AssetExists(ctx, ContentHash) if err != nil { return err } @@ -276,14 +331,14 @@ func (s *SmartContract) CreateDataSample(ctx contractapi.TransactionContextInter return fmt.Errorf("the asset %s already exists", Id) } - valid, err := s.ValidJson(ctx, AbsolutePathToJsonFile) + valid, err := s.ValidJson(ctx, JsonFileContent) if err != nil { return err } if !valid { return fmt.Errorf("the json file provided is not valid") } else { - jsonFileContent, err := s.JsonReader(ctx, AbsolutePathToJsonFile) + jsonFileContent, err := s.JsonReader(ctx, JsonFileContent) if err != nil { return err } else { @@ -301,7 +356,7 @@ func (s *SmartContract) CreateDataSample(ctx contractapi.TransactionContextInter return err } - return ctx.GetStub().PutState(Id, assetJSON) + return ctx.GetStub().PutState(ContentHash, assetJSON) } } @@ -365,6 +420,24 @@ func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, I return &data, nil } +func (s *SmartContract) ReadSchema(ctx contractapi.TransactionContextInterface, hash string) (*Schema, error) { + assetJSON, err := ctx.GetStub().GetState(hash) + if err != nil { + return nil, fmt.Errorf("failed to read from world state: %v", err) + } + if assetJSON == nil { + return nil, fmt.Errorf("the schema with hash %s does not exist", hash) + } + + var schema Schema + err = json.Unmarshal(assetJSON, &schema) + if err != nil { + return nil, err + } + + return &scehma, nil +} + // TransferAsset updates the owner field of asset with given id in world state, and returns the old owner. func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, Id string, newOwners []string) ([]string, error) { data, err := s.ReadAsset(ctx, Id) diff --git a/asset-transfer-basic/chaincode-go/chaincode/smartcontractBACKUP4.go.txt b/asset-transfer-basic/chaincode-go/chaincode/smartcontractBACKUP4.go.txt new file mode 100644 index 00000000..e122e91b --- /dev/null +++ b/asset-transfer-basic/chaincode-go/chaincode/smartcontractBACKUP4.go.txt @@ -0,0 +1,464 @@ +package chaincode + +import ( + "encoding/json" + "fmt" + + "github.com/hyperledger/fabric-contract-api-go/contractapi" + "github.com/xeipuuv/gojsonschema" + + "io/ioutil" + "log" +) + +// SmartContract provides functions for managing an Asset +type SmartContract struct { + contractapi.Contract +} + +// Asset describes basic details of what makes up a simple asset +// Insert struct field in alphabetic order => to achieve determinism across languages +// golang keeps the order when marshal to json but doesn't order automatically + +/*type Data struct { + docType string `json:"docType"` + id string `json:"id"` + title string `json:"title"` + description string `json:"description"` + Type string `json:"Type"` + DOI string `json:"DOI"` + url string `json:"url"` + manifest string `json:"manifest"` + footprint string `json:"footprint"` + keywords string `json:"keywords"` + otherDataIdName string `json:"otherDataIdName"` + otherDataIdValue string `json:"otherDataIdValue"` + fundingAgencies string `json:"fundingAgencies"` + acknowledgment string `json:"acknowledgment"` + noteForChange string `json:"noteForChange"` + contributor string `json:"contributor"` + contributor_id string `json:"contributor_id"` +}*/ + +// Asset describes basic details of what makes up a simple asset +// Insert struct field in alphabetic order => to achieve determinism across languages +// golang keeps the order when marshal to json but doesn't order automatically + +var schemas []Schema + +type Data struct { + Contributor string `json:"Contributor"` + ContributorId string `json:"ContributorId"` + ContentHash string `json:"ContentHash"` + Id string `json:"Id"` + Owners []string `json:"Owners"` + JsonFileContent map[string]interface{} +} + +type Schema struct { + Contributor string `json:"Contributor"` + ContributorId string `json:"ContributorId"` + ContentHash string `json:"ContentHash"` + Id string `json:"Id"` + Owners []string `json:"Owners"` + JsonFileContent map[string]interface{} +} + +// InitLedger adds a base set of Data entries to the ledger +func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface, pathSchema string, pathFirstJsonFile string) error { + + // We use the function jsonReader in order to read the content of the shcema Json File. The schema Json file is composed by us and inserted into + // the docker container of the commited chaincode (For now) + schemaJsonFileContent, error_schema := s.JsonReader(ctx, pathSchema) + firstJsonFileContent, error_file := s.JsonReader(ctx, pathFirstJsonFile) + + if error_schema != nil { + return fmt.Errorf("failed to read shcema.json file: %v", error_schema) + } else if error_file != nil { + return fmt.Errorf("failed to read 1st json files: %v", error_file) + } else { + fmt.Printf("Schema Content: %v", schemaJsonFileContent) + fmt.Printf("Test Json file Content: %v", firstJsonFileContent) + + dataEntries := []Data{ + {Contributor: "pepitoperes@email.com", ContributorId: "ABC123", ContentHash: "ZXCVBNM", Id: "00000", Owners: []string{"CIA", "DEA", "FBI"}, JsonFileContent: firstJsonFileContent}, + } + + //This is the definition of the Schema that we should use for validate all the JSON files from now on. + initSchema := Schema{Contributor: "pepitoperes@email.com", ContributorId: "ABC123", ContentHash: "ZXCVBNM", Id: "00000", Owners: []string{"CIA", "DEA", "FBI"}, JsonFileContent: schemaJsonFileContent} + schemas = append(schemas, initSchema) + + for _, data := range schemas { + assetJSON, err := json.Marshal(data) + if err != nil { + return err + } + + err = ctx.GetStub().PutState(data.Id, assetJSON) + if err != nil { + return fmt.Errorf("failed to put to world state. %v", err) + } + } + + for _, data := range dataEntries { + assetJSON, err := json.Marshal(data) + if err != nil { + return err + } + + err = ctx.GetStub().PutState(data.Id, assetJSON) + if err != nil { + return fmt.Errorf("failed to put to world state. %v", err) + } + } + + } + return nil +} + +func (s *SmartContract) JsonReader(ctx contractapi.TransactionContextInterface, path string) (map[string]interface{}, error) { + + content, err := ioutil.ReadFile(path) + if err != nil { + log.Fatal("Error when opening file: ", err) + } + + // Now let's unmarshall the data into `payload` + var payload map[string]interface{} + err = json.Unmarshal(content, &payload) + if err != nil { + log.Fatal("Error during Unmarshal(): ", err) + } + return payload, nil +} + +// GetAllAssets returns all assets found in world state +func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Data, 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 dataSamples []*Data + for resultsIterator.HasNext() { + queryResponse, err := resultsIterator.Next() + if err != nil { + return nil, err + } + + var data Data + err = json.Unmarshal(queryResponse.Value, &data) + if err != nil { + return nil, err + } + dataSamples = append(dataSamples, &data) + } + + return dataSamples, nil +} + +func (s *SmartContract) CreateNewSchema(ctx contractapi.TransactionContextInterface, + Contributor string, ContributorId string, ContentHash string, Id string, AbsolutePathToJsonFile string) error { + + // We assume this new schema is different from what existed previously + //exists, err := s.AssetExists(ctx, Id) + //if err != nil { + // return err + //} + //if exists { + // return fmt.Errorf("the asset %s already exists", Id) + //} + + jsonFileContent, err := s.JsonReader(ctx, AbsolutePathToJsonFile) + if err != nil { + return err + } else { + newSchema := Schema{ + Contributor: Contributor, + ContributorId: ContributorId, + ContentHash: ContentHash, + Id: Id, + Owners: []string{"DOE", "DOS", "DOJ"}, + JsonFileContent: jsonFileContent, + } + + schemas = append(schemas, newSchema) + + return nil + } + } + + +// GetAllSchemas returns all schemas found in world state + +func (s *SmartContract) GetAllSchemas(ctx contractapi.TransactionContextInterface) ([]Schema, error) { + // range query with empty string for startKey and endKey does an + // open-ended query of all schemas in the chaincode namespace. + //resultsIterator, err := ctx.GetStub().GetStateByRange("", "") + //if err != nil { + // return nil, err + //} + //defer resultsIterator.Close() + + //var schemaSamples []*Schema + //for resultsIterator.HasNext() { + // queryResponse, err := resultsIterator.Next() + // if err != nil { + // return nil, err + // } + + // var schm Schema + // err = json.Unmarshal(queryResponse.Value, &schm) + // if err != nil { + // return nil, err + // } + // schemaSamples = append(schemaSamples, &schm) + //} + + return schemas, 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 +} + +// JSON Validation + +func (s *SmartContract) ValidJson(ctx contractapi.TransactionContextInterface, AbsolutePathToJsonFile string) (bool, error) { + + //schemaLoader := gojsonschema.NewReferenceLoader("file:///Users/fernando/Projects/OSC-IS/fabric-samples/test-network/JsonSchemaValidationTests/Schema.json") + //documentLoader := gojsonschema.NewReferenceLoader("file:////Users/fernando/Projects/OSC-IS/fabric-samples/test-network/JsonSchemaValidationTests/testFile.json") + + //schemaLoader := gojsonschema.NewReferenceLoader("file:///home/chaincode/Schema.json") + //documentLoader := gojsonschema.NewReferenceLoader("file:////home/chaincode/testFile.json") + + // PATH Needs to be absolute path (From root '/'). Add something that takes care of that. + + m := schemas[len(schemas) - 1].JsonFileContent + schemaLoader := gojsonschema.NewGoLoader(m) + documentLoader := gojsonschema.NewReferenceLoader("file://" + AbsolutePathToJsonFile) + + result, err := gojsonschema.Validate(schemaLoader, documentLoader) + + if err != nil { + panic(err.Error()) + } + + if result.Valid() { + fmt.Printf("The document is valid\n") + } else { + fmt.Printf("The document is not valid. see errors :\n") + for _, desc := range result.Errors() { + fmt.Printf("- %s\n", desc) + } + } + return result.Valid(), nil +} + +// CreateDataSample issues a new Data Sample to the world state with given details. +func (s *SmartContract) CreateDataSample(ctx contractapi.TransactionContextInterface, + Contributor string, ContributorId string, ContentHash string, Id string, AbsolutePathToJsonFile string) error { + + exists, err := s.AssetExists(ctx, Id) + if err != nil { + return err + } + if exists { + return fmt.Errorf("the asset %s already exists", Id) + } + + valid, err := s.ValidJson(ctx, AbsolutePathToJsonFile) + if err != nil { + return err + } + if !valid { + return fmt.Errorf("the json file provided is not valid") + } else { + jsonFileContent, err := s.JsonReader(ctx, AbsolutePathToJsonFile) + if err != nil { + return err + } else { + data := Data{ + Contributor: Contributor, + ContributorId: ContributorId, + ContentHash: ContentHash, + Id: Id, + Owners: []string{"DOE", "DOS", "DOJ"}, + JsonFileContent: jsonFileContent, + } + + assetJSON, err := json.Marshal(data) + if err != nil { + return err + + } + return ctx.GetStub().PutState(Id, assetJSON) + } + } + +} +// UpdateAsset updates an existing asset in the world state with provided parameters. +func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, + Contributor string, ContributorId string, ContentHash string, Id string) error { + exists, err := s.AssetExists(ctx, Id) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("the asset %s does not exist", Id) + } + + // overwriting original asset with new asset + + data := Data{ + Contributor: Contributor, + ContributorId: ContributorId, + ContentHash: ContentHash, + Id: Id, + Owners: []string{"DOE", "DOS", "DOJ"}, + } + + assetJSON, err := json.Marshal(data) + if err != nil { + return err + } + + return ctx.GetStub().PutState(Id, assetJSON) +} + +func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, Id string) error { + exists, err := s.AssetExists(ctx, Id) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("the asset %s does not exist", Id) + } + + return ctx.GetStub().DelState(Id) +} + +func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, Id string) (*Data, 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 data Data + err = json.Unmarshal(assetJSON, &data) + if err != nil { + return nil, err + } + + return &data, nil +} + +// TransferAsset updates the owner field of asset with given id in world state, and returns the old owner. +func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, Id string, newOwners []string) ([]string, error) { + data, err := s.ReadAsset(ctx, Id) + if err != nil { + return []string{}, err + } + + data.Owners = newOwners + + assetJSON, err := json.Marshal(data) + if err != nil { + return []string{}, err + } + + err = ctx.GetStub().PutState(Id, assetJSON) + if err != nil { + return []string{}, err + } + + return data.Owners, nil +} + +/* + + +// 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 +} + + + +// TransferAsset updates the owner field of asset with given id in world state, and returns the old owner. +func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) { + asset, err := s.ReadAsset(ctx, id) + if err != nil { + return "", err + } + + oldOwner := asset.Owner + asset.Owner = newOwner + + assetJSON, err := json.Marshal(asset) + if err != nil { + return "", err + } + + err = ctx.GetStub().PutState(id, assetJSON) + if err != nil { + return "", err + } + + return oldOwner, nil +} + +// 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 +} +*/