308 lines
7.2 KiB
Go
308 lines
7.2 KiB
Go
package shim
|
||
|
||
import (
|
||
"bytes"
|
||
"fmt"
|
||
"log"
|
||
"schain/common/signer"
|
||
pb "schain/proto"
|
||
"schain/proto/util"
|
||
"sync"
|
||
"sync/atomic"
|
||
"time"
|
||
|
||
"github.com/pkg/errors"
|
||
)
|
||
|
||
var SuccessNum int32
|
||
|
||
var EndChannel = make(chan bool, 1)
|
||
|
||
type blockValidationRequest struct {
|
||
blockNum uint64
|
||
envelope *pb.Envelope
|
||
gIdx int
|
||
tIdx int
|
||
}
|
||
|
||
func validateSignatureHeader(sHdr *pb.SignatureHeader) error {
|
||
if sHdr == nil {
|
||
return errors.New("nil SignatureHeader provided")
|
||
}
|
||
|
||
// ensure that there is a nonce
|
||
if sHdr.Nonce == nil || len(sHdr.Nonce) == 0 {
|
||
return errors.New("invalid nonce specified in the header")
|
||
}
|
||
|
||
// ensure that there is a creator
|
||
if sHdr.Creator == nil || len(sHdr.Creator) == 0 {
|
||
return errors.New("invalid creator specified in the header")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func validateEndorserTransaction(payload *pb.Payload, hdr *pb.SignatureHeader) (*pb.KVRWSet, error) {
|
||
|
||
tx, err := util.UnmarshalTransaction(payload.Data)
|
||
if err != nil {
|
||
return nil, errors.New("transaction Unmarshal fail")
|
||
|
||
}
|
||
|
||
if tx == nil {
|
||
return nil, errors.New("nil transaction")
|
||
}
|
||
|
||
prp, err := util.UnmarshalProposalResponsePayload(tx.Payload.ProposalResponsePayload)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
ca, err := util.UnmarshalChaincodeAction(prp.Extension)
|
||
if err != nil {
|
||
return nil, errors.WithMessage(err, "error getting chaincodeAction from envelop")
|
||
}
|
||
|
||
csBytes, err := util.GetBytesChaincodeSpec(tx.Payload.Input)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
pHash, err := util.GetProposalHash(hdr, csBytes)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
// ensure that the proposal hash matches
|
||
if !bytes.Equal(pHash, prp.ProposalHash) {
|
||
return nil, errors.New("proposal hash does not match")
|
||
}
|
||
|
||
prpBytes, err := util.GetBytesProposalResponsePayload(pHash, ca.Response, ca.Results)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
for _, endorsement := range tx.Payload.Endorsements {
|
||
|
||
if err = signer.Verify(endorsement.Endorser, endorsement.Signature, append(prpBytes, endorsement.Endorser...)); err != nil {
|
||
fmt.Printf("验证失败!!!!!!!!!!!!!!!!!!!!")
|
||
return nil, err
|
||
}
|
||
//fmt.Println("验证提案签名成功 20210501")
|
||
}
|
||
|
||
kVRWSet, err := util.UnmarshalKVRWSet(ca.Results)
|
||
if err != nil {
|
||
return nil, errors.WithMessage(err, "error getting txID kVRWSet ChaincodeAction")
|
||
}
|
||
|
||
return kVRWSet, nil
|
||
}
|
||
|
||
func validateRWSet(blockNum uint64, gIdx, seq int, txRWSet *pb.KVRWSet) error {
|
||
|
||
for _, write := range txRWSet.Writes {
|
||
detection.Remove(write.Key)
|
||
}
|
||
|
||
// 验证读写集,如果发现脏读,则把这个事务中止
|
||
for _, read := range txRWSet.Reads {
|
||
stateRead, _ := State.Get(read.Key)
|
||
|
||
if stateRead == nil {
|
||
return errors.New("Failed to read a transaction from the state database")
|
||
}
|
||
|
||
if read.Version.TxNum != stateRead.Version.TxNum || read.Version.GroupNum != stateRead.Version.GroupNum ||
|
||
read.Version.BlockNum != stateRead.Version.BlockNum {
|
||
|
||
return errors.New("transaction rwSet validate failure")
|
||
}
|
||
}
|
||
|
||
for _, write := range txRWSet.Writes {
|
||
if write.IsDelete {
|
||
State.Remove(write.Key)
|
||
} else {
|
||
value := &StateDB{Value: write.Value, Version: &pb.Version{BlockNum: blockNum, GroupNum: uint64(gIdx), TxNum: uint64(seq)}}
|
||
State.Set(write.Key, value)
|
||
|
||
}
|
||
}
|
||
|
||
atomic.AddInt32(&SuccessNum, 1)
|
||
|
||
tl, ok := TxLatency.Get(txRWSet.TxID)
|
||
if ok {
|
||
tl.endTime = uint64(time.Now().UnixMilli())
|
||
TxLatency.Set(txRWSet.TxID, tl)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func validateTx(req *blockValidationRequest, vCodes *pb.ValidationCodes) {
|
||
// 验证事务,获取事务验证结果
|
||
validateCode := validateTransaction(req)
|
||
vCodes.Transaction_State = append(vCodes.Transaction_State, validateCode)
|
||
}
|
||
|
||
func validateTransaction(req *blockValidationRequest) pb.TxValidationCode {
|
||
env := req.envelope
|
||
|
||
if env == nil {
|
||
return pb.TxValidationCode_NIL_ENVELOPE
|
||
}
|
||
|
||
// 验证交易负载
|
||
payload, err := util.UnmarshalPayload(env.Payload)
|
||
if err != nil {
|
||
return pb.TxValidationCode_BAD_PAYLOAD
|
||
}
|
||
|
||
sHdr := payload.SignatureHeader
|
||
|
||
// 验证签名头
|
||
err = validateSignatureHeader(sHdr)
|
||
if err != nil {
|
||
return pb.TxValidationCode_BAD_SIGNATURE_HEADER
|
||
}
|
||
|
||
// 验证交易签名
|
||
err = signer.Verify(sHdr.Creator, env.Signature, env.Payload)
|
||
if err != nil {
|
||
fmt.Println("yanzhengshibai1!1!!!!!!")
|
||
return pb.TxValidationCode_BAD_CREATOR_SIGNATURE
|
||
}
|
||
|
||
//获取交易ID
|
||
txId, err := util.GetOrComputeTxIDFromEnvelope(env)
|
||
if err != nil {
|
||
return pb.TxValidationCode_BAD_TXID
|
||
}
|
||
|
||
// 验证交易ID
|
||
err = util.CheckTxID(
|
||
txId,
|
||
sHdr.Nonce,
|
||
sHdr.Creator)
|
||
if err != nil {
|
||
return pb.TxValidationCode_BAD_TXID
|
||
}
|
||
|
||
if payload.Data == nil {
|
||
return pb.TxValidationCode_BAD_PAYLOAD
|
||
}
|
||
|
||
//验证交易背书
|
||
rwSet, err := validateEndorserTransaction(payload, sHdr)
|
||
if err != nil {
|
||
return pb.TxValidationCode_INVALID_ENDORSER_TRANSACTION
|
||
}
|
||
|
||
//验证交易读写集
|
||
err = validateRWSet(req.blockNum, req.gIdx, req.tIdx, rwSet)
|
||
if err != nil {
|
||
return pb.TxValidationCode_BAD_RWSET
|
||
}
|
||
|
||
return pb.TxValidationCode_VALID
|
||
}
|
||
|
||
// validateBlockMataData 验证order签名是否正确
|
||
func validateBlockMataData(block *pb.Block) error {
|
||
blockHeaderBytes := util.BlockHeaderBytes(block.Header)
|
||
creator := block.Metadata.SignatureHeader.Creator
|
||
signature := block.Metadata.Signature
|
||
if err := signer.Verify(creator, signature, blockHeaderBytes); err != nil {
|
||
fmt.Println("验证bad bad bad bad bad bad!!!!!!")
|
||
return err
|
||
}
|
||
//fmt.Println("验证成功!!!!!!!!!!!!!!!!!!!")
|
||
return nil
|
||
}
|
||
|
||
// validateDataHash 验证区块的交易hash是否被修改
|
||
func validateDataHash(block *pb.Block) error {
|
||
dataHash := util.BlockDataHash(block.Data)
|
||
if !bytes.Equal(block.Header.DataHash, dataHash) {
|
||
return errors.New("DataHash is error")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// Validate 验证区块
|
||
func Validate(block *pb.Block) error {
|
||
|
||
var err error
|
||
var wg sync.WaitGroup
|
||
|
||
// 验证DataHash查看交易是否被修改
|
||
err = validateDataHash(block)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 验证MateDate查看order节点签名是否正确
|
||
err = validateBlockMataData(block)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 并发的对每个组的事务进行验证
|
||
for gIdx, data := range block.Data.Data {
|
||
wg.Add(1)
|
||
var vCodes = &pb.ValidationCodes{Transaction_State: []pb.TxValidationCode{}}
|
||
go func(gIndex int, data []byte) {
|
||
defer wg.Done()
|
||
envs, err := util.UnmarshalEnvelopes(data)
|
||
if err != nil {
|
||
log.Fatal(err)
|
||
}
|
||
// 验证每个组中的事务
|
||
for txIndex, env := range envs.Envelope {
|
||
validateTx(&blockValidationRequest{
|
||
envelope: env,
|
||
blockNum: block.Header.Number,
|
||
gIdx: gIndex,
|
||
tIdx: txIndex,
|
||
}, vCodes)
|
||
}
|
||
}(gIdx, data)
|
||
block.Metadata.Transaction_State = append(block.Metadata.Transaction_State, vCodes)
|
||
}
|
||
wg.Wait()
|
||
|
||
return nil
|
||
}
|
||
|
||
// ValidateBlock 验证区块中的交易
|
||
func ValidateBlock(msg *pb.ValidateMessage) error {
|
||
|
||
if msg.Payload != nil {
|
||
block, err := util.UnmarshalBlock(msg.Payload)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 对区块进行验证
|
||
err = Validate(block)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 如果区块验证成功,则把该区块写进账本
|
||
err = Blockchain.AddBlock(block)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
if msg.Type == pb.ValidateMessage_Type_VALIDATE_COMPLETED {
|
||
EndChannel <- true
|
||
}
|
||
|
||
return nil
|
||
}
|