189 lines
5.4 KiB
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),
|
|
}
|
|
}
|