Skip to content

Commit

Permalink
policy update protection test
Browse files Browse the repository at this point in the history
Signed-off-by: Emil Elizarov <emil.elizarov@ibm.com>
  • Loading branch information
Emil Elizarov committed Aug 7, 2023
1 parent c8e012b commit 5f4fc1b
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 1 deletion.
139 changes: 139 additions & 0 deletions integration/smartbft/smartbft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"syscall"
"time"

"github.com/hyperledger/fabric/protoutil"

"github.com/golang/protobuf/proto"

"github.com/hyperledger/fabric/integration/channelparticipation"
Expand Down Expand Up @@ -457,6 +459,143 @@ var _ = Describe("EndToEnd Smart BFT configuration test", func() {
assertBlockReception(map[string]int{"testchannel1": 16}, network.Orderers, peer, network)
})

It("smartbft policy update protection works properly", func() {
By("Create network and run orderers and peer")
networkConfig := nwo.MultiNodeSmartBFT()
networkConfig.Channels = nil

network = nwo.New(networkConfig, testDir, client, StartPort(), components)
network.GenerateConfigTree()
network.Bootstrap()

network.EventuallyTimeout *= 2

var ordererRunners []*ginkgomon.Runner
for _, orderer := range network.Orderers {
runner := network.OrdererRunner(orderer)
runner.Command.Env = append(runner.Command.Env, "FABRIC_LOGGING_SPEC=orderer.common.cluster=debug:orderer.consensus.smartbft=debug:policies.ImplicitOrderer=debug")
ordererRunners = append(ordererRunners, runner)
proc := ifrit.Invoke(runner)
ordererProcesses = append(ordererProcesses, proc)
Eventually(proc.Ready(), network.EventuallyTimeout).Should(BeClosed())
}

peerRunner := network.PeerGroupRunner()
peerProcesses = ifrit.Invoke(peerRunner)

Eventually(peerProcesses.Ready(), network.EventuallyTimeout).Should(BeClosed())
peer := network.Peer("Org1", "peer0")

sess, err := network.ConfigTxGen(commands.OutputBlock{
ChannelID: "testchannel1",
Profile: network.Profiles[0].Name,
ConfigPath: network.RootDir,
OutputBlock: network.OutputBlockPath("testchannel1"),
})
Expect(err).NotTo(HaveOccurred())
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))

genesisBlockBytes, err := os.ReadFile(network.OutputBlockPath("testchannel1"))
Expect(err).NotTo(HaveOccurred())

genesisBlock := &common.Block{}
err = proto.Unmarshal(genesisBlockBytes, genesisBlock)
Expect(err).NotTo(HaveOccurred())

expectedChannelInfoPT := channelparticipation.ChannelInfo{
Name: "testchannel1",
URL: "/participation/v1/channels/testchannel1",
Status: "active",
ConsensusRelation: "consenter",
Height: 1,
}

for _, o := range network.Orderers {
By("joining " + o.Name + " to channel as a consenter")
channelparticipation.Join(network, o, "testchannel1", genesisBlock, expectedChannelInfoPT)
channelInfo := channelparticipation.ListOne(network, o, "testchannel1")
Expect(channelInfo).To(Equal(expectedChannelInfoPT))
}

By("Waiting for followers to see the leader")
Eventually(ordererRunners[1].Err(), network.EventuallyTimeout, time.Second).Should(gbytes.Say("Message from 1"))
Eventually(ordererRunners[2].Err(), network.EventuallyTimeout, time.Second).Should(gbytes.Say("Message from 1"))
Eventually(ordererRunners[3].Err(), network.EventuallyTimeout, time.Second).Should(gbytes.Say("Message from 1"))

channel := "testchannel1"
By(fmt.Sprintf("Peers with Channel %s are %+v\n", channel, network.PeersWithChannel(channel)))
orderer := network.Orderers[0]
network.JoinChannel(channel, orderer, network.PeersWithChannel(channel)...)

By("Adding a new orderer")
orderer5 := &nwo.Orderer{
Name: "orderer5",
Organization: "OrdererOrg",
Id: 5,
}
network.Orderers = append(network.Orderers, orderer5)

ports := nwo.Ports{}
for _, portName := range nwo.OrdererPortNames() {
ports[portName] = network.ReservePort()
}
network.PortsByOrdererID[orderer5.ID()] = ports

network.GenerateCryptoConfig()
network.GenerateOrdererConfig(orderer5)

sess, err = network.Cryptogen(commands.Extend{
Config: network.CryptoConfigPath(),
Input: network.CryptoPath(),
})
Expect(err).NotTo(HaveOccurred())
Eventually(sess, network.EventuallyTimeout).Should(gexec.Exit(0))

ordererCertificatePath := filepath.Join(network.OrdererLocalTLSDir(orderer5), "server.crt")
ordererCertificate, err := ioutil.ReadFile(ordererCertificatePath)
Expect(err).NotTo(HaveOccurred())

ordererIdentity, err := ioutil.ReadFile(network.OrdererCert(orderer5))
Expect(err).NotTo(HaveOccurred())

By("Update the new orderer using config update without updating the policy")
config := nwo.GetConfig(network, peer, orderer, channel)
updatedConfig := proto.Clone(config).(*common.Config)
rawOrderers := updatedConfig.ChannelGroup.Groups["Orderer"].Values["Orderers"]
orderersVal := &common.Orderers{}
Expect(proto.Unmarshal(rawOrderers.Value, orderersVal)).To(Succeed())
orderersVal.ConsenterMapping = append(orderersVal.ConsenterMapping, &common.Consenter{
MspId: "OrdererMSP",
Id: 5,
Identity: ordererIdentity,
ServerTlsCert: ordererCertificate,
ClientTlsCert: ordererCertificate,
Host: "127.0.0.1",
Port: uint32(network.OrdererPort(orderer5, nwo.ClusterPort)),
})
rawOrderers.Value, err = proto.Marshal(orderersVal)
Expect(err).NotTo(HaveOccurred())
updatedConfig.ChannelGroup.Groups["Orderer"].Values["Orderers"].Value = protoutil.MarshalOrPanic(orderersVal)

tempDir, err := ioutil.TempDir(network.RootDir, "updateConfig")
Expect(err).NotTo(HaveOccurred())
updateFile := filepath.Join(tempDir, "update.pb")
defer os.RemoveAll(tempDir)

nwo.ComputeUpdateOrdererConfig(updateFile, network, channel, config, updatedConfig, peer, orderer)

sess, err = network.OrdererAdminSession(orderer, peer, commands.ChannelUpdate{
ChannelID: channel,
Orderer: network.OrdererAddress(orderer, nwo.ListenPort),
File: updateFile,
ClientAuth: network.ClientAuthRequired,
})
Expect(err).NotTo(HaveOccurred())
sess.Wait(network.EventuallyTimeout)
Expect(sess.ExitCode()).ToNot(Equal(0))
Expect(sess.Err).To(gbytes.Say("block validation policy should be a signature policy"))
})

It("smartbft assisted synchronization no rotation", func() {
networkConfig := nwo.MultiNodeSmartBFT()
networkConfig.Channels = nil
Expand Down
4 changes: 3 additions & 1 deletion orderer/consensus/smartbft/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,9 @@ func (c *BFTChain) Order(env *cb.Envelope, configSeq uint64) error {
// discarding the message if the reconfiguration is no longer valid.
// The consenter may return an error, indicating the message was not accepted
func (c *BFTChain) Configure(config *cb.Envelope, configSeq uint64) error {
// TODO: check configuration update validity
if err := c.verifier.ConfigValidator.ValidateConfig(config); err != nil {
return err
}
seq := c.support.Sequence()
if configSeq < seq {
c.Logger.Warnf("Normal message was validated against %d, although current config seq has advanced (%d)", configSeq, seq)
Expand Down

0 comments on commit 5f4fc1b

Please sign in to comment.