103 lines
2.3 KiB
Go
103 lines
2.3 KiB
Go
package parser
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/gtank/ctxd/parser/internal/bytestring"
|
|
"github.com/gtank/ctxd/proto"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type block struct {
|
|
hdr *blockHeader
|
|
vtx []*transaction
|
|
}
|
|
|
|
func NewBlock() *block {
|
|
return &block{}
|
|
}
|
|
|
|
func (b *block) GetVersion() int {
|
|
return int(b.hdr.Version)
|
|
}
|
|
|
|
func (b *block) GetTxCount() int {
|
|
return len(b.vtx)
|
|
}
|
|
|
|
// GetHash returns the block hash in big-endian display order.
|
|
func (b *block) GetHash() []byte {
|
|
return b.hdr.GetHash()
|
|
}
|
|
|
|
// getEncodableHash returns the block hash in little-endian wire order.
|
|
func (b *block) getEncodableHash() []byte {
|
|
return b.hdr.getEncodableHash()
|
|
}
|
|
|
|
// GetHeight() extracts the block height from the coinbase transaction. See
|
|
// BIP34. Returns block height on success, or -1 on error.
|
|
func (b *block) GetHeight() int {
|
|
coinbaseScript := bytestring.String(b.vtx[0].transparentInputs[0].ScriptSig)
|
|
var heightByte byte
|
|
if ok := coinbaseScript.ReadByte(&heightByte); !ok {
|
|
return -1
|
|
}
|
|
heightLen := int(heightByte)
|
|
var heightBytes = make([]byte, heightLen)
|
|
if ok := coinbaseScript.ReadBytes(&heightBytes, heightLen); !ok {
|
|
return -1
|
|
}
|
|
// uint32 should last us a while (Nov 2018)
|
|
var blockHeight uint32
|
|
for i := heightLen - 1; i >= 0; i-- {
|
|
blockHeight <<= 8
|
|
blockHeight = blockHeight | uint32(heightBytes[i])
|
|
}
|
|
return int(blockHeight)
|
|
}
|
|
|
|
func (b *block) ToCompact() *proto.CompactBlock {
|
|
compactBlock := &proto.CompactBlock{
|
|
BlockID: &proto.BlockFilter{
|
|
BlockHeight: uint64(b.GetHeight()),
|
|
BlockHash: b.getEncodableHash(),
|
|
},
|
|
}
|
|
compactBlock.Vtx = make([]*proto.CompactTx, len(b.vtx))
|
|
for idx, tx := range b.vtx {
|
|
compactBlock.Vtx[idx] = tx.ToCompact(idx)
|
|
}
|
|
return compactBlock
|
|
}
|
|
|
|
func (b *block) ParseFromSlice(data []byte) (rest []byte, err error) {
|
|
hdr := NewBlockHeader()
|
|
data, err = hdr.ParseFromSlice(data)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "parsing block header")
|
|
}
|
|
|
|
s := bytestring.String(data)
|
|
var txCount int
|
|
if ok := s.ReadCompactSize(&txCount); !ok {
|
|
return nil, errors.New("could not read tx_count")
|
|
}
|
|
data = []byte(s)
|
|
|
|
vtx := make([]*transaction, 0, txCount)
|
|
for i := 0; len(data) > 0; i++ {
|
|
tx := NewTransaction()
|
|
data, err = tx.ParseFromSlice(data)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, fmt.Sprintf("parsing transaction %d", i))
|
|
}
|
|
vtx = append(vtx, tx)
|
|
}
|
|
|
|
b.hdr = hdr
|
|
b.vtx = vtx
|
|
|
|
return data, nil
|
|
}
|