前回のブログでは、スマート タービン流量計を使用してデータを収集し、Hyperledger のチェーン コードにアップロードしました。チェーン コードの一部のデータ構造は以前に変更されましたが、まだ小さな問題がいくつかあります。
https://blog.csdn.net/qq_43824745/article/details/125876812?spm=1001.2014.3001.5501
以前のテスト チェーンコードは次のとおりです。
/*
SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"encoding/json"
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
type SmartContract struct {
contractapi.Contract
}
type Data struct {
Now string `json:"now(L/H)"`
Total string `json:"total(L)"`
}
type QueryResult struct {
Key string `json:"Key"`
Record *Data
}
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
datas := []Data{
Data{Now:"0", Total: "0"},
}
for data := range datas {
dataAsBytes, _ := json.Marshal(data)
err := ctx.GetStub().PutState("2022-07-20 00:00", dataAsBytes)
if err != nil {
return fmt.Errorf("Failed to put to world state. %s", err.Error())
}
}
return nil
}
func (s *SmartContract) AddData(ctx contractapi.TransactionContextInterface, dataNumber string, now string, total string) error {
data := Data{
Now: now,
Total: total,
}
dataAsBytes, _ := json.Marshal(data)
return ctx.GetStub().PutState(dataNumber, dataAsBytes)
}
func (s *SmartContract) QueryData(ctx contractapi.TransactionContextInterface, dataNumber string) (*Data, error) {
dataAsBytes, err := ctx.GetStub().GetState(dataNumber)
if err != nil {
return nil, fmt.Errorf("Failed to read from world state. %s", err.Error())
}
if dataAsBytes == nil {
return nil, fmt.Errorf("%s does not exist", dataNumber)
}
data := new(Data)
_ = json.Unmarshal(dataAsBytes, data)
return data, nil
}
func (s *SmartContract) QueryAllDatas(ctx contractapi.TransactionContextInterface) ([]QueryResult, error) {
startKey := ""
endKey := ""
resultsIterator, err := ctx.GetStub().GetStateByRange(startKey, endKey)
if err != nil {
return nil, err
}
defer resultsIterator.Close()
results := []QueryResult{}
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}
data := new(Data)
_ = json.Unmarshal(queryResponse.Value, data)
queryResult := QueryResult{Key: queryResponse.Key, Record: data}
results = append(results, queryResult)
}
return results, nil
}
func main() {
chaincode, err := contractapi.NewChaincode(new(SmartContract))
if err != nil {
fmt.Printf("Error create test chaincode: %s", err.Error())
return
}
if err := chaincode.Start(); err != nil {
fmt.Printf("Error starting test chaincode: %s", err.Error())
}
}
分単位で正確にデータを収集した時刻をデータのキーとして使用していることがわかりますが、この操作の利点は、すべてのデータをクエリする場合に、キーが辞書順に並んでいるときに乱れがないことです。結果は次のとおりです。
各クエリ結果は時系列に並べられており、合理的に見えますが、単一のデータをクエリする場合は、クエリ対象のデータに対応する Key を指定する必要があるため、この方法で単一のデータをクエリするのは不便です。 、上記のキーの値は正確な分であり、各レコードがアップロードされたのが何分であるかをユーザーが正確に知ることは不可能であるため、キーの時間を日付形式に調整し、この上で各データに番号を付けることを想定しています。辞書編集上の混乱を避けるため、番号付けには固定長のデジタル ID を使用します。
スクリプトの実行間隔が5分であることを考慮すると、1日に生成できるデータの総量は300未満であるため、3桁のIDを使用して番号付けするだけで十分です。たとえば、Keyは「」です。 2022-07-27 010" (2022 年を意味します) 7 月 27 日の 10 番目のデータについては、このデザインはユーザーが単一のデータをクエリする必要性を合理的に実現していると思います。数字はその日の数字にしか対応していないため、翌日にはまた「001」から数え始める必要があるため、スクリプトが各データのKey値を書き込む際に、そのデータが正しいかどうかを判断する必要があります。現在の日に属している場合は ID が累積され、そうでない場合は ID を 1 に戻します。
変更された test.go とシェル スクリプトは次のとおりです。
test.go:
/*
SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"encoding/json"
"fmt"
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
type SmartContract struct {
contractapi.Contract
}
type Data struct {
Now string `json:"now(L/H)"`
Total string `json:"total(L)"`
Time string `json:"time"`
}
type QueryResult struct {
Key string `json:"Key"`
Record *Data
}
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
datas := []Data{
Data{Now:"0", Total: "0",Time:"12:00"},
}
for data := range datas {
dataAsBytes, _ := json.Marshal(data)
err := ctx.GetStub().PutState("2022-07-20 000", dataAsBytes)
if err != nil {
return fmt.Errorf("Failed to put to world state. %s", err.Error())
}
}
return nil
}
func (s *SmartContract) AddData(ctx contractapi.TransactionContextInterface, dataNumber string, now string, total string,time string) error {
data := Data{
Now: now,
Total: total,
Time: time,
}
dataAsBytes, _ := json.Marshal(data)
return ctx.GetStub().PutState(dataNumber, dataAsBytes)
}
func (s *SmartContract) QueryData(ctx contractapi.TransactionContextInterface, dataNumber string) (*Data, error) {
dataAsBytes, err := ctx.GetStub().GetState(dataNumber)
if err != nil {
return nil, fmt.Errorf("Failed to read from world state. %s", err.Error())
}
if dataAsBytes == nil {
return nil, fmt.Errorf("%s does not exist", dataNumber)
}
data := new(Data)
_ = json.Unmarshal(dataAsBytes, data)
return data, nil
}
func (s *SmartContract) QueryAllDatas(ctx contractapi.TransactionContextInterface) ([]QueryResult, error) {
startKey := ""
endKey := ""
resultsIterator, err := ctx.GetStub().GetStateByRange(startKey, endKey)
if err != nil {
return nil, err
}
defer resultsIterator.Close()
results := []QueryResult{}
for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next()
if err != nil {
return nil, err
}
data := new(Data)
_ = json.Unmarshal(queryResponse.Value, data)
queryResult := QueryResult{Key: queryResponse.Key, Record: data}
results = append(results, queryResult)
}
return results, nil
}
func main() {
chaincode, err := contractapi.NewChaincode(new(SmartContract))
if err != nil {
fmt.Printf("Error create test chaincode: %s", err.Error())
return
}
if err := chaincode.Start(); err != nil {
fmt.Printf("Error starting test chaincode: %s", err.Error())
}
}
スクリプト (実際のデータは使用せず、乱数でのみテストしました):
#!/bin/bash
pre=$(date "+%Y-%m-%d") //pre记录上一条数据的采集时间
num="1" //num记录当前数据是这一天的第几条数据
for i in {1..20}
do
# sudo python /home/pi/RS485_CAN_HAT_Code/485/python/query_now.py
now=$(date "+%Y-%m-%d")
if [ $pre != $now ]
then
num="1"
pre=$now
fi
id=$num
len=${#id}
while [ $len -le 2 ]
do
id="0"$id
let len+=1
done
let num+=1
time=$(date "+%H:%M")
res=$now" "$id
# sleep 3
# echo " " >> data.txt
# while read rows
# do
# n=$rows
# break
# done < data.txt
# sudo python /home/pi/RS485_CAN_HAT_Code/485/python/query_total.py
# sleep 3
# echo " " >> data.txt
# while read rows
# do
# t=$rows
# break
# done < data.txt
n=$RANDOM
t=$RANDOM
echo "这是第"$i"次查询到并添加的数据:"
echo "Now(L/H):"$n" Total(L):"$t" Time:"$time
cmd="'{\"Args\":[\"AddData\",\"$res\",\"$n\",\"$t\",\"$time\"]}'"
echo "Add命令:"$cmd
echo "#!/bin/bash
peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n newtest --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c "$cmd "
exit"> add.sh
docker cp add.sh cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/
docker exec -it cli bash add.sh
sleep 60
#break
done
スクリプトの実行結果:
Org1 はすべてのデータの結果をクエリします。
Org1 クエリの単一データの結果: