|
|
- package blocks
-
- import (
- "crypto/sha256"
- "io"
- "time"
-
- . "github.com/tendermint/tendermint/binary"
- . "github.com/tendermint/tendermint/common"
- "github.com/tendermint/tendermint/merkle"
- )
-
- const (
- defaultBlockPartSizeBytes = 4096
- )
-
- type Block struct {
- Header
- Validation
- Txs
-
- // Volatile
- hash []byte
- }
-
- func ReadBlock(r io.Reader, n *int64, err *error) *Block {
- return &Block{
- Header: ReadHeader(r, n, err),
- Validation: ReadValidation(r, n, err),
- Txs: ReadTxs(r, n, err),
- }
- }
-
- func (b *Block) WriteTo(w io.Writer) (n int64, err error) {
- WriteBinary(w, &b.Header, &n, &err)
- WriteBinary(w, &b.Validation, &n, &err)
- WriteBinary(w, &b.Txs, &n, &err)
- return
- }
-
- func (b *Block) ValidateBasic() error {
- // TODO Basic validation that doesn't involve context.
- return nil
- }
-
- func (b *Block) Hash() []byte {
- if b.hash != nil {
- return b.hash
- } else {
- hashes := [][]byte{
- b.Header.Hash(),
- b.Validation.Hash(),
- b.Txs.Hash(),
- }
- // Merkle hash from sub-hashes.
- return merkle.HashFromByteSlices(hashes)
- }
- }
-
- // The returns parts must be signed afterwards.
- func (b *Block) ToBlockPartSet() *BlockPartSet {
- var parts []*BlockPart
- blockBytes := BinaryBytes(b)
- total := (len(blockBytes) + defaultBlockPartSizeBytes - 1) / defaultBlockPartSizeBytes
- for i := 0; i < total; i++ {
- start := defaultBlockPartSizeBytes * i
- end := MinInt(start+defaultBlockPartSizeBytes, len(blockBytes))
- partBytes := make([]byte, end-start)
- copy(partBytes, blockBytes[start:end]) // Do not ref the original byteslice.
- part := &BlockPart{
- Height: b.Height,
- Index: uint16(i),
- Total: uint16(total),
- Bytes: partBytes,
- Signature: Signature{}, // No signature.
- }
- parts = append(parts, part)
- }
- return NewBlockPartSet(b.Height, parts)
- }
-
- //-----------------------------------------------------------------------------
-
- /*
- BlockPart represents a chunk of the bytes of a block.
- Each block is divided into fixed length chunks (e.g. 4Kb)
- for faster propagation across the gossip network.
- */
- type BlockPart struct {
- Height uint32
- Round uint16 // Add Round? Well I need to know...
- Index uint16
- Total uint16
- Bytes []byte
- Signature
-
- // Volatile
- hash []byte
- }
-
- func ReadBlockPart(r io.Reader, n *int64, err *error) *BlockPart {
- return &BlockPart{
- Height: ReadUInt32(r, n, err),
- Round: ReadUInt16(r, n, err),
- Index: ReadUInt16(r, n, err),
- Total: ReadUInt16(r, n, err),
- Bytes: ReadByteSlice(r, n, err),
- Signature: ReadSignature(r, n, err),
- }
- }
-
- func (bp *BlockPart) WriteTo(w io.Writer) (n int64, err error) {
- WriteUInt32(w, bp.Height, &n, &err)
- WriteUInt16(w, bp.Round, &n, &err)
- WriteUInt16(w, bp.Index, &n, &err)
- WriteUInt16(w, bp.Total, &n, &err)
- WriteByteSlice(w, bp.Bytes, &n, &err)
- WriteBinary(w, bp.Signature, &n, &err)
- return
- }
-
- // Hash returns the hash of the block part data bytes.
- func (bp *BlockPart) Hash() []byte {
- if bp.hash != nil {
- return bp.hash
- } else {
- hasher := sha256.New()
- hasher.Write(bp.Bytes)
- bp.hash = hasher.Sum(nil)
- return bp.hash
- }
- }
-
- //-----------------------------------------------------------------------------
-
- /* Header is part of a Block */
- type Header struct {
- Name string
- Height uint32
- Fees uint64
- Time time.Time
- PrevHash []byte
- ValidationHash []byte
- TxsHash []byte
-
- // Volatile
- hash []byte
- }
-
- func ReadHeader(r io.Reader, n *int64, err *error) (h Header) {
- if *err != nil {
- return Header{}
- }
- return Header{
- Name: ReadString(r, n, err),
- Height: ReadUInt32(r, n, err),
- Fees: ReadUInt64(r, n, err),
- Time: ReadTime(r, n, err),
- PrevHash: ReadByteSlice(r, n, err),
- ValidationHash: ReadByteSlice(r, n, err),
- TxsHash: ReadByteSlice(r, n, err),
- }
- }
-
- func (h *Header) WriteTo(w io.Writer) (n int64, err error) {
- WriteString(w, h.Name, &n, &err)
- WriteUInt32(w, h.Height, &n, &err)
- WriteUInt64(w, h.Fees, &n, &err)
- WriteTime(w, h.Time, &n, &err)
- WriteByteSlice(w, h.PrevHash, &n, &err)
- WriteByteSlice(w, h.ValidationHash, &n, &err)
- WriteByteSlice(w, h.TxsHash, &n, &err)
- return
- }
-
- func (h *Header) Hash() []byte {
- if h.hash != nil {
- return h.hash
- } else {
- hasher := sha256.New()
- _, err := h.WriteTo(hasher)
- if err != nil {
- panic(err)
- }
- h.hash = hasher.Sum(nil)
- return h.hash
- }
- }
-
- /* Validation is part of a block */
- type Validation struct {
- Signatures []Signature
- Txs []Tx
-
- // Volatile
- hash []byte
- }
-
- func ReadValidation(r io.Reader, n *int64, err *error) Validation {
- numSigs := ReadUInt32(r, n, err)
- numAdjs := ReadUInt32(r, n, err)
- sigs := make([]Signature, 0, numSigs)
- for i := uint32(0); i < numSigs; i++ {
- sigs = append(sigs, ReadSignature(r, n, err))
- }
- tx := make([]Tx, 0, numAdjs)
- for i := uint32(0); i < numAdjs; i++ {
- tx = append(tx, ReadTx(r, n, err))
- }
- return Validation{
- Signatures: sigs,
- Txs: tx,
- }
- }
-
- func (v *Validation) WriteTo(w io.Writer) (n int64, err error) {
- WriteUInt32(w, uint32(len(v.Signatures)), &n, &err)
- WriteUInt32(w, uint32(len(v.Txs)), &n, &err)
- for _, sig := range v.Signatures {
- WriteBinary(w, sig, &n, &err)
- }
- for _, tx := range v.Txs {
- WriteBinary(w, tx, &n, &err)
- }
- return
- }
-
- func (v *Validation) Hash() []byte {
- if v.hash != nil {
- return v.hash
- } else {
- hasher := sha256.New()
- _, err := v.WriteTo(hasher)
- if err != nil {
- panic(err)
- }
- v.hash = hasher.Sum(nil)
- return v.hash
- }
- }
-
- /* Txs is part of a block */
- type Txs struct {
- Txs []Tx
-
- // Volatile
- hash []byte
- }
-
- func ReadTxs(r io.Reader, n *int64, err *error) Txs {
- numTxs := ReadUInt32(r, n, err)
- txs := make([]Tx, 0, numTxs)
- for i := uint32(0); i < numTxs; i++ {
- txs = append(txs, ReadTx(r, n, err))
- }
- return Txs{Txs: txs}
- }
-
- func (txs *Txs) WriteTo(w io.Writer) (n int64, err error) {
- WriteUInt32(w, uint32(len(txs.Txs)), &n, &err)
- for _, tx := range txs.Txs {
- WriteBinary(w, tx, &n, &err)
- }
- return
- }
-
- func (txs *Txs) Hash() []byte {
- if txs.hash != nil {
- return txs.hash
- } else {
- bs := make([]Binary, 0, len(txs.Txs))
- for i, tx := range txs.Txs {
- bs[i] = Binary(tx)
- }
- txs.hash = merkle.HashFromBinarySlice(bs)
- return txs.hash
- }
- }
|