239 lines
6.5 KiB
Go
239 lines
6.5 KiB
Go
/*
|
|
Copyright IBM Corp. 2017 All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package server
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
cb "github.com/hyperledger/fabric-protos-go/common"
|
|
ab "github.com/hyperledger/fabric-protos-go/orderer"
|
|
"github.com/hyperledger/fabric/common/ledger/blockledger"
|
|
"github.com/hyperledger/fabric/common/ledger/blockledger/fileledger"
|
|
"github.com/hyperledger/fabric/common/metrics/disabled"
|
|
"github.com/hyperledger/fabric/common/util"
|
|
"github.com/hyperledger/fabric/orderer/common/blockcutter"
|
|
"github.com/hyperledger/fabric/orderer/common/msgprocessor"
|
|
"github.com/hyperledger/fabric/orderer/common/multichannel"
|
|
"github.com/hyperledger/fabric/orderer/common/multichannel/mocks"
|
|
"github.com/hyperledger/fabric/orderer/consensus"
|
|
"github.com/hyperledger/fabric/protoutil"
|
|
"github.com/pkg/errors"
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
type AttestationServerStream struct {
|
|
grpc.ServerStream
|
|
ctx context.Context
|
|
ServerChan chan *ab.BlockAttestationResponse
|
|
}
|
|
|
|
func NewAttestationServerStream() *AttestationServerStream {
|
|
return &AttestationServerStream{
|
|
ctx: context.Background(),
|
|
ServerChan: make(chan *ab.BlockAttestationResponse, 10),
|
|
}
|
|
}
|
|
|
|
func (ss *AttestationServerStream) Context() context.Context {
|
|
return ss.ctx
|
|
}
|
|
|
|
func (ss *AttestationServerStream) Send(resp *ab.BlockAttestationResponse) error {
|
|
ss.ServerChan <- resp
|
|
return nil
|
|
}
|
|
|
|
func (ss *AttestationServerStream) RecvResponse() (*ab.BlockAttestationResponse, error) {
|
|
response, more := <-ss.ServerChan
|
|
if !more {
|
|
return nil, errors.New("empty")
|
|
}
|
|
return response, nil
|
|
}
|
|
|
|
func newLedgerAndFactory(dir string, chainID string, genesisBlockSys *cb.Block) (blockledger.Factory, blockledger.ReadWriter) {
|
|
rlf := newFactory(dir)
|
|
rl := newLedger(rlf, chainID, genesisBlockSys)
|
|
return rlf, rl
|
|
}
|
|
|
|
func newFactory(dir string) blockledger.Factory {
|
|
rlf, err := fileledger.New(dir, &disabled.Provider{})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return rlf
|
|
}
|
|
|
|
func newLedger(rlf blockledger.Factory, chainID string, genesisBlockSys *cb.Block) blockledger.ReadWriter {
|
|
rl, err := rlf.GetOrCreate(chainID)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if genesisBlockSys != nil {
|
|
err = rl.Append(genesisBlockSys)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
return rl
|
|
}
|
|
|
|
func mockCrypto() *mocks.SignerSerializer {
|
|
return &mocks.SignerSerializer{}
|
|
}
|
|
|
|
type mockChainCluster struct {
|
|
*mockChain
|
|
}
|
|
|
|
type mockChain struct {
|
|
queue chan *cb.Envelope
|
|
cutter blockcutter.Receiver
|
|
support consensus.ConsenterSupport
|
|
metadata *cb.Metadata
|
|
done chan struct{}
|
|
}
|
|
|
|
func (mch *mockChain) Errored() <-chan struct{} {
|
|
return nil
|
|
}
|
|
|
|
func (mch *mockChain) Order(env *cb.Envelope, configSeq uint64) error {
|
|
mch.queue <- env
|
|
return nil
|
|
}
|
|
|
|
func (mch *mockChain) Configure(config *cb.Envelope, configSeq uint64) error {
|
|
mch.queue <- config
|
|
return nil
|
|
}
|
|
|
|
func (mch *mockChain) WaitReady() error {
|
|
return nil
|
|
}
|
|
|
|
func (mch *mockChain) Start() {
|
|
go func() {
|
|
defer close(mch.done)
|
|
for {
|
|
msg, ok := <-mch.queue
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
chdr, err := protoutil.ChannelHeader(msg)
|
|
if err != nil {
|
|
logger.Panicf("If a message has arrived to this point, it should already have had header inspected once: %s", err)
|
|
}
|
|
|
|
class := mch.support.ClassifyMsg(chdr)
|
|
switch class {
|
|
case msgprocessor.ConfigMsg:
|
|
batch := mch.support.BlockCutter().Cut()
|
|
if batch != nil {
|
|
block := mch.support.CreateNextBlock(batch)
|
|
mch.support.WriteBlock(block, nil)
|
|
}
|
|
|
|
_, err := mch.support.ProcessNormalMsg(msg)
|
|
if err != nil {
|
|
logger.Warningf("Discarding bad config message: %s", err)
|
|
continue
|
|
}
|
|
block := mch.support.CreateNextBlock([]*cb.Envelope{msg})
|
|
mch.support.WriteConfigBlock(block, nil)
|
|
case msgprocessor.NormalMsg:
|
|
batches, _ := mch.support.BlockCutter().Ordered(msg)
|
|
for _, batch := range batches {
|
|
block := mch.support.CreateNextBlock(batch)
|
|
mch.support.WriteBlock(block, nil)
|
|
}
|
|
case msgprocessor.ConfigUpdateMsg:
|
|
logger.Panicf("Not expecting msg class ConfigUpdateMsg here")
|
|
default:
|
|
logger.Panicf("Unsupported msg classification: %v", class)
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (mch *mockChain) Halt() {
|
|
close(mch.queue)
|
|
}
|
|
|
|
func handleChainCluster(support consensus.ConsenterSupport, metadata *cb.Metadata) (consensus.Chain, error) {
|
|
chain := &mockChain{
|
|
queue: make(chan *cb.Envelope),
|
|
cutter: support.BlockCutter(),
|
|
support: support,
|
|
metadata: metadata,
|
|
done: make(chan struct{}),
|
|
}
|
|
|
|
return &mockChainCluster{mockChain: chain}, nil
|
|
}
|
|
|
|
func Test_attestationserver_BlockAttestations(t *testing.T) {
|
|
ts := util.CreateUtcTimestamp()
|
|
channelHeader := &cb.ChannelHeader{
|
|
ChannelId: "mychannel",
|
|
Timestamp: ts,
|
|
}
|
|
seekInfo := &ab.SeekInfo{
|
|
Start: &ab.SeekPosition{
|
|
Type: &ab.SeekPosition_Specified{
|
|
Specified: &ab.SeekSpecified{Number: 0},
|
|
},
|
|
},
|
|
Stop: &ab.SeekPosition{
|
|
Type: &ab.SeekPosition_Specified{
|
|
Specified: &ab.SeekSpecified{Number: 0},
|
|
},
|
|
},
|
|
}
|
|
envelope := &cb.Envelope{}
|
|
payload := &cb.Payload{
|
|
Header: &cb.Header{
|
|
ChannelHeader: protoutil.MarshalOrPanic(channelHeader),
|
|
SignatureHeader: protoutil.MarshalOrPanic(&cb.SignatureHeader{}),
|
|
},
|
|
Data: protoutil.MarshalOrPanic(seekInfo),
|
|
}
|
|
envelope.Payload = protoutil.MarshalOrPanic(payload)
|
|
|
|
// TODO This is preparation work for the BFT block puller. Right now it is used only in unit tests.
|
|
// We need to update these tests.
|
|
t.Run("Complete block attestation is successfully", func(t *testing.T) {
|
|
t.Skip("Work in progress. BFT Block Puller preparatory work. This test needs to be rewritten.")
|
|
// TODO
|
|
})
|
|
|
|
t.Run("Block attestation returns with BAD_REQUEST when envelope is malformed", func(t *testing.T) {
|
|
mockstream := NewAttestationServerStream()
|
|
asr := NewAttestationService(&multichannel.Registrar{}, &disabled.Provider{}, nil, time.Second, false, false)
|
|
err := asr.BlockAttestations(&cb.Envelope{}, mockstream)
|
|
require.NoError(t, err)
|
|
StatusResponse, _ := mockstream.RecvResponse()
|
|
require.Equal(t, cb.Status_BAD_REQUEST, StatusResponse.GetStatus())
|
|
})
|
|
|
|
t.Run("Block attestion returns with NOTFOUND when custom policy check fails", func(t *testing.T) {
|
|
mockstream := NewAttestationServerStream()
|
|
asr := NewAttestationService(&multichannel.Registrar{}, &disabled.Provider{}, nil, time.Second, false, false)
|
|
err := asr.BlockAttestations(envelope, mockstream)
|
|
require.NoError(t, err)
|
|
StatusResponse, _ := mockstream.RecvResponse()
|
|
require.Equal(t, cb.Status_NOT_FOUND, StatusResponse.GetStatus())
|
|
})
|
|
}
|