Schema validation working for submitting data to Ledger

This commit is contained in:
ofgarzon2662 2023-02-23 11:02:17 -08:00
parent 4d589074ba
commit ea2bd84eb8
2 changed files with 75 additions and 71 deletions

View file

@ -35,12 +35,13 @@ const PDC1 = "PDC1"
const PDC2 = "PDC2" const PDC2 = "PDC2"
type Data struct { type Data struct {
Contributor string `json:"Contributor"` OrgName string `json:"OrgName"`
ContributorId string `json:"ContributorId"` ProjectName string `json:"ProjectName"`
ContentHash string `json:"ContentHash"` ContentHash string `json:"ContentHash"`
Id string `json:"Id"` Comment string `json:"Comment"`
Owner string `json:"Owners"` Date string `json:"Date"`
JsonFileContent map[string]interface{} Submitter string `json:Submitter`
JsonContent map[string]interface{}
} }
type PrivateSchemaContent struct { type PrivateSchemaContent struct {
@ -148,9 +149,9 @@ func main() {
} }
*/ */
func (s *SmartContract) LastSchemaHash(ctx contractapi.TransactionContextInterface) string { /*func (s *SmartContract) LastSchemaHash(ctx contractapi.TransactionContextInterface) string {
return lastSchemaHash return lastSchemaHash
} */
func (s *SmartContract) Hash(ctx contractapi.TransactionContextInterface, doc string) (string, error) { func (s *SmartContract) Hash(ctx contractapi.TransactionContextInterface, doc string) (string, error) {
@ -217,20 +218,16 @@ func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface
return dataSamples, nil return dataSamples, nil
} }
func (s *SmartContract) SchemaExists(ctx contractapi.TransactionContextInterface, Hash string) (bool, error) { func (s *SmartContract) SchemaExists(ctx contractapi.TransactionContextInterface, SchemaID string) (bool, error) {
assetJSON, err := ctx.GetStub().GetState(Hash)
if err != nil { assetJSON, err := s.ReadSchemaFromPDC(ctx, SchemaID)
if assetJSON == nil {
return false, fmt.Errorf("failed to read from world state. Schema doesn't exist: %v", err)
} else if err != nil {
return false, fmt.Errorf("failed to read from world state. Schema doesn't exist: %v", err) return false, fmt.Errorf("failed to read from world state. Schema doesn't exist: %v", err)
} else { } else {
var schema map[string]interface{} return true, nil
err2 := json.Unmarshal(assetJSON, &schema)
if err2 != nil {
return false, fmt.Errorf("failed to read from world state: %v", err2)
} else if err3, ok := schema["Hash"]; ok {
return assetJSON != nil, nil
} else {
return false, fmt.Errorf("failed to read from world state. Hash passed as parameter may correspond to a Data struct rather than to a Schema: %v", err3)
}
} }
} }
@ -285,7 +282,7 @@ func (s *SmartContract) CreateNewSchema(ctx contractapi.TransactionContextInterf
// GetAllSchemas returns all schemas found in world state // 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 // range query with empty string for startKey and endKey does an
// open-ended query of all schemas in the chaincode namespace. // open-ended query of all schemas in the chaincode namespace.
resultsIterator, err := ctx.GetStub().GetStateByRange("", "") resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
@ -318,6 +315,7 @@ func (s *SmartContract) GetAllSchemas(ctx contractapi.TransactionContextInterfac
return schemaSamples, nil return schemaSamples, nil
} }
*/
// AssetExists returns true when asset with given ID exists in world state // AssetExists returns true when asset with given ID exists in world state
func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, Hash string) (bool, error) { func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, Hash string) (bool, error) {
@ -329,7 +327,7 @@ func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface,
err2 := json.Unmarshal(assetJSON, &data) err2 := json.Unmarshal(assetJSON, &data)
if err2 != nil { if err2 != nil {
return false, fmt.Errorf("failed to read from world state: %v", err2) return false, fmt.Errorf("failed to read from world state: %v", err2)
} else if err3, ok := data["Id"]; ok { } else if err3, ok := data["ContentHash"]; ok {
return assetJSON != nil, nil return assetJSON != nil, nil
} else { } else {
return false, fmt.Errorf("failed to read from world state. Hash passed as parameter may correspond to a Schema struct rather than to a Data Struct: %v", err3) return false, fmt.Errorf("failed to read from world state. Hash passed as parameter may correspond to a Schema struct rather than to a Data Struct: %v", err3)
@ -341,20 +339,9 @@ func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface,
// JSON Validation // JSON Validation
func (s *SmartContract) ValidJson(ctx contractapi.TransactionContextInterface, JsonContent string) (bool, error) { func (s *SmartContract) ValidJson(ctx contractapi.TransactionContextInterface, JsonContent string, SchemaID string) (bool, error) {
//schemaLoader := gojsonschema.NewReferenceLoader("file:///Users/fernando/Projects/OSC-IS/fabric-samples/test-network/JsonSchemaValidationTests/Schema.json") schema, err := s.ReadSchemaFromPDC(ctx, SchemaID)
//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
CurrentSchemaHash := s.LastSchemaHash(ctx)
schema, _ := s.ReadSchema(ctx, CurrentSchemaHash)
schemaLoader := gojsonschema.NewGoLoader(schema.JsonSchemaContent) schemaLoader := gojsonschema.NewGoLoader(schema.JsonSchemaContent)
documentLoader := gojsonschema.NewStringLoader(JsonContent) documentLoader := gojsonschema.NewStringLoader(JsonContent)
@ -378,9 +365,20 @@ func (s *SmartContract) ValidJson(ctx contractapi.TransactionContextInterface, J
// CreateDataSample issues a new Data Sample to the world state with given details. // CreateDataSample issues a new Data Sample to the world state with given details.
func (s *SmartContract) CreateDataSample(ctx contractapi.TransactionContextInterface, func (s *SmartContract) CreateDataSample(ctx contractapi.TransactionContextInterface,
Contributor string, ContributorId string, Id string, Owner string, JsonFileContent string, AnonymousFunder string, AssetValue string) error { OrgName string, ProjectName string, Comment string, Date string, Submitter string, JsonFileContent string, SchemaID string) error {
ContentHash, _ := s.Hash(ctx, JsonFileContent) SchemaExists, err := s.SchemaExists(ctx, SchemaID)
if err != nil {
return err
}
if !SchemaExists {
return fmt.Errorf("the Schema with Id %s doesn't exists", SchemaID)
}
ContentHash, err := s.Hash(ctx, JsonFileContent)
if err != nil {
return err
}
exists, err := s.AssetExists(ctx, ContentHash) exists, err := s.AssetExists(ctx, ContentHash)
if err != nil { if err != nil {
return err return err
@ -389,7 +387,7 @@ func (s *SmartContract) CreateDataSample(ctx contractapi.TransactionContextInter
return fmt.Errorf("the asset %s already exists", ContentHash) return fmt.Errorf("the asset %s already exists", ContentHash)
} }
valid, err := s.ValidJson(ctx, JsonFileContent) valid, err := s.ValidJson(ctx, JsonFileContent, SchemaID)
if err != nil { if err != nil {
return err return err
} }
@ -401,12 +399,13 @@ func (s *SmartContract) CreateDataSample(ctx contractapi.TransactionContextInter
return err return err
} else { } else {
data := Data{ data := Data{
Contributor: Contributor, OrgName: OrgName,
ContributorId: ContributorId, ProjectName: ProjectName,
ContentHash: ContentHash, ContentHash: ContentHash,
Id: Id, Comment: Comment,
Owner: Owner, Date: Date,
JsonFileContent: jsonFileContent, Submitter: Submitter,
JsonContent: jsonFileContent,
} }
assetJSON, err := json.Marshal(data) assetJSON, err := json.Marshal(data)
@ -494,7 +493,7 @@ func (s *SmartContract) ReadUser(ctx contractapi.TransactionContextInterface, UU
return &user, nil return &user, nil
} }
func (s *SmartContract) ReadSchema(ctx contractapi.TransactionContextInterface, hash string) (*Schema, error) { /*func (s *SmartContract) ReadSchema(ctx contractapi.TransactionContextInterface, hash string) (*Schema, error) {
assetJSON, err := ctx.GetStub().GetState(hash) assetJSON, err := ctx.GetStub().GetState(hash)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read from world state: %v", err) return nil, fmt.Errorf("failed to read from world state: %v", err)
@ -511,28 +510,9 @@ func (s *SmartContract) ReadSchema(ctx contractapi.TransactionContextInterface,
return &schema, nil return &schema, nil
} }
*/
// TransferAsset updates the owner field of asset with given id in world state, and returns the old owner. // 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) {
data, err := s.ReadAsset(ctx, Id)
if err != nil {
return "Read Asset function failed excecution", err
}
data.Owner = newOwner
assetJSON, err := json.Marshal(data)
if err != nil {
return "Marshal of Data not one", err
}
err = ctx.GetStub().PutState(Id, assetJSON)
if err != nil {
return "Unable to update asset", err
}
return data.Owner, nil
}
func (s *SmartContract) contains(ctx contractapi.TransactionContextInterface, st []string, str string) bool { func (s *SmartContract) contains(ctx contractapi.TransactionContextInterface, st []string, str string) bool {
for _, v := range st { for _, v := range st {
@ -923,13 +903,13 @@ func (s *SmartContract) ReadSchemaFromPDC(ctx contractapi.TransactionContextInte
log.Printf("ReadSchemaFromPDC: collection %v, ID %v", PDC1, SchemaID) log.Printf("ReadSchemaFromPDC: collection %v, ID %v", PDC1, SchemaID)
assetJSON, err := ctx.GetStub().GetPrivateData(PDC1, SchemaID) //get the asset from chaincode state assetJSON, err := ctx.GetStub().GetPrivateData(PDC1, SchemaID) //get the asset from chaincode state
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read asset: %v", err) return nil, fmt.Errorf("failed to read Schema: %v", err)
} }
//No Asset found, return empty response //No Asset found, return empty response
if assetJSON == nil { if assetJSON == nil {
log.Printf("%v does not exist in collection %v", SchemaID, PDC1) log.Printf("%v does not exist in collection %v", SchemaID, PDC1)
return nil, nil return nil, fmt.Errorf("%v does not exist in collection %v", SchemaID, PDC1)
} }
var schema *Schema var schema *Schema
@ -942,7 +922,7 @@ func (s *SmartContract) ReadSchemaFromPDC(ctx contractapi.TransactionContextInte
} }
func (s *SmartContract) GetAllPDCSchemas(ctx contractapi.TransactionContextInterface, SchemaID string) ([]*Schema, error) { func (s *SmartContract) GetAllPDCSchemas(ctx contractapi.TransactionContextInterface) ([]*Schema, error) {
log.Printf("GetAllPDCSchemas: collection %v ", PDC1) log.Printf("GetAllPDCSchemas: collection %v ", PDC1)
resultsIterator, err := ctx.GetStub().GetPrivateDataByRange(PDC1, "", "") resultsIterator, err := ctx.GetStub().GetPrivateDataByRange(PDC1, "", "")

View file

@ -212,6 +212,13 @@ echo "========= CC Query: Get all DataSamples ==========="
peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}' peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'
echo "========= Setting Up Network with PDC and SmartContract ===========" echo "========= Setting Up Network with PDC and SmartContract ==========="
./monitordocker.sh fabric_test ./monitordocker.sh fabric_test
@ -245,11 +252,28 @@ export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.e
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/owner@org1.example.com/msp export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/owner@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051 export CORE_PEER_ADDRESS=localhost:7051
export ASSET_PROPERTIES=$(echo -n "{\"SchemaId\":\"Project1.Schema1\",\"Project\":\"Project1\",\"JsonSchemaContent\":{\"type\": \"object\", \"properties\": { \"number\": { \"type\": \"number\" }, \"street_name\": { \"type\": \"string\" }, \"street_type\": { \"enum\": [\"Street\", \"Avenue\",\"Boulevard\"] }}, \"additionalProperties\": false, \"required\": [ \"number\", \"street_name\"]}}" | base64 | tr -d \\n) export ASSET_PROPERTIES=$(echo -n "{\"SchemaId\":\"Project1.Schema1\",\"Project\":\"Project1\",\"JsonSchemaContent\":{\"type\": \"object\", \"properties\": { \"number\": { \"type\": \"number\" }, \"street_name\": { \"type\": \"string\" }, \"street_type\": { \"enum\": [\"Street\", \"Avenue\",\"Boulevard\"] }}, \"additionalProperties\": true, \"required\": [ \"number\", \"street_name\"]}}" | base64 | tr -d \\n)
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n private -c '{"function":"WriteSchemaToPDC","Args":[]}' --transient "{\"asset_properties\":\"$ASSET_PROPERTIES\"}" peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n private -c '{"function":"WriteSchemaToPDC","Args":[]}' --transient "{\"asset_properties\":\"$ASSET_PROPERTIES\"}"
export ASSET_PROPERTIES=$(echo -n "{\"SchemaId\":\"Project1.Schema2\",\"Project\":\"Project1\",\"JsonSchemaContent\":{\"type\": \"object\", \"properties\": { \"number\": { \"type\": \"number\" }, \"street_name\": { \"type\": \"string\" }, \"street_type\": { \"enum\": [\"Street\", \"Avenue\",\"Boulevard\"] }}, \"additionalProperties\": true, \"required\": [ \"number\", \"street_name\"]}}" | base64 | tr -d \\n)
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n private -c '{"function":"WriteSchemaToPDC","Args":[]}' --transient "{\"asset_properties\":\"$ASSET_PROPERTIES\"}"
echo "========= CC Invoke: Reading of Schema in PDC ===========" echo "========= CC Invoke: Reading of Schema in PDC ==========="
peer chaincode query -C mychannel -n private -c '{"function":"ReadAsset","Args":["Project1.Schema1"]}' peer chaincode query -C mychannel -n private -c '{"function":"ReadSchemaFromPDC","Args":["Project2.Schema1"]}'
peer chaincode query -C mychannel -n private -c '{"function":"ReadSchemaFromPDC","Args":["Project1.Schema2"]}'
echo "========= CC Invoke: Reading all Schemas in PDC ==========="
peer chaincode query -C mychannel -n private -c '{"function":"GetAllPDCSchemas","Args":["1"]}'
echo "========= CC Invoke: Creation of DataSample ==========="
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"CreateDataSample","Args":["CIA Org", "Project 1", "Comment: Proof of live in Mars", "13/13/13", "Project1.Schema1", "{ \"number\": 1603, \"street_name\": \"Pennsylvania\", \"street_type\": \"Avenue\"}"]}'