1// Copyright (c) 2013-2016 The btcsuite developers
2// Use of this source code is governed by an ISC
3// license that can be found in the LICENSE file.
4
5package btcutil
6
7import (
8	"bytes"
9	"fmt"
10	"io"
11
12	"github.com/btcsuite/btcd/chaincfg/chainhash"
13	"github.com/btcsuite/btcd/wire"
14)
15
16// OutOfRangeError describes an error due to accessing an element that is out
17// of range.
18type OutOfRangeError string
19
20// BlockHeightUnknown is the value returned for a block height that is unknown.
21// This is typically because the block has not been inserted into the main chain
22// yet.
23const BlockHeightUnknown = int32(-1)
24
25// Error satisfies the error interface and prints human-readable errors.
26func (e OutOfRangeError) Error() string {
27	return string(e)
28}
29
30// Block defines a bitcoin block that provides easier and more efficient
31// manipulation of raw blocks.  It also memoizes hashes for the block and its
32// transactions on their first access so subsequent accesses don't have to
33// repeat the relatively expensive hashing operations.
34type Block struct {
35	msgBlock                 *wire.MsgBlock  // Underlying MsgBlock
36	serializedBlock          []byte          // Serialized bytes for the block
37	serializedBlockNoWitness []byte          // Serialized bytes for block w/o witness data
38	blockHash                *chainhash.Hash // Cached block hash
39	blockHeight              int32           // Height in the main block chain
40	transactions             []*Tx           // Transactions
41	txnsGenerated            bool            // ALL wrapped transactions generated
42}
43
44// MsgBlock returns the underlying wire.MsgBlock for the Block.
45func (b *Block) MsgBlock() *wire.MsgBlock {
46	// Return the cached block.
47	return b.msgBlock
48}
49
50// Bytes returns the serialized bytes for the Block.  This is equivalent to
51// calling Serialize on the underlying wire.MsgBlock, however it caches the
52// result so subsequent calls are more efficient.
53func (b *Block) Bytes() ([]byte, error) {
54	// Return the cached serialized bytes if it has already been generated.
55	if len(b.serializedBlock) != 0 {
56		return b.serializedBlock, nil
57	}
58
59	// Serialize the MsgBlock.
60	w := bytes.NewBuffer(make([]byte, 0, b.msgBlock.SerializeSize()))
61	err := b.msgBlock.Serialize(w)
62	if err != nil {
63		return nil, err
64	}
65	serializedBlock := w.Bytes()
66
67	// Cache the serialized bytes and return them.
68	b.serializedBlock = serializedBlock
69	return serializedBlock, nil
70}
71
72// BytesNoWitness returns the serialized bytes for the block with transactions
73// encoded without any witness data.
74func (b *Block) BytesNoWitness() ([]byte, error) {
75	// Return the cached serialized bytes if it has already been generated.
76	if len(b.serializedBlockNoWitness) != 0 {
77		return b.serializedBlockNoWitness, nil
78	}
79
80	// Serialize the MsgBlock.
81	var w bytes.Buffer
82	err := b.msgBlock.SerializeNoWitness(&w)
83	if err != nil {
84		return nil, err
85	}
86	serializedBlock := w.Bytes()
87
88	// Cache the serialized bytes and return them.
89	b.serializedBlockNoWitness = serializedBlock
90	return serializedBlock, nil
91}
92
93// Hash returns the block identifier hash for the Block.  This is equivalent to
94// calling BlockHash on the underlying wire.MsgBlock, however it caches the
95// result so subsequent calls are more efficient.
96func (b *Block) Hash() *chainhash.Hash {
97	// Return the cached block hash if it has already been generated.
98	if b.blockHash != nil {
99		return b.blockHash
100	}
101
102	// Cache the block hash and return it.
103	hash := b.msgBlock.BlockHash()
104	b.blockHash = &hash
105	return &hash
106}
107
108// Tx returns a wrapped transaction (btcutil.Tx) for the transaction at the
109// specified index in the Block.  The supplied index is 0 based.  That is to
110// say, the first transaction in the block is txNum 0.  This is nearly
111// equivalent to accessing the raw transaction (wire.MsgTx) from the
112// underlying wire.MsgBlock, however the wrapped transaction has some helpful
113// properties such as caching the hash so subsequent calls are more efficient.
114func (b *Block) Tx(txNum int) (*Tx, error) {
115	// Ensure the requested transaction is in range.
116	numTx := uint64(len(b.msgBlock.Transactions))
117	if txNum < 0 || uint64(txNum) > numTx {
118		str := fmt.Sprintf("transaction index %d is out of range - max %d",
119			txNum, numTx-1)
120		return nil, OutOfRangeError(str)
121	}
122
123	// Generate slice to hold all of the wrapped transactions if needed.
124	if len(b.transactions) == 0 {
125		b.transactions = make([]*Tx, numTx)
126	}
127
128	// Return the wrapped transaction if it has already been generated.
129	if b.transactions[txNum] != nil {
130		return b.transactions[txNum], nil
131	}
132
133	// Generate and cache the wrapped transaction and return it.
134	newTx := NewTx(b.msgBlock.Transactions[txNum])
135	newTx.SetIndex(txNum)
136	b.transactions[txNum] = newTx
137	return newTx, nil
138}
139
140// Transactions returns a slice of wrapped transactions (btcutil.Tx) for all
141// transactions in the Block.  This is nearly equivalent to accessing the raw
142// transactions (wire.MsgTx) in the underlying wire.MsgBlock, however it
143// instead provides easy access to wrapped versions (btcutil.Tx) of them.
144func (b *Block) Transactions() []*Tx {
145	// Return transactions if they have ALL already been generated.  This
146	// flag is necessary because the wrapped transactions are lazily
147	// generated in a sparse fashion.
148	if b.txnsGenerated {
149		return b.transactions
150	}
151
152	// Generate slice to hold all of the wrapped transactions if needed.
153	if len(b.transactions) == 0 {
154		b.transactions = make([]*Tx, len(b.msgBlock.Transactions))
155	}
156
157	// Generate and cache the wrapped transactions for all that haven't
158	// already been done.
159	for i, tx := range b.transactions {
160		if tx == nil {
161			newTx := NewTx(b.msgBlock.Transactions[i])
162			newTx.SetIndex(i)
163			b.transactions[i] = newTx
164		}
165	}
166
167	b.txnsGenerated = true
168	return b.transactions
169}
170
171// TxHash returns the hash for the requested transaction number in the Block.
172// The supplied index is 0 based.  That is to say, the first transaction in the
173// block is txNum 0.  This is equivalent to calling TxHash on the underlying
174// wire.MsgTx, however it caches the result so subsequent calls are more
175// efficient.
176func (b *Block) TxHash(txNum int) (*chainhash.Hash, error) {
177	// Attempt to get a wrapped transaction for the specified index.  It
178	// will be created lazily if needed or simply return the cached version
179	// if it has already been generated.
180	tx, err := b.Tx(txNum)
181	if err != nil {
182		return nil, err
183	}
184
185	// Defer to the wrapped transaction which will return the cached hash if
186	// it has already been generated.
187	return tx.Hash(), nil
188}
189
190// TxLoc returns the offsets and lengths of each transaction in a raw block.
191// It is used to allow fast indexing into transactions within the raw byte
192// stream.
193func (b *Block) TxLoc() ([]wire.TxLoc, error) {
194	rawMsg, err := b.Bytes()
195	if err != nil {
196		return nil, err
197	}
198	rbuf := bytes.NewBuffer(rawMsg)
199
200	var mblock wire.MsgBlock
201	txLocs, err := mblock.DeserializeTxLoc(rbuf)
202	if err != nil {
203		return nil, err
204	}
205	return txLocs, err
206}
207
208// Height returns the saved height of the block in the block chain.  This value
209// will be BlockHeightUnknown if it hasn't already explicitly been set.
210func (b *Block) Height() int32 {
211	return b.blockHeight
212}
213
214// SetHeight sets the height of the block in the block chain.
215func (b *Block) SetHeight(height int32) {
216	b.blockHeight = height
217}
218
219// NewBlock returns a new instance of a bitcoin block given an underlying
220// wire.MsgBlock.  See Block.
221func NewBlock(msgBlock *wire.MsgBlock) *Block {
222	return &Block{
223		msgBlock:    msgBlock,
224		blockHeight: BlockHeightUnknown,
225	}
226}
227
228// NewBlockFromBytes returns a new instance of a bitcoin block given the
229// serialized bytes.  See Block.
230func NewBlockFromBytes(serializedBlock []byte) (*Block, error) {
231	br := bytes.NewReader(serializedBlock)
232	b, err := NewBlockFromReader(br)
233	if err != nil {
234		return nil, err
235	}
236	b.serializedBlock = serializedBlock
237	return b, nil
238}
239
240// NewBlockFromReader returns a new instance of a bitcoin block given a
241// Reader to deserialize the block.  See Block.
242func NewBlockFromReader(r io.Reader) (*Block, error) {
243	// Deserialize the bytes into a MsgBlock.
244	var msgBlock wire.MsgBlock
245	err := msgBlock.Deserialize(r)
246	if err != nil {
247		return nil, err
248	}
249
250	b := Block{
251		msgBlock:    &msgBlock,
252		blockHeight: BlockHeightUnknown,
253	}
254	return &b, nil
255}
256
257// NewBlockFromBlockAndBytes returns a new instance of a bitcoin block given
258// an underlying wire.MsgBlock and the serialized bytes for it.  See Block.
259func NewBlockFromBlockAndBytes(msgBlock *wire.MsgBlock, serializedBlock []byte) *Block {
260	return &Block{
261		msgBlock:        msgBlock,
262		serializedBlock: serializedBlock,
263		blockHeight:     BlockHeightUnknown,
264	}
265}
266