Lite wallet server https://hush.is
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

128 lines
2.9 KiB

package parser
import (
"fmt"
"github.com/pkg/errors"
"github.com/zcash-hackworks/lightwalletd/parser/internal/bytestring"
"github.com/zcash-hackworks/lightwalletd/walletrpc"
)
type block struct {
hdr *blockHeader
vtx []*Transaction
height int
}
func NewBlock() *block {
return &block{height: -1}
}
func (b *block) GetVersion() int {
return int(b.hdr.Version)
}
func (b *block) GetTxCount() int {
return len(b.vtx)
}
func (b *block) Transactions() []*Transaction {
// TODO: these should NOT be mutable
return b.vtx
}
// GetDisplayHash returns the block hash in big-endian display order.
func (b *block) GetDisplayHash() []byte {
return b.hdr.GetDisplayHash()
}
// TODO: encode hash endianness in a type?
// GetEncodableHash returns the block hash in little-endian wire order.
func (b *block) GetEncodableHash() []byte {
return b.hdr.GetEncodableHash()
}
func (b *block) HasSaplingTransactions() bool {
for _, tx := range b.vtx {
if tx.HasSaplingTransactions() {
return true
}
}
return false
}
// 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 {
if b.height != -1 {
return b.height
}
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])
}
b.height = int(blockHeight)
return int(blockHeight)
}
func (b *block) ToCompact() *walletrpc.CompactBlock {
compactBlock := &walletrpc.CompactBlock{
//TODO ProtoVersion: 1,
Height: uint64(b.GetHeight()),
Hash: b.GetEncodableHash(),
Time: b.hdr.Time,
}
// Only Sapling transactions have a meaningful compact encoding
saplingTxns := make([]*walletrpc.CompactTx, 0, len(b.vtx))
for idx, tx := range b.vtx {
if tx.HasSaplingTransactions() {
saplingTxns = append(saplingTxns, tx.ToCompact(idx))
}
}
compactBlock.Vtx = saplingTxns
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
}