tendermint/types/part_set.go

281 lines
5.7 KiB
Go
Raw Normal View History

package types
2014-09-14 15:37:32 -07:00
import (
"bytes"
"errors"
2014-10-17 01:01:59 -07:00
"fmt"
"io"
2014-09-14 15:37:32 -07:00
"sync"
2018-06-30 22:40:03 -07:00
"github.com/tendermint/tendermint/crypto/merkle"
"github.com/tendermint/tendermint/crypto/tmhash"
2018-07-01 19:36:49 -07:00
cmn "github.com/tendermint/tendermint/libs/common"
2014-09-14 15:37:32 -07:00
)
var (
ErrPartSetUnexpectedIndex = errors.New("Error part set unexpected index")
2015-06-18 20:19:39 -07:00
ErrPartSetInvalidProof = errors.New("Error part set invalid proof")
2014-09-14 15:37:32 -07:00
)
type Part struct {
2015-12-10 11:09:25 -08:00
Index int `json:"index"`
2018-02-03 00:42:59 -08:00
Bytes cmn.HexBytes `json:"bytes"`
2015-12-10 11:09:25 -08:00
Proof merkle.SimpleProof `json:"proof"`
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
}
2018-06-30 22:40:03 -07:00
hasher := tmhash.New()
hasher.Write(part.Bytes) // nolint: errcheck, gas
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 {
2015-12-10 11:09:25 -08:00
return fmt.Sprintf(`Part{#%v
2015-12-09 17:09:06 -08:00
%s Bytes: %X...
2015-12-10 11:09:25 -08:00
%s Proof: %v
2014-10-17 01:01:59 -07:00
%s}`,
2015-12-10 11:09:25 -08:00
part.Index,
2017-04-27 16:01:18 -07:00
indent, cmn.Fingerprint(part.Bytes),
2015-12-10 11:09:25 -08:00
indent, part.Proof.StringIndented(indent+" "),
2014-10-17 01:01:59 -07:00
indent)
}
2014-09-14 15:37:32 -07:00
//-------------------------------------
2014-10-30 03:32:09 -07:00
type PartSetHeader struct {
2018-02-03 00:42:59 -08:00
Total int `json:"total"`
Hash cmn.HexBytes `json:"hash"`
2014-10-30 03:32:09 -07:00
}
func (psh PartSetHeader) String() string {
2017-04-27 16:01:18 -07:00
return fmt.Sprintf("%v:%X", psh.Total, cmn.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
}
//-------------------------------------
2014-09-14 15:37:32 -07:00
type PartSet struct {
total int
2014-10-31 18:35:38 -07:00
hash []byte
2014-09-14 15:37:32 -07:00
mtx sync.Mutex
parts []*Part
2017-04-27 16:01:18 -07:00
partsBitArray *cmn.BitArray
count int
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.
func NewPartSetFromData(data []byte, partSize int) *PartSet {
2014-09-14 15:37:32 -07:00
// divide data into 4kb parts.
total := (len(data) + partSize - 1) / partSize
parts := make([]*Part, total)
2018-02-03 00:23:10 -08:00
parts_ := make([]merkle.Hasher, total)
2017-04-27 16:01:18 -07:00
partsBitArray := cmn.NewBitArray(total)
2014-09-14 15:37:32 -07:00
for i := 0; i < total; i++ {
part := &Part{
2015-12-10 11:09:25 -08:00
Index: i,
2017-04-27 16:01:18 -07:00
Bytes: data[i*partSize : cmn.MinInt(len(data), (i+1)*partSize)],
2014-09-14 15:37:32 -07:00
}
parts[i] = part
parts_[i] = part
partsBitArray.SetIndex(i, true)
2014-09-14 15:37:32 -07:00
}
2015-06-18 20:19:39 -07:00
// Compute merkle proofs
2018-02-03 00:23:10 -08:00
root, proofs := merkle.SimpleProofsFromHashers(parts_)
2014-09-14 15:37:32 -07:00
for i := 0; i < total; i++ {
2015-06-18 20:19:39 -07:00
parts[i].Proof = *proofs[i]
2014-09-14 15:37:32 -07:00
}
return &PartSet{
total: total,
2015-12-10 11:09:25 -08:00
hash: root,
2014-09-14 15:37:32 -07:00
parts: parts,
partsBitArray: partsBitArray,
count: 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),
2017-04-27 16:01:18 -07:00
partsBitArray: cmn.NewBitArray(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{}
}
return PartSetHeader{
Total: ps.total,
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
}
return ps.Header().Equals(header)
2014-11-03 15:50:23 -08:00
}
2017-04-27 16:01:18 -07:00
func (ps *PartSet) BitArray() *cmn.BitArray {
2014-09-14 15:37:32 -07:00
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() int {
2014-10-18 01:42:33 -07:00
if ps == nil {
return 0
}
return ps.count
}
func (ps *PartSet) Total() int {
2014-09-14 15:37:32 -07:00
if ps == nil {
return 0
}
return ps.total
}
2018-05-17 10:17:50 -07:00
func (ps *PartSet) AddPart(part *Part) (bool, error) {
2014-09-14 15:37:32 -07:00
ps.mtx.Lock()
defer ps.mtx.Unlock()
// Invalid part index
2015-12-10 11:09:25 -08:00
if part.Index >= ps.total {
2014-09-14 15:37:32 -07:00
return false, ErrPartSetUnexpectedIndex
}
// If part already exists, return false.
2015-12-10 11:09:25 -08:00
if ps.parts[part.Index] != nil {
2014-09-14 15:37:32 -07:00
return false, nil
}
2015-06-18 20:19:39 -07:00
// Check hash proof
2018-05-17 10:17:50 -07:00
if !part.Proof.Verify(part.Index, ps.total, part.Hash(), ps.Hash()) {
return false, ErrPartSetInvalidProof
2014-09-14 15:37:32 -07:00
}
// Add part
2015-12-10 11:09:25 -08:00
ps.parts[part.Index] = part
ps.partsBitArray.SetIndex(part.Index, true)
2014-09-14 15:37:32 -07:00
ps.count++
return true, nil
}
func (ps *PartSet) GetPart(index int) *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() {
2017-04-27 16:01:18 -07:00
cmn.PanicSanity("Cannot GetReader() on incomplete PartSet")
2014-09-14 15:37:32 -07:00
}
2016-03-11 19:49:43 -08:00
return NewPartSetReader(ps.parts)
2014-09-14 15:37:32 -07:00
}
2014-10-18 01:42:33 -07:00
2016-03-11 19:49:43 -08:00
type PartSetReader struct {
i int
parts []*Part
reader *bytes.Reader
}
func NewPartSetReader(parts []*Part) *PartSetReader {
return &PartSetReader{
i: 0,
parts: parts,
reader: bytes.NewReader(parts[0].Bytes),
}
}
func (psr *PartSetReader) Read(p []byte) (n int, err error) {
readerLen := psr.reader.Len()
if readerLen >= len(p) {
return psr.reader.Read(p)
} else if readerLen > 0 {
n1, err := psr.Read(p[:readerLen])
if err != nil {
return n1, err
}
n2, err := psr.Read(p[readerLen:])
return n1 + n2, err
}
psr.i++
2016-03-11 19:49:43 -08:00
if psr.i >= len(psr.parts) {
2016-03-20 22:24:26 -07:00
return 0, io.EOF
2016-03-11 19:49:43 -08:00
}
psr.reader = bytes.NewReader(psr.parts[psr.i].Bytes)
return psr.Read(p)
}
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"
}
ps.mtx.Lock()
defer ps.mtx.Unlock()
return fmt.Sprintf("(%v of %v)", ps.Count(), ps.Total())
2014-10-18 01:42:33 -07:00
}
func (ps *PartSet) MarshalJSON() ([]byte, error) {
if ps == nil {
2018-04-27 07:29:05 -07:00
return []byte("{}"), nil
}
ps.mtx.Lock()
defer ps.mtx.Unlock()
return cdc.MarshalJSON(struct {
CountTotal string `json:"count/total"`
PartsBitArray *cmn.BitArray `json:"parts_bit_array"`
}{
fmt.Sprintf("%d/%d", ps.Count(), ps.Total()),
2018-04-27 07:29:05 -07:00
ps.partsBitArray,
})
}