diff --git a/orderer/consensus/smartbft/assembler.go b/orderer/consensus/smartbft/assembler.go index a9ab98e384a..50c75656556 100644 --- a/orderer/consensus/smartbft/assembler.go +++ b/orderer/consensus/smartbft/assembler.go @@ -11,11 +11,14 @@ import ( "sync/atomic" "github.com/hyperledger-labs/SmartBFT/pkg/types" + "github.com/hyperledger/fabric-lib-go/bccsp" "github.com/hyperledger/fabric-lib-go/common/flogging" cb "github.com/hyperledger/fabric-protos-go-apiv2/common" + "github.com/hyperledger/fabric/common/channelconfig" "github.com/hyperledger/fabric/orderer/common/cluster" "github.com/hyperledger/fabric/protoutil" "github.com/pkg/errors" + "google.golang.org/protobuf/proto" ) //go:generate mockery -dir . -name Ledger -case underscore -output mocks @@ -138,28 +141,52 @@ func lastConfigBlockFromLedger(ledger Ledger) (*cb.Block, error) { return lastConfigBlock, nil } -func PreviousConfigBlockFromLedgerOrPanic(ledger Ledger, logger Logger) *cb.Block { - block, err := previousConfigBlockFromLedger(ledger) +func NextToLastConfigBlockFromLedgerOrPanic(ledger Ledger, bccsp bccsp.BCCSP, logger Logger) *cb.Block { + block, err := nextToLastConfigBlockFromLedger(ledger, bccsp) if err != nil { logger.Panicf("Failed retrieving previous config block: %v", err) } return block } -func previousConfigBlockFromLedger(ledger Ledger) (*cb.Block, error) { - previousBlockSeq := ledger.Height() - 2 - if ledger.Height() == 1 { - previousBlockSeq = 0 +func nextToLastConfigBlockFromLedger(ledger Ledger, bccsp bccsp.BCCSP) (*cb.Block, error) { + block, err := lastConfigBlockFromLedger(ledger) + if err != nil { + return nil, err + } + if block.Header.Number == 0 { + return nil, nil } + + previousBlockSeq := block.Header.Number - 1 previousBlock := ledger.Block(previousBlockSeq) if previousBlock == nil { return nil, errors.Errorf("unable to retrieve block [%d]", previousBlockSeq) } - previousConfigBlock, err := cluster.LastConfigBlock(previousBlock, ledger) + previousLastConfigBlock, err := cluster.LastConfigBlock(previousBlock, ledger) if err != nil { return nil, err } - return previousConfigBlock, nil + + env := &cb.Envelope{} + if err = proto.Unmarshal(previousLastConfigBlock.Data.Data[0], env); err != nil { + return nil, errors.Wrap(err, "failed unmarshaling envelope of config block") + } + bundle, err := channelconfig.NewBundleFromEnvelope(env, bccsp) + if err != nil { + return nil, errors.Wrap(err, "failed getting a new bundle from envelope of config block") + } + + oc, ok := bundle.OrdererConfig() + if !ok { + return nil, errors.New("no orderer config in config block") + } + + if oc.ConsensusType() != "BFT" { + return nil, nil + } + + return previousLastConfigBlock, nil } // LastBlockFromLedgerOrPanic returns the last block from the ledger diff --git a/orderer/consensus/smartbft/chain.go b/orderer/consensus/smartbft/chain.go index e61ff292195..65f46ceb8cc 100644 --- a/orderer/consensus/smartbft/chain.go +++ b/orderer/consensus/smartbft/chain.go @@ -141,12 +141,20 @@ func NewChain( lastBlock := LastBlockFromLedgerOrPanic(support, c.Logger) lastConfigBlock := LastConfigBlockFromLedgerOrPanic(support, c.Logger) + nextToLastConfigBlock := NextToLastConfigBlockFromLedgerOrPanic(support, bccsp, c.Logger) + var err error rtc := RuntimeConfig{ logger: logger, id: selfID, } - rtc, err := rtc.BlockCommitted(lastConfigBlock, bccsp) + if nextToLastConfigBlock != nil { + rtc, err = rtc.BlockCommitted(nextToLastConfigBlock, bccsp) + if err != nil { + return nil, errors.Wrap(err, "failed constructing RuntimeConfig") + } + } + rtc, err = rtc.BlockCommitted(lastConfigBlock, bccsp) if err != nil { return nil, errors.Wrap(err, "failed constructing RuntimeConfig") } diff --git a/orderer/consensus/smartbft/util.go b/orderer/consensus/smartbft/util.go index a3bcf171b5f..2e22cc42ad7 100644 --- a/orderer/consensus/smartbft/util.go +++ b/orderer/consensus/smartbft/util.go @@ -46,6 +46,7 @@ type RuntimeConfig struct { LastCommittedBlockHash string RemoteNodes []cluster.RemoteNode ID2Identities NodeIdentitiesByID + ID2IdentitiesPrev NodeIdentitiesByID LastBlock *cb.Block LastConfigBlock *cb.Block Nodes []uint64 @@ -65,6 +66,7 @@ func (rtc RuntimeConfig) BlockCommitted(block *cb.Block, bccsp bccsp.BCCSP) (Run LastCommittedBlockHash: hex.EncodeToString(protoutil.BlockHeaderHash(block.Header)), Nodes: rtc.Nodes, ID2Identities: rtc.ID2Identities, + ID2IdentitiesPrev: rtc.ID2IdentitiesPrev, RemoteNodes: rtc.RemoteNodes, LastBlock: block, LastConfigBlock: rtc.LastConfigBlock, @@ -91,6 +93,7 @@ func (rtc RuntimeConfig) configBlockCommitted(block *cb.Block, bccsp bccsp.BCCSP LastCommittedBlockHash: hex.EncodeToString(protoutil.BlockHeaderHash(block.Header)), Nodes: nodeConf.nodeIDs, ID2Identities: nodeConf.id2Identities, + ID2IdentitiesPrev: rtc.ID2Identities, RemoteNodes: nodeConf.remoteNodes, LastBlock: block, LastConfigBlock: block, diff --git a/orderer/consensus/smartbft/verifier.go b/orderer/consensus/smartbft/verifier.go index 0e5c6ee3b20..0dcec78442b 100644 --- a/orderer/consensus/smartbft/verifier.go +++ b/orderer/consensus/smartbft/verifier.go @@ -8,6 +8,7 @@ package smartbft import ( "bytes" + "encoding/asn1" "encoding/base64" "encoding/hex" "fmt" @@ -209,11 +210,30 @@ func (v *Verifier) verifyRequest(rawRequest []byte, noConfigAllowed bool) (types // VerifyConsenterSig verifies consenter signature func (v *Verifier) VerifyConsenterSig(signature types.Signature, prop types.Proposal) ([]byte, error) { - id2Identity := v.RuntimeConfig.Load().(RuntimeConfig).ID2Identities + rtc := v.RuntimeConfig.Load().(RuntimeConfig) - identity, exists := id2Identity[signature.ID] + var ( + identity []byte + exists bool + ) + identity, exists = rtc.ID2Identities[signature.ID] if !exists { - return nil, errors.Errorf("node with id of %d doesn't exist", signature.ID) + if len(prop.Header) == 0 { + return nil, errors.New("proposal header cannot be nil") + } + hdr := &asn1Header{} + if _, err := asn1.Unmarshal(prop.Header, hdr); err != nil { + return nil, errors.Wrap(err, "bad header") + } + numBlockProp := hdr.Number.Uint64() + if numBlockProp <= rtc.LastBlock.GetHeader().GetNumber() { + identity, exists = rtc.ID2IdentitiesPrev[signature.ID] + if !exists { + return nil, errors.Errorf("node with id of %d doesn't exist", signature.ID) + } + } else { + return nil, errors.Errorf("node with id of %d doesn't exist", signature.ID) + } } sig := &Signature{}