diff --git a/orderer/sbft/backend/backend.go b/orderer/sbft/backend/backend.go index 568140ae869..f7b405b0064 100644 --- a/orderer/sbft/backend/backend.go +++ b/orderer/sbft/backend/backend.go @@ -17,6 +17,7 @@ limitations under the License. package backend import ( + "bytes" "fmt" "io" "sort" @@ -37,6 +38,7 @@ import ( "crypto/rsa" "crypto/sha256" "encoding/asn1" + "encoding/gob" "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/orderer/rawledger" @@ -48,6 +50,10 @@ import ( "github.com/op/go-logging" ) +const headerIndex = 0 +const signaturesIndex = 1 +const metadataLen = 2 + var logger = logging.MustGetLogger("backend") type Backend struct { @@ -289,9 +295,6 @@ func (t *Backend) Timer(d time.Duration, tf func()) s.Canceller { // Deliver writes the ledger func (t *Backend) Deliver(batch *s.Batch) { - // TODO: proof - // TODO: header - // proof := batch.Signatures[0] blockContents := make([]*cb.Envelope, 0, len(batch.Payloads)) for _, p := range batch.Payloads { envelope := &cb.Envelope{} @@ -302,7 +305,12 @@ func (t *Backend) Deliver(batch *s.Batch) { logger.Warningf("Payload cannot be unmarshalled.") } } - t.ledger.Append(blockContents, nil) + // This a quick and dirty solution to make it work. + // SBFT needs to use Rawledger's structures and signatures over the Block. + metadata := make([][]byte, metadataLen) + metadata[headerIndex] = batch.Header + metadata[signaturesIndex] = encodeSignatures(batch.Signatures) + t.ledger.Append(blockContents, metadata) } func (t *Backend) Persist(key string, data proto.Message) { @@ -333,8 +341,8 @@ func (t *Backend) LastBatch() *s.Batch { if status != cb.Status_SUCCESS { panic("Fatal ledger error: unable to get last block.") } - header := []byte{} - sgns := make(map[uint64][]byte) + header := getHeader(block.Metadata) + sgns := decodeSignatures(getEncodedSignatures(block.Metadata)) batch := s.Batch{Header: header, Payloads: data, Signatures: sgns} return &batch } @@ -404,3 +412,41 @@ func CheckSig(publicKey crypto.PublicKey, data []byte, sig []byte) error { return fmt.Errorf("Unsupported public key type.") } } + +func getHeader(metadata *cb.BlockMetadata) []byte { + if metadata == nil || len(metadata.Metadata) < metadataLen { + return nil + } + return metadata.Metadata[headerIndex] +} + +func getEncodedSignatures(metadata *cb.BlockMetadata) []byte { + if metadata == nil || len(metadata.Metadata) < metadataLen { + return nil + } + return metadata.Metadata[signaturesIndex] +} + +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 encodedSignatures == nil { + 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 index cd3f66758e5..84bf7ac0d0e 100644 --- a/orderer/sbft/backend/backend_test.go +++ b/orderer/sbft/backend/backend_test.go @@ -21,7 +21,14 @@ import ( "crypto/elliptic" crand "crypto/rand" "crypto/rsa" + "reflect" "testing" + + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric/orderer/common/bootstrap/static" + "github.com/hyperledger/fabric/orderer/rawledger/ramledger" + "github.com/hyperledger/fabric/orderer/sbft/simplebft" + cb "github.com/hyperledger/fabric/protos/common" ) func TestSignAndVerifyRsa(t *testing.T) { @@ -59,3 +66,64 @@ func TestSignAndVerifyEcdsa(t *testing.T) { t.Errorf("Signature check failed: %s", err) } } + +func TestLedgerReadWrite(t *testing.T) { + genesis, err := static.New().GenesisBlock() + if err != nil { + panic("Failed to generate genesis block.") + } + _, rl := ramledger.New(10, genesis) + b := Backend{ledger: rl} + + 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(&batch) + batch2 := b.LastBatch() + + if !reflect.DeepEqual(batch, *batch2) { + t.Errorf("The wrong batch was returned by LastBatch after Deliver: %v (original was: %v)", batch2, &batch) + } +} + +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) + } +}