diff --git a/common/configtx/tool/provisional/provisional.go b/common/configtx/tool/provisional/provisional.go index 57776a3e03e..074a92fb78b 100644 --- a/common/configtx/tool/provisional/provisional.go +++ b/common/configtx/tool/provisional/provisional.go @@ -63,8 +63,6 @@ const ( ConsensusTypeSolo = "solo" // ConsensusTypeKafka identifies the Kafka-based consensus implementation. ConsensusTypeKafka = "kafka" - // ConsensusTypeSbft identifies the SBFT consensus implementation. - ConsensusTypeSbft = "sbft" // TestChainID is the default value of ChainID. It is used by all testing // networks. It it necessary to set and export this variable so that test @@ -131,7 +129,7 @@ func New(conf *genesisconfig.Profile) Generator { } switch conf.Orderer.OrdererType { - case ConsensusTypeSolo, ConsensusTypeSbft: + case ConsensusTypeSolo: case ConsensusTypeKafka: bs.ordererGroups = append(bs.ordererGroups, config.TemplateKafkaBrokers(conf.Orderer.Kafka.Brokers)) default: diff --git a/examples/cluster/config/core.yaml b/examples/cluster/config/core.yaml index 7370d3478ef..70c02f80f2f 100644 --- a/examples/cluster/config/core.yaml +++ b/examples/cluster/config/core.yaml @@ -240,7 +240,7 @@ peer: # SHA2 is hardcoded in several places, not only BCCSP Hash: SHA2 Security: 256 - # Location of Key Store, can be subdirectory of SbftLocal.DataDir + # Location of Key Store FileKeyStore: # If "", defaults to 'mspConfigPath'/keystore # TODO: Ensure this is read with fabric/core/config.GetPath() once ready diff --git a/examples/cluster/config/orderer.yaml b/examples/cluster/config/orderer.yaml index c080e1eb9f4..73bb5295d6a 100644 --- a/examples/cluster/config/orderer.yaml +++ b/examples/cluster/config/orderer.yaml @@ -159,49 +159,3 @@ Kafka: # certificates from the Kafka cluster. RootCAs: #File: uncomment to read Certificate from a file - -################################################################################ -# -# SECTION: SBFT Local -# -# - This section applies to the configuration of the SBFT-based orderer. -# -################################################################################ -SbftLocal: - - # Address to use for SBFT internal communication - PeerCommAddr: ":6101" - CertFile: "sbft/testdata/cert1.pem" - KeyFile: "sbft/testdata/key.pem" - # Directory for SBFT data (persistence) - DataDir: "/tmp" - -################################################################################ -# -# SECTION: Genesis -# -# - This section is pending removal but is left to support SBFT -# to be migrated to configtx.yaml. -# -################################################################################ -Genesis: - - # Deprecated Batch Timeout: The amount of time to wait before creating a - # batch. - DeprecatedBatchTimeout: 10s - - # DeprecatedBatchSize: The absolute maximum number of bytes allowed for - # the serialized messages in a batch. - DeprecatedBatchSize: 99 MB - - # Defines the SBFT parameters when 'sbft' is specified as the 'OrdererType' - SbftShared: - # Number of peers - "N": 1 - # Fault tolerance - F: 0 - # Timeout of requests (seconds) - RequestTimeoutNsec: 1000000000 - # Peers (PeerCommAddr) with the path of their cert - Peers: - ":6101": "sbft/testdata/cert1.pem" diff --git a/orderer/localconfig/config.go b/orderer/localconfig/config.go index 8c5a8789402..d4380270b18 100644 --- a/orderer/localconfig/config.go +++ b/orderer/localconfig/config.go @@ -64,8 +64,6 @@ type TopLevel struct { FileLedger FileLedger RAMLedger RAMLedger Kafka Kafka - Genesis Genesis - SbftLocal SbftLocal } // General contains config which should be common among all orderer types. @@ -125,32 +123,6 @@ type Retry struct { Stop time.Duration } -// Genesis is a deprecated structure which was used to put -// values into the genesis block, but this is now handled elsewhere. -// SBFT did not reference these values via the genesis block however -// so it is being left here for backwards compatibility purposes. -type Genesis struct { - DeprecatedBatchTimeout time.Duration - DeprecatedBatchSize uint32 - SbftShared SbftShared -} - -// SbftLocal contains configuration for the SBFT peer/replica. -type SbftLocal struct { - PeerCommAddr string - CertFile string - KeyFile string - DataDir string -} - -// SbftShared contains config for the SBFT network. -type SbftShared struct { - N uint64 - F uint64 - RequestTimeoutNsec uint64 - Peers map[string]string // Address to Cert mapping -} - var defaults = TopLevel{ General: General{ LedgerType: "file", @@ -186,20 +158,6 @@ var defaults = TopLevel{ Enabled: false, }, }, - Genesis: Genesis{ - SbftShared: SbftShared{ - N: 1, - F: 0, - RequestTimeoutNsec: uint64(time.Second.Nanoseconds()), - Peers: map[string]string{":6101": "sbft/testdata/cert1.pem"}, - }, - }, - SbftLocal: SbftLocal{ - PeerCommAddr: ":6101", - CertFile: "sbft/testdata/cert1.pem", - KeyFile: "sbft/testdata/key.pem", - DataDir: "/tmp", - }, } // Load parses the orderer.yaml file and environment, producing a struct suitable for config use diff --git a/orderer/main.go b/orderer/main.go index 5f0498bdd58..65ed9324ad4 100644 --- a/orderer/main.go +++ b/orderer/main.go @@ -35,7 +35,6 @@ import ( "github.com/hyperledger/fabric/orderer/ledger" "github.com/hyperledger/fabric/orderer/localconfig" "github.com/hyperledger/fabric/orderer/multichain" - "github.com/hyperledger/fabric/orderer/sbft" "github.com/hyperledger/fabric/orderer/solo" cb "github.com/hyperledger/fabric/protos/common" ab "github.com/hyperledger/fabric/protos/orderer" @@ -194,7 +193,6 @@ func initializeMultiChainManager(conf *config.TopLevel, signer crypto.LocalSigne consenters := make(map[string]multichain.Consenter) consenters["solo"] = solo.New() consenters["kafka"] = kafka.New(conf.Kafka.Version, conf.Kafka.Retry, conf.Kafka.TLS) - consenters["sbft"] = sbft.New(makeSbftConsensusConfig(conf), makeSbftStackConfig(conf)) return multichain.NewManagerImpl(lf, consenters, signer) } diff --git a/orderer/network_test.go b/orderer/network_test.go deleted file mode 100644 index be447255f76..00000000000 --- a/orderer/network_test.go +++ /dev/null @@ -1,512 +0,0 @@ -/* -Copyright Digital Asset Holdings, LLC 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "crypto/rand" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "fmt" - "io/ioutil" - "math" - "math/big" - "os" - "os/exec" - "runtime" - "testing" - "time" - - "encoding/json" - - "github.com/golang/protobuf/proto" - genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig" - "github.com/hyperledger/fabric/common/configtx/tool/provisional" - cb "github.com/hyperledger/fabric/protos/common" - ab "github.com/hyperledger/fabric/protos/orderer" - "github.com/hyperledger/fabric/protos/utils" - "github.com/op/go-logging" - "golang.org/x/net/context" - "google.golang.org/grpc" -) - -const ppc64 = "ppc64le" - -const keyfile = "sbft/testdata/key.pem" -const maindir = "github.com/hyperledger/fabric/orderer" - -var ordererDir string -var mainexe string - -type Peer struct { - id uint64 - cancel context.CancelFunc - cmd *exec.Cmd -} - -type Receiver struct { - id uint64 - retch chan []byte - signals chan bool -} - -func skipInShortMode(t *testing.T) { - if testing.Short() { - t.Skip("Skipping test in short mode.") - } -} - -func build() { - buildcmd := exec.Command("go", "build", "-o", mainexe, maindir) - buildcmd.Stdout = os.Stdout - buildcmd.Stderr = os.Stderr - panicOnError(buildcmd.Run()) -} - -func deleteExe() { - panicOnError(os.Remove(mainexe)) -} - -func TestMain(m *testing.M) { - var err error - ordererDir, err = os.Getwd() - if err != nil { - panic(err) - } - mainexe = os.TempDir() + "/" + "orderer" - - build() - code := m.Run() - deleteExe() - os.Exit(code) -} - -func TestTwoReplicasBroadcastAndDeliverUsingTheSame(t *testing.T) { - parallelIfNotPpc64(t) - startingPort := 2000 - skipInShortMode(t) - peers := InitPeers(2, startingPort) - StartPeers(peers) - r, err := Receive(peers[0], startingPort) - defer r.Stop() - defer StopPeers(peers) - if err != nil { - t.Errorf("Failed to start up receiver: %s", err) - } - WaitForConnection(peers) - if berr := Broadcast(peers[0], startingPort, []byte{0, 1, 2, 3, 4}); berr != nil { - t.Errorf("Failed to broadcast message: %s", berr) - } - if !AssertWithTimeout(func() bool { - return r.Received() == 2 - }, 30) { - t.Errorf("Failed to receive some messages. (Received %d)", r.Received()) - } -} - -func TestTwoReplicasBroadcastAndDeliverUsingDifferent(t *testing.T) { - parallelIfNotPpc64(t) - logging.SetLevel(logging.DEBUG, "sbft") - startingPort := 2500 - skipInShortMode(t) - peers := InitPeers(2, startingPort) - StartPeers(peers) - r, err := Receive(peers[1], startingPort) - defer r.Stop() - defer StopPeers(peers) - if err != nil { - t.Errorf("Failed to start up receiver: %s", err) - } - WaitForConnection(peers) - if berr := Broadcast(peers[0], startingPort, []byte{0, 1, 2, 3, 4}); berr != nil { - t.Errorf("Failed to broadcast message: %s", berr) - } - if !AssertWithTimeout(func() bool { - return r.Received() == 2 - }, 30) { - t.Errorf("Failed to receive some messages. (Received %d)", r.Received()) - } -} - -func TestTenReplicasBroadcastAndDeliverUsingDifferent(t *testing.T) { - parallelIfNotPpc64(t) - startingPort := 3000 - skipInShortMode(t) - peers := InitPeers(10, startingPort) - StartPeers(peers) - r, err := Receive(peers[9], startingPort) - defer r.Stop() - defer StopPeers(peers) - if err != nil { - t.Errorf("Failed to start up receiver: %s", err) - } - WaitForConnection(peers) - if berr := Broadcast(peers[1], startingPort, []byte{0, 1, 2, 3, 4}); berr != nil { - t.Errorf("Failed to broadcast message: %s", berr) - } - if !AssertWithTimeout(func() bool { - return r.Received() == 2 - }, 30) { - t.Errorf("Failed to receive some messages. (Received %d)", r.Received()) - } -} - -func TestFourReplicasBombedWithBroadcasts(t *testing.T) { - parallelIfNotPpc64(t) - startingPort := 4000 - skipInShortMode(t) - // Add for debug mode: - // logging.SetLevel(logging.DEBUG, "sbft") - broadcastCount := 15 - peers := InitPeers(4, startingPort) - StartPeers(peers) - r, err := Receive(peers[2], startingPort) - defer r.Stop() - defer StopPeers(peers) - if err != nil { - t.Errorf("Failed to start up receiver: %s", err) - } - WaitForConnection(peers) - for x := 0; x < broadcastCount; x++ { - if berr := Broadcast(peers[2], startingPort, []byte{0, 1, 2, byte(x), 3, 4, byte(x)}); berr != nil { - t.Errorf("Failed to broadcast message: %s (broadcast number %d)", berr, x) - } - time.Sleep(time.Second) - } - if !AssertWithTimeout(func() bool { - return r.Received() == broadcastCount+1 - }, 30) { - t.Errorf("Failed to receive some messages. (Received %d)", r.Received()) - } -} - -func TestTenReplicasBombedWithBroadcasts(t *testing.T) { - parallelIfNotPpc64(t) - startingPort := 5000 - skipInShortMode(t) - broadcastCount := 15 - peers := InitPeers(10, startingPort) - StartPeers(peers) - r, err := Receive(peers[3], startingPort) - defer r.Stop() - defer StopPeers(peers) - if err != nil { - t.Errorf("Failed to start up receiver: %s", err) - } - WaitForConnection(peers) - for x := 0; x < broadcastCount; x++ { - if berr := Broadcast(peers[2], startingPort, []byte{0, 1, 2, byte(x), 3, 4, byte(x)}); berr != nil { - t.Errorf("Failed to broadcast message: %s (broadcast number %d)", berr, x) - } - time.Sleep(time.Second) - } - if !AssertWithTimeout(func() bool { - return r.Received() == broadcastCount+1 - }, 60) { - t.Errorf("Failed to receive some messages. (Received %d)", r.Received()) - } -} - -func TestTenReplicasBombedWithBroadcastsIfLedgersConsistent(t *testing.T) { - parallelIfNotPpc64(t) - startingPort := 6000 - skipInShortMode(t) - broadcastCount := 15 - peers := InitPeers(10, startingPort) - StartPeers(peers) - defer StopPeers(peers) - - receivers := make([]*Receiver, 0, len(peers)) - for i := 0; i < len(peers); i++ { - r, err := Receive(peers[i], startingPort) - if err != nil { - t.Errorf("Failed to start up receiver: %s", err) - } - receivers = append(receivers, r) - } - - WaitForConnection(peers) - for x := 0; x < broadcastCount; x++ { - if berr := Broadcast(peers[2], startingPort, []byte{0, 1, 2, byte(x), 3, 4, byte(x)}); berr != nil { - t.Errorf("Failed to broadcast message: %s (broadcast number %d)", berr, x) - } - time.Sleep(time.Second) - } - - for i := 0; i < len(receivers); i++ { - r := receivers[i] - if !AssertWithTimeout(func() bool { - return r.Received() == broadcastCount+1 - }, 60) { - t.Errorf("Failed to receive some messages. (Received %d)", r.Received()) - } - } - for _, r := range receivers { - r.Stop() - } -} - -func parallelIfNotPpc64(t *testing.T) { - if runtime.GOARCH != ppc64 { - t.Parallel() - } -} - -func InitPeers(num uint64, startingPort int) []*Peer { - peers := make([]*Peer, 0, num) - certFiles := make([]string, 0, num) - peersWithCerts := map[string]string{} - for i := uint64(0); i < num; i++ { - certFile := generateCertificate(i, keyfile) - certFiles = append(certFiles, certFile) - peerCommPort := listenAddress(i, startingPort) - peersWithCerts[peerCommPort] = certFile - } - for i := uint64(0); i < num; i++ { - peerCommPort := listenAddress(i, startingPort) - grpcPort := grpcPort(i, startingPort) - configEnv := generateConfigEnv(num, grpcPort, peerCommPort, certFiles[i], peersWithCerts) - peers = append(peers, initPeer(i, configEnv)) - } - return peers -} - -func StartPeers(peers []*Peer) { - for _, p := range peers { - p.start() - if runtime.GOARCH == ppc64 { - time.Sleep(3 * time.Second) - } - } -} - -func StopPeers(peers []*Peer) { - for _, p := range peers { - p.stop() - } -} - -func generateConfigEnv(peerNum uint64, grpcPort int, peerCommPort string, certFile string, peersWithCerts map[string]string) []string { - tempDir, err := ioutil.TempDir("", "sbft_test_config") - panicOnError(err) - envs := []string{} - envs = append(envs, fmt.Sprintf("ORDERER_GENERAL_LEDGERTYPE=%s", "ram")) - envs = append(envs, fmt.Sprintf("ORDERER_GENERAL_LOCALMSPDIR=%s", ordererDir+"/../sampleconfig/msp")) - envs = append(envs, fmt.Sprintf("ORDERER_GENERAL_LISTENPORT=%d", grpcPort)) - envs = append(envs, fmt.Sprintf("CONFIGTX_ORDERER_ORDERERTYPE=%s", "sbft")) - envs = append(envs, fmt.Sprintf("ORDERER_GENERAL_GENESISPROFILE=%s", genesisconfig.SampleInsecureProfile)) - envs = append(envs, fmt.Sprintf("ORDERER_GENESIS_DEPRECATEDBATCHTIMEOUT=%d", 1000)) - envs = append(envs, fmt.Sprintf("ORDERER_GENESIS_DEPRECATED=%d", 1000000000)) - envs = append(envs, fmt.Sprintf("ORDERER_GENESIS_SBFTSHARED_REQUESTTIMEOUTNSEC=%d", 1000000000)) - envs = append(envs, fmt.Sprintf("ORDERER_GENESIS_SBFTSHARED_N=%d", peerNum)) - envs = append(envs, fmt.Sprintf("ORDERER_GENESIS_SBFTSHARED_F=%d", (peerNum-1)/3)) - js, _ := json.Marshal(peersWithCerts) - envs = append(envs, fmt.Sprintf("ORDERER_GENESIS_SBFTSHARED_PEERS=%s", js)) - envs = append(envs, fmt.Sprintf("ORDERER_SBFTLOCAL_PEERCOMMADDR=%s", peerCommPort)) - envs = append(envs, fmt.Sprintf("ORDERER_SBFTLOCAL_CERTFILE=%s", certFile)) - envs = append(envs, fmt.Sprintf("ORDERER_SBFTLOCAL_KEYFILE=%s", keyfile)) - envs = append(envs, fmt.Sprintf("ORDERER_SBFTLOCAL_DATADIR=%s", tempDir)) - return envs -} - -func initPeer(uid uint64, configEnv []string) (p *Peer) { - ctx, cancel := context.WithCancel(context.Background()) - p = &Peer{id: uid, cancel: cancel} - p.cmd = exec.CommandContext(ctx, mainexe) - p.cmd.Stdout = os.Stdout - p.cmd.Stderr = os.Stderr - p.cmd.Env = append(configEnv, os.Environ()...) - return -} - -func (p *Peer) start() { - err := p.cmd.Start() - panicOnError(err) -} - -func (p *Peer) stop() { - p.cancel() - p.cmd.Wait() -} - -func Broadcast(p *Peer, startingPort int, bytes []byte) error { - timeout := 5 * time.Second - grpcAddress := grpcAddress(p.id, startingPort) - logger.Warningf("Broadcast - dialing: %s", grpcAddress) - clientconn, err := grpc.Dial(grpcAddress, grpc.WithBlock(), grpc.WithTimeout(timeout), grpc.WithInsecure()) - if err != nil { - logger.Warning("Broadcast - failure") - return err - } - defer clientconn.Close() - client := ab.NewAtomicBroadcastClient(clientconn) - bstream, err := client.Broadcast(context.Background()) - if err != nil { - return err - } - h := &cb.Header{ - ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{ChannelId: provisional.TestChainID}), - SignatureHeader: utils.MarshalOrPanic(&cb.SignatureHeader{})} - pl := &cb.Payload{Data: bytes, Header: h} - mpl, err := proto.Marshal(pl) - panicOnError(err) - logger.Warningf("Broadcast - sending: %s", grpcAddress) - if e := bstream.Send(&cb.Envelope{Payload: mpl}); e != nil { - return e - } - _, err = bstream.Recv() - panicOnError(err) - logger.Warningf("Broadcast - done: %s", grpcAddress) - return nil -} - -func Receive(p *Peer, startingPort int) (*Receiver, error) { - retch := make(chan []byte, 100) - signals := make(chan bool, 100) - timeout := 4 * time.Second - grpcAddress := grpcAddress(p.id, startingPort) - logger.Warning("Receiver - dial") - clientconn, err := grpc.Dial(grpcAddress, grpc.WithBlock(), grpc.WithTimeout(timeout), grpc.WithInsecure()) - if err != nil { - return nil, err - } - client := ab.NewAtomicBroadcastClient(clientconn) - dstream, err := client.Deliver(context.Background()) - if err != nil { - return nil, err - } - dstream.Send(&cb.Envelope{ - Payload: utils.MarshalOrPanic(&cb.Payload{ - Header: &cb.Header{ - ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{ - ChannelId: provisional.TestChainID, - }), - SignatureHeader: utils.MarshalOrPanic(&cb.SignatureHeader{}), - }, - - Data: utils.MarshalOrPanic(&ab.SeekInfo{ - Start: &ab.SeekPosition{Type: &ab.SeekPosition_Newest{Newest: &ab.SeekNewest{}}}, - Stop: &ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: math.MaxUint64}}}, - Behavior: ab.SeekInfo_BLOCK_UNTIL_READY, - }), - }), - }) - - go func() { - num := uint64(0) - for { - select { - case <-signals: - clientconn.Close() - return - default: - m, inerr := dstream.Recv() - if inerr != nil { - clientconn.Close() - return - } - b, ok := m.Type.(*ab.DeliverResponse_Block) - if !ok { - continue - } - for _, tx := range b.Block.Data.Data { - pl := &cb.Payload{} - e := &cb.Envelope{} - merr1 := proto.Unmarshal(tx, e) - merr2 := proto.Unmarshal(e.Payload, pl) - if merr1 == nil && merr2 == nil { - logger.Warning("Receiver - received a message") - retch <- tx - num++ - } - } - } - } - }() - return &Receiver{id: p.id, retch: retch, signals: signals}, nil -} - -func (r *Receiver) Received() int { - return len(r.retch) -} - -func (r *Receiver) Stop() { - close(r.signals) -} - -func AssertWithTimeout(assertion func() bool, timeoutSec int) bool { - for spent := 0; spent <= timeoutSec && !assertion(); spent++ { - time.Sleep(time.Second) - } - return assertion() -} - -func WaitForConnection(peers []*Peer) { - l := len(peers) - m := math.Max(float64(3), float64(l-3)) - _ = <-time.After(time.Duration(m) * time.Second) -} - -func listenAddress(id uint64, startingPort int) string { - return fmt.Sprintf(":%d", startingPort+2*int(id)) -} - -func grpcAddress(id uint64, startingPort int) string { - return fmt.Sprintf(":%d", grpcPort(id, startingPort)) -} - -func grpcPort(id uint64, startingPort int) int { - return startingPort + 1 + 2*int(id) -} - -func generateCertificate(id uint64, keyFile string) string { - tempDir, err := ioutil.TempDir("", "sbft_test_cert") - panicOnError(err) - readBytes, err := ioutil.ReadFile(keyFile) - panicOnError(err) - b, _ := pem.Decode(readBytes) - priv, err := x509.ParsePKCS1PrivateKey(b.Bytes) - panicOnError(err) - notBefore := time.Now() - notAfter := notBefore.Add(time.Hour) - template := x509.Certificate{ - SerialNumber: big.NewInt(int64(id)), - Subject: pkix.Name{ - Organization: []string{"Acme Co"}, - }, - NotBefore: notBefore, - NotAfter: notAfter, - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) - panicOnError(err) - certPath := fmt.Sprintf("%s/cert%d.pem", tempDir, id) - certOut, err := os.Create(certPath) - panicOnError(err) - pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) - certOut.Close() - return certPath -} - -func panicOnError(err error) { - if err != nil { - panic(err) - } -} diff --git a/orderer/sample_clients/single_tx_client/single_tx_client.go b/orderer/sample_clients/single_tx_client/single_tx_client.go index 2ed76b8722a..a0189265d58 100644 --- a/orderer/sample_clients/single_tx_client/single_tx_client.go +++ b/orderer/sample_clients/single_tx_client/single_tx_client.go @@ -31,7 +31,7 @@ import ( "google.golang.org/grpc" ) -var logger = logging.MustGetLogger("sbft_test") +var logger = logging.MustGetLogger("single_tx_client") var UPDATE byte = 0 var SEND byte = 1 diff --git a/orderer/sbft/.protoroot b/orderer/sbft/.protoroot deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/orderer/sbft/backend/backend.go b/orderer/sbft/backend/backend.go deleted file mode 100644 index 89c7abc8627..00000000000 --- a/orderer/sbft/backend/backend.go +++ /dev/null @@ -1,529 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package backend - -import ( - "bytes" - "fmt" - "io" - "sort" - "strings" - "sync" - "time" - - "golang.org/x/net/context" - "google.golang.org/grpc" - "google.golang.org/grpc/transport" - - "crypto/ecdsa" - crand "crypto/rand" - "math/big" - - "crypto" - "crypto/rsa" - "crypto/sha256" - "encoding/asn1" - "encoding/gob" - - "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric/orderer/common/filter" - commonfilter "github.com/hyperledger/fabric/orderer/common/filter" - "github.com/hyperledger/fabric/orderer/multichain" - "github.com/hyperledger/fabric/orderer/sbft/connection" - "github.com/hyperledger/fabric/orderer/sbft/persist" - s "github.com/hyperledger/fabric/orderer/sbft/simplebft" - cb "github.com/hyperledger/fabric/protos/common" - "github.com/op/go-logging" -) - -const headerIndex = 0 -const signaturesIndex = 1 -const metadataLen = 2 - -var logger = logging.MustGetLogger("backend") - -type Backend struct { - conn *connection.Manager - lock sync.Mutex - peers map[uint64]chan<- *s.MultiChainMsg - queue chan Executable - persistence *persist.Persist - - self *PeerInfo - // address to PeerInfo mapping - peerInfo map[string]*PeerInfo - - // chainId to instance mapping - consensus map[string]s.Receiver - lastBatches map[string]*s.Batch - supports map[string]multichain.ConsenterSupport -} - -type consensusConn Backend - -type StackConfig struct { - ListenAddr string - CertFile string - KeyFile string - DataDir string -} - -type PeerInfo struct { - info connection.PeerInfo - id uint64 -} - -type peerInfoSlice []*PeerInfo - -func (pi peerInfoSlice) Len() int { - return len(pi) -} - -func (pi peerInfoSlice) Less(i, j int) bool { - return strings.Compare(pi[i].info.Fingerprint(), pi[j].info.Fingerprint()) == -1 -} - -func (pi peerInfoSlice) Swap(i, j int) { - pi[i], pi[j] = pi[j], pi[i] -} - -func NewBackend(peers map[string][]byte, conn *connection.Manager, persist *persist.Persist) (*Backend, error) { - c := &Backend{ - conn: conn, - peers: make(map[uint64]chan<- *s.MultiChainMsg), - peerInfo: make(map[string]*PeerInfo), - supports: make(map[string]multichain.ConsenterSupport), - consensus: make(map[string]s.Receiver), - lastBatches: make(map[string]*s.Batch), - } - - var peerInfo []*PeerInfo - for addr, cert := range peers { - pi, err := connection.NewPeerInfo(addr, cert) - if err != nil { - return nil, err - } - cpi := &PeerInfo{info: pi} - if pi.Fingerprint() == conn.Self.Fingerprint() { - c.self = cpi - } - peerInfo = append(peerInfo, cpi) - c.peerInfo[pi.Fingerprint()] = cpi - } - - sort.Sort(peerInfoSlice(peerInfo)) - for i, pi := range peerInfo { - pi.id = uint64(i) - logger.Infof("replica %d: %s", i, pi.info.Fingerprint()) - } - - if c.self == nil { - return nil, fmt.Errorf("peer list does not contain local node") - } - - logger.Infof("we are replica %d (%s)", c.self.id, c.self.info) - - for _, peer := range c.peerInfo { - if peer == c.self { - continue - } - go c.connectWorker(peer) - } - RegisterConsensusServer(conn.Server, (*consensusConn)(c)) - c.persistence = persist - c.queue = make(chan Executable) - go c.run() - return c, nil -} - -// GetMyId returns the ID of the backend in the SFTT network (1..N) -func (b *Backend) GetMyId() uint64 { - return b.self.id -} - -// Enqueue enqueues an Envelope for a chainId for ordering, marshalling it first -func (b *Backend) Enqueue(chainID string, env *cb.Envelope) bool { - requestbytes, err := proto.Marshal(env) - if err != nil { - return false - } - b.enqueueRequest(chainID, requestbytes) - return true -} - -func (b *Backend) connectWorker(peer *PeerInfo) { - timeout := 1 * time.Second - - delay := time.After(0) - for { - // pace reconnect attempts - <-delay - - // set up for next - delay = time.After(timeout) - - logger.Infof("connecting to replica %d (%s)", peer.id, peer.info) - conn, err := b.conn.DialPeer(peer.info, grpc.WithBlock(), grpc.WithTimeout(timeout)) - if err != nil { - logger.Warningf("could not connect to replica %d (%s): %s", peer.id, peer.info, err) - continue - } - - ctx := context.TODO() - - client := NewConsensusClient(conn) - consensus, err := client.Consensus(ctx, &Handshake{}) - if err != nil { - logger.Warningf("could not establish consensus stream with replica %d (%s): %s", peer.id, peer.info, err) - continue - } - logger.Noticef("connection to replica %d (%s) established", peer.id, peer.info) - - for { - msg, err := consensus.Recv() - if err == io.EOF || err == transport.ErrConnClosing { - break - } - if err != nil { - logger.Warningf("consensus stream with replica %d (%s) broke: %v", peer.id, peer.info, err) - break - } - b.enqueueForReceive(msg.ChainID, msg.Msg, peer.id) - } - } -} - -func (b *Backend) enqueueConnection(chainID string, peerid uint64) { - go func() { - b.queue <- &connectionEvent{chainID: chainID, peerid: peerid} - }() -} - -func (b *Backend) enqueueRequest(chainID string, request []byte) { - go func() { - b.queue <- &requestEvent{chainId: chainID, req: request} - }() -} - -func (b *Backend) enqueueForReceive(chainID string, msg *s.Msg, src uint64) { - go func() { - b.queue <- &msgEvent{chainId: chainID, msg: msg, src: src} - }() -} - -func (b *Backend) initTimer(t *Timer, d time.Duration) { - send := func() { - if t.execute { - b.queue <- t - } - } - time.AfterFunc(d, send) -} - -func (b *Backend) run() { - for { - e := <-b.queue - e.Execute(b) - } -} - -// AddSbftPeer adds a new SBFT peer for the given chainId using the given support and configuration -func (b *Backend) AddSbftPeer(chainID string, support multichain.ConsenterSupport, config *s.Config) (*s.SBFT, error) { - b.supports[chainID] = support - return s.New(b.GetMyId(), chainID, config, b) -} - -func (b *Backend) Validate(chainID string, req *s.Request) ([][]*s.Request, [][]filter.Committer, bool) { - // ([][]*cb.Envelope, [][]filter.Committer, bool) { - // If the message is a valid normal message and fills a batch, the batch, committers, true is returned - // If the message is a valid special message (like a config message) it terminates the current batch - // and returns the current batch and committers (if it is not empty), plus a second batch containing the special transaction and commiter, and true - env := &cb.Envelope{} - err := proto.Unmarshal(req.Payload, env) - if err != nil { - logger.Panicf("Request format error: %s", err) - } - envbatch, committers, accepted := b.supports[chainID].BlockCutter().Ordered(env) - if accepted { - if len(envbatch) == 1 { - rb1 := toRequestBatch(envbatch[0]) - return [][]*s.Request{rb1}, committers, true - } - if len(envbatch) == 2 { - rb1 := toRequestBatch(envbatch[0]) - rb2 := toRequestBatch(envbatch[1]) - return [][]*s.Request{rb1, rb2}, committers, true - } - - return nil, nil, true - } - return nil, nil, false -} - -func (b *Backend) Cut(chainID string) ([]*s.Request, []filter.Committer) { - envbatch, committers := b.supports[chainID].BlockCutter().Cut() - return toRequestBatch(envbatch), committers -} - -func toRequestBatch(envelopes []*cb.Envelope) []*s.Request { - rqs := make([]*s.Request, 0, len(envelopes)) - for _, e := range envelopes { - requestbytes, err := proto.Marshal(e) - if err != nil { - logger.Panicf("Cannot marshal envelope: %s", err) - } - rq := &s.Request{Payload: requestbytes} - rqs = append(rqs, rq) - } - return rqs -} - -// Consensus implements the SBFT consensus gRPC interface -func (c *consensusConn) Consensus(_ *Handshake, srv Consensus_ConsensusServer) error { - pi := connection.GetPeerInfo(srv) - peer, ok := c.peerInfo[pi.Fingerprint()] - - if !ok || !peer.info.Cert().Equal(pi.Cert()) { - logger.Infof("rejecting connection from unknown replica %s", pi) - return fmt.Errorf("unknown peer certificate") - } - logger.Infof("connection from replica %d (%s)", peer.id, pi) - - ch := make(chan *s.MultiChainMsg) - c.lock.Lock() - if oldch, ok := c.peers[peer.id]; ok { - logger.Debugf("replacing connection from replica %d", peer.id) - close(oldch) - } - c.peers[peer.id] = ch - c.lock.Unlock() - - for chainID, _ := range c.supports { - ((*Backend)(c)).enqueueConnection(chainID, peer.id) - } - - var err error - for msg := range ch { - err = srv.Send(msg) - if err != nil { - c.lock.Lock() - delete(c.peers, peer.id) - c.lock.Unlock() - - logger.Infof("lost connection from replica %d (%s): %s", peer.id, pi, err) - } - } - - return err -} - -// Unicast sends to all external SBFT peers -func (b *Backend) Broadcast(msg *s.MultiChainMsg) error { - b.lock.Lock() - for _, ch := range b.peers { - ch <- msg - } - b.lock.Unlock() - return nil -} - -// Unicast sends to a specific external SBFT peer identified by chainId and dest -func (b *Backend) Unicast(chainID string, msg *s.Msg, dest uint64) error { - b.lock.Lock() - ch, ok := b.peers[dest] - b.lock.Unlock() - - if !ok { - err := fmt.Errorf("peer not found: %v", dest) - logger.Debug(err) - return err - } - ch <- &s.MultiChainMsg{Msg: msg, ChainID: chainID} - return nil -} - -// AddReceiver adds a receiver instance for a given chainId -func (b *Backend) AddReceiver(chainId string, recv s.Receiver) { - b.consensus[chainId] = recv - b.lastBatches[chainId] = &s.Batch{Header: nil, Signatures: nil, Payloads: [][]byte{}} -} - -// Send sends to a specific SBFT peer identified by chainId and dest -func (b *Backend) Send(chainID string, msg *s.Msg, dest uint64) { - if dest == b.self.id { - b.enqueueForReceive(chainID, msg, b.self.id) - return - } - b.Unicast(chainID, msg, dest) -} - -// Timer starts a timer -func (b *Backend) Timer(d time.Duration, tf func()) s.Canceller { - tm := &Timer{tf: tf, execute: true} - b.initTimer(tm, d) - return tm -} - -// Deliver writes a block -func (b *Backend) Deliver(chainId string, batch *s.Batch, committers []commonfilter.Committer) { - blockContents := make([]*cb.Envelope, 0, len(batch.Payloads)) - for _, p := range batch.Payloads { - envelope := &cb.Envelope{} - err := proto.Unmarshal(p, envelope) - if err == nil { - blockContents = append(blockContents, envelope) - } else { - logger.Warningf("Payload cannot be unmarshalled.") - } - } - block := b.supports[chainId].CreateNextBlock(blockContents) - - // TODO SBFT needs to use Rawledger's structures and signatures over the Block. - // This a quick and dirty solution to make it work. - block.Metadata = &cb.BlockMetadata{} - metadata := make([][]byte, metadataLen) - metadata[headerIndex] = batch.Header - metadata[signaturesIndex] = encodeSignatures(batch.Signatures) - block.Metadata.Metadata = metadata - b.lastBatches[chainId] = batch - b.supports[chainId].WriteBlock(block, committers, nil) -} - -// Persist persists data identified by a chainId and a key -func (b *Backend) Persist(chainId string, key string, data proto.Message) { - compk := fmt.Sprintf("chain-%s-%s", chainId, key) - if data == nil { - b.persistence.DelState(compk) - } else { - bytes, err := proto.Marshal(data) - if err != nil { - panic(err) - } - b.persistence.StoreState(compk, bytes) - } -} - -// Restore loads persisted data identified by chainId and key -func (b *Backend) Restore(chainId string, key string, out proto.Message) bool { - compk := fmt.Sprintf("chain-%s-%s", chainId, key) - val, err := b.persistence.ReadState(compk) - if err != nil { - return false - } - err = proto.Unmarshal(val, out) - return (err == nil) -} - -// LastBatch returns the last batch for a given chain identified by its ID -func (b *Backend) LastBatch(chainId string) *s.Batch { - return b.lastBatches[chainId] -} - -// Sign signs a given data -func (b *Backend) Sign(data []byte) []byte { - return Sign(b.conn.Cert.PrivateKey, data) -} - -// CheckSig checks a signature -func (b *Backend) CheckSig(data []byte, src uint64, sig []byte) error { - leaf := b.conn.Cert.Leaf - if leaf == nil { - panic("No public key found: certificate leaf is nil.") - } - return CheckSig(leaf.PublicKey, data, sig) -} - -// Reconnect requests connection to a replica identified by its ID and chainId -func (b *Backend) Reconnect(chainId string, replica uint64) { - b.enqueueConnection(chainId, replica) -} - -// Sign signs a given data -func Sign(privateKey crypto.PrivateKey, data []byte) []byte { - var err error - var encsig []byte - hash := sha256.Sum256(data) - switch pvk := privateKey.(type) { - case *rsa.PrivateKey: - encsig, err = pvk.Sign(crand.Reader, hash[:], crypto.SHA256) - if err != nil { - panic(err) - } - case *ecdsa.PrivateKey: - r, s, err := ecdsa.Sign(crand.Reader, pvk, hash[:]) - if err != nil { - panic(err) - } - encsig, _ = asn1.Marshal(struct{ R, S *big.Int }{r, s}) - default: - panic("Unsupported private key type given.") - } - if err != nil { - panic(err) - } - return encsig -} - -// CheckSig checks a signature -func CheckSig(publicKey crypto.PublicKey, data []byte, sig []byte) error { - hash := sha256.Sum256(data) - switch p := publicKey.(type) { - case *ecdsa.PublicKey: - s := struct{ R, S *big.Int }{} - rest, err := asn1.Unmarshal(sig, &s) - if err != nil { - return err - } - if len(rest) != 0 { - return fmt.Errorf("invalid signature (problem with asn unmarshalling for ECDSA)") - } - ok := ecdsa.Verify(p, hash[:], s.R, s.S) - if !ok { - return fmt.Errorf("invalid signature (problem with verification)") - } - return nil - case *rsa.PublicKey: - err := rsa.VerifyPKCS1v15(p, crypto.SHA256, hash[:], sig) - return err - default: - return fmt.Errorf("Unsupported public key type.") - } -} - -func encodeSignatures(signatures map[uint64][]byte) []byte { - var buf bytes.Buffer - enc := gob.NewEncoder(&buf) - err := enc.Encode(signatures) - if err != nil { - panic(err) - } - return buf.Bytes() -} - -func decodeSignatures(encodedSignatures []byte) map[uint64][]byte { - if len(encodedSignatures) == 0 { - return nil - } - buf := bytes.NewBuffer(encodedSignatures) - var r map[uint64][]byte - dec := gob.NewDecoder(buf) - err := dec.Decode(&r) - if err != nil { - panic(err) - } - return r -} diff --git a/orderer/sbft/backend/backend_test.go b/orderer/sbft/backend/backend_test.go deleted file mode 100644 index 133938d3292..00000000000 --- a/orderer/sbft/backend/backend_test.go +++ /dev/null @@ -1,141 +0,0 @@ -/* -Copyright Digital Asset Holdings, LLC 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package backend - -import ( - "crypto/ecdsa" - "crypto/elliptic" - crand "crypto/rand" - "crypto/rsa" - "reflect" - "testing" - - "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric/orderer/common/filter" - "github.com/hyperledger/fabric/orderer/mocks/multichain" - mc "github.com/hyperledger/fabric/orderer/multichain" - "github.com/hyperledger/fabric/orderer/sbft/simplebft" - cb "github.com/hyperledger/fabric/protos/common" -) - -func TestSignAndVerifyRsa(t *testing.T) { - data := []byte{1, 1, 1, 1, 1} - privateKey, err := rsa.GenerateKey(crand.Reader, 1024) - if err != nil { - panic("RSA failed to generate private key in test.") - } - s := Sign(privateKey, data) - if s == nil { - t.Error("Nil signature was generated.") - } - - publicKey := privateKey.Public() - err = CheckSig(publicKey, data, s) - if err != nil { - t.Errorf("Signature check failed: %s", err) - } -} - -func TestSignAndVerifyEcdsa(t *testing.T) { - data := []byte{1, 1, 1, 1, 1} - privateKey, err := ecdsa.GenerateKey(elliptic.P256(), crand.Reader) - if err != nil { - panic("ECDSA failed to generate private key in test.") - } - s := Sign(privateKey, data) - if s == nil { - t.Error("Nil signature was generated.") - } - - publicKey := privateKey.Public() - err = CheckSig(publicKey, data, s) - if err != nil { - t.Errorf("Signature check failed: %s", err) - } -} - -func TestLedgerReadWrite(t *testing.T) { - testChainID1 := "testID1" - testChainID2 := "testID2" - testChainID3 := "testID2" - b := Backend{supports: map[string]mc.ConsenterSupport{}, lastBatches: map[string]*simplebft.Batch{}} - - b.supports[testChainID1] = &multichain.ConsenterSupport{Batches: make(chan []*cb.Envelope, 10)} - b.supports[testChainID2] = &multichain.ConsenterSupport{Batches: make(chan []*cb.Envelope, 10)} - b.supports[testChainID3] = &multichain.ConsenterSupport{Batches: make(chan []*cb.Envelope, 10)} - - header := []byte("header") - e1 := &cb.Envelope{Payload: []byte("data1")} - e2 := &cb.Envelope{Payload: []byte("data2")} - ebytes1, _ := proto.Marshal(e1) - ebytes2, _ := proto.Marshal(e2) - data := [][]byte{ebytes1, ebytes2} - sgns := make(map[uint64][]byte) - sgns[uint64(1)] = []byte("sgn1") - sgns[uint64(22)] = []byte("sgn22") - batch := simplebft.Batch{Header: header, Payloads: data, Signatures: sgns} - - b.Deliver(testChainID1, &batch, []filter.Committer{}) - batch1 := b.LastBatch(testChainID1) - batch2 := b.LastBatch(testChainID2) - b.Deliver(testChainID3, &batch, []filter.Committer{}) - batch3 := b.LastBatch(testChainID3) - - if !reflect.DeepEqual(batch, *batch1) { - t.Errorf("The wrong batch was returned by LastBatch(chainID1) after Deliver: %v (original was: %v)", batch1, &batch) - } - if !reflect.DeepEqual(batch, *batch3) { - t.Errorf("The wrong batch was returned by LastBatch(chainID3) after Deliver: %v (original was: %v)", batch3, &batch) - } - if batch2 != nil { - t.Error("The second chain should be empty.") - } -} - -func TestEncoderEncodesDecodesSgnsWithoutPanic(t *testing.T) { - defer func() { - if r := recover(); r != nil { - t.Errorf("Encoding/decoding failed for valid signatures, code panicked.") - } - }() - sgns1 := make(map[uint64][]byte) - e1 := encodeSignatures(sgns1) - - sgns2 := make(map[uint64][]byte) - sgns2[uint64(1)] = []byte("sgn1") - e2 := encodeSignatures(sgns2) - - sgns3 := make(map[uint64][]byte) - sgns3[uint64(22)] = []byte("sgn22") - sgns3[uint64(143)] = []byte("sgn22") - sgns3[uint64(200)] = []byte("sgn200") - e3 := encodeSignatures(sgns3) - - rsgns1 := decodeSignatures(e1) - rsgns2 := decodeSignatures(e2) - rsgns3 := decodeSignatures(e3) - - if !reflect.DeepEqual(sgns1, rsgns1) { - t.Errorf("Decoding error: %v (original: %v). (1)", rsgns1, sgns1) - } - if !reflect.DeepEqual(sgns2, rsgns2) { - t.Errorf("Decoding error: %v (original: %v). (2)", rsgns2, sgns2) - } - if !reflect.DeepEqual(sgns3, rsgns3) { - t.Errorf("Decoding error: %v (original: %v). (3)", rsgns3, sgns3) - } -} diff --git a/orderer/sbft/backend/consensus.pb.go b/orderer/sbft/backend/consensus.pb.go deleted file mode 100644 index 7bc7c943594..00000000000 --- a/orderer/sbft/backend/consensus.pb.go +++ /dev/null @@ -1,162 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: backend/consensus.proto - -/* -Package backend is a generated protocol buffer package. - -It is generated from these files: - backend/consensus.proto - -It has these top-level messages: - Handshake -*/ -package backend - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import simplebft "github.com/hyperledger/fabric/orderer/sbft/simplebft" - -import ( - context "golang.org/x/net/context" - grpc "google.golang.org/grpc" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type Handshake struct { -} - -func (m *Handshake) Reset() { *m = Handshake{} } -func (m *Handshake) String() string { return proto.CompactTextString(m) } -func (*Handshake) ProtoMessage() {} -func (*Handshake) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -func init() { - proto.RegisterType((*Handshake)(nil), "backend.handshake") -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// Client API for Consensus service - -type ConsensusClient interface { - Consensus(ctx context.Context, in *Handshake, opts ...grpc.CallOption) (Consensus_ConsensusClient, error) -} - -type consensusClient struct { - cc *grpc.ClientConn -} - -func NewConsensusClient(cc *grpc.ClientConn) ConsensusClient { - return &consensusClient{cc} -} - -func (c *consensusClient) Consensus(ctx context.Context, in *Handshake, opts ...grpc.CallOption) (Consensus_ConsensusClient, error) { - stream, err := grpc.NewClientStream(ctx, &_Consensus_serviceDesc.Streams[0], c.cc, "/backend.consensus/consensus", opts...) - if err != nil { - return nil, err - } - x := &consensusConsensusClient{stream} - if err := x.ClientStream.SendMsg(in); err != nil { - return nil, err - } - if err := x.ClientStream.CloseSend(); err != nil { - return nil, err - } - return x, nil -} - -type Consensus_ConsensusClient interface { - Recv() (*simplebft.MultiChainMsg, error) - grpc.ClientStream -} - -type consensusConsensusClient struct { - grpc.ClientStream -} - -func (x *consensusConsensusClient) Recv() (*simplebft.MultiChainMsg, error) { - m := new(simplebft.MultiChainMsg) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// Server API for Consensus service - -type ConsensusServer interface { - Consensus(*Handshake, Consensus_ConsensusServer) error -} - -func RegisterConsensusServer(s *grpc.Server, srv ConsensusServer) { - s.RegisterService(&_Consensus_serviceDesc, srv) -} - -func _Consensus_Consensus_Handler(srv interface{}, stream grpc.ServerStream) error { - m := new(Handshake) - if err := stream.RecvMsg(m); err != nil { - return err - } - return srv.(ConsensusServer).Consensus(m, &consensusConsensusServer{stream}) -} - -type Consensus_ConsensusServer interface { - Send(*simplebft.MultiChainMsg) error - grpc.ServerStream -} - -type consensusConsensusServer struct { - grpc.ServerStream -} - -func (x *consensusConsensusServer) Send(m *simplebft.MultiChainMsg) error { - return x.ServerStream.SendMsg(m) -} - -var _Consensus_serviceDesc = grpc.ServiceDesc{ - ServiceName: "backend.consensus", - HandlerType: (*ConsensusServer)(nil), - Methods: []grpc.MethodDesc{}, - Streams: []grpc.StreamDesc{ - { - StreamName: "consensus", - Handler: _Consensus_Consensus_Handler, - ServerStreams: true, - }, - }, - Metadata: "backend/consensus.proto", -} - -func init() { proto.RegisterFile("backend/consensus.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 172 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x4c, 0xce, 0xbd, 0xae, 0x82, 0x40, - 0x10, 0x05, 0xe0, 0x7b, 0x1b, 0x0d, 0xd8, 0xd1, 0xa8, 0x94, 0x3c, 0xc0, 0x8e, 0x41, 0x5b, 0x1b, - 0xed, 0x4c, 0x78, 0x01, 0xbb, 0xfd, 0x19, 0xd8, 0x0d, 0xb0, 0x4b, 0x66, 0x96, 0xc2, 0xb7, 0x37, - 0x2a, 0x59, 0xed, 0x66, 0x72, 0x4e, 0xbe, 0x9c, 0x7c, 0xab, 0xa4, 0xee, 0xd1, 0x1b, 0xd0, 0xc1, - 0x33, 0x7a, 0x9e, 0x59, 0x4c, 0x14, 0x62, 0x28, 0xd6, 0x4b, 0x50, 0xee, 0xd9, 0x8d, 0xd3, 0x80, - 0xaa, 0x8d, 0x90, 0xae, 0x4f, 0xa7, 0xda, 0xe4, 0x99, 0x95, 0xde, 0xb0, 0x95, 0x3d, 0xd6, 0xb7, - 0x3c, 0x4b, 0x46, 0x71, 0xfe, 0x7d, 0x0a, 0xb1, 0x58, 0x22, 0xb5, 0xcb, 0x9d, 0xf8, 0x62, 0xcd, - 0x3c, 0x44, 0x77, 0xb5, 0xd2, 0xf9, 0x86, 0xbb, 0xea, 0xef, 0xf0, 0x7f, 0x39, 0xdd, 0xeb, 0xce, - 0x45, 0x3b, 0x2b, 0xa1, 0xc3, 0x08, 0xf6, 0x31, 0x21, 0x0d, 0x68, 0x3a, 0x24, 0x68, 0xa5, 0x22, - 0xa7, 0x21, 0x90, 0x41, 0x42, 0x02, 0x7e, 0xcd, 0x5a, 0x74, 0xb5, 0x7a, 0xaf, 0x3a, 0x3e, 0x03, - 0x00, 0x00, 0xff, 0xff, 0x1d, 0x79, 0xa9, 0x9a, 0xd4, 0x00, 0x00, 0x00, -} diff --git a/orderer/sbft/backend/consensus.proto b/orderer/sbft/backend/consensus.proto deleted file mode 100644 index 26b2c32c91d..00000000000 --- a/orderer/sbft/backend/consensus.proto +++ /dev/null @@ -1,14 +0,0 @@ -syntax = "proto3"; - -package backend; - -option go_package = "github.com/hyperledger/fabric/orderer/sbft/backend"; - -import "simplebft/simplebft.proto"; - -service consensus { - rpc consensus(handshake) returns (stream simplebft.MultiChainMsg) {} -} - -message handshake { -} diff --git a/orderer/sbft/backend/events.go b/orderer/sbft/backend/events.go deleted file mode 100644 index 2da4ba79d0b..00000000000 --- a/orderer/sbft/backend/events.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright Digital Asset Holdings, LLC 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package backend - -import ( - s "github.com/hyperledger/fabric/orderer/sbft/simplebft" -) - -type Timer struct { - tf func() - execute bool -} - -func (t *Timer) Cancel() { - t.execute = false -} - -type Executable interface { - Execute(*Backend) -} - -func (t *Timer) Execute(backend *Backend) { - if t.execute { - t.tf() - } -} - -type msgEvent struct { - chainId string - msg *s.Msg - src uint64 -} - -func (m *msgEvent) Execute(backend *Backend) { - backend.consensus[m.chainId].Receive(m.msg, m.src) -} - -type requestEvent struct { - chainId string - req []byte -} - -func (r *requestEvent) Execute(backend *Backend) { - backend.consensus[r.chainId].Request(r.req) -} - -type connectionEvent struct { - chainID string - peerid uint64 -} - -func (c *connectionEvent) Execute(backend *Backend) { - backend.consensus[c.chainID].Connection(c.peerid) -} diff --git a/orderer/sbft/config.go b/orderer/sbft/config.go deleted file mode 100644 index f4ac4dc1dc3..00000000000 --- a/orderer/sbft/config.go +++ /dev/null @@ -1,86 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sbft - -import ( - "encoding/json" - "fmt" - "io/ioutil" - - "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric/orderer/sbft/crypto" - "github.com/hyperledger/fabric/orderer/sbft/persist" -) - -func ReadJsonConfig(file string) (*ConsensusConfig, error) { - configData, err := ioutil.ReadFile(file) - if err != nil { - return nil, err - } - - jconfig := &JsonConfig{} - err = json.Unmarshal(configData, jconfig) - if err != nil { - return nil, err - } - - config := &ConsensusConfig{} - config.Consensus = jconfig.Consensus - config.Peers = make(map[string][]byte) - for n, p := range jconfig.Peers { - if p.Address == "" { - return nil, fmt.Errorf("The required peer address is missing (for peer %d)", n) - } - cert, err := crypto.ParseCertPEM(p.Cert) - if err != nil { - fmt.Println("exiting") - return nil, err - } - config.Peers[p.Address] = cert - } - - // XXX check for duplicate cert - if config.Consensus.N != 0 && int(config.Consensus.N) != len(config.Peers) { - return nil, fmt.Errorf("peer config does not match pbft N") - } - - config.Consensus.N = uint64(len(config.Peers)) - - return config, nil -} - -func SaveConfig(p *persist.Persist, c *ConsensusConfig) error { - craw, err := proto.Marshal(c) - if err != nil { - return err - } - err = p.StoreState("config", craw) - return err -} - -func RestoreConfig(p *persist.Persist) (*ConsensusConfig, error) { - raw, err := p.ReadState("config") - if err != nil { - return nil, err - } - config := &ConsensusConfig{} - err = proto.Unmarshal(raw, config) - if err != nil { - return nil, err - } - return config, nil -} diff --git a/orderer/sbft/config.pb.go b/orderer/sbft/config.pb.go deleted file mode 100644 index b7f336f7471..00000000000 --- a/orderer/sbft/config.pb.go +++ /dev/null @@ -1,132 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: config.proto - -/* -Package sbft is a generated protocol buffer package. - -It is generated from these files: - config.proto - -It has these top-level messages: - ConsensusConfig - JsonConfig - Peer -*/ -package sbft - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" -import simplebft "github.com/hyperledger/fabric/orderer/sbft/simplebft" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type ConsensusConfig struct { - Consensus *simplebft.Config `protobuf:"bytes,1,opt,name=consensus" json:"consensus,omitempty"` - Peers map[string][]byte `protobuf:"bytes,2,rep,name=peers" json:"peers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value,proto3"` -} - -func (m *ConsensusConfig) Reset() { *m = ConsensusConfig{} } -func (m *ConsensusConfig) String() string { return proto.CompactTextString(m) } -func (*ConsensusConfig) ProtoMessage() {} -func (*ConsensusConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -func (m *ConsensusConfig) GetConsensus() *simplebft.Config { - if m != nil { - return m.Consensus - } - return nil -} - -func (m *ConsensusConfig) GetPeers() map[string][]byte { - if m != nil { - return m.Peers - } - return nil -} - -type JsonConfig struct { - Consensus *simplebft.Config `protobuf:"bytes,1,opt,name=consensus" json:"consensus,omitempty"` - Peers []*Peer `protobuf:"bytes,2,rep,name=peers" json:"peers,omitempty"` -} - -func (m *JsonConfig) Reset() { *m = JsonConfig{} } -func (m *JsonConfig) String() string { return proto.CompactTextString(m) } -func (*JsonConfig) ProtoMessage() {} -func (*JsonConfig) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -func (m *JsonConfig) GetConsensus() *simplebft.Config { - if m != nil { - return m.Consensus - } - return nil -} - -func (m *JsonConfig) GetPeers() []*Peer { - if m != nil { - return m.Peers - } - return nil -} - -type Peer struct { - Address string `protobuf:"bytes,1,opt,name=address" json:"address,omitempty"` - Cert string `protobuf:"bytes,2,opt,name=cert" json:"cert,omitempty"` -} - -func (m *Peer) Reset() { *m = Peer{} } -func (m *Peer) String() string { return proto.CompactTextString(m) } -func (*Peer) ProtoMessage() {} -func (*Peer) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } - -func (m *Peer) GetAddress() string { - if m != nil { - return m.Address - } - return "" -} - -func (m *Peer) GetCert() string { - if m != nil { - return m.Cert - } - return "" -} - -func init() { - proto.RegisterType((*ConsensusConfig)(nil), "sbft.consensus_config") - proto.RegisterType((*JsonConfig)(nil), "sbft.json_config") - proto.RegisterType((*Peer)(nil), "sbft.peer") -} - -func init() { proto.RegisterFile("config.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 271 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x91, 0x4d, 0x4b, 0xc3, 0x40, - 0x10, 0x86, 0x49, 0x9b, 0x2a, 0x99, 0xf4, 0x50, 0x17, 0x0f, 0xb1, 0xa7, 0x98, 0x53, 0x10, 0xd9, - 0x85, 0x2a, 0x58, 0x3c, 0x2a, 0xde, 0x25, 0x47, 0x2f, 0x9a, 0x8f, 0x49, 0x1a, 0x4d, 0xb3, 0x61, - 0x76, 0x23, 0xe4, 0x8f, 0xf9, 0xfb, 0x64, 0xb3, 0xb5, 0x41, 0x8f, 0xde, 0xde, 0x19, 0x9e, 0xd9, - 0xf7, 0x81, 0x85, 0x65, 0x2e, 0xdb, 0xb2, 0xae, 0x78, 0x47, 0x52, 0x4b, 0xe6, 0xaa, 0xac, 0xd4, - 0xeb, 0x0b, 0x55, 0xef, 0xbb, 0x06, 0xb3, 0x52, 0x8b, 0x63, 0xb2, 0x40, 0xf4, 0xe5, 0xc0, 0x2a, - 0x97, 0xad, 0xc2, 0x56, 0xf5, 0xea, 0xd5, 0xde, 0x32, 0x01, 0xde, 0x71, 0x17, 0x38, 0xa1, 0x13, - 0xfb, 0x9b, 0x33, 0x3e, 0x5d, 0x3e, 0x8e, 0x54, 0x32, 0x31, 0xec, 0x0e, 0x16, 0x1d, 0x22, 0xa9, - 0x60, 0x16, 0xce, 0x63, 0x7f, 0x73, 0xc9, 0x4d, 0x2d, 0xff, 0xfb, 0x2e, 0x7f, 0x36, 0xcc, 0x53, - 0xab, 0x69, 0x48, 0x2c, 0xbf, 0xde, 0x02, 0x4c, 0x4b, 0xb6, 0x82, 0xf9, 0x07, 0x0e, 0x63, 0xa3, - 0x97, 0x98, 0xc8, 0xce, 0x61, 0xf1, 0x99, 0x36, 0x3d, 0x06, 0xb3, 0xd0, 0x89, 0x97, 0x89, 0x1d, - 0xee, 0x67, 0x5b, 0x27, 0x7a, 0x03, 0xff, 0x5d, 0xc9, 0xf6, 0xdf, 0xca, 0xe1, 0x6f, 0x65, 0xb0, - 0xca, 0x66, 0x75, 0x70, 0x8b, 0x6e, 0xc1, 0x35, 0x81, 0x05, 0x70, 0x9a, 0x16, 0x05, 0xa1, 0x52, - 0x07, 0xb3, 0x9f, 0x91, 0x31, 0x70, 0x73, 0x24, 0x3d, 0xca, 0x79, 0xc9, 0x98, 0x1f, 0xae, 0x5f, - 0xae, 0xaa, 0x5a, 0xef, 0xfa, 0x8c, 0xe7, 0x72, 0x2f, 0x76, 0x43, 0x87, 0xd4, 0x60, 0x51, 0x21, - 0x89, 0x32, 0xcd, 0xa8, 0xce, 0x85, 0xa4, 0x02, 0x09, 0x49, 0x98, 0xbe, 0xec, 0x64, 0xfc, 0x85, - 0x9b, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x82, 0x1e, 0x52, 0x33, 0xb6, 0x01, 0x00, 0x00, -} diff --git a/orderer/sbft/config.proto b/orderer/sbft/config.proto deleted file mode 100644 index 95eb9b33882..00000000000 --- a/orderer/sbft/config.proto +++ /dev/null @@ -1,38 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -syntax = "proto3"; - -option go_package = "github.com/hyperledger/fabric/orderer/sbft"; - -package sbft; - -import "simplebft/simplebft.proto"; - -message consensus_config { - simplebft.Config consensus = 1; - map peers = 2; -}; - -message json_config { - simplebft.Config consensus = 1; - repeated peer peers = 2; -}; - -message peer { - string address = 1; - string cert = 2; -}; diff --git a/orderer/sbft/connection/connection.go b/orderer/sbft/connection/connection.go deleted file mode 100644 index a247e1288db..00000000000 --- a/orderer/sbft/connection/connection.go +++ /dev/null @@ -1,163 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package connection - -import ( - "crypto/sha256" - "crypto/tls" - "crypto/x509" - "fmt" - "net" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/peer" - "google.golang.org/grpc/transport" -) - -type PeerInfo struct { - addr string - cert *x509.Certificate - cp *x509.CertPool -} - -type Manager struct { - Server *grpc.Server - Listener net.Listener - Self PeerInfo - tlsConfig *tls.Config - Cert *tls.Certificate -} - -func New(addr string, certFile string, keyFile string) (_ *Manager, err error) { - c := &Manager{} - - cert, err := tls.LoadX509KeyPair(certFile, keyFile) - if err != nil { - return nil, err - } - cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - return nil, err - } - - c.Cert = &cert - c.Self, _ = NewPeerInfo("", cert.Certificate[0]) - - c.tlsConfig = &tls.Config{ - Certificates: []tls.Certificate{cert}, - ClientAuth: tls.RequestClientCert, - InsecureSkipVerify: true, - } - - c.Listener, err = net.Listen("tcp", addr) - if err != nil { - return nil, err - } - - serverTls := c.tlsConfig - serverTls.ServerName = addr - c.Server = grpc.NewServer(grpc.Creds(credentials.NewTLS(serverTls))) - go c.Server.Serve(c.Listener) - return c, nil -} - -func (c *Manager) DialPeer(peer PeerInfo, opts ...grpc.DialOption) (*grpc.ClientConn, error) { - return dialPeer(&c.tlsConfig.Certificates[0], peer, opts...) -} - -// to check client: credentials.FromContext() -> AuthInfo - -type patchedAuthenticator struct { - credentials.TransportCredentials - pinnedCert *x509.Certificate - tunneledError error -} - -func dialPeer(cert *tls.Certificate, peer PeerInfo, opts ...grpc.DialOption) (*grpc.ClientConn, error) { - clientTLS := &tls.Config{InsecureSkipVerify: true} - if cert != nil { - clientTLS.Certificates = []tls.Certificate{*cert} - } - - creds := credentials.NewTLS(clientTLS) - patchedCreds := &patchedAuthenticator{ - TransportCredentials: creds, - pinnedCert: peer.cert, - } - opts = append(opts, grpc.WithTransportCredentials(patchedCreds)) - conn, err := grpc.Dial(peer.addr, opts...) - if err != nil { - if patchedCreds.tunneledError != nil { - err = patchedCreds.tunneledError - } - return nil, err - } - - return conn, nil -} - -func DialPeer(peer PeerInfo, opts ...grpc.DialOption) (*grpc.ClientConn, error) { - return dialPeer(nil, peer, opts...) -} - -func GetPeerInfo(s grpc.Stream) PeerInfo { - var pi PeerInfo - - ctx := s.Context() - trs, ok := transport.StreamFromContext(ctx) - if ok { - pi.addr = trs.ServerTransport().RemoteAddr().String() - } - - p, _ := peer.FromContext(ctx) - switch creds := p.AuthInfo.(type) { - case credentials.TLSInfo: - state := creds.State - if len(state.PeerCertificates) > 0 { - pi.cert = state.PeerCertificates[0] - } - } - - return pi -} - -func NewPeerInfo(addr string, cert []byte) (_ PeerInfo, err error) { - var p PeerInfo - - p.addr = addr - p.cert, err = x509.ParseCertificate(cert) - if err != nil { - return - } - p.cp = x509.NewCertPool() - p.cp.AddCert(p.cert) - return p, nil -} - -func (pi *PeerInfo) Fingerprint() string { - return fmt.Sprintf("%x", sha256.Sum256(pi.cert.Raw)) -} - -func (pi *PeerInfo) Cert() *x509.Certificate { - cert := *pi.cert - return &cert -} - -func (pi PeerInfo) String() string { - return fmt.Sprintf("%.6s [%s]", pi.Fingerprint(), pi.addr) -} diff --git a/orderer/sbft/connection/connection_test.go b/orderer/sbft/connection/connection_test.go deleted file mode 100644 index 92582874780..00000000000 --- a/orderer/sbft/connection/connection_test.go +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright Digital Asset Holdings, LLC 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package connection - -import ( - "crypto/sha256" - "encoding/pem" - "fmt" - "testing" -) - -const cert = ` ------BEGIN CERTIFICATE----- -MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG -EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy -bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP -VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv -h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE -ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ -EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC -DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7 -qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD -VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g -K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI -KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n -ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB -BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY -/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/ -zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza -HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto -WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6 -yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx ------END CERTIFICATE-----` - -func TestPeerInfoWithWrongCert(t *testing.T) { - addr := "localhost" - cert := []byte{0, 1, 2, 3} - _, err := NewPeerInfo(addr, cert) - if err == nil { - t.Fatalf("Peer accepted a wrong certificate.") - } -} - -func TestPeerInfoWithOkCert(t *testing.T) { - addr := "localhost" - block, _ := pem.Decode([]byte(cert)) - pi, err := NewPeerInfo(addr, block.Bytes) - if err != nil { - t.Fatalf("Peer creation failed.") - } - fp := fmt.Sprintf("%x", sha256.Sum256(block.Bytes)) - if pi.Fingerprint() != fp { - t.Fatalf("Wrong fingerprint.") - } - if pi.Cert() == nil { - t.Fatalf("Certificate field is empty.") - } -} diff --git a/orderer/sbft/consenter.go b/orderer/sbft/consenter.go deleted file mode 100644 index 2f5da7f3dbd..00000000000 --- a/orderer/sbft/consenter.go +++ /dev/null @@ -1,120 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package sbft - -import ( - "github.com/hyperledger/fabric/orderer/multichain" - "github.com/hyperledger/fabric/orderer/sbft/backend" - "github.com/hyperledger/fabric/orderer/sbft/connection" - "github.com/hyperledger/fabric/orderer/sbft/persist" - "github.com/hyperledger/fabric/orderer/sbft/simplebft" - cb "github.com/hyperledger/fabric/protos/common" - "github.com/op/go-logging" -) - -type consensusStack struct { - persist *persist.Persist - backend *backend.Backend -} - -var logger = logging.MustGetLogger("orderer/sbft") - -// Consenter interface implementation for new main application -type consenter struct { - config *ConsensusConfig - consensusStack *consensusStack - sbftStackConfig *backend.StackConfig - sbftPeers map[string]*simplebft.SBFT -} - -type chain struct { - chainID string - consensusStack *consensusStack -} - -// New creates a new consenter for the SBFT consensus scheme. -// It accepts messages being delivered via Enqueue, orders them, and then uses the blockcutter to form the messages -// into blocks before writing to the given ledger. -func New(c *ConsensusConfig, sc *backend.StackConfig) multichain.Consenter { - return &consenter{config: c, sbftStackConfig: sc} -} - -func (sbft *consenter) HandleChain(support multichain.ConsenterSupport, metadata *cb.Metadata) (multichain.Chain, error) { - return newChain(sbft, support), nil -} - -func newChain(sbft *consenter, support multichain.ConsenterSupport) *chain { - logger.Infof("Starting a chain: %d", support.ChainID()) - - if sbft.sbftPeers == nil { - sbft.consensusStack = createConsensusStack(sbft) - sbft.sbftPeers = make(map[string]*simplebft.SBFT) - } - sbft.sbftPeers[support.ChainID()] = initSbftPeer(support.ChainID(), sbft, support) - - return &chain{ - chainID: support.ChainID(), - consensusStack: sbft.consensusStack, - } -} - -func createConsensusStack(sbft *consenter) *consensusStack { - logger.Infof("%v %v %v", sbft.sbftStackConfig.ListenAddr, sbft.sbftStackConfig.CertFile, sbft.sbftStackConfig.KeyFile) - conn, err := connection.New(sbft.sbftStackConfig.ListenAddr, sbft.sbftStackConfig.CertFile, sbft.sbftStackConfig.KeyFile) - if err != nil { - logger.Errorf("Error when trying to connect: %s", err) - panic(err) - } - persist := persist.New(sbft.sbftStackConfig.DataDir) - backend, err := backend.NewBackend(sbft.config.Peers, conn, persist) - if err != nil { - logger.Errorf("Backend instantiation error.") - panic(err) - } - return &consensusStack{ - backend: backend, - persist: persist, - } -} - -func initSbftPeer(chainID string, sbft *consenter, support multichain.ConsenterSupport) *simplebft.SBFT { - sbftPeer, err := sbft.consensusStack.backend.AddSbftPeer(support.ChainID(), support, sbft.config.Consensus) - if err != nil { - logger.Errorf("SBFT peer instantiation error.") - panic(err) - } - return sbftPeer -} - -// Chain interface implementation: - -// Start allocates the necessary resources for staying up to date with this Chain. -// It implements the multichain.Chain interface. It is called by multichain.NewManagerImpl() -// which is invoked when the ordering process is launched, before the call to NewServer(). -func (ch *chain) Start() { - -} - -// Halt frees the resources which were allocated for this Chain -func (ch *chain) Halt() { - panic("There is no way to halt SBFT") -} - -// Enqueue accepts a message and returns true on acceptance, or false on shutdown -func (ch *chain) Enqueue(env *cb.Envelope) bool { - return ch.consensusStack.backend.Enqueue(ch.chainID, env) -} diff --git a/orderer/sbft/crypto/crypto.go b/orderer/sbft/crypto/crypto.go deleted file mode 100644 index c1795f12318..00000000000 --- a/orderer/sbft/crypto/crypto.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package crypto - -import ( - "encoding/pem" - "fmt" - "io/ioutil" -) - -func ParseCertPEM(certFile string) ([]byte, error) { - certBytes, err := ioutil.ReadFile(certFile) - if err != nil { - return nil, err - } - - var b *pem.Block - for { - b, certBytes = pem.Decode(certBytes) - if b == nil { - break - } - if b.Type == "CERTIFICATE" { - break - } - } - - if b == nil { - return nil, fmt.Errorf("no certificate found") - } - - return b.Bytes, nil -} diff --git a/orderer/sbft/crypto/crypto_test.go b/orderer/sbft/crypto/crypto_test.go deleted file mode 100644 index 30977e0f687..00000000000 --- a/orderer/sbft/crypto/crypto_test.go +++ /dev/null @@ -1,63 +0,0 @@ -/* -Copyright Digital Asset Holdings, LLC 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package crypto - -import ( - "io/ioutil" - "testing" -) - -const cert = ` ------BEGIN CERTIFICATE----- -MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i -YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG -EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy -bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP -VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv -h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE -ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ -EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC -DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7 -qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD -VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g -K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI -KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n -ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB -BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY -/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/ -zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza -HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto -WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6 -yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx ------END CERTIFICATE-----` - -func TestPeerInfoWithWrongCert(t *testing.T) { - f := "/tmp/dat1" - err := ioutil.WriteFile(f, []byte(cert), 0644) - if err != nil { - panic("Failed to write certificate into file.") - } - c, cerr := ParseCertPEM(f) - if cerr != nil { - t.Fatalf("Certificate parsing error. (1)") - } - if len(c) == 0 { - t.Fatalf("Certificate parsing error. (2)") - } -} diff --git a/orderer/sbft/local-deploy.sh b/orderer/sbft/local-deploy.sh deleted file mode 100755 index 309094e99f5..00000000000 --- a/orderer/sbft/local-deploy.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/sh -# -# Copyright IBM Corp. All Rights Reserved. -# -# SPDX-License-Identifier: Apache-2.0 -# - - -set -e - -dest=$1 -count=$2 -nodeidmax=$((count-1)) - -if test -z "$count" -then - echo "usage: local-deploy.sh " >&1 - exit 1 -fi - - -fail=$((($count - 1)/3)) - -mkdir $dest -cd $dest - -certtool --generate-privkey --outfile key.pem 2>/dev/null -mkdir data - -peerconf="" - -for n in $(seq 0 $nodeidmax) -do - cat > template$n.cfg </dev/null - certtool -i --infile cert$n.pem --outder --outfile data/config.peers.:$((6100+$n)) 2>/dev/null - - peerconf=$(cat < config.json < run-$n.sh < s.cur.subject.Seq.Seq || seq.View > s.view { - return true - } - return false - } - - if pp := m.GetPreprepare(); pp != nil { - return test(pp.Seq) && !s.cur.checkpointDone - } else if p := m.GetPrepare(); p != nil { - return test(p.Seq) - } else if c := m.GetCommit(); c != nil { - return test(c.Seq) - } else if chk := m.GetCheckpoint(); chk != nil { - return test(&SeqView{Seq: chk.Seq}) - } - return false -} - -func (s *SBFT) recordBacklogMsg(m *Msg, src uint64) { - if src == s.id { - panic(fmt.Sprintf("should never have to backlog my own message (replica ID: %d)", src)) - } - - s.replicaState[src].backLog = append(s.replicaState[src].backLog, m) - - if len(s.replicaState[src].backLog) > maxBacklogSeq*msgPerSeq { - log.Debugf("replica %d: backlog for %d full, discarding and reconnecting", s.id, src) - s.discardBacklog(src) - s.sys.Reconnect(s.chainId, src) - } -} - -func (s *SBFT) discardBacklog(src uint64) { - s.replicaState[src].backLog = nil -} - -func (s *SBFT) processBacklog() { - processed := true - - for processed { - processed = false - for src := range s.replicaState { - state := &s.replicaState[src] - src := uint64(src) - - for len(state.backLog) > 0 { - m, rest := state.backLog[0], state.backLog[1:] - if s.testBacklogMessage(m, src) { - break - } - state.backLog = rest - - log.Debugf("replica %d: processing stored message from %d: %s", s.id, src, m) - - s.handleQueueableMessage(m, src) - processed = true - } - } - } -} diff --git a/orderer/sbft/simplebft/batch.go b/orderer/sbft/simplebft/batch.go deleted file mode 100644 index 1b7ec1873d2..00000000000 --- a/orderer/sbft/simplebft/batch.go +++ /dev/null @@ -1,121 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "fmt" - "reflect" - - "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric/orderer/common/filter" -) - -func (s *SBFT) makeBatch(seq uint64, prevHash []byte, data [][]byte) *Batch { - datahash := merkleHashData(data) - - batchhead := &BatchHeader{ - Seq: seq, - PrevHash: prevHash, - DataHash: datahash, - } - rawHeader, err := proto.Marshal(batchhead) - if err != nil { - panic(err) - } - return &Batch{ - Header: rawHeader, - Payloads: data, - } -} - -func (s *SBFT) checkBatch(b *Batch, checkData bool, needSigs bool) (*BatchHeader, error) { - batchheader := &BatchHeader{} - err := proto.Unmarshal(b.Header, batchheader) - if err != nil { - return nil, err - } - - if checkData { - datahash := merkleHashData(b.Payloads) - if !reflect.DeepEqual(datahash, batchheader.DataHash) { - return nil, fmt.Errorf("malformed batches: invalid hash") - } - } - - if batchheader.PrevHash == nil { - // TODO check against root hash, which should be part of constructor - } else if needSigs { - if len(b.Signatures) < s.oneCorrectQuorum() { - return nil, fmt.Errorf("insufficient number of signatures on batches: need %d, got %d", s.oneCorrectQuorum(), len(b.Signatures)) - } - } - - bh := b.Hash() - for r, sig := range b.Signatures { - err = s.sys.CheckSig(bh, r, sig) - if err != nil { - return nil, err - } - } - - return batchheader, nil -} - -//////////////////////////////////////// - -// Hash returns the hash of the Batch. -func (b *Batch) Hash() []byte { - return hash(b.Header) -} - -func (b *Batch) DecodeHeader() *BatchHeader { - batchheader := &BatchHeader{} - err := proto.Unmarshal(b.Header, batchheader) - if err != nil { - panic(err) - } - - return batchheader -} - -func (s *SBFT) getCommittersFromBatch(reqBatch *Batch) (bool, []filter.Committer) { - reqs := make([]*Request, 0, len(reqBatch.Payloads)) - for _, pl := range reqBatch.Payloads { - req := &Request{Payload: pl} - reqs = append(reqs, req) - } - batches := make([][]*Request, 0, 1) - comms := [][]filter.Committer{} - for _, r := range reqs { - b, c, valid := s.sys.Validate(s.chainId, r) - if !valid { - return false, nil - } - batches = append(batches, b...) - comms = append(comms, c...) - } - if len(batches) > 1 || len(batches) != len(comms) { - return false, nil - } - - if len(batches) == 0 { - _, committer := s.sys.Cut(s.chainId) - return true, committer - } else { - return true, comms[0] - } -} diff --git a/orderer/sbft/simplebft/calendarqueue_test.go b/orderer/sbft/simplebft/calendarqueue_test.go deleted file mode 100644 index cd2635b5821..00000000000 --- a/orderer/sbft/simplebft/calendarqueue_test.go +++ /dev/null @@ -1,134 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "sort" - "time" -) - -type calendarQueue struct { - dayLength time.Duration - yearLength time.Duration - today time.Duration - nextYear time.Duration - slots [][]testElem - maxLen int -} - -func newCalendarQueue(dayLength time.Duration, days int) *calendarQueue { - return &calendarQueue{ - dayLength: dayLength, - yearLength: dayLength * time.Duration(days), - nextYear: dayLength * time.Duration(days), - slots: make([][]testElem, days), - } -} - -func (t *calendarQueue) slot(d time.Duration) int { - return int(d/t.dayLength) % len(t.slots) -} - -func (t *calendarQueue) Add(e testElem) { - sl := t.slot(e.at) - t.slots[sl] = append(t.slots[sl], e) - l := len(t.slots[sl]) - if l > t.maxLen { - t.maxLen = l - } - sort.Sort(testElemQueue(t.slots[sl])) -} - -func (t *calendarQueue) Pop() (testElem, bool) { - var lowest *time.Duration - sl := t.slot(t.today) - start := sl - today := t.today - for ; today < t.nextYear; today, sl = today+t.dayLength, sl+1 { - if len(t.slots[sl]) == 0 { - continue - } - e := t.slots[sl][0] - if e.at >= t.nextYear { - if lowest == nil || *lowest > e.at { - lowest = &e.at - } - continue - } - t.slots[sl] = t.slots[sl][1:] - t.today = today - return e, true - } - - // next deadline is after this year, but we only - // searched part of the calendar so far. Search the - // remaining prefix. - for i := 0; i < start; i++ { - if len(t.slots[i]) == 0 { - continue - } - e := t.slots[i][0] - if e.at >= t.nextYear { - if lowest == nil || *lowest > e.at { - lowest = &e.at - } - } - } - - if lowest == nil { - return testElem{}, false - } - - t.today = *lowest / t.dayLength * t.dayLength - t.nextYear = (t.today/t.yearLength + 1) * t.yearLength - return t.Pop() // retry! -} - -func (t *calendarQueue) filter(fn func(testElem) bool) { - for sli, sl := range t.slots { - var del []int - for i, e := range sl { - if !fn(e) { - del = append(del, i) - } - } - - // now delete - for i, e := range del { - correctedPos := e - i - // in-place remove - sl = sl[:correctedPos+copy(sl[correctedPos:], sl[correctedPos+1:])] - } - t.slots[sli] = sl - } -} - -///////////////////////////////////////// - -type testElemQueue []testElem - -func (q testElemQueue) Len() int { - return len(q) -} - -func (q testElemQueue) Less(i, j int) bool { - return q[i].at < q[j].at -} - -func (q testElemQueue) Swap(i, j int) { - q[i], q[j] = q[j], q[i] -} diff --git a/orderer/sbft/simplebft/checkpoint.go b/orderer/sbft/simplebft/checkpoint.go deleted file mode 100644 index adddb0d6be5..00000000000 --- a/orderer/sbft/simplebft/checkpoint.go +++ /dev/null @@ -1,104 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "fmt" - "reflect" -) - -func (s *SBFT) makeCheckpoint() *Checkpoint { - sig := s.sys.Sign(s.cur.subject.Digest) - c := &Checkpoint{ - Seq: s.cur.subject.Seq.Seq, - Digest: s.cur.subject.Digest, - Signature: sig, - } - return c -} - -func (s *SBFT) sendCheckpoint() { - s.broadcast(&Msg{&Msg_Checkpoint{s.makeCheckpoint()}}) -} - -func (s *SBFT) handleCheckpoint(c *Checkpoint, src uint64) { - if s.cur.checkpointDone { - return - } - - if c.Seq < s.cur.subject.Seq.Seq { - // old message - return - } - - err := s.checkBytesSig(c.Digest, src, c.Signature) - if err != nil { - log.Infof("replica %d: checkpoint signature invalid for %d from %d", s.id, c.Seq, src) - return - } - - // TODO should we always accept checkpoints? - if c.Seq != s.cur.subject.Seq.Seq { - log.Infof("replica %d: checkpoint does not match expected subject %v, got %v", s.id, &s.cur.subject, c) - return - } - if _, ok := s.cur.checkpoint[src]; ok { - log.Infof("replica %d: duplicate checkpoint for %d from %d", s.id, c.Seq, src) - } - s.cur.checkpoint[src] = c - - max := "_" - sums := make(map[string][]uint64) - for csrc, c := range s.cur.checkpoint { - sum := fmt.Sprintf("%x", c.Digest) - sums[sum] = append(sums[sum], csrc) - - if len(sums[sum]) >= s.oneCorrectQuorum() { - max = sum - } - } - - replicas, ok := sums[max] - if !ok { - return - } - - // got a weak checkpoint - - cpset := make(map[uint64][]byte) - for _, r := range replicas { - cp := s.cur.checkpoint[r] - cpset[r] = cp.Signature - } - - c = s.cur.checkpoint[replicas[0]] - - if !reflect.DeepEqual(c.Digest, s.cur.subject.Digest) { - log.Warningf("replica %d: weak checkpoint %x does not match our state %x --- primary %d of view %d is probably Byzantine, sending view change", - s.id, c.Digest, s.cur.subject.Digest, s.primaryID(), s.view) - s.sendViewChange() - return - } - - // ignore null requests - batch := *s.cur.preprep.Batch - batch.Signatures = cpset - s.deliverBatch(&batch, s.cur.committers) - log.Infof("replica %d: request %s %s delivered on %d (completed common case)", s.id, s.cur.subject.Seq, hash2str(s.cur.subject.Digest), s.id) - s.maybeSendNextBatch() - s.processBacklog() -} diff --git a/orderer/sbft/simplebft/commit.go b/orderer/sbft/simplebft/commit.go deleted file mode 100644 index b2ba6383ad6..00000000000 --- a/orderer/sbft/simplebft/commit.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import "reflect" - -func (s *SBFT) maybeSendCommit() { - if s.cur.prepared || len(s.cur.prep) < s.commonCaseQuorum()-1 { - return - } - s.sendCommit() - s.processBacklog() -} - -func (s *SBFT) sendCommit() { - s.cur.prepared = true - c := s.cur.subject - s.sys.Persist(s.chainId, prepared, &c) - s.broadcast(&Msg{&Msg_Commit{&c}}) -} - -func (s *SBFT) handleCommit(c *Subject, src uint64) { - if c.Seq.Seq < s.cur.subject.Seq.Seq { - // old message - return - } - - if !reflect.DeepEqual(c, &s.cur.subject) { - log.Warningf("replica %d: commit does not match expected subject %v %x, got %v %x", - s.id, s.cur.subject.Seq, s.cur.subject.Digest, c.Seq, c.Digest) - return - } - if _, ok := s.cur.commit[src]; ok { - log.Infof("replica %d: duplicate commit for %v from %d", s.id, *c.Seq, src) - return - } - s.cur.commit[src] = c - s.cancelViewChangeTimer() - - //maybe mark as committed - if s.cur.committed || len(s.cur.commit) < s.commonCaseQuorum() { - return - } - s.cur.committed = true - log.Noticef("replica %d: executing %v %x", s.id, s.cur.subject.Seq, s.cur.subject.Digest) - - s.sys.Persist(s.chainId, committed, &s.cur.subject) - - s.sendCheckpoint() - s.processBacklog() -} diff --git a/orderer/sbft/simplebft/connection.go b/orderer/sbft/simplebft/connection.go deleted file mode 100644 index e8bc816230f..00000000000 --- a/orderer/sbft/simplebft/connection.go +++ /dev/null @@ -1,91 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -// Connection is an event from system to notify a new connection with -// replica. -// On connection, we send our latest (weak) checkpoint, and we expect -// to receive one from replica. -func (s *SBFT) Connection(replica uint64) { - batch := *s.sys.LastBatch(s.chainId) - batch.Payloads = nil // don't send the big payload - hello := &Hello{Batch: &batch} - if s.isPrimary() && s.activeView && s.lastNewViewSent != nil { - hello.NewView = s.lastNewViewSent - } - s.sys.Send(s.chainId, &Msg{&Msg_Hello{hello}}, replica) - - svc := s.replicaState[s.id].signedViewchange - if svc != nil { - s.sys.Send(s.chainId, &Msg{&Msg_ViewChange{svc}}, replica) - } - - // A reconnecting replica can play forward its blockchain to - // the batches listed in the hello message. However, the - // currently in-flight batches will not be reflected in the - // Hello message, nor will all messages be present to actually - // commit the in-flight batches at the reconnecting replica. - // - // Therefore we also send the most recent (pre)prepare, - // commit, checkpoint so that the reconnecting replica can - // catch up on the in-flight batches. - - batchheader, err := s.checkBatch(&batch, false, true) - if err != nil { - panic(err) - } - - if s.cur.subject.Seq.Seq > batchheader.Seq && s.activeView { - if s.isPrimary() { - s.sys.Send(s.chainId, &Msg{&Msg_Preprepare{s.cur.preprep}}, replica) - } else { - s.sys.Send(s.chainId, &Msg{&Msg_Prepare{&s.cur.subject}}, replica) - } - if s.cur.prepared { - s.sys.Send(s.chainId, &Msg{&Msg_Commit{&s.cur.subject}}, replica) - } - if s.cur.committed { - s.sys.Send(s.chainId, &Msg{&Msg_Checkpoint{s.makeCheckpoint()}}, replica) - } - } -} - -func (s *SBFT) handleHello(h *Hello, src uint64) { - bh, err := s.checkBatch(h.Batch, false, true) - log.Debugf("replica %d: got hello for batches %d from replica %d", s.id, bh.Seq, src) - - if err != nil { - log.Warningf("replica %d: invalid hello batches from %d: %s", s.id, src, err) - return - } - - if s.sys.LastBatch(s.chainId).DecodeHeader().Seq < bh.Seq { - log.Debugf("replica %d: delivering batches %d after hello from replica %d", s.id, bh.Seq, src) - blockOK, committers := s.getCommittersFromBatch(h.Batch) - if blockOK { - s.deliverBatch(h.Batch, committers) - } else { - log.Debugf("replica %d: we got a hello from %d with an erroneous block", s.id, src) - } - } - - s.handleNewView(h.NewView, src) - - s.replicaState[src].hello = h - s.discardBacklog(src) - s.processBacklog() -} diff --git a/orderer/sbft/simplebft/crypto.go b/orderer/sbft/simplebft/crypto.go deleted file mode 100644 index 574e133f267..00000000000 --- a/orderer/sbft/simplebft/crypto.go +++ /dev/null @@ -1,95 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "crypto/sha256" - "encoding/base64" - - "github.com/golang/protobuf/proto" -) - -func hash2str(h []byte) string { - return base64.RawStdEncoding.EncodeToString(h) -} - -func hash(data []byte) []byte { - h := sha256.Sum256(data) - return h[:] -} - -func merkleHashData(data [][]byte) []byte { - var digests [][]byte - for _, d := range data { - digests = append(digests, hash(d)) - } - return merkleHashDigests(digests) -} - -func merkleHashDigests(digests [][]byte) []byte { - for len(digests) > 1 { - var nextDigests [][]byte - var prev []byte - for _, d := range digests { - if prev == nil { - prev = d - } else { - h := sha256.New() - h.Write(prev) - h.Write(d) - nextDigests = append(nextDigests, h.Sum(nil)) - prev = nil - } - } - if prev != nil { - nextDigests = append(nextDigests, prev) - } - digests = nextDigests - } - - if len(digests) == 0 { - return nil - } - return digests[0] -} - -//////////////////////////////////////////////// - -func (s *SBFT) sign(msg proto.Message) *Signed { - bytes, err := proto.Marshal(msg) - if err != nil { - panic(err) - } - sig := s.sys.Sign(bytes) - return &Signed{Data: bytes, Signature: []byte(sig)} -} - -func (s *SBFT) checkSig(sig *Signed, signer uint64, msg proto.Message) error { - err := s.checkBytesSig(sig.Data, signer, sig.Signature) - if err != nil { - return err - } - err = proto.Unmarshal(sig.Data, msg) - if err != nil { - return err - } - return nil -} - -func (s *SBFT) checkBytesSig(digest []byte, signer uint64, sig []byte) error { - return s.sys.CheckSig(digest, signer, sig) -} diff --git a/orderer/sbft/simplebft/crypto_test.go b/orderer/sbft/simplebft/crypto_test.go deleted file mode 100644 index 966a216f571..00000000000 --- a/orderer/sbft/simplebft/crypto_test.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "encoding/base64" - "testing" -) - -func TestMerkleHash(t *testing.T) { - data := [][]byte{[]byte("A"), []byte("B"), []byte("C")} - digest := "2+EeNqqJqWMQPef4rQnBEAwGzNXFrUJMp0HvsGidxCc=" - h := merkleHashData(data) - hs := base64.StdEncoding.EncodeToString(h) - if hs != digest { - t.Errorf("wrong digest, expected %s, got %s", digest, hs) - } -} diff --git a/orderer/sbft/simplebft/newview.go b/orderer/sbft/simplebft/newview.go deleted file mode 100644 index da028f22bfd..00000000000 --- a/orderer/sbft/simplebft/newview.go +++ /dev/null @@ -1,196 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "bytes" - "fmt" - "reflect" -) - -func (s *SBFT) maybeSendNewView() { - if s.lastNewViewSent != nil && s.lastNewViewSent.View == s.view { - return - } - - vset := make(map[uint64]*Signed) - var vcs []*ViewChange - - for src, state := range s.replicaState { - if state.viewchange != nil && state.viewchange.View == s.view { - vset[uint64(src)] = state.signedViewchange - vcs = append(vcs, state.viewchange) - } - } - - xset, _, ok := s.makeXset(vcs) - if !ok { - log.Debugf("replica %d: xset not yet sufficient", s.id) - return - } - - var batch *Batch - if xset == nil { - // no need for batches, it is contained in the vset - } else if reflect.DeepEqual(s.cur.subject.Digest, xset.Digest) { - batch = s.cur.preprep.Batch - } else { - log.Warningf("replica %d: forfeiting primary - do not have request in store for %d %x", s.id, xset.Seq.Seq, xset.Digest) - xset = nil - } - - nv := &NewView{ - View: s.view, - Vset: vset, - Xset: xset, - Batch: batch, - } - - log.Noticef("replica %d: sending new view for %d", s.id, nv.View) - s.lastNewViewSent = nv - s.broadcast(&Msg{&Msg_NewView{nv}}) -} - -func (s *SBFT) checkNewViewSignatures(nv *NewView) ([]*ViewChange, error) { - var vcs []*ViewChange - for vcsrc, svc := range nv.Vset { - vc := &ViewChange{} - err := s.checkSig(svc, vcsrc, vc) - if err == nil { - _, err = s.checkBatch(vc.Checkpoint, false, true) - if vc.View != nv.View { - err = fmt.Errorf("view does not match") - } - } - if err != nil { - return nil, fmt.Errorf("viewchange from %d: %s", vcsrc, err) - } - vcs = append(vcs, vc) - } - - return vcs, nil -} - -func (s *SBFT) handleNewView(nv *NewView, src uint64) { - if nv == nil { - return - } - - if nv.View < s.view { - log.Debugf("replica %d: discarding old new view from %d for %d, we are in %d", s.id, src, nv.View, s.view) - return - } - - if nv.View == s.view && s.activeView { - log.Debugf("replica %d: discarding new view from %d for %d, we are already active in %d", s.id, src, nv.View, s.view) - return - } - - if src != s.primaryIDView(nv.View) { - log.Warningf("replica %d: invalid new view from %d for %d", s.id, src, nv.View) - return - } - - vcs, err := s.checkNewViewSignatures(nv) - if err != nil { - log.Warningf("replica %d: invalid new view from %d: %s", s.id, src, err) - s.sendViewChange() - return - } - - xset, prevBatch, ok := s.makeXset(vcs) - - if !ok || !reflect.DeepEqual(nv.Xset, xset) { - log.Warningf("replica %d: invalid new view from %d: xset incorrect: %v, %v", s.id, src, nv.Xset, xset) - s.sendViewChange() - return - } - - if nv.Xset == nil { - if nv.Batch != nil { - log.Warningf("replica %d: invalid new view from %d: null request should come with null batches", s.id, src) - s.sendViewChange() - return - } - } else if nv.Batch == nil || !bytes.Equal(nv.Batch.Hash(), nv.Xset.Digest) { - log.Warningf("replica %d: invalid new view from %d: batches head hash does not match xset: %x, %x, %v", - s.id, src, hash(nv.Batch.Header), nv.Xset.Digest, nv) - s.sendViewChange() - return - } - - if nv.Batch != nil { - _, err = s.checkBatch(nv.Batch, true, false) - if err != nil { - log.Warningf("replica %d: invalid new view from %d: invalid batches, %s", - s.id, src, err) - s.sendViewChange() - return - } - } - - s.view = nv.View - s.discardBacklog(s.primaryID()) - - // maybe deliver previous batches - if s.sys.LastBatch(s.chainId).DecodeHeader().Seq < prevBatch.DecodeHeader().Seq { - if prevBatch.DecodeHeader().Seq == s.cur.subject.Seq.Seq { - // we just received a signature set for a request which we preprepared, but never delivered. - // check first if the locally preprepared request matches the signature set - if !reflect.DeepEqual(prevBatch.DecodeHeader().DataHash, s.cur.preprep.Batch.DecodeHeader().DataHash) { - log.Warningf("replica %d: [seq %d] request checkpointed in a previous view does not match locally preprepared one, delivering batches without payload", s.id, s.cur.subject.Seq.Seq) - } else { - log.Debugf("replica %d: [seq %d] request checkpointed in a previous view with matching preprepare, completing and delivering the batches with payload", s.id, s.cur.subject.Seq.Seq) - prevBatch.Payloads = s.cur.preprep.Batch.Payloads - } - } - // TODO we should not do this here, as prevBatch was already delivered - blockOK, committers := s.getCommittersFromBatch(prevBatch) - if !blockOK { - log.Panic("Replica %d: our last checkpointed batch is erroneous (block cutter).", s.id) - } - // TODO what should we do with the remaining? - s.deliverBatch(prevBatch, committers) - } - - // after a new-view message, prepare to accept new requests. - s.activeView = true - s.cur.checkpointDone = true - s.cur.subject.Seq.Seq = 0 - - log.Infof("replica %d now active in view %d; primary: %v", s.id, s.view, s.isPrimary()) - - //process pre-prepare if piggybacked to new-view - if nv.Batch != nil { - pp := &Preprepare{ - Seq: &SeqView{Seq: nv.Batch.DecodeHeader().Seq, View: s.view}, - Batch: nv.Batch, - } - blockOK, committers := s.getCommittersFromBatch(nv.Batch) - if !blockOK { - log.Debugf("Replica %d: new view %d batch erroneous (block cutter).", s.id, nv.View) - s.sendViewChange() - } - - s.handleCheckedPreprepare(pp, committers) - } else { - s.cancelViewChangeTimer() - s.maybeSendNextBatch() - } - - s.processBacklog() -} diff --git a/orderer/sbft/simplebft/newview_test.go b/orderer/sbft/simplebft/newview_test.go deleted file mode 100644 index 3ce929d8bdb..00000000000 --- a/orderer/sbft/simplebft/newview_test.go +++ /dev/null @@ -1,186 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "reflect" - "testing" -) - -func TestXsetNoByz(t *testing.T) { - s := &SBFT{config: Config{N: 4, F: 1}, view: 3} - vcs := []*ViewChange{ - &ViewChange{ - View: 3, - Pset: nil, - Qset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}, - &Subject{&SeqView{2, 2}, []byte("val2")}}, - Checkpoint: s.makeBatch(1, []byte("prev"), nil), - }, - &ViewChange{ - View: 3, - Pset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}}, - Qset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}}, - Checkpoint: s.makeBatch(1, []byte("prev"), nil), - }, - &ViewChange{ - View: 3, - Pset: []*Subject{&Subject{&SeqView{2, 2}, []byte("val2")}}, - Qset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}, - &Subject{&SeqView{2, 2}, []byte("val2")}}, - Checkpoint: s.makeBatch(1, []byte("prev"), nil), - }, - } - - xset, _, ok := s.makeXset(vcs) - if !ok { - t.Fatal("no xset") - } - - if !reflect.DeepEqual(xset, &Subject{&SeqView{3, 2}, []byte("val2")}) { - t.Error(xset) - } -} - -func TestXsetNoNew(t *testing.T) { - s := &SBFT{config: Config{N: 4, F: 1}, view: 3} - prev := s.makeBatch(2, []byte("prev"), nil) - vcs := []*ViewChange{ - &ViewChange{ - View: 3, - Pset: []*Subject{&Subject{&SeqView{2, 2}, []byte("val2")}}, - Qset: []*Subject{&Subject{&SeqView{2, 2}, []byte("val2")}}, - Checkpoint: prev, - }, - &ViewChange{ - View: 3, - Pset: []*Subject{&Subject{&SeqView{2, 2}, []byte("val2")}}, - Qset: []*Subject{&Subject{&SeqView{2, 2}, []byte("val2")}}, - Checkpoint: prev, - }, - &ViewChange{ - View: 3, - Pset: []*Subject{&Subject{&SeqView{2, 2}, []byte("val2")}}, - Qset: []*Subject{&Subject{&SeqView{2, 2}, []byte("val2")}}, - Checkpoint: prev, - }, - } - - xset, prevBatch, ok := s.makeXset(vcs) - if !ok { - t.Fatal("no xset") - } - - if xset != nil { - t.Errorf("should have null request") - } - - if !reflect.DeepEqual(prevBatch, prev) { - t.Errorf("batches don't match: %v, %v", prevBatch.DecodeHeader(), prev.DecodeHeader()) - } -} - -func TestXsetByz0(t *testing.T) { - s := &SBFT{config: Config{N: 4, F: 1}, view: 3} - vcs := []*ViewChange{ - &ViewChange{ - View: 3, - Pset: nil, - Qset: nil, - Checkpoint: s.makeBatch(1, []byte("prev"), nil), - }, - &ViewChange{ - View: 3, - Pset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}}, - Qset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}}, - Checkpoint: s.makeBatch(1, []byte("prev"), nil), - }, - &ViewChange{ - View: 3, - Pset: []*Subject{&Subject{&SeqView{2, 2}, []byte("val2")}}, - Qset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}, - &Subject{&SeqView{2, 2}, []byte("val2")}}, - Checkpoint: s.makeBatch(1, []byte("prev"), nil), - }, - } - - _, _, ok := s.makeXset(vcs) - if ok { - t.Error("should not have received an xset") - } - - vcs = append(vcs, &ViewChange{ - View: 3, - Pset: []*Subject{&Subject{&SeqView{2, 2}, []byte("val2")}}, - Qset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}, - &Subject{&SeqView{2, 2}, []byte("val2")}}, - Checkpoint: s.makeBatch(2, []byte("prev"), nil), - }) - - xset, _, ok := s.makeXset(vcs) - if !ok { - t.Error("no xset") - } - if xset != nil { - t.Error("expected null request") - } -} - -func TestXsetByz2(t *testing.T) { - s := &SBFT{config: Config{N: 4, F: 1}, view: 3} - vcs := []*ViewChange{ - &ViewChange{ - View: 3, - Pset: nil, - Qset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}}, - Checkpoint: s.makeBatch(1, []byte("prev"), nil), - }, - &ViewChange{ - View: 3, - Pset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}}, - Qset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}}, - Checkpoint: s.makeBatch(1, []byte("prev"), nil), - }, - &ViewChange{ - View: 3, - Pset: []*Subject{&Subject{&SeqView{2, 2}, []byte("val2")}}, - Qset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}, - &Subject{&SeqView{2, 2}, []byte("val2")}}, - Checkpoint: s.makeBatch(1, []byte("prev"), nil), - }, - } - - _, _, ok := s.makeXset(vcs) - if ok { - t.Error("should not have received an xset") - } - - vcs = append(vcs, &ViewChange{ - View: 3, - Pset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}}, - Qset: []*Subject{&Subject{&SeqView{1, 2}, []byte("val1")}}, - Checkpoint: s.makeBatch(1, []byte("prev"), nil), - }) - - xset, _, ok := s.makeXset(vcs) - if !ok { - t.Error("no xset") - } - if !reflect.DeepEqual(xset, &Subject{&SeqView{3, 2}, []byte("val1")}) { - t.Error(xset) - } -} diff --git a/orderer/sbft/simplebft/prepare.go b/orderer/sbft/simplebft/prepare.go deleted file mode 100644 index e065451eb8d..00000000000 --- a/orderer/sbft/simplebft/prepare.go +++ /dev/null @@ -1,42 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import "reflect" - -func (s *SBFT) sendPrepare() { - p := s.cur.subject - s.broadcast(&Msg{&Msg_Prepare{&p}}) -} - -func (s *SBFT) handlePrepare(p *Subject, src uint64) { - if p.Seq.Seq < s.cur.subject.Seq.Seq { - // old message - return - } - - if !reflect.DeepEqual(p, &s.cur.subject) { - log.Infof("replica %d: prepare does not match expected subject %v, got %v", s.id, &s.cur.subject, p) - return - } - if _, ok := s.cur.prep[src]; ok { - log.Infof("replica %d: duplicate prepare for %v from %d", s.id, *p.Seq, src) - return - } - s.cur.prep[src] = p - s.maybeSendCommit() -} diff --git a/orderer/sbft/simplebft/preprepare.go b/orderer/sbft/simplebft/preprepare.go deleted file mode 100644 index 5d3cb97aff2..00000000000 --- a/orderer/sbft/simplebft/preprepare.go +++ /dev/null @@ -1,124 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "bytes" - "time" - - "github.com/hyperledger/fabric/orderer/common/filter" -) - -func (s *SBFT) sendPreprepare(batch []*Request, committers []filter.Committer) { - seq := s.nextSeq() - - data := make([][]byte, len(batch)) - for i, req := range batch { - data[i] = req.Payload - } - - lasthash := hash(s.sys.LastBatch(s.chainId).Header) - - m := &Preprepare{ - Seq: &seq, - Batch: s.makeBatch(seq.Seq, lasthash, data), - } - - s.sys.Persist(s.chainId, preprepared, m) - s.broadcast(&Msg{&Msg_Preprepare{m}}) - log.Infof("replica %d: sendPreprepare", s.id) - s.handleCheckedPreprepare(m, committers) -} - -func (s *SBFT) handlePreprepare(pp *Preprepare, src uint64) { - if src == s.id { - log.Infof("replica %d: ignoring preprepare from self: %d", s.id, src) - return - } - if src != s.primaryID() { - log.Infof("replica %d: preprepare from non-primary %d", s.id, src) - return - } - nextSeq := s.nextSeq() - if *pp.Seq != nextSeq { - log.Infof("replica %d: preprepare does not match expected %v, got %v", s.id, nextSeq, *pp.Seq) - return - } - if s.cur.subject.Seq.Seq == pp.Seq.Seq { - log.Infof("replica %d: duplicate preprepare for %v", s.id, *pp.Seq) - return - } - if pp.Batch == nil { - log.Infof("replica %d: preprepare without batches", s.id) - return - } - - batchheader, err := s.checkBatch(pp.Batch, true, false) - if err != nil || batchheader.Seq != pp.Seq.Seq { - log.Infof("replica %d: preprepare %v batches head inconsistent from %d: %s", s.id, pp.Seq, src, err) - return - } - - prevhash := s.sys.LastBatch(s.chainId).Hash() - if !bytes.Equal(batchheader.PrevHash, prevhash) { - log.Infof("replica %d: preprepare batches prev hash does not match expected %s, got %s", s.id, hash2str(batchheader.PrevHash), hash2str(prevhash)) - return - } - - blockOK, committers := s.getCommittersFromBatch(pp.Batch) - if !blockOK { - log.Debugf("Replica %d found Byzantine block in preprepare, Seq: %d View: %d", s.id, pp.Seq.Seq, pp.Seq.View) - s.sendViewChange() - return - } - log.Infof("replica %d: handlePrepare", s.id) - s.handleCheckedPreprepare(pp, committers) -} - -func (s *SBFT) acceptPreprepare(pp *Preprepare, committers []filter.Committer) { - sub := Subject{Seq: pp.Seq, Digest: pp.Batch.Hash()} - - log.Infof("replica %d: accepting preprepare for %v, %x", s.id, sub.Seq, sub.Digest) - s.sys.Persist(s.chainId, preprepared, pp) - - s.cur = reqInfo{ - subject: sub, - timeout: s.sys.Timer(time.Duration(s.config.RequestTimeoutNsec)*time.Nanosecond, s.requestTimeout), - preprep: pp, - prep: make(map[uint64]*Subject), - commit: make(map[uint64]*Subject), - checkpoint: make(map[uint64]*Checkpoint), - committers: committers, - } -} - -func (s *SBFT) handleCheckedPreprepare(pp *Preprepare, committers []filter.Committer) { - s.acceptPreprepare(pp, committers) - if !s.isPrimary() { - s.sendPrepare() - s.processBacklog() - } - - s.maybeSendCommit() -} - -//////////////////////////////////////////////// - -func (s *SBFT) requestTimeout() { - log.Infof("replica %d: request timed out: %s", s.id, s.cur.subject.Seq) - s.sendViewChange() -} diff --git a/orderer/sbft/simplebft/request.go b/orderer/sbft/simplebft/request.go deleted file mode 100644 index c3b2adce922..00000000000 --- a/orderer/sbft/simplebft/request.go +++ /dev/null @@ -1,113 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "time" -) - -// Request proposes a new request to the BFT network. -func (s *SBFT) Request(req []byte) { - log.Debugf("replica %d: broadcasting a request", s.id) - s.broadcast(&Msg{&Msg_Request{&Request{req}}}) -} - -func (s *SBFT) handleRequest(req *Request, src uint64) { - key := hash2str(hash(req.Payload)) - log.Infof("replica %d: inserting %x into pending", s.id, key) - s.pending[key] = req - if s.isPrimary() && s.activeView { - batches, committers, valid := s.sys.Validate(s.chainId, req) - if !valid { - // this one is problematic, lets skip it - delete(s.pending, key) - return - } - s.validated[key] = valid - if len(batches) == 0 { - s.startBatchTimer() - } else { - s.batches = append(s.batches, batches...) - s.primarycommitters = append(s.primarycommitters, committers...) - s.maybeSendNextBatch() - } - } -} - -//////////////////////////////////////////////// - -func (s *SBFT) startBatchTimer() { - if s.batchTimer == nil { - s.batchTimer = s.sys.Timer(time.Duration(s.config.BatchDurationNsec), s.cutAndMaybeSend) - } -} - -func (s *SBFT) cutAndMaybeSend() { - batch, committers := s.sys.Cut(s.chainId) - s.batches = append(s.batches, batch) - s.primarycommitters = append(s.primarycommitters, committers) - s.maybeSendNextBatch() -} - -func (s *SBFT) maybeSendNextBatch() { - if s.batchTimer != nil { - s.batchTimer.Cancel() - s.batchTimer = nil - } - - if !s.isPrimary() || !s.activeView { - return - } - - if !s.cur.checkpointDone { - return - } - - if len(s.batches) == 0 { - hasPending := len(s.pending) != 0 - for k, req := range s.pending { - if s.validated[k] == false { - batches, committers, valid := s.sys.Validate(s.chainId, req) - s.batches = append(s.batches, batches...) - s.primarycommitters = append(s.primarycommitters, committers...) - if !valid { - log.Panicf("Replica %d: one of our own pending requests is erroneous.", s.id) - delete(s.pending, k) - continue - } - s.validated[k] = true - } - } - if len(s.batches) == 0 { - // if we have no pending, every req was included in batches - if !hasPending { - return - } - // we have pending reqs that were just sent for validation or - // were already sent (they are in s.validated) - batch, committers := s.sys.Cut(s.chainId) - s.batches = append(s.batches, batch) - s.primarycommitters = append(s.primarycommitters, committers) - } - } - - batch := s.batches[0] - s.batches = s.batches[1:] - committers := s.primarycommitters[0] - s.primarycommitters = s.primarycommitters[1:] - s.sendPreprepare(batch, committers) -} diff --git a/orderer/sbft/simplebft/simplebft.go b/orderer/sbft/simplebft/simplebft.go deleted file mode 100644 index a426ab8c17a..00000000000 --- a/orderer/sbft/simplebft/simplebft.go +++ /dev/null @@ -1,293 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "fmt" - "math" - "reflect" - "time" - - "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric/orderer/common/filter" - "github.com/op/go-logging" -) - -const preprepared string = "preprepared" -const prepared string = "prepared" -const committed string = "committed" -const viewchange string = "viewchange" - -// Receiver defines the API that is exposed by SBFT to the system. -type Receiver interface { - Receive(msg *Msg, src uint64) - Request(req []byte) - Connection(replica uint64) - GetChainId() string -} - -// System defines the API that needs to be provided for SBFT. -type System interface { - Send(chainId string, msg *Msg, dest uint64) - Timer(d time.Duration, f func()) Canceller - Deliver(chainId string, batch *Batch, committers []filter.Committer) - AddReceiver(chainId string, receiver Receiver) - Persist(chainId string, key string, data proto.Message) - Restore(chainId string, key string, out proto.Message) bool - LastBatch(chainId string) *Batch - Sign(data []byte) []byte - CheckSig(data []byte, src uint64, sig []byte) error - Reconnect(chainId string, replica uint64) - Validate(chainID string, req *Request) ([][]*Request, [][]filter.Committer, bool) - Cut(chainID string) ([]*Request, []filter.Committer) -} - -// Canceller allows cancelling of a scheduled timer event. -type Canceller interface { - Cancel() -} - -// SBFT is a simplified PBFT implementation. -type SBFT struct { - sys System - - config Config - id uint64 - view uint64 - batches [][]*Request - batchTimer Canceller - cur reqInfo - activeView bool - lastNewViewSent *NewView - viewChangeTimeout time.Duration - viewChangeTimer Canceller - replicaState []replicaInfo - pending map[string]*Request - validated map[string]bool - chainId string - primarycommitters [][]filter.Committer -} - -type reqInfo struct { - subject Subject - timeout Canceller - preprep *Preprepare - prep map[uint64]*Subject - commit map[uint64]*Subject - checkpoint map[uint64]*Checkpoint - prepared bool - committed bool - checkpointDone bool - committers []filter.Committer -} - -type replicaInfo struct { - backLog []*Msg - hello *Hello - signedViewchange *Signed - viewchange *ViewChange -} - -var log = logging.MustGetLogger("sbft") - -type dummyCanceller struct{} - -func (d dummyCanceller) Cancel() {} - -// New creates a new SBFT instance. -func New(id uint64, chainID string, config *Config, sys System) (*SBFT, error) { - if config.F*3+1 > config.N { - return nil, fmt.Errorf("invalid combination of N (%d) and F (%d)", config.N, config.F) - } - - s := &SBFT{ - config: *config, - sys: sys, - id: id, - chainId: chainID, - viewChangeTimer: dummyCanceller{}, - replicaState: make([]replicaInfo, config.N), - pending: make(map[string]*Request), - validated: make(map[string]bool), - batches: make([][]*Request, 0, 3), - primarycommitters: make([][]filter.Committer, 0), - } - s.sys.AddReceiver(chainID, s) - - s.view = 0 - s.cur.subject.Seq = &SeqView{} - s.cur.prepared = true - s.cur.committed = true - s.cur.checkpointDone = true - s.cur.timeout = dummyCanceller{} - s.activeView = true - - svc := &Signed{} - if s.sys.Restore(s.chainId, viewchange, svc) { - vc := &ViewChange{} - err := proto.Unmarshal(svc.Data, vc) - if err != nil { - return nil, err - } - fmt.Println(fmt.Sprintf("rep %d VIEW %d %d", s.id, s.view, vc.View)) - s.view = vc.View - s.replicaState[s.id].signedViewchange = svc - s.activeView = false - } - - pp := &Preprepare{} - if s.sys.Restore(s.chainId, preprepared, pp) && pp.Seq.View >= s.view { - s.view = pp.Seq.View - s.activeView = true - if pp.Seq.Seq > s.seq() { - // TODO double add to BC? - _, committers := s.getCommittersFromBatch(pp.Batch) - s.acceptPreprepare(pp, committers) - } - } - c := &Subject{} - if s.sys.Restore(s.chainId, prepared, c) && reflect.DeepEqual(c, &s.cur.subject) && c.Seq.View >= s.view { - s.cur.prepared = true - } - ex := &Subject{} - if s.sys.Restore(s.chainId, committed, ex) && reflect.DeepEqual(c, &s.cur.subject) && ex.Seq.View >= s.view { - s.cur.committed = true - } - - s.cancelViewChangeTimer() - return s, nil -} - -//////////////////////////////////////////////// - -func (s *SBFT) GetChainId() string { - return s.chainId -} - -func (s *SBFT) primaryIDView(v uint64) uint64 { - return v % s.config.N -} - -func (s *SBFT) primaryID() uint64 { - return s.primaryIDView(s.view) -} - -func (s *SBFT) isPrimary() bool { - return s.primaryID() == s.id -} - -func (s *SBFT) seq() uint64 { - return s.sys.LastBatch(s.chainId).DecodeHeader().Seq -} - -func (s *SBFT) nextSeq() SeqView { - return SeqView{Seq: s.seq() + 1, View: s.view} -} - -func (s *SBFT) nextView() uint64 { - return s.view + 1 -} - -func (s *SBFT) commonCaseQuorum() int { - //When N=3F+1 this should be 2F+1 (N-F) - //More generally, we need every two common case quorums of size X to intersect in at least F+1 orderers, - //hence 2X>=N+F+1, or X is: - return int(math.Ceil(float64(s.config.N+s.config.F+1) / float64(2))) -} - -func (s *SBFT) viewChangeQuorum() int { - //When N=3F+1 this should be 2F+1 (N-F) - //More generally, we need every view change quorum to intersect with every common case quorum at least F+1 orderers, hence: - //Y >= N-X+F+1 - return int(s.config.N+s.config.F+1) - s.commonCaseQuorum() -} - -func (s *SBFT) oneCorrectQuorum() int { - return int(s.config.F + 1) -} - -func (s *SBFT) broadcast(m *Msg) { - for i := uint64(0); i < s.config.N; i++ { - s.sys.Send(s.chainId, m, i) - } -} - -//////////////////////////////////////////////// - -// Receive is the ingress method for SBFT messages. -func (s *SBFT) Receive(m *Msg, src uint64) { - log.Debugf("replica %d: received message from %d: %s", s.id, src, m) - - if h := m.GetHello(); h != nil { - s.handleHello(h, src) - return - } else if req := m.GetRequest(); req != nil { - s.handleRequest(req, src) - return - } else if vs := m.GetViewChange(); vs != nil { - s.handleViewChange(vs, src) - return - } else if nv := m.GetNewView(); nv != nil { - s.handleNewView(nv, src) - return - } - - if s.testBacklogMessage(m, src) { - log.Debugf("replica %d: message for future seq, storing for later", s.id) - s.recordBacklogMsg(m, src) - return - } - - s.handleQueueableMessage(m, src) -} - -func (s *SBFT) handleQueueableMessage(m *Msg, src uint64) { - if pp := m.GetPreprepare(); pp != nil { - s.handlePreprepare(pp, src) - return - } else if p := m.GetPrepare(); p != nil { - s.handlePrepare(p, src) - return - } else if c := m.GetCommit(); c != nil { - s.handleCommit(c, src) - return - } else if c := m.GetCheckpoint(); c != nil { - s.handleCheckpoint(c, src) - return - } - - log.Warningf("replica %d: received invalid message from %d", s.id, src) -} - -func (s *SBFT) deliverBatch(batch *Batch, committers []filter.Committer) { - if committers == nil { - log.Warningf("replica %d: commiter is nil", s.id) - panic("Committer is nil.") - } - s.cur.checkpointDone = true - s.cur.timeout.Cancel() - // s.primarycommitters[0] - s.sys.Deliver(s.chainId, batch, committers) - // s.primarycommitters = s.primarycommitters[1:] - - for _, req := range batch.Payloads { - key := hash2str(hash(req)) - log.Infof("replica %d: attempting to remove %x from pending", s.id, key) - delete(s.pending, key) - delete(s.validated, key) - } -} diff --git a/orderer/sbft/simplebft/simplebft.pb.go b/orderer/sbft/simplebft/simplebft.pb.go deleted file mode 100644 index d8c399e9d36..00000000000 --- a/orderer/sbft/simplebft/simplebft.pb.go +++ /dev/null @@ -1,808 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: simplebft/simplebft.proto - -/* -Package simplebft is a generated protocol buffer package. - -It is generated from these files: - simplebft/simplebft.proto - -It has these top-level messages: - Config - MultiChainMsg - Msg - Request - SeqView - BatchHeader - Batch - Preprepare - Subject - ViewChange - Signed - NewView - Checkpoint - Hello -*/ -package simplebft - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type Config struct { - N uint64 `protobuf:"varint,1,opt,name=n" json:"n,omitempty"` - F uint64 `protobuf:"varint,2,opt,name=f" json:"f,omitempty"` - BatchDurationNsec uint64 `protobuf:"varint,3,opt,name=batch_duration_nsec,json=batchDurationNsec" json:"batch_duration_nsec,omitempty"` - BatchSizeBytes uint64 `protobuf:"varint,4,opt,name=batch_size_bytes,json=batchSizeBytes" json:"batch_size_bytes,omitempty"` - RequestTimeoutNsec uint64 `protobuf:"varint,5,opt,name=request_timeout_nsec,json=requestTimeoutNsec" json:"request_timeout_nsec,omitempty"` -} - -func (m *Config) Reset() { *m = Config{} } -func (m *Config) String() string { return proto.CompactTextString(m) } -func (*Config) ProtoMessage() {} -func (*Config) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -func (m *Config) GetN() uint64 { - if m != nil { - return m.N - } - return 0 -} - -func (m *Config) GetF() uint64 { - if m != nil { - return m.F - } - return 0 -} - -func (m *Config) GetBatchDurationNsec() uint64 { - if m != nil { - return m.BatchDurationNsec - } - return 0 -} - -func (m *Config) GetBatchSizeBytes() uint64 { - if m != nil { - return m.BatchSizeBytes - } - return 0 -} - -func (m *Config) GetRequestTimeoutNsec() uint64 { - if m != nil { - return m.RequestTimeoutNsec - } - return 0 -} - -type MultiChainMsg struct { - ChainID string `protobuf:"bytes,1,opt,name=chainID" json:"chainID,omitempty"` - Msg *Msg `protobuf:"bytes,2,opt,name=msg" json:"msg,omitempty"` -} - -func (m *MultiChainMsg) Reset() { *m = MultiChainMsg{} } -func (m *MultiChainMsg) String() string { return proto.CompactTextString(m) } -func (*MultiChainMsg) ProtoMessage() {} -func (*MultiChainMsg) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -func (m *MultiChainMsg) GetChainID() string { - if m != nil { - return m.ChainID - } - return "" -} - -func (m *MultiChainMsg) GetMsg() *Msg { - if m != nil { - return m.Msg - } - return nil -} - -type Msg struct { - // Types that are valid to be assigned to Type: - // *Msg_Request - // *Msg_Preprepare - // *Msg_Prepare - // *Msg_Commit - // *Msg_ViewChange - // *Msg_NewView - // *Msg_Checkpoint - // *Msg_Hello - Type isMsg_Type `protobuf_oneof:"type"` -} - -func (m *Msg) Reset() { *m = Msg{} } -func (m *Msg) String() string { return proto.CompactTextString(m) } -func (*Msg) ProtoMessage() {} -func (*Msg) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } - -type isMsg_Type interface { - isMsg_Type() -} - -type Msg_Request struct { - Request *Request `protobuf:"bytes,1,opt,name=request,oneof"` -} -type Msg_Preprepare struct { - Preprepare *Preprepare `protobuf:"bytes,2,opt,name=preprepare,oneof"` -} -type Msg_Prepare struct { - Prepare *Subject `protobuf:"bytes,3,opt,name=prepare,oneof"` -} -type Msg_Commit struct { - Commit *Subject `protobuf:"bytes,4,opt,name=commit,oneof"` -} -type Msg_ViewChange struct { - ViewChange *Signed `protobuf:"bytes,5,opt,name=view_change,json=viewChange,oneof"` -} -type Msg_NewView struct { - NewView *NewView `protobuf:"bytes,6,opt,name=new_view,json=newView,oneof"` -} -type Msg_Checkpoint struct { - Checkpoint *Checkpoint `protobuf:"bytes,7,opt,name=checkpoint,oneof"` -} -type Msg_Hello struct { - Hello *Hello `protobuf:"bytes,8,opt,name=hello,oneof"` -} - -func (*Msg_Request) isMsg_Type() {} -func (*Msg_Preprepare) isMsg_Type() {} -func (*Msg_Prepare) isMsg_Type() {} -func (*Msg_Commit) isMsg_Type() {} -func (*Msg_ViewChange) isMsg_Type() {} -func (*Msg_NewView) isMsg_Type() {} -func (*Msg_Checkpoint) isMsg_Type() {} -func (*Msg_Hello) isMsg_Type() {} - -func (m *Msg) GetType() isMsg_Type { - if m != nil { - return m.Type - } - return nil -} - -func (m *Msg) GetRequest() *Request { - if x, ok := m.GetType().(*Msg_Request); ok { - return x.Request - } - return nil -} - -func (m *Msg) GetPreprepare() *Preprepare { - if x, ok := m.GetType().(*Msg_Preprepare); ok { - return x.Preprepare - } - return nil -} - -func (m *Msg) GetPrepare() *Subject { - if x, ok := m.GetType().(*Msg_Prepare); ok { - return x.Prepare - } - return nil -} - -func (m *Msg) GetCommit() *Subject { - if x, ok := m.GetType().(*Msg_Commit); ok { - return x.Commit - } - return nil -} - -func (m *Msg) GetViewChange() *Signed { - if x, ok := m.GetType().(*Msg_ViewChange); ok { - return x.ViewChange - } - return nil -} - -func (m *Msg) GetNewView() *NewView { - if x, ok := m.GetType().(*Msg_NewView); ok { - return x.NewView - } - return nil -} - -func (m *Msg) GetCheckpoint() *Checkpoint { - if x, ok := m.GetType().(*Msg_Checkpoint); ok { - return x.Checkpoint - } - return nil -} - -func (m *Msg) GetHello() *Hello { - if x, ok := m.GetType().(*Msg_Hello); ok { - return x.Hello - } - return nil -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*Msg) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { - return _Msg_OneofMarshaler, _Msg_OneofUnmarshaler, _Msg_OneofSizer, []interface{}{ - (*Msg_Request)(nil), - (*Msg_Preprepare)(nil), - (*Msg_Prepare)(nil), - (*Msg_Commit)(nil), - (*Msg_ViewChange)(nil), - (*Msg_NewView)(nil), - (*Msg_Checkpoint)(nil), - (*Msg_Hello)(nil), - } -} - -func _Msg_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*Msg) - // type - switch x := m.Type.(type) { - case *Msg_Request: - b.EncodeVarint(1<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Request); err != nil { - return err - } - case *Msg_Preprepare: - b.EncodeVarint(2<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Preprepare); err != nil { - return err - } - case *Msg_Prepare: - b.EncodeVarint(3<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Prepare); err != nil { - return err - } - case *Msg_Commit: - b.EncodeVarint(4<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Commit); err != nil { - return err - } - case *Msg_ViewChange: - b.EncodeVarint(5<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.ViewChange); err != nil { - return err - } - case *Msg_NewView: - b.EncodeVarint(6<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.NewView); err != nil { - return err - } - case *Msg_Checkpoint: - b.EncodeVarint(7<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Checkpoint); err != nil { - return err - } - case *Msg_Hello: - b.EncodeVarint(8<<3 | proto.WireBytes) - if err := b.EncodeMessage(x.Hello); err != nil { - return err - } - case nil: - default: - return fmt.Errorf("Msg.Type has unexpected type %T", x) - } - return nil -} - -func _Msg_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*Msg) - switch tag { - case 1: // type.request - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(Request) - err := b.DecodeMessage(msg) - m.Type = &Msg_Request{msg} - return true, err - case 2: // type.preprepare - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(Preprepare) - err := b.DecodeMessage(msg) - m.Type = &Msg_Preprepare{msg} - return true, err - case 3: // type.prepare - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(Subject) - err := b.DecodeMessage(msg) - m.Type = &Msg_Prepare{msg} - return true, err - case 4: // type.commit - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(Subject) - err := b.DecodeMessage(msg) - m.Type = &Msg_Commit{msg} - return true, err - case 5: // type.view_change - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(Signed) - err := b.DecodeMessage(msg) - m.Type = &Msg_ViewChange{msg} - return true, err - case 6: // type.new_view - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(NewView) - err := b.DecodeMessage(msg) - m.Type = &Msg_NewView{msg} - return true, err - case 7: // type.checkpoint - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(Checkpoint) - err := b.DecodeMessage(msg) - m.Type = &Msg_Checkpoint{msg} - return true, err - case 8: // type.hello - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - msg := new(Hello) - err := b.DecodeMessage(msg) - m.Type = &Msg_Hello{msg} - return true, err - default: - return false, nil - } -} - -func _Msg_OneofSizer(msg proto.Message) (n int) { - m := msg.(*Msg) - // type - switch x := m.Type.(type) { - case *Msg_Request: - s := proto.Size(x.Request) - n += proto.SizeVarint(1<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(s)) - n += s - case *Msg_Preprepare: - s := proto.Size(x.Preprepare) - n += proto.SizeVarint(2<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(s)) - n += s - case *Msg_Prepare: - s := proto.Size(x.Prepare) - n += proto.SizeVarint(3<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(s)) - n += s - case *Msg_Commit: - s := proto.Size(x.Commit) - n += proto.SizeVarint(4<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(s)) - n += s - case *Msg_ViewChange: - s := proto.Size(x.ViewChange) - n += proto.SizeVarint(5<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(s)) - n += s - case *Msg_NewView: - s := proto.Size(x.NewView) - n += proto.SizeVarint(6<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(s)) - n += s - case *Msg_Checkpoint: - s := proto.Size(x.Checkpoint) - n += proto.SizeVarint(7<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(s)) - n += s - case *Msg_Hello: - s := proto.Size(x.Hello) - n += proto.SizeVarint(8<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(s)) - n += s - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -type Request struct { - Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` -} - -func (m *Request) Reset() { *m = Request{} } -func (m *Request) String() string { return proto.CompactTextString(m) } -func (*Request) ProtoMessage() {} -func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } - -func (m *Request) GetPayload() []byte { - if m != nil { - return m.Payload - } - return nil -} - -type SeqView struct { - View uint64 `protobuf:"varint,1,opt,name=view" json:"view,omitempty"` - Seq uint64 `protobuf:"varint,2,opt,name=seq" json:"seq,omitempty"` -} - -func (m *SeqView) Reset() { *m = SeqView{} } -func (m *SeqView) String() string { return proto.CompactTextString(m) } -func (*SeqView) ProtoMessage() {} -func (*SeqView) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } - -func (m *SeqView) GetView() uint64 { - if m != nil { - return m.View - } - return 0 -} - -func (m *SeqView) GetSeq() uint64 { - if m != nil { - return m.Seq - } - return 0 -} - -type BatchHeader struct { - Seq uint64 `protobuf:"varint,1,opt,name=seq" json:"seq,omitempty"` - PrevHash []byte `protobuf:"bytes,2,opt,name=prev_hash,json=prevHash,proto3" json:"prev_hash,omitempty"` - DataHash []byte `protobuf:"bytes,3,opt,name=data_hash,json=dataHash,proto3" json:"data_hash,omitempty"` -} - -func (m *BatchHeader) Reset() { *m = BatchHeader{} } -func (m *BatchHeader) String() string { return proto.CompactTextString(m) } -func (*BatchHeader) ProtoMessage() {} -func (*BatchHeader) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } - -func (m *BatchHeader) GetSeq() uint64 { - if m != nil { - return m.Seq - } - return 0 -} - -func (m *BatchHeader) GetPrevHash() []byte { - if m != nil { - return m.PrevHash - } - return nil -} - -func (m *BatchHeader) GetDataHash() []byte { - if m != nil { - return m.DataHash - } - return nil -} - -type Batch struct { - Header []byte `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` - Payloads [][]byte `protobuf:"bytes,2,rep,name=payloads,proto3" json:"payloads,omitempty"` - Signatures map[uint64][]byte `protobuf:"bytes,3,rep,name=signatures" json:"signatures,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value,proto3"` -} - -func (m *Batch) Reset() { *m = Batch{} } -func (m *Batch) String() string { return proto.CompactTextString(m) } -func (*Batch) ProtoMessage() {} -func (*Batch) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } - -func (m *Batch) GetHeader() []byte { - if m != nil { - return m.Header - } - return nil -} - -func (m *Batch) GetPayloads() [][]byte { - if m != nil { - return m.Payloads - } - return nil -} - -func (m *Batch) GetSignatures() map[uint64][]byte { - if m != nil { - return m.Signatures - } - return nil -} - -type Preprepare struct { - Seq *SeqView `protobuf:"bytes,1,opt,name=seq" json:"seq,omitempty"` - Batch *Batch `protobuf:"bytes,2,opt,name=batch" json:"batch,omitempty"` -} - -func (m *Preprepare) Reset() { *m = Preprepare{} } -func (m *Preprepare) String() string { return proto.CompactTextString(m) } -func (*Preprepare) ProtoMessage() {} -func (*Preprepare) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } - -func (m *Preprepare) GetSeq() *SeqView { - if m != nil { - return m.Seq - } - return nil -} - -func (m *Preprepare) GetBatch() *Batch { - if m != nil { - return m.Batch - } - return nil -} - -type Subject struct { - Seq *SeqView `protobuf:"bytes,1,opt,name=seq" json:"seq,omitempty"` - Digest []byte `protobuf:"bytes,2,opt,name=digest,proto3" json:"digest,omitempty"` -} - -func (m *Subject) Reset() { *m = Subject{} } -func (m *Subject) String() string { return proto.CompactTextString(m) } -func (*Subject) ProtoMessage() {} -func (*Subject) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } - -func (m *Subject) GetSeq() *SeqView { - if m != nil { - return m.Seq - } - return nil -} - -func (m *Subject) GetDigest() []byte { - if m != nil { - return m.Digest - } - return nil -} - -type ViewChange struct { - View uint64 `protobuf:"varint,1,opt,name=view" json:"view,omitempty"` - Pset []*Subject `protobuf:"bytes,2,rep,name=pset" json:"pset,omitempty"` - Qset []*Subject `protobuf:"bytes,3,rep,name=qset" json:"qset,omitempty"` - Checkpoint *Batch `protobuf:"bytes,4,opt,name=checkpoint" json:"checkpoint,omitempty"` -} - -func (m *ViewChange) Reset() { *m = ViewChange{} } -func (m *ViewChange) String() string { return proto.CompactTextString(m) } -func (*ViewChange) ProtoMessage() {} -func (*ViewChange) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } - -func (m *ViewChange) GetView() uint64 { - if m != nil { - return m.View - } - return 0 -} - -func (m *ViewChange) GetPset() []*Subject { - if m != nil { - return m.Pset - } - return nil -} - -func (m *ViewChange) GetQset() []*Subject { - if m != nil { - return m.Qset - } - return nil -} - -func (m *ViewChange) GetCheckpoint() *Batch { - if m != nil { - return m.Checkpoint - } - return nil -} - -type Signed struct { - Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"` -} - -func (m *Signed) Reset() { *m = Signed{} } -func (m *Signed) String() string { return proto.CompactTextString(m) } -func (*Signed) ProtoMessage() {} -func (*Signed) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } - -func (m *Signed) GetData() []byte { - if m != nil { - return m.Data - } - return nil -} - -func (m *Signed) GetSignature() []byte { - if m != nil { - return m.Signature - } - return nil -} - -type NewView struct { - View uint64 `protobuf:"varint,1,opt,name=view" json:"view,omitempty"` - Vset map[uint64]*Signed `protobuf:"bytes,2,rep,name=vset" json:"vset,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - Xset *Subject `protobuf:"bytes,3,opt,name=xset" json:"xset,omitempty"` - Batch *Batch `protobuf:"bytes,4,opt,name=batch" json:"batch,omitempty"` -} - -func (m *NewView) Reset() { *m = NewView{} } -func (m *NewView) String() string { return proto.CompactTextString(m) } -func (*NewView) ProtoMessage() {} -func (*NewView) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } - -func (m *NewView) GetView() uint64 { - if m != nil { - return m.View - } - return 0 -} - -func (m *NewView) GetVset() map[uint64]*Signed { - if m != nil { - return m.Vset - } - return nil -} - -func (m *NewView) GetXset() *Subject { - if m != nil { - return m.Xset - } - return nil -} - -func (m *NewView) GetBatch() *Batch { - if m != nil { - return m.Batch - } - return nil -} - -type Checkpoint struct { - Seq uint64 `protobuf:"varint,1,opt,name=seq" json:"seq,omitempty"` - Digest []byte `protobuf:"bytes,2,opt,name=digest,proto3" json:"digest,omitempty"` - Signature []byte `protobuf:"bytes,3,opt,name=signature,proto3" json:"signature,omitempty"` -} - -func (m *Checkpoint) Reset() { *m = Checkpoint{} } -func (m *Checkpoint) String() string { return proto.CompactTextString(m) } -func (*Checkpoint) ProtoMessage() {} -func (*Checkpoint) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } - -func (m *Checkpoint) GetSeq() uint64 { - if m != nil { - return m.Seq - } - return 0 -} - -func (m *Checkpoint) GetDigest() []byte { - if m != nil { - return m.Digest - } - return nil -} - -func (m *Checkpoint) GetSignature() []byte { - if m != nil { - return m.Signature - } - return nil -} - -type Hello struct { - Batch *Batch `protobuf:"bytes,1,opt,name=batch" json:"batch,omitempty"` - NewView *NewView `protobuf:"bytes,2,opt,name=new_view,json=newView" json:"new_view,omitempty"` -} - -func (m *Hello) Reset() { *m = Hello{} } -func (m *Hello) String() string { return proto.CompactTextString(m) } -func (*Hello) ProtoMessage() {} -func (*Hello) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } - -func (m *Hello) GetBatch() *Batch { - if m != nil { - return m.Batch - } - return nil -} - -func (m *Hello) GetNewView() *NewView { - if m != nil { - return m.NewView - } - return nil -} - -func init() { - proto.RegisterType((*Config)(nil), "simplebft.Config") - proto.RegisterType((*MultiChainMsg)(nil), "simplebft.MultiChainMsg") - proto.RegisterType((*Msg)(nil), "simplebft.Msg") - proto.RegisterType((*Request)(nil), "simplebft.Request") - proto.RegisterType((*SeqView)(nil), "simplebft.SeqView") - proto.RegisterType((*BatchHeader)(nil), "simplebft.BatchHeader") - proto.RegisterType((*Batch)(nil), "simplebft.Batch") - proto.RegisterType((*Preprepare)(nil), "simplebft.Preprepare") - proto.RegisterType((*Subject)(nil), "simplebft.Subject") - proto.RegisterType((*ViewChange)(nil), "simplebft.ViewChange") - proto.RegisterType((*Signed)(nil), "simplebft.Signed") - proto.RegisterType((*NewView)(nil), "simplebft.NewView") - proto.RegisterType((*Checkpoint)(nil), "simplebft.Checkpoint") - proto.RegisterType((*Hello)(nil), "simplebft.Hello") -} - -func init() { proto.RegisterFile("simplebft/simplebft.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 842 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x55, 0xdd, 0x8e, 0xdb, 0x44, - 0x14, 0x5e, 0xaf, 0x1d, 0x67, 0x73, 0xb2, 0x94, 0xed, 0x50, 0x2a, 0xb3, 0xf4, 0x22, 0x32, 0xa8, - 0xe4, 0x02, 0x92, 0x55, 0xa8, 0x00, 0x55, 0x42, 0x42, 0x49, 0x11, 0x01, 0xb4, 0x15, 0xf2, 0x56, - 0x2b, 0xd1, 0x0b, 0x22, 0xc7, 0x3e, 0xb1, 0x87, 0x4d, 0x6c, 0xc7, 0x33, 0x4e, 0x9a, 0x3e, 0x0c, - 0x17, 0x3c, 0x01, 0x0f, 0xc0, 0x1b, 0xf1, 0x12, 0x68, 0x7e, 0x62, 0x7b, 0xf3, 0x53, 0x55, 0xf2, - 0xc5, 0xcc, 0xf9, 0xbe, 0x39, 0xe7, 0x7c, 0x67, 0xce, 0x19, 0xc3, 0x27, 0x8c, 0x2e, 0xb2, 0x39, - 0x4e, 0x67, 0xbc, 0x5f, 0xae, 0x7a, 0x59, 0x9e, 0xf2, 0x94, 0xb4, 0x4a, 0x83, 0xfb, 0x8f, 0x01, - 0xf6, 0x28, 0x4d, 0x66, 0x34, 0x22, 0xe7, 0x60, 0x24, 0x8e, 0xd1, 0x31, 0xba, 0x96, 0x67, 0x24, - 0x62, 0x37, 0x73, 0x4e, 0xd5, 0x6e, 0x46, 0x7a, 0xf0, 0xd1, 0xd4, 0xe7, 0x41, 0x3c, 0x09, 0x8b, - 0xdc, 0xe7, 0x34, 0x4d, 0x26, 0x09, 0xc3, 0xc0, 0x31, 0x25, 0xfe, 0x50, 0x42, 0x2f, 0x34, 0xf2, - 0x92, 0x61, 0x40, 0xba, 0x70, 0xa1, 0xf8, 0x8c, 0xbe, 0xc5, 0xc9, 0x74, 0xc3, 0x91, 0x39, 0x96, - 0x24, 0x3f, 0x90, 0xf6, 0x1b, 0xfa, 0x16, 0x87, 0xc2, 0x4a, 0xae, 0xe0, 0x51, 0x8e, 0xcb, 0x02, - 0x19, 0x9f, 0x70, 0xba, 0xc0, 0xb4, 0xe0, 0xca, 0x75, 0x43, 0xb2, 0x89, 0xc6, 0x5e, 0x29, 0x48, - 0xf8, 0x76, 0x7f, 0x85, 0x0f, 0xae, 0x8b, 0x39, 0xa7, 0xa3, 0xd8, 0xa7, 0xc9, 0x35, 0x8b, 0x88, - 0x03, 0xcd, 0x40, 0xac, 0x7f, 0x7e, 0x21, 0xd3, 0x6f, 0x79, 0xdb, 0x2d, 0xe9, 0x80, 0xb9, 0x60, - 0x91, 0x94, 0xd1, 0x1e, 0x3c, 0xe8, 0x55, 0x75, 0xb8, 0x66, 0x91, 0x27, 0x20, 0xf7, 0x2f, 0x13, - 0x4c, 0xe1, 0xa3, 0x07, 0x4d, 0x1d, 0x4a, 0xfa, 0x68, 0x0f, 0x48, 0x8d, 0xed, 0x29, 0x64, 0x7c, - 0xe2, 0x6d, 0x49, 0xe4, 0x5b, 0x80, 0x2c, 0x47, 0xf1, 0xf9, 0x39, 0xea, 0x00, 0x1f, 0xd7, 0x8e, - 0xfc, 0x56, 0x82, 0xe3, 0x13, 0xaf, 0x46, 0x15, 0x81, 0xb6, 0xa7, 0xcc, 0xbd, 0x40, 0x37, 0xc5, - 0xf4, 0x4f, 0x0c, 0x64, 0xa0, 0x2d, 0xff, 0x4b, 0xb0, 0x83, 0x74, 0xb1, 0xa0, 0x5c, 0xd6, 0xef, - 0x18, 0x5d, 0x73, 0xc8, 0x33, 0x68, 0xaf, 0x28, 0xae, 0x27, 0x41, 0xec, 0x27, 0x11, 0xca, 0x22, - 0xb6, 0x07, 0x0f, 0xeb, 0x47, 0x68, 0x94, 0x60, 0x28, 0x72, 0x12, 0xbc, 0x91, 0xa4, 0x91, 0x3e, - 0x9c, 0x25, 0xb8, 0x9e, 0x08, 0x8b, 0x63, 0xef, 0x45, 0x79, 0x89, 0xeb, 0x5b, 0x8a, 0x6b, 0x91, - 0x54, 0xa2, 0x96, 0x42, 0x7d, 0x10, 0x63, 0x70, 0x97, 0xa5, 0x34, 0xe1, 0x4e, 0x73, 0x4f, 0xfd, - 0xa8, 0x04, 0x45, 0xa4, 0x8a, 0x4a, 0xba, 0xd0, 0x88, 0x71, 0x3e, 0x4f, 0x9d, 0x33, 0x79, 0xe6, - 0xa2, 0x76, 0x66, 0x2c, 0xec, 0xe3, 0x13, 0x4f, 0x11, 0x86, 0x36, 0x58, 0x7c, 0x93, 0xa1, 0xfb, - 0x19, 0x34, 0x75, 0xf9, 0xc5, 0x3d, 0x67, 0xfe, 0x66, 0x9e, 0xfa, 0xa1, 0xbc, 0xa3, 0x73, 0x6f, - 0xbb, 0x75, 0xfb, 0xd0, 0xbc, 0xc1, 0xa5, 0x4c, 0x8d, 0x80, 0x25, 0x75, 0xa8, 0x46, 0x96, 0x6b, - 0x72, 0x01, 0x26, 0xc3, 0xa5, 0xee, 0x66, 0xb1, 0x74, 0x7f, 0x87, 0xf6, 0x50, 0xf4, 0xe1, 0x18, - 0xfd, 0x10, 0xf3, 0x2d, 0xc1, 0x28, 0x09, 0xe4, 0x53, 0x68, 0x65, 0x39, 0xae, 0x26, 0xb1, 0xcf, - 0x62, 0x79, 0xf0, 0xdc, 0x3b, 0x13, 0x86, 0xb1, 0xcf, 0x62, 0x01, 0x86, 0x3e, 0xf7, 0x15, 0x68, - 0x2a, 0x50, 0x18, 0x04, 0xe8, 0xfe, 0x6b, 0x40, 0x43, 0xfa, 0x26, 0x8f, 0xc1, 0x8e, 0xa5, 0x7f, - 0x9d, 0xae, 0xde, 0x91, 0x4b, 0x38, 0xd3, 0x89, 0x33, 0xe7, 0xb4, 0x63, 0x4a, 0xd7, 0x7a, 0x4f, - 0x7e, 0x00, 0x60, 0x34, 0x4a, 0x7c, 0x5e, 0xe4, 0xc8, 0x1c, 0xb3, 0x63, 0x76, 0xdb, 0x83, 0x4e, - 0xad, 0x4a, 0xd2, 0xb3, 0xbc, 0x45, 0x45, 0xf9, 0x31, 0xe1, 0xf9, 0xc6, 0xab, 0x9d, 0xb9, 0xfc, - 0x1e, 0x3e, 0xdc, 0x81, 0x85, 0xbc, 0x3b, 0xdc, 0x6c, 0xe5, 0xdd, 0xe1, 0x86, 0x3c, 0x82, 0xc6, - 0xca, 0x9f, 0x17, 0xa8, 0xa5, 0xa9, 0xcd, 0xf3, 0xd3, 0xef, 0x0c, 0xf7, 0x35, 0x40, 0xd5, 0xbb, - 0xe4, 0xf3, 0xaa, 0x30, 0x3b, 0xad, 0xa7, 0xca, 0xad, 0x8a, 0xf5, 0x14, 0x1a, 0x72, 0xaa, 0xf5, - 0x1c, 0x5c, 0xec, 0xe6, 0xeb, 0x29, 0xd8, 0xfd, 0x09, 0x9a, 0xba, 0x65, 0xdf, 0xd3, 0xf1, 0x63, - 0xb0, 0x43, 0x1a, 0x89, 0xa1, 0x54, 0x79, 0xea, 0x9d, 0xfb, 0xb7, 0x01, 0x70, 0x5b, 0xf5, 0xef, - 0xa1, 0x3b, 0x7f, 0x0a, 0x56, 0xc6, 0x90, 0xcb, 0x02, 0x1f, 0x9c, 0x1a, 0x4f, 0xe2, 0x82, 0xb7, - 0x14, 0x3c, 0xf3, 0x38, 0x4f, 0xe0, 0xe4, 0xea, 0x5e, 0xcb, 0x5b, 0x47, 0x84, 0xd6, 0x38, 0xee, - 0x73, 0xb0, 0xd5, 0xb4, 0x89, 0xfc, 0x44, 0x7b, 0xe8, 0x36, 0x90, 0x6b, 0xf2, 0x04, 0x5a, 0xe5, - 0xa5, 0x69, 0x75, 0x95, 0xc1, 0xfd, 0xcf, 0x80, 0xa6, 0x9e, 0xbb, 0x83, 0xea, 0xae, 0xc0, 0x5a, - 0x55, 0xea, 0x9e, 0xec, 0x4f, 0x6b, 0xef, 0x96, 0x21, 0x57, 0xcd, 0x21, 0x99, 0x42, 0xe7, 0x1b, - 0xa5, 0xd3, 0x38, 0xa6, 0xf3, 0x8d, 0xe2, 0xe9, 0xbb, 0xb4, 0xde, 0x79, 0x97, 0x97, 0xbf, 0x40, - 0xab, 0x0c, 0x71, 0xa0, 0xc1, 0xbe, 0xa8, 0x37, 0xd8, 0xa1, 0x27, 0xa8, 0xde, 0x73, 0xaf, 0x00, - 0xaa, 0x17, 0xe3, 0xc0, 0x30, 0x1e, 0x69, 0x83, 0xfb, 0x35, 0x34, 0x77, 0x6b, 0xf8, 0x07, 0x34, - 0xe4, 0x9b, 0x52, 0x49, 0x32, 0xde, 0x29, 0x89, 0x7c, 0x55, 0x7b, 0x06, 0x4f, 0x8f, 0x3d, 0x83, - 0xe5, 0x23, 0x38, 0xfc, 0xe6, 0xf5, 0xb3, 0x88, 0xf2, 0xb8, 0x98, 0xf6, 0x82, 0x74, 0xd1, 0x8f, - 0x37, 0x19, 0xe6, 0x73, 0x0c, 0x23, 0xcc, 0xfb, 0x33, 0x7f, 0x9a, 0xd3, 0xa0, 0x9f, 0xe6, 0x21, - 0xe6, 0x98, 0xf7, 0xd9, 0xbd, 0x7f, 0xf0, 0xd4, 0x96, 0x3f, 0xe1, 0xaf, 0xff, 0x0f, 0x00, 0x00, - 0xff, 0xff, 0x42, 0xf4, 0xb2, 0x00, 0xa1, 0x07, 0x00, 0x00, -} diff --git a/orderer/sbft/simplebft/simplebft.proto b/orderer/sbft/simplebft/simplebft.proto deleted file mode 100644 index 13013003009..00000000000 --- a/orderer/sbft/simplebft/simplebft.proto +++ /dev/null @@ -1,108 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -syntax = "proto3"; - -option go_package = "github.com/hyperledger/fabric/orderer/sbft/simplebft"; - -package simplebft; - -message Config { - uint64 n = 1; - uint64 f = 2; - uint64 batch_duration_nsec = 3; - uint64 batch_size_bytes = 4; - uint64 request_timeout_nsec = 5; -}; - -message MultiChainMsg { - string chainID = 1; - Msg msg = 2; -} - -message Msg { - oneof type { - Request request = 1; - Preprepare preprepare = 2; - Subject prepare = 3; - Subject commit = 4; - Signed view_change = 5; - NewView new_view = 6; - Checkpoint checkpoint = 7; - Hello hello = 8; - }; -}; - -message Request { - bytes payload = 1; -}; - -message SeqView { - uint64 view = 1; - uint64 seq = 2; -}; - -message BatchHeader { - uint64 seq = 1; - bytes prev_hash = 2; - bytes data_hash = 3; -}; - -message Batch { - bytes header = 1; - repeated bytes payloads = 2; - map signatures = 3; -}; - -message Preprepare { - SeqView seq = 1; - Batch batch = 2; -}; - -message Subject { - SeqView seq = 1; - bytes digest = 2; -}; - -message ViewChange { - uint64 view = 1; - repeated Subject pset = 2; - repeated Subject qset = 3; - Batch checkpoint = 4; -}; - -message Signed { - bytes data = 1; - bytes signature = 2; -}; - -message NewView { - uint64 view = 1; - map vset = 2; - Subject xset = 3; - Batch batch = 4; -}; - -message Checkpoint { - uint64 seq = 1; - bytes digest = 2; - bytes signature = 3; -}; - -message Hello { - Batch batch = 1; - NewView new_view = 2; -}; diff --git a/orderer/sbft/simplebft/simplebft_bench_test.go b/orderer/sbft/simplebft/simplebft_bench_test.go deleted file mode 100644 index 6797faf2457..00000000000 --- a/orderer/sbft/simplebft/simplebft_bench_test.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "testing" - - "github.com/op/go-logging" -) - -func BenchmarkRequestN1(b *testing.B) { - logging.SetLevel(logging.WARNING, "sbft") - - sys := newTestSystem(1) - s, _ := New(0, chainId, &Config{N: 1, F: 0, BatchDurationNsec: 2000000000, BatchSizeBytes: 1, RequestTimeoutNsec: 20000000000}, sys.NewAdapter(0)) - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.Request([]byte{byte(i), byte(i >> 8), byte(i >> 16)}) - sys.Run() - } - logging.SetLevel(logging.NOTICE, "sbft") -} - -func BenchmarkRequestN4(b *testing.B) { - logging.SetLevel(logging.WARNING, "sbft") - - N := uint64(4) - var repls []*SBFT - var adapters []*testSystemAdapter - sys := newTestSystem(N) - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 11, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - b.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - repls[0].Request([]byte{byte(i), byte(i >> 8), byte(i >> 16)}) - sys.Run() - } - logging.SetLevel(logging.NOTICE, "sbft") -} - -func BenchmarkRequestN80(b *testing.B) { - logging.SetLevel(logging.WARNING, "sbft") - - N := uint64(80) - var repls []*SBFT - var adapters []*testSystemAdapter - sys := newTestSystem(N) - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: (N - 1) / 3, BatchDurationNsec: 2000000000, BatchSizeBytes: 11, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - b.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - repls[0].Request([]byte{byte(i), byte(i >> 8), byte(i >> 16)}) - sys.Run() - } - logging.SetLevel(logging.NOTICE, "sbft") -} diff --git a/orderer/sbft/simplebft/simplebft_test.go b/orderer/sbft/simplebft/simplebft_test.go deleted file mode 100644 index cc3e75e3bc0..00000000000 --- a/orderer/sbft/simplebft/simplebft_test.go +++ /dev/null @@ -1,1515 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "reflect" - "testing" - "time" - - "math" - - "fmt" - "strconv" - - "github.com/golang/protobuf/proto" - "github.com/op/go-logging" -) - -const chainId = "id" -const lowN uint64 = 4 //keep lowN greater or equal to 4 -const highN uint64 = 10 //keep highN greater or equal to 10 - -var testLog = logging.MustGetLogger("test") - -func init() { - // logging.SetLevel(logging.NOTICE, "") - // logging.SetLevel(logging.DEBUG, "test") - logging.SetLevel(logging.DEBUG, "sbft") -} - -func skipInShortMode(t *testing.T) { - if testing.Short() { - t.Skip("Skipping test in short mode.") - } -} - -func connectAll(sys *testSystem, chainIds []string) { - for _, chainId := range chainIds { - connectAllForChainId(sys, chainId) - } -} - -func connectAllForDefaultChain(sys *testSystem) { - connectAllForChainId(sys, chainId) -} - -func connectAllForChainId(sys *testSystem, chainId string) { - // map iteration is non-deterministic, so use linear iteration instead - max := uint64(0) - for _, a := range sys.adapters { - if a.id > max { - max = a.id - } - } - - for i := uint64(0); i <= max; i++ { - a, ok := sys.adapters[i] - if !ok { - continue - } - - for j := uint64(0); j <= max; j++ { - b, ok := sys.adapters[j] - if !ok { - continue - } - if a.id != b.id { - a.receivers[chainId].Connection(b.id) - } - } - } - sys.Run() -} - -func TestMultiChain(t *testing.T) { - skipInShortMode(t) - N := lowN - M := uint64(5) - sys := newTestSystem(N) - chainIds := make([]string, 0, M) - var repls map[string][]*SBFT = map[string][]*SBFT{} - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - for j := uint64(0); j < M; j++ { - chainId := fmt.Sprintf("%d", j) - s, err := New(i, chainId, &Config{N: N, F: 0, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls[chainId] = append(repls[chainId], s) - if uint64(len(chainIds)) < M { - chainIds = append(chainIds, chainId) - } - } - adapters = append(adapters, a) - } - connectAll(sys, chainIds) - r1 := []byte{1, 2, 3} - for i := uint64(0); i < N; i++ { - for j := uint64(0); j < M; j++ { - if j%uint64(2) == 0 { - chainId := fmt.Sprintf("%d", j) - repls[chainId][i].Request(r1) - } - } - } - sys.Run() - for _, a := range adapters { - for chainId := range a.batches { - // we check that if this is a chain where we sent a req then the req - // was written to the "ledger" - j, _ := strconv.ParseInt(chainId, 10, 64) - if j%2 == 0 && len(a.batches[chainId]) != 1 { - t.Fatalf("expected one batches on chain %s", chainId) - } - // in other cases, we should have at most an empty ledger - if j%2 != 0 && len(a.batches[chainId]) != 0 { - t.Fatalf("expected one batches on chain %s", chainId) - } - } - } -} - -func TestSBFT(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - connectAllForDefaultChain(sys) - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - r2 := []byte{3, 1, 2} - r3 := []byte{3, 5, 2} - repls[1].Request(r2) - repls[1].Request(r3) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 2 { - t.Fatal("expected execution of 2 batches") - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - if !reflect.DeepEqual([][]byte{r2, r3}, a.batches[chainId][1].Payloads) { - t.Error("wrong request executed (2)") - } - } -} - -func TestQuorumSizes(t *testing.T) { - for N := uint64(1); N < 100; N++ { - for f := uint64(0); f <= uint64(math.Floor(float64(N-1)/float64(3))); f++ { - sys := newTestSystem(N) - a := sys.NewAdapter(0) - s, err := New(0, chainId, &Config{N: N, F: f, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - if uint64(2*s.commonCaseQuorum())-N < f+1 { - t.Fatal("insufficient intersection of two common case quorums", "N = ", N, " F = ", f) - } - if uint64(s.commonCaseQuorum()+s.viewChangeQuorum())-N < f+1 { - t.Fatal("insufficient intersection of common case and view change quorums", "N = ", N, " F = ", f) - } - if f < uint64(math.Floor(float64(N-1)/float64(3))) { - //end test for unoptimized f - continue - } - //test additionally when f is optimized - switch int(math.Mod(float64(N), float64(3))) { - case 1: - if s.commonCaseQuorum() != int(N-f) || s.viewChangeQuorum() != int(N-f) { - t.Fatal("quorum sizes are wrong in default case N mod 3 == 1") - } - case 2: - if s.viewChangeQuorum() >= s.commonCaseQuorum() || s.viewChangeQuorum() >= int(N-f) { - t.Fatal("view change quorums size not optimized when N mod 3 == 2") - } - case 3: - if s.commonCaseQuorum() >= int(N-f) || s.viewChangeQuorum() >= int(N-f) { - t.Fatal("quorum sizes not optimized when N mod 3 == 3") - } - } - } - } -} - -func TestSBFTDelayed(t *testing.T) { - skipInShortMode(t) - N := lowN - BS := uint64(1) - sys := newTestSystemWithBatchSize(N, BS) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: BS, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - // make replica 3 lag out against 1 and 2 - for i := uint64(1); i < 3; i++ { - adapters[i].arrivals[3] = 200 * time.Millisecond - adapters[3].arrivals[i] = 200 * time.Millisecond - } - - connectAllForDefaultChain(sys) - r1 := []byte{1, 2, 3} - r2 := []byte{3, 1, 2} - repls[0].Request(r1) - repls[1].Request(r2) - sys.Run() - for i, a := range adapters { - if len(a.batches[chainId]) != 2 { - t.Errorf("expected execution of 2 batches on %d", i) - continue - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - if !reflect.DeepEqual([][]byte{r2}, a.batches[chainId][1].Payloads) { - t.Error("wrong request executed (2)") - } - } -} - -func TestN1(t *testing.T) { - skipInShortMode(t) - N := uint64(1) - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 0, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - connectAllForDefaultChain(sys) - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 1 { - t.Fatal("expected execution of 1 batches") - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - } -} - -func TestMonotonicViews(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - repls[0].sendViewChange() - sys.Run() - - view := repls[0].view - testLog.Notice("TEST: Replica 0 is in view ", view) - testLog.Notice("TEST: restarting replica 0") - repls[0], _ = New(0, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, adapters[0]) - for _, a := range adapters { - if a.id != 0 { - a.receivers[chainId].Connection(0) - adapters[0].receivers[chainId].Connection(a.id) - } - } - sys.Run() - - if repls[0].view < view { - t.Fatalf("Replica 0 must be at least in view %d, but is in view %d", view, repls[0].view) - } -} - -func TestByzPrimaryN4(t *testing.T) { - skipInShortMode(t) - N := uint64(4) - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 1, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - r1 := []byte{1, 2, 3} - r2 := []byte{5, 6, 7} - - // change preprepare to 2, 3 - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if pp := msg.msg.GetPreprepare(); pp != nil && msg.src == 0 && msg.dst >= 2 { - pp := *pp - batch := *pp.Batch - batch.Payloads = [][]byte{r2} - pp.Batch = &batch - h := merkleHashData(batch.Payloads) - bh := &BatchHeader{} - proto.Unmarshal(pp.Batch.Header, bh) - bh.DataHash = h - bhraw, _ := proto.Marshal(bh) - pp.Batch.Header = bhraw - msg.msg = &Msg{&Msg_Preprepare{&pp}} - } - } - return e, true - } - - connectAllForDefaultChain(sys) - repls[0].Request(r1) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 2 { - t.Fatal("expected execution of 2 batches") - } - if !reflect.DeepEqual([][]byte{r2}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed first") - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][1].Payloads) { - t.Error("wrong request executed second") - } - } -} - -func TestNewPrimaryHandlingViewChange(t *testing.T) { - skipInShortMode(t) - N := uint64(7) - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 2, BatchDurationNsec: 2000000000, BatchSizeBytes: 1, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - r1 := []byte{1, 2, 3} - r2 := []byte{5, 6, 7} - - // change preprepare to 2-6 - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if pp := msg.msg.GetPreprepare(); pp != nil && msg.src == 0 && msg.dst >= 2 { - pp := *pp - batch := *pp.Batch - batch.Payloads = [][]byte{r2} - pp.Batch = &batch - h := merkleHashData(batch.Payloads) - bh := &BatchHeader{} - proto.Unmarshal(pp.Batch.Header, bh) - bh.DataHash = h - bhraw, _ := proto.Marshal(bh) - pp.Batch.Header = bhraw - msg.msg = &Msg{&Msg_Preprepare{&pp}} - } - } - return e, true - } - - connectAllForDefaultChain(sys) - repls[0].Request(r1) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) < 1 { - t.Fatal("expected execution of at least one batches") - } - if a.batches[chainId][0].Payloads != nil && !reflect.DeepEqual(adapters[2].batches[chainId][0].Payloads, a.batches[chainId][0].Payloads) { - t.Error("consensus violated on first batches at replica", a.id) - } - } -} - -func TestByzPrimaryBullyingSingleReplica(t *testing.T) { - skipInShortMode(t) - N := highN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 1, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - r1 := []byte{1, 2, 3} - r2 := []byte{5, 6, 7} - - // change preprepare to 1 - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if pp := msg.msg.GetPreprepare(); pp != nil && msg.src == 0 && msg.dst == 1 { - pp := *pp - batch := *pp.Batch - batch.Payloads = [][]byte{r2} - pp.Batch = &batch - h := merkleHashData(batch.Payloads) - bh := &BatchHeader{} - proto.Unmarshal(pp.Batch.Header, bh) - bh.DataHash = h - bhraw, _ := proto.Marshal(bh) - pp.Batch.Header = bhraw - msg.msg = &Msg{&Msg_Preprepare{&pp}} - } - } - return e, true - } - - connectAllForDefaultChain(sys) - repls[0].Request(r1) - sys.Run() - for _, a := range adapters { - if a.id != 1 && len(a.batches[chainId]) != 1 { - t.Fatal("expected execution of 1 batches at all except replica 1") - } - } -} - -func TestViewChange(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 1, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - // network outage after prepares are received - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if c := msg.msg.GetCommit(); c != nil && c.Seq.View == 0 { - return e, false - } - } - return e, true - } - - connectAllForDefaultChain(sys) - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 1 { - t.Fatal("expected execution of 1 batches") - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - } -} - -func TestMsgReordering(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 1, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - var preprep *testMsgEvent - - // forcing pre-prepare from primary 0 to reach replica 1 after some delay - // effectively delivering pre-prepare instead of checkpoint - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if msg.src == 0 && msg.dst == 1 { - c := msg.msg.GetPreprepare() - if c != nil && c.Seq.View == 0 { - preprep = msg //memorizing pre-prepare - return e, false // but dropping it - } - d := msg.msg.GetCheckpoint() - if d != nil { - msg.msg = &Msg{&Msg_Preprepare{preprep.msg.GetPreprepare()}} - return e, true //and delivering it - } - return e, false //droping other msgs from 0 to 1 - } - } - return e, true - } - - connectAllForDefaultChain(sys) - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 1 { - t.Fatal("expected execution of 1 batches") - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - } -} - -func TestBacklogReordering(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 1, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - var preprep *testMsgEvent - - // forcing pre-prepare from primary 0 to reach replica 1 after some delay - // effectively delivering pre-prepare instead of checkpoint - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if msg.src == 0 && msg.dst == 1 { - c := msg.msg.GetPreprepare() - if c != nil && c.Seq.View == 0 { - preprep = msg //memorizing pre-prepare - return e, false // but dropping it - } - d := msg.msg.GetCheckpoint() - if d != nil { - msg.msg = &Msg{&Msg_Preprepare{preprep.msg.GetPreprepare()}} - return e, true //and delivering it - } - return e, true //letting prepare and commit from 0 to 1 pass - } - } - return e, true - } - - connectAllForDefaultChain(sys) - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 1 { - t.Fatal("expected execution of 1 batches") - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - } -} - -func TestViewChangeWithRetransmission(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 1, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - // network outage after prepares are received - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if c := msg.msg.GetPrepare(); c != nil && c.Seq.View == 0 { - return e, false - } - } - return e, true - } - - connectAllForDefaultChain(sys) - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 1 { - t.Fatal("expected execution of 1 batches") - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - } -} - -func TestViewChangeXset(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 1, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - phase := 1 - - // network outage after prepares are received - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if msg.src == msg.dst { - return e, true - } - - switch phase { - case 1: - if p := msg.msg.GetPrepare(); p != nil && p.Seq.View == 0 { - return e, false - } - case 2: - if nv := msg.msg.GetNewView(); nv != nil { - phase = 3 - return e, true - } - if msg.src == 3 || msg.dst == 3 { - return e, false - } - if c := msg.msg.GetCommit(); c != nil && c.Seq.View == 1 { - return e, false - } - case 3: - if msg.src == 3 || msg.dst == 3 { - return e, false - } - } - } - return e, true - } - - connectAllForDefaultChain(sys) - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - phase = 2 - - r2 := []byte{5, 6, 7} - repls[1].Request(r2) - sys.Run() - - for i, a := range adapters { - // 3 is disconnected - if i == 3 { - continue - } - if len(a.batches[chainId]) != 2 { - t.Fatalf("expected execution of 1 batches: %v", a.batches[chainId]) - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed first") - } - if !reflect.DeepEqual([][]byte{r2}, a.batches[chainId][1].Payloads) { - t.Error("wrong request executed second") - } - } -} - -func TestRestart(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - connectAllForDefaultChain(sys) - // move to view 1 - for _, r := range repls { - r.sendViewChange() - } - sys.Run() - - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - - testLog.Notice("restarting 0") - repls[0], _ = New(0, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, adapters[0]) - for _, a := range adapters { - if a.id != 0 { - a.receivers[chainId].Connection(0) - adapters[0].receivers[chainId].Connection(a.id) - } - } - - r2 := []byte{3, 1, 2} - r3 := []byte{3, 5, 2} - repls[1].Request(r2) - repls[1].Request(r3) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 2 { - t.Fatalf("expected execution of 2 batches, %d got %v", a.id, a.batches) - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - if !reflect.DeepEqual([][]byte{r2, r3}, a.batches[chainId][1].Payloads) { - t.Error("wrong request executed (2)") - } - } -} - -func TestAbdicatingPrimary(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - phase := 1 - // Dropping all phase 1 msgs except requests and viewchange to 0 - // (preprepare to primary 0 is automatically delivered) - sys.filterFn = func(e testElem) (testElem, bool) { - if phase == 1 { - if msg, ok := e.ev.(*testMsgEvent); ok { - if c := msg.msg.GetRequest(); c != nil { - return e, true - } - if c := msg.msg.GetViewChange(); c != nil && msg.dst == 0 { - return e, true - } - return e, false - } - return e, true - } - return e, true - } - - connectAllForDefaultChain(sys) - - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - - phase = 2 - - testLog.Notice("TEST: restarting connections from 0") - for _, a := range adapters { - if a.id != 0 { - a.receivers[chainId].Connection(0) - adapters[0].receivers[chainId].Connection(a.id) - } - } - - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 1 { - t.Fatalf("expected execution of 1 batches, %d got %v", a.id, a.batches[chainId]) - } - } -} - -func TestRestartAfterPrepare(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - restarted := false - - // network outage after prepares are received - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if msg.src == msg.dst || msg.src != 0 { - return e, true - } - - if p := msg.msg.GetPrepare(); p != nil && p.Seq.Seq == 3 && !restarted { - restarted = true - testLog.Notice("restarting 0") - repls[0], _ = New(0, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, adapters[0]) - for _, a := range adapters { - if a.id != 0 { - a.receivers[chainId].Connection(0) - adapters[0].receivers[chainId].Connection(a.id) - } - } - } - } - - return e, true - } - - connectAllForDefaultChain(sys) - // move to view 1 - for _, r := range repls { - r.sendViewChange() - } - sys.Run() - - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - - r2 := []byte{3, 1, 2} - r3 := []byte{3, 5, 2} - repls[1].Request(r2) - repls[1].Request(r3) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 2 { - t.Fatal("expected execution of 2 batches") - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - if !reflect.DeepEqual([][]byte{r2, r3}, a.batches[chainId][1].Payloads) { - t.Error("wrong request executed (2)") - } - } -} - -func TestRestartAfterCommit(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - restarted := false - - // network outage after prepares are received - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if msg.src == msg.dst || msg.src != 0 { - return e, true - } - - if c := msg.msg.GetCommit(); c != nil && c.Seq.Seq == 3 && !restarted { - restarted = true - testLog.Notice("restarting 0") - repls[0], _ = New(0, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, adapters[0]) - for _, a := range adapters { - if a.id != 0 { - a.receivers[chainId].Connection(0) - adapters[0].receivers[chainId].Connection(a.id) - } - } - } - } - - return e, true - } - - connectAllForDefaultChain(sys) - // move to view 1 - for _, r := range repls { - r.sendViewChange() - } - sys.Run() - - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - - r2 := []byte{3, 1, 2} - r3 := []byte{3, 5, 2} - repls[1].Request(r2) - repls[1].Request(r3) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 2 { - t.Fatal("expected execution of 2 batches") - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - if !reflect.DeepEqual([][]byte{r2, r3}, a.batches[chainId][1].Payloads) { - t.Error("wrong request executed (2)") - } - } -} - -func TestRestartAfterCheckpoint(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - restarted := false - - // network outage after prepares are received - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if msg.src == msg.dst || msg.src != 0 { - return e, true - } - - if c := msg.msg.GetCheckpoint(); c != nil && c.Seq == 3 && !restarted { - restarted = true - testLog.Notice("restarting 0") - repls[0], _ = New(0, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, adapters[0]) - for _, a := range adapters { - if a.id != 0 { - a.receivers[chainId].Connection(0) - adapters[0].receivers[chainId].Connection(a.id) - } - } - } - } - - return e, true - } - - connectAllForDefaultChain(sys) - // move to view 1 - for _, r := range repls { - r.sendViewChange() - } - sys.Run() - - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - - r2 := []byte{3, 1, 2} - r3 := []byte{3, 5, 2} - repls[1].Request(r2) - repls[1].Request(r3) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 2 { - t.Fatal("expected execution of 2 batches") - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - if !reflect.DeepEqual([][]byte{r2, r3}, a.batches[chainId][1].Payloads) { - t.Error("wrong request executed (2)") - } - } -} - -func TestErroneousViewChange(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - restarted := false - - // network outage after prepares are received - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if msg.src == msg.dst || msg.src != 0 { - return e, true - } - - if c := msg.msg.GetCheckpoint(); c != nil && c.Seq == 3 && !restarted { - restarted = true - testLog.Notice("restarting 0") - repls[0], _ = New(0, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, adapters[0]) - for _, a := range adapters { - if a.id != 0 { - a.receivers[chainId].Connection(0) - adapters[0].receivers[chainId].Connection(a.id) - } - } - } - } - - return e, true - } - - // iteration order here is essential to trigger the bug - outer := []uint64{2, 3, 0, 1} - inner := []uint64{0, 1, 2, 3} - for _, i := range outer { - a, ok := sys.adapters[i] - if !ok { - continue - } - - for _, j := range inner { - b, ok := sys.adapters[j] - if !ok { - continue - } - if a.id != b.id { - a.receivers[chainId].Connection(b.id) - } - } - } - sys.Run() - - // move to view 1 - for _, r := range repls { - r.sendViewChange() - } - sys.Run() - - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - - r2 := []byte{3, 1, 2} - r3 := []byte{3, 5, 2} - repls[1].Request(r2) - repls[1].Request(r3) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 2 { - t.Fatal("expected execution of 2 batches") - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - if !reflect.DeepEqual([][]byte{r2, r3}, a.batches[chainId][1].Payloads) { - t.Error("wrong request executed (2)") - } - } -} - -func TestRestartMissedViewChange(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - disconnect := false - - // network outage after prepares are received - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if disconnect && (msg.src == 0 || msg.dst == 0) { - return e, false - } - } - - return e, true - } - - connectAllForDefaultChain(sys) - - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - - disconnect = true - // move to view 1 - for _, r := range repls { - if r.id != 0 { - r.sendViewChange() - } - } - sys.Run() - - r2 := []byte{3, 1, 2} - repls[1].Request(r2) - sys.Run() - - disconnect = false - testLog.Notice("restarting 0") - repls[0], _ = New(0, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, adapters[0]) - for _, a := range adapters { - if a.id != 0 { - a.receivers[chainId].Connection(0) - adapters[0].receivers[chainId].Connection(a.id) - } - } - - r3 := []byte{3, 5, 2} - repls[1].Request(r3) - - sys.Run() - - for _, a := range adapters { - if len(a.batches[chainId]) == 0 { - t.Fatalf("expected execution of some batches on %d", a.id) - } - - if !reflect.DeepEqual([][]byte{r3}, a.batches[chainId][len(a.batches[chainId])-1].Payloads) { - t.Errorf("wrong request executed on %d: %v", a.id, a.batches[chainId][2]) - } - } -} - -func TestFullBacklog(t *testing.T) { - skipInShortMode(t) - N := lowN - BS := uint64(1) - sys := newTestSystemWithBatchSize(N, BS) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: BS, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - r1 := []byte{1, 2, 3} - - connectAllForDefaultChain(sys) - sys.enqueue(200*time.Millisecond, &testTimer{id: 999, tf: func() { - repls[0].sys.Send(chainId, &Msg{&Msg_Prepare{&Subject{Seq: &SeqView{Seq: 100}}}}, 1) - }}) - for i := 0; i < 10; i++ { - sys.enqueue(time.Duration(i)*100*time.Millisecond, &testTimer{id: 999, tf: func() { - repls[0].Request(r1) - }}) - } - sys.Run() - if len(repls[1].replicaState[2].backLog) > 4*3 { - t.Errorf("backlog too long: %d", len(repls[1].replicaState[0].backLog)) - } - for _, a := range adapters { - if len(a.batches[chainId]) == 0 { - t.Fatalf("expected execution of batches on %d", a.id) - } - bh := a.batches[chainId][len(a.batches[chainId])-1].DecodeHeader() - if bh.Seq != 10 { - t.Errorf("wrong request executed on %d: %v", a.id, bh) - } - } -} - -func TestHelloMsg(t *testing.T) { - skipInShortMode(t) - N := lowN - BS := uint64(1) - sys := newTestSystemWOTimersWithBatchSize(N, BS) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: uint64(BS), RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - phase := 1 - - // We are going to deliver only pre-prepare of the first request to replica 1 - // other messages pertaining to first request, destined to 1 will be dropped - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if msg.dst == 1 { - c := msg.msg.GetPreprepare() - if c != nil && c.Seq.View == 0 && phase == 1 { - return e, true // letting the first pre-prepare be delivered to 1 - } - if phase > 1 { - return e, true //letting msgs outside phase 1 through - } - return e, false //dropping other phase 1 msgs - } - } - return e, true - } - - connectAllForDefaultChain(sys) - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - - phase = 2 //start delivering msgs to replica 1 - - testLog.Notice("restarting replica 1") - repls[1], _ = New(1, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: BS, RequestTimeoutNsec: 20000000000}, adapters[1]) - for _, a := range adapters { - if a.id != 1 { - a.receivers[chainId].Connection(1) - adapters[1].receivers[chainId].Connection(a.id) - } - } - - sys.Run() - - phase = 3 - - r3 := []byte{3, 5, 2} - repls[1].Request(r3) - sys.Run() - - for i, a := range adapters { - if len(a.batches[chainId]) != 2 { - t.Fatalf("expected execution of 2 batches but executed %d %d", len(a.batches[chainId]), i) - } - } -} - -func TestViewChangeTimer(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - phase := 1 - - // network outage after prepares are received - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if msg.dst == msg.src { - return e, true - } else if msg.src == 1 && phase == 2 { - return e, false - } - testLog.Debugf("passing msg from %d to %d, phase %d", msg.src, msg.dst, phase) - } - - return e, true - } - - connectAllForDefaultChain(sys) - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - - repls[3].sendViewChange() - - sys.enqueue(10*time.Minute, &testTimer{id: 999, tf: func() { - if repls[3].view != 1 { - t.Fatalf("expected view not to advance past 1, we are in %d", repls[3].view) - } - }}) - - sys.enqueue(11*time.Minute, &testTimer{id: 999, tf: func() { - phase = 2 - repls[2].sendViewChange() - }}) - - sys.enqueue(12*time.Minute, &testTimer{id: 999, tf: func() { - if repls[3].view != 2 { - t.Fatalf("expected view not to advance past 2, 3 is in %d", repls[3].view) - } - }}) - - sys.enqueue(20*time.Minute, &testTimer{id: 999, tf: func() { - for _, r := range repls { - if r.view > 4 { - t.Fatalf("expected view not to advance too much, we are in %d", r.view) - } - } - }}) - - sys.Run() - r2 := []byte{3, 1, 2} - r3 := []byte{3, 5, 2} - repls[2].Request(r2) - repls[2].Request(r3) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 2 { - t.Fatalf("%d: expected execution of 2 batches: %v", a.id, a.batches[chainId]) - } - if a.id != 3 { - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Errorf("%d: wrong request executed (1): %v", a.id, a.batches[chainId]) - } - } - if !reflect.DeepEqual([][]byte{r2, r3}, a.batches[chainId][1].Payloads) { - t.Errorf("%d: wrong request executed (2): %v", a.id, a.batches[chainId]) - } - } -} - -func TestResendViewChange(t *testing.T) { - skipInShortMode(t) - N := lowN - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 1, BatchDurationNsec: 2000000000, BatchSizeBytes: 10, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - phase := make(map[uint64]int) - - // prevent first view change from being delivered - sys.filterFn = func(e testElem) (testElem, bool) { - if msg, ok := e.ev.(*testMsgEvent); ok { - if msg.dst == msg.src { - return e, true - } else if phase[msg.src] == 0 && msg.msg.GetViewChange() != nil { - return e, false - } else if msg.msg.GetHello() != nil { - phase[msg.src] = 1 - } - } - - return e, true - } - - for _, r := range repls { - r.sendViewChange() - } - sys.Run() - - connectAllForDefaultChain(sys) - r1 := []byte{1, 2, 3} - repls[0].Request(r1) - sys.Run() - r2 := []byte{3, 1, 2} - r3 := []byte{3, 5, 2} - repls[1].Request(r2) - repls[1].Request(r3) - sys.Run() - for _, a := range adapters { - if len(a.batches[chainId]) != 2 { - t.Fatal("expected execution of 2 batches") - } - if !reflect.DeepEqual([][]byte{r1}, a.batches[chainId][0].Payloads) { - t.Error("wrong request executed (1)") - } - if !reflect.DeepEqual([][]byte{r2, r3}, a.batches[chainId][1].Payloads) { - t.Error("wrong request executed (2)") - } - } -} - -func TestTenReplicasBombedWithRequests(t *testing.T) { - skipInShortMode(t) - N := highN - requestNumber := 11 - sys := newTestSystem(N) - var repls []*SBFT - var adapters []*testSystemAdapter - for i := uint64(0); i < N; i++ { - a := sys.NewAdapter(i) - s, err := New(i, chainId, &Config{N: N, F: 3, BatchDurationNsec: 2000000000, BatchSizeBytes: 3, RequestTimeoutNsec: 20000000000}, a) - if err != nil { - t.Fatal(err) - } - repls = append(repls, s) - adapters = append(adapters, a) - } - - connectAllForDefaultChain(sys) - for i := 0; i < requestNumber; i++ { - r := []byte{byte(i), 2, 3} - repls[2].Request(r) - } - sys.Run() - for _, a := range adapters { - i := 0 - for _, b := range a.batches[chainId] { - i = i + len(b.Payloads) - } - if i != requestNumber { - t.Fatalf("expected execution of %d requests but: %d", requestNumber, i) - } - } -} diff --git a/orderer/sbft/simplebft/testsys_test.go b/orderer/sbft/simplebft/testsys_test.go deleted file mode 100644 index fce8201f328..00000000000 --- a/orderer/sbft/simplebft/testsys_test.go +++ /dev/null @@ -1,358 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "crypto/ecdsa" - "crypto/elliptic" - crand "crypto/rand" - "crypto/sha256" - "encoding/asn1" - "fmt" - "math/big" - "math/rand" - "reflect" - "runtime" - "time" - - "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric/orderer/common/filter" -) - -const defaultMaxReqCount = uint64(5) - -var maxReqCount uint64 - -type testSystemAdapter struct { - id uint64 - sys *testSystem - - // chainId to instance mapping - receivers map[string]Receiver - batches map[string][]*Batch - persistence map[string][]byte - - arrivals map[uint64]time.Duration - reqs []*Request - - key *ecdsa.PrivateKey -} - -func (t *testSystemAdapter) AddReceiver(chainId string, recv Receiver) { - if t.receivers == nil { - t.receivers = make(map[string]Receiver) - } - if t.receivers[chainId] != nil { - // remove all events for us - t.sys.queue.filter(func(e testElem) bool { - switch e := e.ev.(type) { - case *testTimer: - if e.id == t.id { - return false - } - case *testMsgEvent: - if e.dst == t.id { - return false - } - } - return true - }) - } - - t.receivers[chainId] = recv -} - -func (t *testSystemAdapter) getArrival(dest uint64) time.Duration { - // XXX for now, define fixed variance per destination - arr, ok := t.arrivals[dest] - if !ok { - inflight := 20 * time.Millisecond - variance := 1 * time.Millisecond - if dest == t.id { - inflight = 0 - } - variance = time.Duration(t.sys.rand.Int31n(int32(variance))) - arr = inflight + variance - t.arrivals[dest] = arr - } - return arr -} - -func (t *testSystemAdapter) Send(chainId string, msg *Msg, dest uint64) { - arr := t.getArrival(dest) - ev := &testMsgEvent{ - inflight: arr, - src: t.id, - dst: dest, - msg: msg, - chainId: chainId, - } - // simulate time for marshalling (and unmarshalling) - bytes, _ := proto.Marshal(msg) - m2 := &Msg{} - _ = proto.Unmarshal(bytes, m2) - t.sys.enqueue(arr, ev) -} - -type testMsgEvent struct { - inflight time.Duration - src, dst uint64 - msg *Msg - chainId string -} - -func (ev *testMsgEvent) Exec(t *testSystem) { - r := t.adapters[ev.dst] - if r == nil { - testLog.Errorf("message to non-existing %s", ev) - return - } - r.receivers[ev.chainId].Receive(ev.msg, ev.src) -} - -func (ev *testMsgEvent) String() string { - return fmt.Sprintf("Message", t.id, t.cancelled, fun) -} - -func (t *testSystemAdapter) Timer(d time.Duration, tf func()) Canceller { - tt := &testTimer{id: t.id, tf: tf} - if !t.sys.disableTimers { - t.sys.enqueue(d, tt) - } - return tt -} - -func (t *testSystemAdapter) Deliver(chainId string, batch *Batch, committer []filter.Committer) { - if t.batches == nil { - t.batches = make(map[string][]*Batch) - } - if t.batches[chainId] == nil { - t.batches[chainId] = make([]*Batch, 0, 1) - } - t.batches[chainId] = append(t.batches[chainId], batch) -} - -func (t *testSystemAdapter) Validate(chainID string, req *Request) ([][]*Request, [][]filter.Committer, bool) { - r := t.reqs - if t.reqs == nil || uint64(len(t.reqs)) == maxReqCount-uint64(1) { - t.reqs = make([]*Request, 0, maxReqCount-1) - } - if uint64(len(r)) == maxReqCount-uint64(1) { - c := [][]filter.Committer{{}} - return [][]*Request{append(r, req)}, c, true - } - t.reqs = append(t.reqs, req) - return nil, nil, true -} - -func (t *testSystemAdapter) Cut(chainID string) ([]*Request, []filter.Committer) { - r := t.reqs - t.reqs = make([]*Request, 0, maxReqCount) - return r, []filter.Committer{} -} - -func (t *testSystemAdapter) Persist(chainId string, key string, data proto.Message) { - compk := fmt.Sprintf("chain-%s-%s", chainId, key) - if data == nil { - delete(t.persistence, compk) - } else { - bytes, err := proto.Marshal(data) - if err != nil { - panic(err) - } - t.persistence[compk] = bytes - } -} - -func (t *testSystemAdapter) Restore(chainId string, key string, out proto.Message) bool { - compk := fmt.Sprintf("chain-%s-%s", chainId, key) - val, ok := t.persistence[compk] - if !ok { - return false - } - err := proto.Unmarshal(val, out) - return (err == nil) -} - -func (t *testSystemAdapter) LastBatch(chainId string) *Batch { - if len(t.batches[chainId]) == 0 { - return t.receivers[chainId].(*SBFT).makeBatch(0, nil, nil) - } - return t.batches[chainId][len(t.batches[chainId])-1] -} - -func (t *testSystemAdapter) Sign(data []byte) []byte { - hash := sha256.Sum256(data) - r, s, err := ecdsa.Sign(crand.Reader, t.key, hash[:]) - if err != nil { - panic(err) - } - sig, err := asn1.Marshal(struct{ R, S *big.Int }{r, s}) - if err != nil { - panic(err) - } - return sig -} - -func (t *testSystemAdapter) CheckSig(data []byte, src uint64, sig []byte) error { - rs := struct{ R, S *big.Int }{} - rest, err := asn1.Unmarshal(sig, &rs) - if err != nil { - return err - } - if len(rest) != 0 { - return fmt.Errorf("invalid signature") - } - hash := sha256.Sum256(data) - ok := ecdsa.Verify(&t.sys.adapters[src].key.PublicKey, hash[:], rs.R, rs.S) - if !ok { - return fmt.Errorf("invalid signature") - } - return nil -} - -func (t *testSystemAdapter) Reconnect(chainId string, replica uint64) { - testLog.Infof("dropping connection from %d to %d", replica, t.id) - t.sys.queue.filter(func(e testElem) bool { - switch e := e.ev.(type) { - case *testMsgEvent: - if e.dst == t.id && e.src == replica { - return false - } - } - return true - }) - arr := t.sys.adapters[replica].arrivals[t.id] * 10 - t.sys.enqueue(arr, &testTimer{id: t.id, tf: func() { - testLog.Infof("reconnecting %d to %d", replica, t.id) - t.sys.adapters[replica].receivers[chainId].Connection(t.id) - }}) -} - -// ============================================== - -type testEvent interface { - Exec(t *testSystem) -} - -// ============================================== - -type testSystem struct { - rand *rand.Rand - now time.Duration - queue *calendarQueue - adapters map[uint64]*testSystemAdapter - filterFn func(testElem) (testElem, bool) - disableTimers bool -} - -type testElem struct { - at time.Duration - ev testEvent -} - -func (t testElem) String() string { - return fmt.Sprintf("Event<%s: %s>", t.at, t.ev) -} - -func newTestSystem(n uint64) *testSystem { - return newTestSystemWithBatchSize(n, defaultMaxReqCount) -} - -func newTestSystemWithBatchSize(n uint64, batchSize uint64) *testSystem { - return newTestSystemWithParams(n, batchSize, false) -} - -func newTestSystemWOTimersWithBatchSize(n uint64, batchSize uint64) *testSystem { - return newTestSystemWithParams(n, batchSize, true) -} - -func newTestSystemWithParams(n uint64, batchSize uint64, disableTimers bool) *testSystem { - maxReqCount = batchSize - return &testSystem{ - rand: rand.New(rand.NewSource(0)), - adapters: make(map[uint64]*testSystemAdapter), - queue: newCalendarQueue(time.Millisecond/time.Duration(n*n), int(n*n)), - disableTimers: disableTimers, - } -} - -func (t *testSystem) NewAdapter(id uint64) *testSystemAdapter { - key, err := ecdsa.GenerateKey(elliptic.P256(), crand.Reader) - if err != nil { - panic(err) - } - a := &testSystemAdapter{ - id: id, - sys: t, - arrivals: make(map[uint64]time.Duration), - persistence: make(map[string][]byte), - key: key, - } - t.adapters[id] = a - return a -} - -func (t *testSystem) enqueue(d time.Duration, ev testEvent) { - e := testElem{at: t.now + d, ev: ev} - if t.filterFn != nil { - var keep bool - e, keep = t.filterFn(e) - if !keep { - return - } - } - testLog.Debugf("enqueuing %s\n", e) - t.queue.Add(e) -} - -func (t *testSystem) Run() { - for { - e, ok := t.queue.Pop() - if !ok { - break - } - t.now = e.at - testLog.Debugf("executing %s\n", e) - e.ev.Exec(t) - } - - testLog.Debugf("max len: %d", t.queue.maxLen) - t.queue.maxLen = 0 -} diff --git a/orderer/sbft/simplebft/testsys_test_test.go b/orderer/sbft/simplebft/testsys_test_test.go deleted file mode 100644 index e222aa25ad1..00000000000 --- a/orderer/sbft/simplebft/testsys_test_test.go +++ /dev/null @@ -1,96 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import ( - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/rsa" - "crypto/sha256" - "testing" - "time" -) - -func TestSys(t *testing.T) { - s := newTestSystem(1) - called := false - s.enqueue(1*time.Second, &testTimer{tf: func() { - called = true - }}) - s.Run() - if !called { - t.Fatal("expected execution") - } -} - -// func TestMsg(t *testing.T) { -// s := newTestSystem() -// a := s.NewAdapter(0) -// called := false -// a.Send(nil, 0) -// s.enqueue(1*time.Second, &testTimer{tf: func() { -// called = true -// }}) -// s.Run() -// if !called { -// t.Fatal("expected execution") -// } -// } - -func BenchmarkEcdsaSign(b *testing.B) { - key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - val := sha256.Sum256(make([]byte, 32, 32)) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - ecdsa.Sign(rand.Reader, key, val[:]) - } -} - -func BenchmarkRsaSign(b *testing.B) { - key, _ := rsa.GenerateKey(rand.Reader, 2048) - val := sha256.Sum256(make([]byte, 32, 32)) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - rsa.SignPSS(rand.Reader, key, crypto.SHA256, val[:], nil) - } -} - -func BenchmarkEcdsaVerify(b *testing.B) { - key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - val := sha256.Sum256(make([]byte, 32, 32)) - r, s, _ := ecdsa.Sign(rand.Reader, key, val[:]) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - ecdsa.Verify(&key.PublicKey, val[:], r, s) - } -} - -func BenchmarkRsaVerify(b *testing.B) { - key, _ := rsa.GenerateKey(rand.Reader, 2048) - val := sha256.Sum256(make([]byte, 32, 32)) - sig, _ := rsa.SignPSS(rand.Reader, key, crypto.SHA256, val[:], nil) - - b.ResetTimer() - for i := 0; i < b.N; i++ { - rsa.VerifyPSS(&key.PublicKey, crypto.SHA256, val[:], sig, nil) - } -} diff --git a/orderer/sbft/simplebft/viewchange.go b/orderer/sbft/simplebft/viewchange.go deleted file mode 100644 index b2b885377f8..00000000000 --- a/orderer/sbft/simplebft/viewchange.go +++ /dev/null @@ -1,127 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import "time" - -func (s *SBFT) sendViewChange() { - s.view = s.nextView() - s.cur.timeout.Cancel() - s.activeView = false - for src := range s.replicaState { - state := &s.replicaState[src] - if state.viewchange != nil && state.viewchange.View < s.view { - state.viewchange = nil - } - } - log.Noticef("replica %d: sending viewchange for view %d", s.id, s.view) - - var q, p []*Subject - if s.cur.prepared { - p = append(p, &s.cur.subject) - } - if s.cur.preprep != nil { - q = append(q, &s.cur.subject) - } - - // TODO fix batches synchronization as we send no payload here - checkpoint := *s.sys.LastBatch(s.chainId) - checkpoint.Payloads = nil // don't send the big payload - - vc := &ViewChange{ - View: s.view, - Qset: q, - Pset: p, - Checkpoint: &checkpoint, - } - svc := s.sign(vc) - s.viewChangeTimer.Cancel() - s.cur.timeout.Cancel() - - s.sys.Persist(s.chainId, viewchange, svc) - s.broadcast(&Msg{&Msg_ViewChange{svc}}) -} - -func (s *SBFT) cancelViewChangeTimer() { - s.viewChangeTimer.Cancel() - s.viewChangeTimeout = time.Duration(s.config.RequestTimeoutNsec) * 2 -} - -func (s *SBFT) handleViewChange(svc *Signed, src uint64) { - vc := &ViewChange{} - err := s.checkSig(svc, src, vc) - if err == nil { - _, err = s.checkBatch(vc.Checkpoint, false, true) - } - if err != nil { - log.Noticef("replica %d: invalid viewchange: %s", s.id, err) - return - } - if vc.View < s.view { - log.Debugf("replica %d: old view change from %d for view %d, we are in view %d", s.id, src, vc.View, s.view) - return - } - if ovc := s.replicaState[src].viewchange; ovc != nil && vc.View <= ovc.View { - log.Noticef("replica %d: duplicate view change for %d from %d", s.id, vc.View, src) - return - } - - log.Infof("replica %d: viewchange from %d: %v", s.id, src, vc) - s.replicaState[src].viewchange = vc - s.replicaState[src].signedViewchange = svc - - min := vc.View - - //amplify current primary abdication - if s.view == min-1 && s.primaryID() == src { - s.sendViewChange() - return - } - - quorum := 0 - for _, state := range s.replicaState { - if state.viewchange != nil { - quorum++ - if state.viewchange.View < min { - min = state.viewchange.View - } - } - } - - if quorum == s.oneCorrectQuorum() { - // catch up to the minimum view - if s.view < min { - log.Noticef("replica %d: we are behind on view change, resending for newer view", s.id) - s.view = min - 1 - s.sendViewChange() - return - } - } - - if quorum == s.viewChangeQuorum() { - log.Noticef("replica %d: received view change quorum, starting view change timer", s.id) - s.viewChangeTimer = s.sys.Timer(s.viewChangeTimeout, func() { - s.viewChangeTimeout *= 2 - log.Noticef("replica %d: view change timed out, sending next", s.id) - s.sendViewChange() - }) - } - - if s.isPrimary() { - s.maybeSendNewView() - } -} diff --git a/orderer/sbft/simplebft/xset.go b/orderer/sbft/simplebft/xset.go deleted file mode 100644 index 8fd1053fd2b..00000000000 --- a/orderer/sbft/simplebft/xset.go +++ /dev/null @@ -1,141 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package simplebft - -import "reflect" - -// makeXset returns a request subject that should be proposed as batches -// for new-view. If there is no request to select (null request), it -// will return nil for subject. makeXset always returns a batches for -// the most recent checkpoint. -func (s *SBFT) makeXset(vcs []*ViewChange) (*Subject, *Batch, bool) { - // first select base commit (equivalent to checkpoint/low water mark) - var best *Batch - for _, vc := range vcs { - seq := vc.Checkpoint.DecodeHeader().Seq - if best == nil || seq > best.DecodeHeader().Seq { - best = vc.Checkpoint - } - } - - if best == nil { - return nil, nil, false - } - - next := best.DecodeHeader().Seq + 1 - log.Debugf("replica %d: xset starts at commit %d", s.id, next) - - // now determine which request could have executed for best+1 - var xset *Subject - - // This is according to Castro's TOCS PBFT, Fig. 4 - // find some message m in S, - emptycount := 0 -nextm: - for _, m := range vcs { - notfound := true - // which has in its Pset - for _, mtuple := range m.Pset { - log.Debugf("replica %d: trying %v", s.id, mtuple) - if mtuple.Seq.Seq < next { - continue - } - - // we found an entry for next - notfound = false - - // A1. where 2f+1 messages mp from S - count := 0 - nextmp: - for _, mp := range vcs { - // "low watermark" is less than n - if mp.Checkpoint.DecodeHeader().Seq > mtuple.Seq.Seq { - continue - } - // and all in its Pset - for _, mptuple := range mp.Pset { - log.Debugf("replica %d: matching %v", s.id, mptuple) - if mptuple.Seq.Seq != mtuple.Seq.Seq { - continue - } - - // either v' < v or (v' == v and d' == d) - if mptuple.Seq.View < mtuple.Seq.View || - (mptuple.Seq.View == mtuple.Seq.View && reflect.DeepEqual(mptuple.Digest, mtuple.Digest)) { - continue - } else { - continue nextmp - } - } - count += 1 - } - if count < s.viewChangeQuorum() { - continue - } - log.Debugf("replica %d: found %d replicas for Pset %d/%d", s.id, count, mtuple.Seq.Seq, mtuple.Seq.View) - - // A2. f+1 messages mp from S - count = 0 - for _, mp := range vcs { - // and all in its Qset - for _, mptuple := range mp.Qset { - if mptuple.Seq.Seq != mtuple.Seq.Seq { - continue - } - if mptuple.Seq.View < mtuple.Seq.View { - continue - } - // d' == d - if !reflect.DeepEqual(mptuple.Digest, mtuple.Digest) { - continue - } - count += 1 - // there exists one ... - break - } - } - if count < s.oneCorrectQuorum() { - continue - } - log.Debugf("replica %d: found %d replicas for Qset %d", s.id, count, mtuple.Seq.Seq) - - log.Debugf("replica %d: selecting %d with %x", s.id, next, mtuple.Digest) - xset = &Subject{ - Seq: &SeqView{Seq: next, View: s.view}, - Digest: mtuple.Digest, - } - break nextm - } - - if notfound { - emptycount += 1 - } - } - - // B. otherwise select null request - // We actually don't select a null request, but report the most recent batches instead. - if emptycount >= s.viewChangeQuorum() { - log.Debugf("replica %d: no pertinent requests found for %d", s.id, next) - return nil, best, true - } - - if xset == nil { - return nil, nil, false - } - - return xset, best, true -} diff --git a/orderer/sbft/testdata/cert1.pem b/orderer/sbft/testdata/cert1.pem deleted file mode 100644 index cce757fe786..00000000000 --- a/orderer/sbft/testdata/cert1.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDHjCCAdagAwIBAgIEODubmDANBgkqhkiG9w0BAQsFADAAMB4XDTE2MDkyOTA5 -MjE1OVoXDTE3MDkyOTA5MjE1OVowADCCAVIwDQYJKoZIhvcNAQEBBQADggE/ADCC -AToCggExAKCVvOxTZHmrzEePUND1RaU+vMaUBAzJuaQMCd9lkV1al9aIiSouRoUF -AstJFzCcH3MKs5bUCde/SOC2103jcj5wU+SJy9xs3ra0c6BdI2RsiBmBujwHhJ6M -iU3tn+rC9WakX50UuY3h0Vy88PANZdPqOlISGv/S1pwp+sQxUn70T4vaW0Cdkgvp -XeDxvnxWdR9RWuuIyb3tN7v/y4g+bvj0GMSWkhyn0U1LkP/zQcX4+DNSpN3BiP0Y -Svi7+cOM7c+Itd3H59QaqhzzaXVZQgiVXdQqcfGhMKluCcB86vTWP+nvHK3XyLTA -EPkzzVZdCOAs24y/n2TVN7JCaYc7qFm7Xb4hbMwihKk94ITafp+l0DC/rKZLjKWM -nIeXLgWFlnqtxB/59pxsQLdnrnf8sHUCAwEAAaNAMD4wDAYDVR0TAQH/BAIwADAP -BgNVHQ8BAf8EBQMDB6AAMB0GA1UdDgQWBBRG2R59HhC+pUwPJbq2F1LKjLc7STAN -BgkqhkiG9w0BAQsFAAOCATEAIXX/f7oJF0mKpDtyQ5d385DzVNqZimNZbY7HGFB0 -aXP+jMKg54hM1EjxyDvI0DD4fxbH+SY5tUOX3Z6Y9BaU0v6yiXmIgHAolKTGbxh2 -G/ZQu+IiCfUSkIBJlcW+J0SYuNCinNrftj6+AxXt8ujwg9j5Ysgwt1IyH8CLa9tc -+IVGxuueQy8952bSdJjZv7B3D3rAfkbw4ZoPByvM3AaZgAhNaFLfi1b9R3c3sdP5 -wQZZSdJtptI/cpajoVof/9/UGUBK/cUZGcjK42iJKlTTaV7wH0MP2CIotG65Gt9m -sj2BZnoSVH75GIVYA2Z1M4obTpUmVbFWhJSCp2/Y4n9egzJ1c4+paMoh3LzRTZP0 -C0+Shlk5lbL+l6C/n+3LDriw/RQYd2vM6aNfwfPq6qmJOA== ------END CERTIFICATE----- diff --git a/orderer/sbft/testdata/config.json b/orderer/sbft/testdata/config.json deleted file mode 100644 index 2e556a73e4c..00000000000 --- a/orderer/sbft/testdata/config.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "consensus": { - "n" : 1, - "f" : 0, - "batch_size_bytes" : 1000, - "batch_duration_nsec" : 1000000000, - "request_timeout_nsec" : 1000000000 - }, - "peers": [ -{ - "id": 0, - "address": ":6101", - "cert": "testdata/cert1.pem" -}] -} diff --git a/orderer/sbft/testdata/key.pem b/orderer/sbft/testdata/key.pem deleted file mode 100644 index bf076374abf..00000000000 --- a/orderer/sbft/testdata/key.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIFfAIBAAKCATEAoJW87FNkeavMR49Q0PVFpT68xpQEDMm5pAwJ32WRXVqX1oiJ -Ki5GhQUCy0kXMJwfcwqzltQJ179I4LbXTeNyPnBT5InL3GzetrRzoF0jZGyIGYG6 -PAeEnoyJTe2f6sL1ZqRfnRS5jeHRXLzw8A1l0+o6UhIa/9LWnCn6xDFSfvRPi9pb -QJ2SC+ld4PG+fFZ1H1Fa64jJve03u//LiD5u+PQYxJaSHKfRTUuQ//NBxfj4M1Kk -3cGI/RhK+Lv5w4ztz4i13cfn1BqqHPNpdVlCCJVd1Cpx8aEwqW4JwHzq9NY/6e8c -rdfItMAQ+TPNVl0I4CzbjL+fZNU3skJphzuoWbtdviFszCKEqT3ghNp+n6XQML+s -pkuMpYych5cuBYWWeq3EH/n2nGxAt2eud/ywdQIDAQABAoIBMDDur8zLdHhm0y6T -CytBMeGyhk90Vu+WoIzOZku+ZVcu/cmPfUxvIWnzJvDO6tQTHrotbp/tKLqnPQvM -azr+rZc9HzMqkgYu3oaJ4hnhh6FYOPicwST9nXm6lTQ7zlj441JNkB0LbadAQk2h -/UEItBio7PCJN9TwaBjZ6eHSrbKlu3+AIAJGgXRDvimHQGYe6j2KysuuuNq4bG2V -0mj1uduZ/frEmMq2fmsT9XVVW+/URNb5L9lOxoBfUQsXPCzIKJDUDG2Zo0INrP5+ -X2xid6CjEn2K0ZHn7OHoWfp911nrq/ChbUbjRMZ536ogFBRj3Pzcj/kZBJDuWmBx -lY0fnA3ZQWHdd5WlEqP+F38fNao2lLiz+gO1J4rhzf4Y3GvhHExgGIq+ZpsflkI9 -UxmEs5kCgZkAwgRO1cYSzMCxHgfv9kskul/icF7l2c6F9HtIUa9iSsi11Padary1 -wGxMh/kUhqWh3xrQ+LHdUtODOMlqnxKBxpNnU9trqUCE2vYpEHmFdaw2PKXkmeEf -ymO36aq1xDB784+OUzFF958aGW7trDVfBl2MEsgE9lNb+P1PJhSbawZMBjbNFM6W -k9Xp9EWbSxylmgZeVX7zwocCgZkA0+MyTlrfERbOLQ4zCUCPtv5ndD7FCcFzuUzY -eSU2C1/eqUEcB6fLZFgF8BVjJVhnhl88Yz4QH+Ft4+mU/kSoUEu/pGYH+kDHJ1BC -eOhL60cdEbrDi7MUdhYw1qI2MIEZNFuR79fn+/wekmPHaUaVcWlZTmbISvpr9BQ6 -hZlQM6vMQRg4VlPB29VlX6yKsxGNxG8zyaScKCMCgZkAuTBZe21L5oqKxQp4fpOt -JAR/5BiAtsyNShYeqnGIla9M+FDJYudraJc22Zbjg743avhyvN8xTWy81QhUMC// -FWb/eqh29B+0cDgEbEhCHlbZkjwantKmgI18L5qVUwWgWpQNGtVuXnRL+jjKvdRX -toC2QfsP2Xspz9khokyLKLXi/Q9z40dprQTDAjkqiKB4ZTNs+Zhq3aMCgZkAz8m1 -EqwApxSTOhH7sK4UgaM4twG7XtbMcsJOY3c/aaYpiBfmsgc16YB8yjVfFkd8toR8 -huJdE7aRenkdeMDBwoSWOlUoq5yM8Ru/JCzCDsedVT6u9ze18BvQ5xsKQ0TG/9Zw -5iD4Sd+z52FcM/xZH2/teXpIH2c3KJQR0+RGh3WJh6iFzvqyWLALiuh82CB1w1Y+ -FheMX7sCgZgxAVZ/roev84uyoQYuMplqY4b0C+pQ1lbHvE0FNb7PBY6gbGy7FftL -XfZ0xBWaCB3uhCPFeMYBP6pPv4LtOnBTGkViaLOZTewxjE3Gu6LuMGyavvI7Tnfi -Oj+Wrt6jOJyxEVeMLvDnp6nOZHv5e0gscNYet3urdo2j8Tsm0adhvqSWxodkDyDk -+j1eTD/b+UmQPI+JUr29PQ== ------END RSA PRIVATE KEY----- diff --git a/orderer/sbft_test.go b/orderer/sbft_test.go deleted file mode 100644 index ac28e6d814e..00000000000 --- a/orderer/sbft_test.go +++ /dev/null @@ -1,298 +0,0 @@ -/* -Copyright Digital Asset Holdings, LLC 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "fmt" - "io/ioutil" - "os" - "testing" - "time" - - "net" - - "bytes" - - "github.com/golang/protobuf/proto" - genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig" - "github.com/hyperledger/fabric/common/configtx/tool/provisional" - "github.com/hyperledger/fabric/common/localmsp" - cf "github.com/hyperledger/fabric/core/config" - mspmgmt "github.com/hyperledger/fabric/msp/mgmt" - "github.com/hyperledger/fabric/orderer/ledger" - "github.com/hyperledger/fabric/orderer/ledger/ram" - "github.com/hyperledger/fabric/orderer/localconfig" - "github.com/hyperledger/fabric/orderer/multichain" - "github.com/hyperledger/fabric/orderer/sbft" - "github.com/hyperledger/fabric/orderer/sbft/backend" - "github.com/hyperledger/fabric/orderer/sbft/crypto" - "github.com/hyperledger/fabric/orderer/sbft/simplebft" - cb "github.com/hyperledger/fabric/protos/common" - ab "github.com/hyperledger/fabric/protos/orderer" - "github.com/hyperledger/fabric/protos/utils" - "github.com/op/go-logging" - "golang.org/x/net/context" - "google.golang.org/grpc" -) - -var genesisBlock *cb.Block -var pwd string - -func init() { - var err error - pwd, err = os.Getwd() - if err != nil { - panic(err) - } - os.Chdir("..") - - genConf := genesisconfig.Load(genesisconfig.SampleInsecureProfile) - genConf.Orderer.OrdererType = sbftName - genesisBlock = provisional.New(genConf).GenesisBlock() - - os.Chdir(pwd) -} - -const update byte = 0 -const sent byte = 1 - -const neededUpdates = 2 -const neededSent = 1 - -var testData = []byte{0, 1, 2, 3} - -const sbftName = "sbft" - -type item struct { - itemtype byte - payload []byte -} - -func TestSbftPeer(t *testing.T) { - - t.Parallel() - skipInShortMode(t) - logging.SetLevel(logging.DEBUG, "") - - mspDir, err := cf.GetDevMspDir() - if err != nil { - panic("could not get DevMspDir") - } - - // Start SBFT - dataTmpDir, err := ioutil.TempDir("", "sbft_test") - if err != nil { - panic("Failed to create a temporary directory") - } - // We only need the path as the directory will be created - // by the peer - os.RemoveAll(dataTmpDir) - defer func() { - os.RemoveAll(dataTmpDir) - }() - peers := make(map[string][]byte) - peers["6101"], err = crypto.ParseCertPEM("sbft/testdata/cert1.pem") - panicOnError(err) - listenAddr := ":6101" - certFile := "sbft/testdata/cert1.pem" - keyFile := "sbft/testdata/key.pem" - cons := &simplebft.Config{N: 1, F: 0, BatchDurationNsec: 1000, BatchSizeBytes: 1000000000, RequestTimeoutNsec: 1000000000} - c := &sbft.ConsensusConfig{Consensus: cons, Peers: peers} - sc := &backend.StackConfig{ListenAddr: listenAddr, CertFile: certFile, KeyFile: keyFile, DataDir: dataTmpDir} - sbftConsenter := sbft.New(c, sc) - <-time.After(5 * time.Second) - // End SBFT - - // Start GRPC - logger.Info("Creating a GRPC server.") - conf := config.Load() - conf.General.LocalMSPDir = mspDir - conf.General.LocalMSPID = "DEFAULT" - lf := newRAMLedgerFactory() - consenters := make(map[string]multichain.Consenter) - consenters[sbftName] = sbftConsenter - - err = mspmgmt.LoadLocalMsp(conf.General.LocalMSPDir, conf.General.BCCSP, conf.General.LocalMSPID) - if err != nil { // Handle errors reading the config file - panic(fmt.Errorf("Failed initializing crypto [%s]", err)) - } - signer := localmsp.NewSigner() - manager := multichain.NewManagerImpl(lf, consenters, signer) - - server := NewServer(manager, signer) - grpcServer := grpc.NewServer() - grpcAddr := fmt.Sprintf("%s:%d", conf.General.ListenAddress, conf.General.ListenPort) - lis, err := net.Listen("tcp", grpcAddr) - if err != nil { - panic("Listening on the given port failed.") - } - ab.RegisterAtomicBroadcastServer(grpcServer, server) - go grpcServer.Serve(lis) - // End GRPC - - // Start Test Setup - logger.Info("Creating an Atomic Broadcast GRPC connection.") - timeout := 4 * time.Second - clientconn, err := grpc.Dial(grpcAddr, grpc.WithBlock(), grpc.WithTimeout(timeout), grpc.WithInsecure()) - if err != nil { - t.Errorf("Failed to connect to GRPC: %s", err) - return - } - client := ab.NewAtomicBroadcastClient(clientconn) - - <-time.After(4 * time.Second) - - resultch := make(chan item) - errorch := make(chan error) - - logger.Info("Starting a goroutine waiting for ledger updates.") - go updateReceiver(t, resultch, errorch, client) - - logger.Info("Starting a single broadcast sender goroutine.") - go broadcastSender(t, resultch, errorch, client) - // End Test Setup - - checkResults(t, resultch, errorch) -} - -func checkResults(t *testing.T, resultch chan item, errorch chan error) { - l := len(errorch) - for i := 0; i < l; i++ { - errres := <-errorch - t.Error(errres) - } - - updates := 0 - sentBroadcast := 0 - testDataReceived := false - for i := 0; i < neededUpdates+neededSent; i++ { - select { - case result := <-resultch: - switch result.itemtype { - case update: - updates++ - if bytes.Equal(result.payload, testData) { - testDataReceived = true - } - case sent: - sentBroadcast++ - } - case <-time.After(30 * time.Second): - continue - } - } - if updates != neededUpdates { - t.Errorf("We did not get all the ledger updates.") - } else if sentBroadcast != neededSent { - t.Errorf("We were unable to send all the broadcasts.") - } else if !testDataReceived { - t.Errorf("We did not receive an update containing the test data sent in a broadcast.") - } else { - logger.Info("Successfully sent and received everything.") - } -} - -func updateReceiver(t *testing.T, resultch chan item, errorch chan error, client ab.AtomicBroadcastClient) { - logger.Info("{Update Receiver} Creating a ledger update delivery stream.") - dstream, err := client.Deliver(context.Background()) - if err != nil { - errorch <- fmt.Errorf("Failed to get Deliver stream: %s", err) - return - } - err = dstream.Send(&cb.Envelope{ - Payload: utils.MarshalOrPanic(&cb.Payload{ - Header: &cb.Header{ - ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{ - ChannelId: provisional.TestChainID, - }), - SignatureHeader: utils.MarshalOrPanic(&cb.SignatureHeader{}), - }, - Data: utils.MarshalOrPanic(&ab.SeekInfo{ - Start: &ab.SeekPosition{Type: &ab.SeekPosition_Newest{Newest: &ab.SeekNewest{}}}, - Stop: &ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: ^uint64(0)}}}, - Behavior: ab.SeekInfo_BLOCK_UNTIL_READY, - }), - }), - }) - if err != nil { - errorch <- fmt.Errorf("Failed to send to Deliver stream: %s", err) - return - } - logger.Info("{Update Receiver} Listening to ledger updates.") - for i := 0; i < neededUpdates; { - m, inerr := dstream.Recv() - logger.Info("{Update Receiver} Got message: ", m, "err:", inerr) - if inerr != nil { - errorch <- fmt.Errorf("Failed to receive consensus: %s", inerr) - return - } - b, ok := m.Type.(*ab.DeliverResponse_Block) - if !ok { - logger.Info("{Update Receiver} Received s status message.") - continue - } - logger.Info("{Update Receiver} Received a ledger update.") - for i, tx := range b.Block.Data.Data { - pl := &cb.Payload{} - e := &cb.Envelope{} - merr1 := proto.Unmarshal(tx, e) - merr2 := proto.Unmarshal(e.Payload, pl) - if merr1 == nil && merr2 == nil { - logger.Infof("{Update Receiver} %d - %v", i+1, pl.Data) - resultch <- item{itemtype: update, payload: pl.Data} - } - } - i++ - } - logger.Info("{Update Receiver} Exiting...") -} - -func broadcastSender(t *testing.T, resultch chan item, errorch chan error, client ab.AtomicBroadcastClient) { - logger.Info("{Broadcast Sender} Waiting before sending.") - <-time.After(5 * time.Second) - bstream, err := client.Broadcast(context.Background()) - if err != nil { - errorch <- fmt.Errorf("Failed to get broadcast stream: %s", err) - return - } - h := &cb.Header{ - ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{ChannelId: provisional.TestChainID}), - SignatureHeader: utils.MarshalOrPanic(&cb.SignatureHeader{})} - bs := testData - pl := &cb.Payload{Data: bs, Header: h} - mpl, err := proto.Marshal(pl) - if err != nil { - panic("Failed to marshal payload.") - } - bstream.Send(&cb.Envelope{Payload: mpl}) - logger.Infof("{Broadcast Sender} Broadcast sent: %v", bs) - logger.Info("{Broadcast Sender} Exiting...") - resultch <- item{itemtype: sent, payload: mpl} -} - -func newRAMLedgerFactory() ledger.Factory { - rlf := ramledger.New(10) - rl, err := rlf.GetOrCreate(provisional.TestChainID) - if err != nil { - panic(err) - } - err = rl.Append(genesisBlock) - if err != nil { - panic(err) - } - return rlf -} diff --git a/orderer/util.go b/orderer/util.go index 1cb41335013..012a608ef7a 100644 --- a/orderer/util.go +++ b/orderer/util.go @@ -27,10 +27,6 @@ import ( jsonledger "github.com/hyperledger/fabric/orderer/ledger/json" ramledger "github.com/hyperledger/fabric/orderer/ledger/ram" config "github.com/hyperledger/fabric/orderer/localconfig" - "github.com/hyperledger/fabric/orderer/sbft" - "github.com/hyperledger/fabric/orderer/sbft/backend" - sbftcrypto "github.com/hyperledger/fabric/orderer/sbft/crypto" - "github.com/hyperledger/fabric/orderer/sbft/simplebft" ) func createLedgerFactory(conf *config.TopLevel) (ledger.Factory, string) { @@ -87,24 +83,3 @@ func createSubDir(parentDirPath string, subDir string) (string, bool) { } return subDirPath, created } - -// XXX The functions below need to be moved to the SBFT package ASAP - -func makeSbftConsensusConfig(conf *config.TopLevel) *sbft.ConsensusConfig { - cfg := simplebft.Config{N: conf.Genesis.SbftShared.N, F: conf.Genesis.SbftShared.F, - BatchDurationNsec: uint64(conf.Genesis.DeprecatedBatchTimeout), - BatchSizeBytes: uint64(conf.Genesis.DeprecatedBatchSize), - RequestTimeoutNsec: conf.Genesis.SbftShared.RequestTimeoutNsec} - peers := make(map[string][]byte) - for addr, cert := range conf.Genesis.SbftShared.Peers { - peers[addr], _ = sbftcrypto.ParseCertPEM(cert) - } - return &sbft.ConsensusConfig{Consensus: &cfg, Peers: peers} -} - -func makeSbftStackConfig(conf *config.TopLevel) *backend.StackConfig { - return &backend.StackConfig{ListenAddr: conf.SbftLocal.PeerCommAddr, - CertFile: conf.SbftLocal.CertFile, - KeyFile: conf.SbftLocal.KeyFile, - DataDir: conf.SbftLocal.DataDir} -} diff --git a/orderer/util_test.go b/orderer/util_test.go index 7c3ed5b954d..d75ace49989 100644 --- a/orderer/util_test.go +++ b/orderer/util_test.go @@ -19,11 +19,8 @@ package main import ( "os" "testing" - "time" config "github.com/hyperledger/fabric/orderer/localconfig" - "github.com/hyperledger/fabric/orderer/sbft" - "github.com/hyperledger/fabric/orderer/sbft/backend" "github.com/stretchr/testify/assert" ) @@ -127,49 +124,3 @@ func TestCreateTempDir(t *testing.T) { }) } - -func TestMakeSbftStackConfig(t *testing.T) { - stackConfig := makeSbftStackConfig( - &config.TopLevel{ - SbftLocal: config.SbftLocal{ - PeerCommAddr: "0.0.0.0:0", - CertFile: "certfile", - KeyFile: "keyfile", - DataDir: "datadir", - }, - }, - ) - assert.NotNil(t, stackConfig) - assert.IsType(t, &backend.StackConfig{}, stackConfig) - assert.Equal(t, "0.0.0.0:0", stackConfig.ListenAddr) - assert.Equal(t, "certfile", stackConfig.CertFile) - assert.Equal(t, "keyfile", stackConfig.KeyFile) - assert.Equal(t, "datadir", stackConfig.DataDir) -} - -func TestMakeSbftConsensusConfig(t *testing.T) { - consensusConfig := makeSbftConsensusConfig( - &config.TopLevel{ - Genesis: config.Genesis{ - DeprecatedBatchSize: 1, - DeprecatedBatchTimeout: 2 * time.Second, - SbftShared: config.SbftShared{ - F: 3, - N: 4, - Peers: map[string]string{ - "peer": "PEM", - }, - RequestTimeoutNsec: 5, - }, - }, - }, - ) - assert.NotNil(t, consensusConfig) - assert.IsType(t, &sbft.ConsensusConfig{}, consensusConfig) - assert.EqualValues(t, 1, consensusConfig.GetConsensus().BatchSizeBytes) - assert.EqualValues(t, 2*time.Second, consensusConfig.GetConsensus().BatchDurationNsec) - assert.EqualValues(t, 3, consensusConfig.GetConsensus().F) - assert.EqualValues(t, 4, consensusConfig.GetConsensus().N) - assert.EqualValues(t, 5, consensusConfig.GetConsensus().RequestTimeoutNsec) - assert.Len(t, consensusConfig.Peers, 1) -} diff --git a/sampleconfig/core.yaml b/sampleconfig/core.yaml index 34e301c5484..92f4db0aaec 100644 --- a/sampleconfig/core.yaml +++ b/sampleconfig/core.yaml @@ -194,7 +194,7 @@ peer: # SHA2 is hardcoded in several places, not only BCCSP Hash: SHA2 Security: 256 - # Location of Key Store, can be subdirectory of SbftLocal.DataDir + # Location of Key Store FileKeyStore: # If "", defaults to 'mspConfigPath'/keystore # TODO: Ensure this is read with fabric/core/config.GetPath() once ready diff --git a/sampleconfig/orderer.yaml b/sampleconfig/orderer.yaml index 18ece045ef1..82465912117 100644 --- a/sampleconfig/orderer.yaml +++ b/sampleconfig/orderer.yaml @@ -158,49 +158,3 @@ Kafka: # certificates from the Kafka cluster. RootCAs: #File: uncomment to read Certificate from a file - -################################################################################ -# -# SECTION: SBFT Local -# -# - This section applies to the configuration of the SBFT-based orderer. -# -################################################################################ -SbftLocal: - - # Address to use for SBFT internal communication - PeerCommAddr: ":6101" - CertFile: "sbft/testdata/cert1.pem" - KeyFile: "sbft/testdata/key.pem" - # Directory for SBFT data (persistence) - DataDir: "/tmp" - -################################################################################ -# -# SECTION: Genesis -# -# - This section is pending removal but is left to support SBFT -# to be migrated to configtx.yaml. -# -################################################################################ -Genesis: - - # Deprecated Batch Timeout: The amount of time to wait before creating a - # batch. - DeprecatedBatchTimeout: 10s - - # DeprecatedBatchSize: The absolute maximum number of bytes allowed for - # the serialized messages in a batch. - DeprecatedBatchSize: 99 MB - - # Defines the SBFT parameters when 'sbft' is specified as the 'OrdererType' - SbftShared: - # Number of peers - "N": 1 - # Fault tolerance - F: 0 - # Timeout of requests (seconds) - RequestTimeoutNsec: 1000000000 - # Peers (PeerCommAddr) with the path of their cert - Peers: - ":6101": "sbft/testdata/cert1.pem"