sample_chain/order/handle.go

194 lines
5.0 KiB
Go

package order
import (
"context"
"fmt"
"log"
"schain/peer/shim"
"schain/proto/util"
"sync"
"sync/atomic"
"time"
"schain/common/signer"
"schain/config"
"schain/order/core"
pb "schain/proto"
)
type Handler struct {
serialLock sync.Mutex
chatStream OrderChaincodeStream
peerClients []pb.ChaincodeSupportClient
start time.Time
rwSet map[string]core.ReadWriteTransaction
envelopes []*pb.Envelope
envGroup []*pb.Envelopes
signer *signer.Signer
group *core.TransactionGroup
num uint64
}
func NewOrderHandler(ServerStream OrderChaincodeStream) *Handler {
conf := config.OrderConf
sig, err := signer.NewSigner(conf)
if err != nil {
log.Fatal(err)
}
clients, err := shim.GetPeerClient()
if err != nil {
log.Fatal(err)
}
return &Handler{
chatStream: ServerStream,
peerClients: clients,
rwSet: make(map[string]core.ReadWriteTransaction),
envelopes: []*pb.Envelope{},
envGroup: []*pb.Envelopes{},
signer: sig,
group: core.NewGroup(),
num: 0,
}
}
func (h *Handler) serialSend(msg *pb.ChaincodeMessage) error {
h.serialLock.Lock()
defer h.serialLock.Unlock()
return h.chatStream.Send(msg)
}
func (h *Handler) serialSendAsync(msg *pb.ChaincodeMessage, errc chan<- error) {
go func() {
errc <- h.serialSend(msg)
}()
}
func (h *Handler) initBLock() {
h.group = core.NewGroup()
h.num = 0
h.start = time.Now()
h.rwSet = make(map[string]core.ReadWriteTransaction)
h.envelopes = nil
h.envGroup = nil
}
func (h *Handler) HandleMessage(msg *pb.ChaincodeMessage, errc chan error) error {
if msg.Type == pb.ChaincodeMessage_Type_TRANSACTION {
envelope, err := util.UnmarshalEnvelope(msg.Payload)
if err != nil {
log.Println(err)
}
kvRwSet, err := util.GetKVRWSetKwFromEnvelope(envelope)
if err != nil {
log.Println(err)
}
//拷贝交易的分组信息
cloneGroup := core.DeepCopyGroup(h.group)
// 分析事务直接的依赖关系
deps := core.FindTransactionDependency(kvRwSet, h.rwSet)
var isAbort bool
if deps != nil {
h.group.GroupTransactionsByDeps(deps)
isAbort = core.TxReorder(kvRwSet.TxID, h.group)
}
// 如果该事务不可序列化,则把该事务删除
if isAbort {
err = fmt.Errorf("transaction reorder fail")
resp := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_Type_ERROR, Payload: []byte(err.Error()), TxID: kvRwSet.TxID}
h.serialSendAsync(resp, errc)
for _, read := range kvRwSet.Reads {
txs := h.rwSet[read.Key]
txs.ReadTransactions = core.DeleteTx(txs.ReadTransactions, kvRwSet.TxID)
h.rwSet[read.Key] = txs
}
for _, write := range kvRwSet.Writes {
txs := h.rwSet[write.Key]
txs.WriteTransactions = core.DeleteTx(txs.WriteTransactions, kvRwSet.TxID)
h.rwSet[write.Key] = txs
}
h.group = cloneGroup
} else {
atomic.AddUint64(&h.num, 1)
h.envelopes = append(h.envelopes, envelope)
resp := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_Type_COMPLETED, TxID: kvRwSet.TxID}
h.serialSendAsync(resp, errc)
}
}
// 判断是否满足成块条件
if h.num == config.BlockSize || (int(time.Since(h.start)) > config.CreateBlockTime*1e6 && h.start.UnixMilli() > 0) || msg.Type == pb.ChaincodeMessage_Type_COMPLETED {
//将写写冲突的事务删除
for _, rwTransaction := range h.rwSet {
for i, wt := range rwTransaction.WriteTransactions {
if i > 0 {
_, h.envelopes = core.GetEnvelope(wt, h.envelopes)
err := fmt.Errorf("this is a transaction that writes conflict")
resp := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_Type_ERROR, Payload: []byte(err.Error()), TxID: wt}
h.serialSendAsync(resp, errc)
}
}
}
h.envGroup = core.CreateEnvelopeGroup(h.group, h.envelopes)
//h.envGroup = append(envGroup, &pb.Envelopes{Envelope: h.envelopes})
info, err := h.peerClients[0].GetBlockInfo(context.Background(), &pb.Empty{})
if err != nil {
log.Fatal(err)
}
newBlock := util.CreateNewBlock(info.Height, info.CurrentBlockHash, h.envGroup)
blockHeaderBytes := util.BlockHeaderBytes(newBlock.Header)
sig, err := h.signer.Sign(blockHeaderBytes)
if err != nil {
log.Fatal(err)
}
shdr, err := util.CreateSignatureHeader(h.signer)
if err != nil {
log.Fatal(err)
}
block := util.NewBlockSign(newBlock, shdr, sig)
blockBytes := util.BlockBytes(block)
var blockMsg *pb.ValidateMessage
if msg.Type == pb.ChaincodeMessage_Type_COMPLETED && h.num != 0 {
blockMsg = &pb.ValidateMessage{Type: pb.ValidateMessage_Type_VALIDATE_COMPLETED, Payload: blockBytes}
} else if h.num == 0 {
blockMsg = &pb.ValidateMessage{Type: pb.ValidateMessage_Type_VALIDATE_COMPLETED}
} else {
blockMsg = &pb.ValidateMessage{Type: pb.ValidateMessage_Type_VALIDATE, Payload: blockBytes}
}
var wg sync.WaitGroup
for _, peerClient := range h.peerClients {
wg.Add(1)
go func(client pb.ChaincodeSupportClient) {
defer wg.Done()
_, err = client.ValidateBlock(context.Background(), blockMsg)
if err != nil {
log.Fatal(err)
}
}(peerClient)
}
wg.Wait()
h.initBLock()
}
return nil
}