mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-18 16:05:10 +00:00
- switch to ClientConnInterface - use command type alias for map of commands - add error return to command functions and handle in app.go - inline formatJSON function in getAllAssets.go - replace most panics with error returns - remove error wrapping in listen.go and further down the line - use strconv.ParseUint instead of ParseFloat - use WithCancelCause in transact.go to grab and propagate error from go routine - unmarshal and return []Asset in atb.GetAllAssets - switch to rand package - remove dependency to protobuf reflect package - switch to sync.OnceValues for caching parser - fixed typo in events sample connect.go Signed-off-by: Stanislav Jakuschevskij <stas@two-giants.com>
93 lines
2.3 KiB
Go
93 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
var storeFile = envOrDefault("STORE_FILE", "store.log")
|
|
var simulatedFailureCount = getSimulatedFailureCount()
|
|
var transactionCount uint = 0 // Used only to simulate failures
|
|
|
|
// Apply writes for a given transaction to off-chain data store, ideally in a single operation for fault tolerance.
|
|
type writer = func(data ledgerUpdate) error
|
|
|
|
// Ledger update made by a specific transaction.
|
|
type ledgerUpdate struct {
|
|
BlockNumber uint64
|
|
TransactionID string
|
|
Writes []write
|
|
}
|
|
|
|
// Description of a ledger Write that can be applied to an off-chain data store.
|
|
type write struct {
|
|
// Channel whose ledger is being updated.
|
|
ChannelName string `json:"channelName"`
|
|
// Namespace within the ledger.
|
|
Namespace string `json:"namespace"`
|
|
// Key name within the ledger namespace.
|
|
Key string `json:"key"`
|
|
// Whether the key and associated value are being deleted.
|
|
IsDelete bool `json:"isDelete"`
|
|
// If `isDelete` is false, the Value written to the key; otherwise ignored.
|
|
Value string `json:"value"`
|
|
}
|
|
|
|
// Apply writes for a given transaction to off-chain data store, ideally in a single operation for fault tolerance.
|
|
// This implementation just writes to a file.
|
|
func applyWritesToOffChainStore(data ledgerUpdate) error {
|
|
if err := simulateFailureIfRequired(); err != nil {
|
|
return err
|
|
}
|
|
|
|
writes := []string{}
|
|
for _, write := range data.Writes {
|
|
marshaled, err := json.Marshal(write)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
writes = append(writes, string(marshaled))
|
|
}
|
|
|
|
f, err := os.OpenFile(storeFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := f.Write([]byte(strings.Join(writes, "\n") + "\n")); err != nil {
|
|
f.Close()
|
|
return err
|
|
}
|
|
|
|
if err := f.Close(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func simulateFailureIfRequired() error {
|
|
if simulatedFailureCount > 0 && transactionCount >= simulatedFailureCount {
|
|
transactionCount = 0
|
|
return errors.New("expected error: simulated write failure")
|
|
}
|
|
|
|
transactionCount += 1
|
|
|
|
return nil
|
|
}
|
|
|
|
func getSimulatedFailureCount() uint {
|
|
valueAsString := envOrDefault("SIMULATED_FAILURE_COUNT", "0")
|
|
result, err := strconv.ParseUint(valueAsString, 10, 0)
|
|
if err != nil {
|
|
panic(fmt.Errorf("invalid SIMULATED_FAILURE_COUNT value: %s", valueAsString))
|
|
}
|
|
|
|
return uint(result)
|
|
}
|