go_study/fabric-main/orderer/consensus/smartbft/assembler_test.go

189 lines
5.4 KiB
Go

/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package smartbft_test
import (
"sync/atomic"
"testing"
"github.com/SmartBFT-Go/consensus/pkg/types"
"github.com/hyperledger/fabric-protos-go/common"
"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/orderer/consensus/smartbft"
"github.com/hyperledger/fabric/orderer/consensus/smartbft/mocks"
"github.com/hyperledger/fabric/protoutil"
"github.com/stretchr/testify/require"
)
var (
configTx = makeTx(int32(common.HeaderType_CONFIG))
nonConfigTx = makeTx(int32(common.HeaderType_ENDORSER_TRANSACTION))
)
func TestAssembler(t *testing.T) {
lastBlock := makeNonConfigBlock(19, 10)
lastHash := protoutil.BlockHeaderHash(lastBlock.Header)
lastConfigBlock := makeConfigBlock(10)
ledger := &mocks.Ledger{}
ledger.On("Height").Return(uint64(20))
ledger.On("Block", uint64(19)).Return(lastBlock)
ledger.On("Block", uint64(10)).Return(lastConfigBlock)
for _, testCase := range []struct {
name string
panicVal string
requests [][]byte
expectedProposal types.Proposal
}{
{
name: "Must contain at least one request",
panicVal: "Programming error, no requests in proposal",
},
{
name: "Must not contain an invalid request",
panicVal: "Programming error, received bad envelope but should have" +
" validated it: error unmarshalling Envelope: proto: cannot parse invalid wire-format data",
requests: [][]byte{{1, 2, 3}},
},
{
name: "Config transaction is first in the batch",
requests: [][]byte{configTx, nonConfigTx},
expectedProposal: proposalFromRequests(10, 20, 20, lastHash, []byte("metadata"), configTx),
},
{
name: "Config transaction is in the middle of the batch",
requests: [][]byte{nonConfigTx, configTx, nonConfigTx},
expectedProposal: proposalFromRequests(10, 20, 10, lastHash, []byte("metadata"), nonConfigTx),
},
{
name: "Config transaction is at the end of the batch",
requests: [][]byte{nonConfigTx, nonConfigTx, configTx},
expectedProposal: proposalFromRequests(10, 20, 10, lastHash, []byte("metadata"), nonConfigTx, nonConfigTx),
},
} {
t.Run(testCase.name, func(t *testing.T) {
logger := flogging.MustGetLogger("test")
assembler := &smartbft.Assembler{
VerificationSeq: func() uint64 {
return 10
},
Logger: logger,
RuntimeConfig: &atomic.Value{},
}
rtc := smartbft.RuntimeConfig{
LastBlock: smartbft.LastBlockFromLedgerOrPanic(ledger, logger),
LastConfigBlock: smartbft.LastConfigBlockFromLedgerOrPanic(ledger, logger),
}
assembler.RuntimeConfig.Store(rtc)
if testCase.panicVal != "" {
require.Panics(t, func() {
assembler.AssembleProposal([]byte{1, 2, 3}, testCase.requests)
})
return
}
prop := assembler.AssembleProposal([]byte("metadata"), testCase.requests)
require.Equal(t, testCase.expectedProposal, prop)
})
}
}
func makeTx(headerType int32) []byte {
return protoutil.MarshalOrPanic(&common.Envelope{
Payload: protoutil.MarshalOrPanic(&common.Payload{
Header: &common.Header{
ChannelHeader: protoutil.MarshalOrPanic(&common.ChannelHeader{
Type: headerType,
ChannelId: "test-chain",
}),
},
}),
})
}
func makeNonConfigBlock(seq, lastConfigSeq uint64) *common.Block {
return &common.Block{
Header: &common.BlockHeader{
Number: seq,
},
Data: &common.BlockData{
Data: [][]byte{nonConfigTx},
},
Metadata: &common.BlockMetadata{
Metadata: [][]byte{
{},
protoutil.MarshalOrPanic(&common.Metadata{
Value: protoutil.MarshalOrPanic(&common.LastConfig{Index: lastConfigSeq}),
}),
},
},
}
}
func makeConfigBlock(seq uint64) *common.Block {
return &common.Block{
Header: &common.BlockHeader{
Number: seq,
},
Data: &common.BlockData{
Data: [][]byte{protoutil.MarshalOrPanic(&common.Envelope{
Payload: protoutil.MarshalOrPanic(&common.Payload{
Data: protoutil.MarshalOrPanic(&common.ConfigEnvelope{
Config: &common.Config{
Sequence: 10,
},
}),
}),
})},
},
Metadata: &common.BlockMetadata{
Metadata: [][]byte{
{},
protoutil.MarshalOrPanic(&common.Metadata{
Value: protoutil.MarshalOrPanic(&common.LastConfig{Index: 666}),
}),
},
},
}
}
func proposalFromRequests(verificationSeq, seq, lastConfigSeq uint64, lastBlockHash, metadata []byte, requests ...[]byte) types.Proposal {
block := protoutil.NewBlock(seq, nil)
block.Data = &common.BlockData{Data: requests}
block.Header.DataHash = protoutil.BlockDataHash(block.Data)
block.Header.PreviousHash = lastBlockHash
block.Metadata.Metadata[common.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&common.Metadata{
Value: protoutil.MarshalOrPanic(&common.LastConfig{Index: lastConfigSeq}),
})
block.Metadata.Metadata[common.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&common.Metadata{
Value: protoutil.MarshalOrPanic(&common.OrdererBlockMetadata{
ConsenterMetadata: metadata,
LastConfig: &common.LastConfig{
Index: lastConfigSeq,
},
}),
})
tuple := &smartbft.ByteBufferTuple{
A: protoutil.MarshalOrPanic(block.Data),
B: protoutil.MarshalOrPanic(block.Metadata),
}
return types.Proposal{
Header: protoutil.BlockHeaderBytes(block.Header),
Payload: tuple.ToBytes(),
Metadata: metadata,
VerificationSequence: int64(verificationSeq),
}
}