From e69779195fe55cb52ab79cf2b0ea7e7fe472e0ff Mon Sep 17 00:00:00 2001 From: George Tankersley Date: Wed, 12 Sep 2018 00:00:00 +0000 Subject: [PATCH] parser: tidy up the BlockHeader API --- parser/block.go | 35 ++++++++++++++++++++++++----------- parser/block_test.go | 18 +++++++----------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/parser/block.go b/parser/block.go index 7b836a1..a98e15e 100644 --- a/parser/block.go +++ b/parser/block.go @@ -4,7 +4,6 @@ import ( "bytes" "crypto/sha256" "encoding/binary" - "io" "log" "github.com/pkg/errors" @@ -16,7 +15,7 @@ const ( ) // A block header as defined in version 2018.0-beta-29 of the Zcash Protocol Spec. -type RawBlockHeader struct { +type rawBlockHeader struct { // The block version number indicates which set of block validation rules // to follow. The current and only defined block version number for Zcash // is 4. @@ -57,30 +56,39 @@ type RawBlockHeader struct { Solution [EQUIHASH_SIZE]byte } -// EquihashSize is a concrete instance of Bitcoin's CompactSize encoding. +// EquihashSize is a concrete instance of Bitcoin's CompactSize encoding. This +// representation is a hack allowing us to use Go's binary parsing. In contexts +// outside of Zcash this could be a variable-length field. type EquihashSize struct { SizeTag byte // always the byte value 253 Size uint16 // always 1344 } -func readRawBlockHeader(r io.Reader) (*RawBlockHeader, error) { - var blockHeader RawBlockHeader - err := binary.Read(r, binary.LittleEndian, &blockHeader) - if err != nil { - return nil, errors.Wrap(err, "failed reading block header") +func ReadBlockHeader(blockHeader *BlockHeader, data []byte) error { + if blockHeader.rawBlockHeader == nil { + blockHeader.rawBlockHeader = new(rawBlockHeader) } - return &blockHeader, nil + return blockHeader.UnmarshalBinary(data) } -func (hdr *RawBlockHeader) MarshalBinary() ([]byte, error) { +func (hdr *rawBlockHeader) MarshalBinary() ([]byte, error) { serBytes := make([]byte, 0, SER_BLOCK_HEADER_SIZE) serBuf := bytes.NewBuffer(serBytes) err := binary.Write(serBuf, binary.LittleEndian, hdr) return serBytes[:SER_BLOCK_HEADER_SIZE], err } +func (hdr *rawBlockHeader) UnmarshalBinary(data []byte) error { + reader := bytes.NewReader(data) + err := binary.Read(reader, binary.LittleEndian, hdr) + if err != nil { + return errors.Wrap(err, "failed parsing block header") + } + return nil +} + type BlockHeader struct { - *RawBlockHeader + *rawBlockHeader cachedBlockHash []byte } @@ -102,3 +110,8 @@ func (hdr *BlockHeader) GetBlockHash() []byte { hdr.cachedBlockHash = digest[:] return hdr.cachedBlockHash } + +func (hdr *BlockHeader) GetSerializedSize() int { + // TODO: Make this dynamic. Low priority; it's unlikely to change. + return SER_BLOCK_HEADER_SIZE +} diff --git a/parser/block_test.go b/parser/block_test.go index c24af5d..a23661e 100644 --- a/parser/block_test.go +++ b/parser/block_test.go @@ -27,32 +27,32 @@ func TestBlockHeader(t *testing.T) { } // Try to read the header - reader := bytes.NewReader(decodedBlockData) - rawHeader, err := readRawBlockHeader(reader) + blockHeader := &BlockHeader{} + err = ReadBlockHeader(blockHeader, decodedBlockData) if err != nil { t.Error(err) continue } // Some basic sanity checks - if rawHeader.Version != 4 { + if blockHeader.Version != 4 { t.Error("Read wrong version in a test block.") break } - if rawHeader.Time < lastBlockTime { + if blockHeader.Time < lastBlockTime { t.Error("Block times not increasing.") break } - lastBlockTime = rawHeader.Time + lastBlockTime = blockHeader.Time - if rawHeader.SolutionSize.Size != 1344 { + if blockHeader.SolutionSize.Size != 1344 { t.Error("Got wrong Equihash solution size.") break } // Re-serialize and check for consistency - serializedHeader, err := rawHeader.MarshalBinary() + serializedHeader, err := blockHeader.MarshalBinary() if err != nil { t.Errorf("Error serializing header: %v", err) break @@ -73,10 +73,6 @@ func TestBlockHeader(t *testing.T) { break } - blockHeader := &BlockHeader{ - rawHeader, - nil, - } hash := blockHeader.GetBlockHash() // This is not necessarily true for anything but our current test cases.