tendermint/types/part_set.go

253 lines
5.1 KiB
Go
Raw Normal View History

package types
2014-09-14 15:37:32 -07:00
import (
"bytes"
"crypto/sha256"
"errors"
2014-10-17 01:01:59 -07:00
"fmt"
"io"
2014-10-17 01:01:59 -07:00
"strings"
2014-09-14 15:37:32 -07:00
"sync"
2015-04-27 20:55:28 -07:00
"github.com/tendermint/tendermint/binary"
2015-04-01 17:30:16 -07:00
. "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/merkle"
2014-09-14 15:37:32 -07:00
)
const (
partSize = 4096 // 4KB
)
var (
ErrPartSetUnexpectedIndex = errors.New("Error part set unexpected index")
ErrPartSetInvalidTrail = errors.New("Error part set invalid trail")
)
type Part struct {
2015-05-01 17:26:49 -07:00
Index uint `json:"index"`
Trail [][]byte `json:"trail"`
Bytes []byte `json:"bytes"`
2014-09-14 15:37:32 -07:00
// Cache
hash []byte
}
2014-10-30 03:32:09 -07:00
func (part *Part) Hash() []byte {
if part.hash != nil {
return part.hash
2014-09-14 15:37:32 -07:00
} else {
hasher := sha256.New()
2014-10-30 03:32:09 -07:00
_, err := hasher.Write(part.Bytes)
2014-09-14 15:37:32 -07:00
if err != nil {
panic(err)
}
2014-10-30 03:32:09 -07:00
part.hash = hasher.Sum(nil)
return part.hash
2014-09-14 15:37:32 -07:00
}
}
2014-10-30 03:32:09 -07:00
func (part *Part) String() string {
2014-12-23 01:35:54 -08:00
return part.StringIndented("")
2014-10-17 01:01:59 -07:00
}
2014-12-23 01:35:54 -08:00
func (part *Part) StringIndented(indent string) string {
2014-10-30 03:32:09 -07:00
trailStrings := make([]string, len(part.Trail))
for i, hash := range part.Trail {
2014-10-17 01:01:59 -07:00
trailStrings[i] = fmt.Sprintf("%X", hash)
}
return fmt.Sprintf(`Part{
%s Index: %v
%s Trail:
%s %v
%s}`,
2014-10-30 03:32:09 -07:00
indent, part.Index,
2014-10-17 01:01:59 -07:00
indent,
indent, strings.Join(trailStrings, "\n"+indent+" "),
indent)
}
2014-09-14 15:37:32 -07:00
//-------------------------------------
2014-10-30 03:32:09 -07:00
type PartSetHeader struct {
2015-05-01 17:26:49 -07:00
Total uint `json:"total"`
Hash []byte `json:"hash"`
2014-10-30 03:32:09 -07:00
}
func (psh PartSetHeader) String() string {
return fmt.Sprintf("PartSet{T:%v %X}", psh.Total, Fingerprint(psh.Hash))
2014-10-30 03:32:09 -07:00
}
2014-11-03 15:50:23 -08:00
func (psh PartSetHeader) IsZero() bool {
return psh.Total == 0
}
2014-10-30 03:32:09 -07:00
func (psh PartSetHeader) Equals(other PartSetHeader) bool {
2014-10-31 18:35:38 -07:00
return psh.Total == other.Total && bytes.Equal(psh.Hash, other.Hash)
2014-10-30 03:32:09 -07:00
}
2015-04-27 20:55:28 -07:00
func (psh PartSetHeader) WriteSignBytes(w io.Writer, n *int64, err *error) {
2015-05-01 17:26:49 -07:00
binary.WriteTo([]byte(Fmt(`{"hash":"%X","total":%v}`, psh.Hash, psh.Total)), w, n, err)
2015-04-27 20:55:28 -07:00
}
2014-10-30 03:32:09 -07:00
//-------------------------------------
2014-09-14 15:37:32 -07:00
type PartSet struct {
total uint
2014-10-31 18:35:38 -07:00
hash []byte
2014-09-14 15:37:32 -07:00
mtx sync.Mutex
parts []*Part
partsBitArray BitArray
count uint
2014-09-14 15:37:32 -07:00
}
2014-12-23 01:35:54 -08:00
// Returns an immutable, full PartSet from the data bytes.
// The data bytes are split into "partSize" chunks, and merkle tree computed.
2014-09-14 15:37:32 -07:00
func NewPartSetFromData(data []byte) *PartSet {
// divide data into 4kb parts.
total := (len(data) + partSize - 1) / partSize
parts := make([]*Part, total)
parts_ := make([]merkle.Hashable, total)
partsBitArray := NewBitArray(uint(total))
for i := 0; i < total; i++ {
part := &Part{
Index: uint(i),
2014-09-14 15:37:32 -07:00
Bytes: data[i*partSize : MinInt(len(data), (i+1)*partSize)],
}
parts[i] = part
parts_[i] = part
partsBitArray.SetIndex(uint(i), true)
}
// Compute merkle trails
trails, rootTrail := merkle.HashTrailsFromHashables(parts_)
2014-09-14 15:37:32 -07:00
for i := 0; i < total; i++ {
parts[i].Trail = trails[i].Flatten()
2014-09-14 15:37:32 -07:00
}
return &PartSet{
total: uint(total),
hash: rootTrail.Hash,
2014-09-14 15:37:32 -07:00
parts: parts,
partsBitArray: partsBitArray,
count: uint(total),
2014-09-14 15:37:32 -07:00
}
}
// Returns an empty PartSet ready to be populated.
2014-10-30 03:32:09 -07:00
func NewPartSetFromHeader(header PartSetHeader) *PartSet {
2014-09-14 15:37:32 -07:00
return &PartSet{
2014-10-30 03:32:09 -07:00
total: header.Total,
2014-10-31 18:35:38 -07:00
hash: header.Hash,
2014-10-30 03:32:09 -07:00
parts: make([]*Part, header.Total),
partsBitArray: NewBitArray(uint(header.Total)),
2014-09-14 15:37:32 -07:00
count: 0,
}
}
2014-10-30 03:32:09 -07:00
func (ps *PartSet) Header() PartSetHeader {
if ps == nil {
return PartSetHeader{}
} else {
return PartSetHeader{
Total: ps.total,
2014-10-31 18:35:38 -07:00
Hash: ps.hash,
2014-10-30 03:32:09 -07:00
}
}
}
2014-11-03 15:50:23 -08:00
func (ps *PartSet) HasHeader(header PartSetHeader) bool {
if ps == nil {
return false
} else {
return ps.Header().Equals(header)
}
}
2014-09-14 15:37:32 -07:00
func (ps *PartSet) BitArray() BitArray {
ps.mtx.Lock()
defer ps.mtx.Unlock()
return ps.partsBitArray.Copy()
}
2014-10-30 03:32:09 -07:00
func (ps *PartSet) Hash() []byte {
2014-10-21 01:18:46 -07:00
if ps == nil {
return nil
}
2014-10-30 03:32:09 -07:00
return ps.hash
2014-09-14 15:37:32 -07:00
}
2014-10-30 03:32:09 -07:00
func (ps *PartSet) HashesTo(hash []byte) bool {
2014-10-26 13:26:27 -07:00
if ps == nil {
return false
}
2014-10-30 03:32:09 -07:00
return bytes.Equal(ps.hash, hash)
2014-10-26 13:26:27 -07:00
}
func (ps *PartSet) Count() uint {
2014-10-18 01:42:33 -07:00
if ps == nil {
return 0
}
return ps.count
}
func (ps *PartSet) Total() uint {
2014-09-14 15:37:32 -07:00
if ps == nil {
return 0
}
return ps.total
}
func (ps *PartSet) AddPart(part *Part) (bool, error) {
ps.mtx.Lock()
defer ps.mtx.Unlock()
// Invalid part index
if part.Index >= ps.total {
return false, ErrPartSetUnexpectedIndex
}
// If part already exists, return false.
if ps.parts[part.Index] != nil {
return false, nil
}
// Check hash trail
if !merkle.VerifyHashTrail(uint(part.Index), uint(ps.total), part.Hash(), part.Trail, ps.hash) {
2014-09-14 15:37:32 -07:00
return false, ErrPartSetInvalidTrail
}
// Add part
ps.parts[part.Index] = part
ps.partsBitArray.SetIndex(uint(part.Index), true)
ps.count++
return true, nil
}
func (ps *PartSet) GetPart(index uint) *Part {
2014-09-14 15:37:32 -07:00
ps.mtx.Lock()
defer ps.mtx.Unlock()
return ps.parts[index]
}
func (ps *PartSet) IsComplete() bool {
return ps.count == ps.total
}
func (ps *PartSet) GetReader() io.Reader {
2014-09-14 15:37:32 -07:00
if !ps.IsComplete() {
panic("Cannot GetReader() on incomplete PartSet")
}
buf := []byte{}
for _, part := range ps.parts {
buf = append(buf, part.Bytes...)
}
return bytes.NewReader(buf)
}
2014-10-18 01:42:33 -07:00
2014-12-23 01:35:54 -08:00
func (ps *PartSet) StringShort() string {
2014-10-18 01:42:33 -07:00
if ps == nil {
return "nil-PartSet"
} else {
return fmt.Sprintf("(%v of %v)", ps.Count(), ps.Total())
}
}