-
Javier Diaz authoredJavier Diaz authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
chaincode.go 5.65 KiB
// Copyright 2022-2024 ETSI OSG/SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"log"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
// Protobuf definitions
type Uuid struct {
Uuid string `json:"uuid"`
}
type DltRecordId struct {
DomainUuid Uuid `json:"domain_uuid"`
Type string `json:"type"`
RecordUuid Uuid `json:"record_uuid"`
}
type DltRecord struct {
RecordId DltRecordId `json:"record_id"`
DataJson string `json:"data_json"`
}
type SmartContract struct {
contractapi.Contract
}
// InitLedger activates the chaincode
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
return nil
}
func (s *SmartContract) StoreRecord(ctx contractapi.TransactionContextInterface, recordId DltRecordId, dataJson string) error {
key, err := createHashKey(recordId)
if err != nil {
return fmt.Errorf("failed to create hash key: %v", err)
}
// Check if the same record does not exist before adding it to the ledger
exists, err := s.RecordExists(ctx, key)
if err == nil && exists != nil {
return fmt.Errorf("the record %s already exists", key)
}
// Trigger an event if the transaction is successful
storedRecord := DltRecord{
RecordId: recordId,
DataJson: dataJson,
}
eventJson, err := json.Marshal(storedRecord)
if err != nil {
return fmt.Errorf("failed to marshal stored record: %v", err)
}
ctx.GetStub().SetEvent("StoreRecord", eventJson)
// Store the record in the ledger
return ctx.GetStub().PutState(key, []byte(dataJson))
}
func (s *SmartContract) RetrieveRecord(ctx contractapi.TransactionContextInterface, recordId DltRecordId) (string, error) {
key, err := createHashKey(recordId)
if err != nil {
return "", fmt.Errorf("failed to create hash key: %v", err)
}
// Get the record from the ledger
dataBytes, err := ctx.GetStub().GetState(key)
if err != nil || dataBytes == nil {
return "", fmt.Errorf("data not found for key %s", key)
}
return string(dataBytes), nil
}
func (s *SmartContract) UpdateRecord(ctx contractapi.TransactionContextInterface, recordId DltRecordId, dataJson string) error {
key, err := createHashKey(recordId)
if err != nil {
return fmt.Errorf("failed to create hash key: %v", err)
}
// Check if the record exists before updating it
_, err = s.RecordExists(ctx, key)
if err != nil {
return err
}
// Trigger an event if the transaction is successful
eventData := DltRecord{RecordId: recordId, DataJson: dataJson}
eventJson, err := json.Marshal(eventData)
if err != nil {
return fmt.Errorf("failed to marshal event data: %v", err)
}
ctx.GetStub().SetEvent("UpdateRecord", eventJson)
// Update the record in the ledger
return ctx.GetStub().PutState(key, []byte(dataJson))
}
func (s *SmartContract) DeleteRecord(ctx contractapi.TransactionContextInterface, recordId DltRecordId) error {
key, err := createHashKey(recordId)
if err != nil {
return fmt.Errorf("failed to create hash key: %v", err)
}
// Check if the record exists before deleting it
exists, err := s.RecordExists(ctx, key)
if err != nil {
return err
}
// Trigger an event if the transaction is successful
eventData := DltRecord{RecordId: recordId, DataJson: string(exists)}
eventJson, err := json.Marshal(eventData)
if err != nil {
return fmt.Errorf("failed to marshal event data: %v", err)
}
ctx.GetStub().SetEvent("DeleteRecord", eventJson)
// Delete the record from the ledger
return ctx.GetStub().DelState(key)
}
func (s *SmartContract) RecordExists(ctx contractapi.TransactionContextInterface, key string) ([]byte, error) {
jsonData, err := ctx.GetStub().GetState(key)
if err != nil {
return nil, fmt.Errorf("failed to read from world state: %v", err)
}
if jsonData == nil {
return nil, fmt.Errorf("the record %s does not exist", key)
}
return jsonData, nil
}
func (s *SmartContract) GetAllRecords(ctx contractapi.TransactionContextInterface) ([]map[string]interface{}, error) {
// Range query with empty string for startKey and endKey does an
// open-ended query of all records in the chaincode namespace.
resultsIterator, err := ctx.GetStub().GetStateByRange("", "")
if err != nil {
return nil, err
}
defer resultsIterator.Close()
var records []map[string]interface{}
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}
var generic map[string]interface{}
if err := json.Unmarshal(queryResponse.Value, &generic); err != nil {
return nil, fmt.Errorf("invalid JSON data: %v", err)
}
records = append(records, generic)
}
return records, nil
}
func createHashKey(recordId DltRecordId) (string, error) {
recordIdJson, err := json.Marshal(recordId)
if err != nil {
return "", fmt.Errorf("failed to marshal record ID: %v", err)
}
hash := sha256.New()
hash.Write(recordIdJson)
return hex.EncodeToString(hash.Sum(nil)), nil
}
func main() {
recordChaincode, err := contractapi.NewChaincode(&SmartContract{})
if err != nil {
log.Panicf("Error creating chaincode: %v", err)
}
if err := recordChaincode.Start(); err != nil {
log.Panicf("Error starting chaincode: %v", err)
}
}