Skip to content

Commit

Permalink
Handle header and signatures
Browse files Browse the repository at this point in the history
This change adds real header and signature handling (placeholders are
removed). We use Golang's gob to serialize those objects and store them
in metadata.

Change-Id: If72907341e67cc60ebe74240648e190715dd7b5a
Signed-off-by: Gabor Hosszu <gabor@digitalasset.com>
  • Loading branch information
gaborh-da committed Nov 29, 2016
1 parent 0c5736c commit 10e4697
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 6 deletions.
58 changes: 52 additions & 6 deletions orderer/sbft/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package backend

import (
"bytes"
"fmt"
"io"
"sort"
Expand All @@ -37,6 +38,7 @@ import (
"crypto/rsa"
"crypto/sha256"
"encoding/asn1"
"encoding/gob"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/orderer/rawledger"
Expand All @@ -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 {
Expand Down Expand Up @@ -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{}
Expand All @@ -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) {
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
68 changes: 68 additions & 0 deletions orderer/sbft/backend/backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
}
}

0 comments on commit 10e4697

Please sign in to comment.