Initial implementation.

This commit is contained in:
Dave Collins 2013-05-28 17:32:35 -05:00
parent 727d687cf3
commit ef6c01960f
7 changed files with 825 additions and 0 deletions

13
LICENSE Normal file
View file

@ -0,0 +1,13 @@
Copyright (c) 2013 Conformal Systems LLC.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View file

@ -2,3 +2,54 @@ btcutil
======= =======
Package btcutil provides bitcoin-specific convenience functions and types. Package btcutil provides bitcoin-specific convenience functions and types.
The test coverage is currently ~76%, however it will improved to 100% in the
near future. See `test_coverage.txt` for the gocov coverage report.
Alternatively, if you are running a POSIX OS, you can run the `cov_report.sh`
script for a real-time report. Package btcutil is licensed under the liberal
ISC license.
This package was developed for btcd, an alternative full-node implementation of
bitcoin which is under active development by Conformal. Although it was
primarily written for btcd, this package has intentionally been designed so it
can be used as a standalone package for any projects needing the functionality
provided.
## Documentation
Full `go doc` style documentation for the project can be viewed online without
installing this package by using the GoDoc site here:
http://godoc.org/github.com/conformal/btcutil
You can also view the documentation locally once the package is installed with
the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to
http://localhost:6060/pkg/github.com/conformal/btcutil
## Installation
```bash
$ go get github.com/conformal/btcutil
```
## GPG Verification Key
All official release tags are signed by Conformal so users can ensure the code
has not been tampered with and is coming from Conformal. To verify the
signature perform the following:
- Download the public key from the Conformal website at
https://opensource.conformal.com/GIT-GPG-KEY-conformal.txt
- Import the public key into your GPG keyring:
```bash
gpg --import GIT-GPG-KEY-conformal.txt
```
- Verify the release tag with the following command where `TAG_NAME` is a
placeholder for the specific tag:
```bash
git tag -v TAG_NAME
```
## License
Package btcutil is licensed under the liberal ISC License.

226
block.go Normal file
View file

@ -0,0 +1,226 @@
// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil
import (
"bytes"
"fmt"
"github.com/conformal/btcwire"
)
// OutOfRangeError describes an error due to accessing an element that is out
// of range.
type OutOfRangeError string
// BlockHeightUnknown is the value returned for a block height that is unknown.
// This is typically because the block has not been inserted into the main chain
// yet.
const BlockHeightUnknown = int64(-1)
// Error satisfies the error interface and prints human-readable errors.
func (e OutOfRangeError) Error() string {
return string(e)
}
// Block defines a bitcoin block that provides easier and more efficient
// manipulation of raw wire protocol blocks. It also memoizes hashes for the
// block and its transactions on their first access so subsequent accesses don't
// have to repeat the relatively expensive hashing operations.
type Block struct {
msgBlock *btcwire.MsgBlock // Underlying MsgBlock
rawBlock []byte // Raw wire encoded bytes for the block
protocolVersion uint32 // Protocol version used to encode rawBlock
blockSha *btcwire.ShaHash // Cached block hash
blockHeight int64 // Height in the main block chain
txShas []*btcwire.ShaHash // Cached transaction hashes
txShasGenerated bool // ALL transaction hashes generated
}
// MsgBlock returns the underlying btcwire.MsgBlock for the Block.
func (b *Block) MsgBlock() *btcwire.MsgBlock {
// Return the cached block.
return b.msgBlock
}
// Bytes returns the raw wire protocol encoded bytes for the Block and the
// protocol version used to encode it. This is equivalent to calling BtcEncode
// on the underlying btcwire.MsgBlock, however it caches the result so
// subsequent calls are more efficient.
func (b *Block) Bytes() ([]byte, uint32, error) {
// Return the cached raw block bytes and associated protocol version if
// it has already been generated.
if len(b.rawBlock) != 0 {
return b.rawBlock, b.protocolVersion, nil
}
// Encode the MsgBlock into raw block bytes.
var w bytes.Buffer
err := b.msgBlock.BtcEncode(&w, b.protocolVersion)
if err != nil {
return nil, 0, err
}
rawBlock := w.Bytes()
// Cache the encoded bytes and return them.
b.rawBlock = rawBlock
return rawBlock, b.protocolVersion, nil
}
// Sha returns the block identifier hash for the Block. This is equivalent to
// calling BlockSha on the underlying btcwire.MsgBlock, however it caches the
// result so subsequent calls are more efficient.
func (b *Block) Sha() (*btcwire.ShaHash, error) {
// Return the cached block hash if it has already been generated.
if b.blockSha != nil {
return b.blockSha, nil
}
// Generate the block hash. Ignore the error since BlockSha can't
// currently fail.
sha, _ := b.msgBlock.BlockSha(b.protocolVersion)
// Cache the block hash and return it.
b.blockSha = &sha
return &sha, nil
}
// TxSha returns the hash for the requested transaction number in the Block.
// The supplied index is 0 based. That is to say, the first transaction is the
// block is txNum 0. This is equivalent to calling TxSha on the underlying
// btcwire.MsgTx, however it caches the result so subsequent calls are more
// efficient.
func (b *Block) TxSha(txNum int) (*btcwire.ShaHash, error) {
// Ensure the requested transaction is in range.
numTx := b.msgBlock.Header.TxnCount
if txNum < 0 || uint64(txNum) > numTx {
str := fmt.Sprintf("transaction index %d is out of range - max %d",
txNum, numTx-1)
return nil, OutOfRangeError(str)
}
// Generate slice to hold all of the transaction hashes if needed.
if len(b.txShas) == 0 {
b.txShas = make([]*btcwire.ShaHash, numTx)
}
// Return the cached hash if it has already been generated.
if b.txShas[txNum] != nil {
return b.txShas[txNum], nil
}
// Generate the hash for the transaction. Ignore the error since TxSha
// can't currently fail.
sha, _ := b.msgBlock.Transactions[txNum].TxSha(b.protocolVersion)
// Cache the transaction hash and return it.
b.txShas[txNum] = &sha
return &sha, nil
}
// TxShas returns a slice of hashes for all transactions in the Block. This is
// equivalent to calling TxSha on each underlying btcwire.MsgTx, however it
// caches the result so subsequent calls are more efficient.
func (b *Block) TxShas() ([]*btcwire.ShaHash, error) {
// Return cached hashes if they have ALL already been generated. This
// flag is necessary because the transaction hashes are lazily generated
// in a sparse fashion.
if b.txShasGenerated {
return b.txShas, nil
}
// Generate slice to hold all of the transaction hashes if needed.
if len(b.txShas) == 0 {
b.txShas = make([]*btcwire.ShaHash, b.msgBlock.Header.TxnCount)
}
// Generate and cache the transaction hashes for all that haven't already
// been done.
for i, hash := range b.txShas {
if hash == nil {
// Ignore the error since TxSha can't currently fail.
sha, _ := b.msgBlock.Transactions[i].TxSha(b.protocolVersion)
b.txShas[i] = &sha
}
}
b.txShasGenerated = true
return b.txShas, nil
}
// ProtocolVersion returns the protocol version that was used to create the
// underlying btcwire.MsgBlock.
func (b *Block) ProtocolVersion() uint32 {
return b.protocolVersion
}
// TxLoc() returns the offsets and lengths of each transaction in a raw block.
// It is used to allow fast indexing into the
func (b *Block) TxLoc() (txlocD []btcwire.TxLoc, err error) {
rawMsg, pver, err := b.Bytes()
if err != nil {
return
}
rbuf := bytes.NewBuffer(rawMsg)
var mblock btcwire.MsgBlock
txloc, err := mblock.BtcDecodeTxLoc(rbuf, pver)
if err != nil {
return
}
return txloc, err
}
// Height returns the saved height of the block in the blockchain. This value
// will be BlockHeightUnknown if it hasn't already explicitly been set.
func (b *Block) Height() int64 {
return b.blockHeight
}
// SetHeight sets the height of the block in the blockchain.
func (b *Block) SetHeight(height int64) {
b.blockHeight = height
}
// NewBlock returns a new instance of a bitcoin block given an underlying
// btcwire.MsgBlock and protocol version. See Block.
func NewBlock(msgBlock *btcwire.MsgBlock, pver uint32) *Block {
return &Block{
msgBlock: msgBlock,
protocolVersion: pver,
blockHeight: BlockHeightUnknown,
}
}
// NewBlockFromBytes returns a new instance of a bitcoin block given the
// raw wire encoded bytes and protocol version used to encode those bytes.
// See Block.
func NewBlockFromBytes(rawBlock []byte, pver uint32) (*Block, error) {
// Decode the raw block bytes into a MsgBlock.
var msgBlock btcwire.MsgBlock
br := bytes.NewBuffer(rawBlock)
err := msgBlock.BtcDecode(br, pver)
if err != nil {
return nil, err
}
b := Block{
msgBlock: &msgBlock,
rawBlock: rawBlock,
protocolVersion: pver,
blockHeight: BlockHeightUnknown,
}
return &b, nil
}
// NewBlockFromBlockAndBytes returns a new instance of a bitcoin block given
// an underlying btcwire.MsgBlock, protocol version and raw Block. See Block.
func NewBlockFromBlockAndBytes(msgBlock *btcwire.MsgBlock, rawBlock []byte, pver uint32) *Block {
return &Block{
msgBlock: msgBlock,
rawBlock: rawBlock,
protocolVersion: pver,
blockHeight: BlockHeightUnknown,
}
}

487
block_test.go Normal file
View file

@ -0,0 +1,487 @@
// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package btcutil_test
import (
"bytes"
"github.com/conformal/btcutil"
"github.com/conformal/btcwire"
"github.com/davecgh/go-spew/spew"
"reflect"
"testing"
"time"
)
// TestBlock tests the API for Block.
func TestBlock(t *testing.T) {
pver := btcwire.ProtocolVersion
b := btcutil.NewBlock(&Block100000, pver)
// Ensure we get the same data back out.
if gotPver := b.ProtocolVersion(); gotPver != pver {
t.Errorf("ProtocolVersion: wrong protocol version - got %v, want %v",
gotPver, pver)
}
if msgBlock := b.MsgBlock(); !reflect.DeepEqual(msgBlock, &Block100000) {
t.Errorf("MsgBlock: mismatched MsgBlock - got %v, want %v",
spew.Sdump(msgBlock), spew.Sdump(&Block100000))
}
// Ensure block height set and get work properly.
wantHeight := int64(100000)
b.SetHeight(wantHeight)
if gotHeight := b.Height(); gotHeight != wantHeight {
t.Errorf("Height: mismatched height - got %v, want %v",
gotHeight, wantHeight)
}
// Hash for block 100,000.
wantShaStr := "3ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506"
wantSha, err := btcwire.NewShaHashFromStr(wantShaStr)
if err != nil {
t.Errorf("NewShaHashFromStr: %v", err)
}
// Request the sha multiple times to test generation and caching.
for i := 0; i < 2; i++ {
sha, err := b.Sha()
if err != nil {
t.Errorf("Sha: %v", err)
continue
}
if !sha.IsEqual(wantSha) {
t.Errorf("Sha #%d mismatched sha - got %v, want %v", i,
sha, wantSha)
}
}
// Shas for the transactions in Block100000.
wantTxShas := []string{
"8c14f0db3df150123e6f3dbbf30f8b955a8249b62ac1d1ff16284aefa3d06d87",
"fff2525b8931402dd09222c50775608f75787bd2b87e56995a7bdd30f79702c4",
"6359f0868171b1d194cbee1af2f16ea598ae8fad666d9b012c8ed2b79a236ec4",
"e9a66845e05d5abc0ad04ec80f774a7e585c6e8db975962d069a522137b80c1d",
}
// Request sha for all transactions one at a time.
for i, txSha := range wantTxShas {
wantSha, err := btcwire.NewShaHashFromStr(txSha)
if err != nil {
t.Errorf("NewShaHashFromStr: %v", err)
}
// Request the sha multiple times to test generation and caching.
for j := 0; j < 2; j++ {
sha, err := b.TxSha(i)
if err != nil {
t.Errorf("TxSha: %v", err)
continue
}
if !sha.IsEqual(wantSha) {
t.Errorf("TxSha #%d mismatched sha - got %v, "+
"want %v", j, sha, wantSha)
continue
}
}
}
// Create a new block to nuke all cached data.
b = btcutil.NewBlock(&Block100000, pver)
// Request slice of all transaction shas multiple times to test
// generation and caching.
for i := 0; i < 2; i++ {
txShas, err := b.TxShas()
if err != nil {
t.Errorf("TxShas: %v", err)
continue
}
// Ensure we get the expected number of transaction shas.
if len(txShas) != len(wantTxShas) {
t.Errorf("TxShas #%d mismatched number of shas -"+
"got %d, want %d", i, len(txShas),
len(wantTxShas))
continue
}
// Ensure all of the shas match.
for j, txSha := range wantTxShas {
wantSha, err := btcwire.NewShaHashFromStr(txSha)
if err != nil {
t.Errorf("NewShaHashFromStr: %v", err)
}
if !txShas[j].IsEqual(wantSha) {
t.Errorf("TxShas #%d mismatched shas - "+
"got %v, want %v", j,
spew.Sdump(txShas),
spew.Sdump(wantTxShas))
continue
}
}
}
// Encode the test block to bytes.
var block100000Buf bytes.Buffer
err = Block100000.BtcEncode(&block100000Buf, pver)
if err != nil {
t.Errorf("BtcEncode: %v", err)
}
block100000Bytes := block100000Buf.Bytes()
// Request raw bytes multiple times to test generation and caching.
for i := 0; i < 2; i++ {
rawBytes, tmpPver, err := b.Bytes()
if err != nil {
t.Errorf("Bytes: %v", err)
continue
}
if !bytes.Equal(rawBytes, block100000Bytes) {
t.Errorf("Bytes #%d wrong bytes - got %v, want %v", i,
spew.Sdump(rawBytes),
spew.Sdump(block100000Bytes))
continue
}
if tmpPver != pver {
t.Errorf("Bytes #%d wrong protocol version - "+
"got %v, want %v", i, spew.Sdump(rawBytes),
spew.Sdump(block100000Bytes))
continue
}
}
}
// TestNewBlockFromBytes tests creation of a Block from raw bytes.
func TestNewBlockFromBytes(t *testing.T) {
// Encode the test block to bytes.
pver := btcwire.ProtocolVersion
var block100000Buf bytes.Buffer
err := Block100000.BtcEncode(&block100000Buf, pver)
if err != nil {
t.Errorf("BtcEncode: %v", err)
}
block100000Bytes := block100000Buf.Bytes()
// Create a new block from the encoded bytes.
b, err := btcutil.NewBlockFromBytes(block100000Bytes, pver)
if err != nil {
t.Errorf("NewBlockFromBytes: %v", err)
return
}
// Ensure we get the same data back out.
rawBytes, tmpPver, err := b.Bytes()
if err != nil {
t.Errorf("Bytes: %v", err)
return
}
if !bytes.Equal(rawBytes, block100000Bytes) {
t.Errorf("Bytes: wrong bytes - got %v, want %v",
spew.Sdump(rawBytes),
spew.Sdump(block100000Bytes))
}
if tmpPver != pver {
t.Errorf("Bytes: wrong protocol version - got %v, want %v",
tmpPver, pver)
}
// Ensure the generated MsgBlock is correct.
if msgBlock := b.MsgBlock(); !reflect.DeepEqual(msgBlock, &Block100000) {
t.Errorf("MsgBlock: mismatched MsgBlock - got %v, want %v",
spew.Sdump(msgBlock), spew.Sdump(&Block100000))
}
}
// TestNewBlockFromBlockAndBytes tests creation of a Block from a MsgBlock and
// raw bytes.
func TestNewBlockFromBlockAndBytes(t *testing.T) {
// Encode the test block to bytes.
pver := btcwire.ProtocolVersion
var block100000Buf bytes.Buffer
err := Block100000.BtcEncode(&block100000Buf, pver)
if err != nil {
t.Errorf("BtcEncode: %v", err)
}
block100000Bytes := block100000Buf.Bytes()
// Create a new block from the encoded bytes.
b := btcutil.NewBlockFromBlockAndBytes(&Block100000,
block100000Bytes, pver)
// Ensure we get the same data back out.
rawBytes, tmpPver, err := b.Bytes()
if err != nil {
t.Errorf("Bytes: %v", err)
return
}
if !bytes.Equal(rawBytes, block100000Bytes) {
t.Errorf("Bytes: wrong bytes - got %v, want %v",
spew.Sdump(rawBytes),
spew.Sdump(block100000Bytes))
}
if tmpPver != pver {
t.Errorf("Bytes: wrong protocol version - got %v, want %v",
tmpPver, pver)
}
if msgBlock := b.MsgBlock(); !reflect.DeepEqual(msgBlock, &Block100000) {
t.Errorf("MsgBlock: mismatched MsgBlock - got %v, want %v",
spew.Sdump(msgBlock), spew.Sdump(&Block100000))
}
}
// Block100000 defines block 100,000 of the block chain. It is used to
// test Block operations.
var Block100000 btcwire.MsgBlock = btcwire.MsgBlock{
Header: btcwire.BlockHeader{
Version: 1,
PrevBlock: btcwire.ShaHash([32]byte{ // Make go vet happy.
0x50, 0x12, 0x01, 0x19, 0x17, 0x2a, 0x61, 0x04,
0x21, 0xa6, 0xc3, 0x01, 0x1d, 0xd3, 0x30, 0xd9,
0xdf, 0x07, 0xb6, 0x36, 0x16, 0xc2, 0xcc, 0x1f,
0x1c, 0xd0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
}), // 000000000002d01c1fccc21636b607dfd930d31d01c3a62104612a1719011250
MerkleRoot: btcwire.ShaHash([32]byte{ // Make go vet happy.
0x66, 0x57, 0xa9, 0x25, 0x2a, 0xac, 0xd5, 0xc0,
0xb2, 0x94, 0x09, 0x96, 0xec, 0xff, 0x95, 0x22,
0x28, 0xc3, 0x06, 0x7c, 0xc3, 0x8d, 0x48, 0x85,
0xef, 0xb5, 0xa4, 0xac, 0x42, 0x47, 0xe9, 0xf3,
}), // f3e94742aca4b5ef85488dc37c06c3282295ffec960994b2c0d5ac2a25a95766
Timestamp: time.Unix(1293623863, 0), // 2010-12-29 11:57:43 +0000 UTC
Bits: 0x1b04864c, // 453281356
Nonce: 0x10572b0f, // 274148111
TxnCount: 4,
},
Transactions: []*btcwire.MsgTx{
&btcwire.MsgTx{
Version: 1,
TxIn: []*btcwire.TxIn{
&btcwire.TxIn{
PreviousOutpoint: btcwire.OutPoint{
Hash: btcwire.ShaHash{},
Index: 0xffffffff,
},
SignatureScript: []byte{
0x04, 0x4c, 0x86, 0x04, 0x1b, 0x02, 0x06, 0x02,
},
Sequence: 0xffffffff,
},
},
TxOut: []*btcwire.TxOut{
&btcwire.TxOut{
Value: 0x12a05f200, // 5000000000
PkScript: []byte{
0x41, // OP_DATA_65
0x04, 0x1b, 0x0e, 0x8c, 0x25, 0x67, 0xc1, 0x25,
0x36, 0xaa, 0x13, 0x35, 0x7b, 0x79, 0xa0, 0x73,
0xdc, 0x44, 0x44, 0xac, 0xb8, 0x3c, 0x4e, 0xc7,
0xa0, 0xe2, 0xf9, 0x9d, 0xd7, 0x45, 0x75, 0x16,
0xc5, 0x81, 0x72, 0x42, 0xda, 0x79, 0x69, 0x24,
0xca, 0x4e, 0x99, 0x94, 0x7d, 0x08, 0x7f, 0xed,
0xf9, 0xce, 0x46, 0x7c, 0xb9, 0xf7, 0xc6, 0x28,
0x70, 0x78, 0xf8, 0x01, 0xdf, 0x27, 0x6f, 0xdf,
0x84, // 65-byte signature
0xac, // OP_CHECKSIG
},
},
},
LockTime: 0,
},
&btcwire.MsgTx{
Version: 1,
TxIn: []*btcwire.TxIn{
&btcwire.TxIn{
PreviousOutpoint: btcwire.OutPoint{
Hash: btcwire.ShaHash([32]byte{ // Make go vet happy.
0x03, 0x2e, 0x38, 0xe9, 0xc0, 0xa8, 0x4c, 0x60,
0x46, 0xd6, 0x87, 0xd1, 0x05, 0x56, 0xdc, 0xac,
0xc4, 0x1d, 0x27, 0x5e, 0xc5, 0x5f, 0xc0, 0x07,
0x79, 0xac, 0x88, 0xfd, 0xf3, 0x57, 0xa1, 0x87,
}), // 87a157f3fd88ac7907c05fc55e271dc4acdc5605d187d646604ca8c0e9382e03
Index: 0,
},
SignatureScript: []byte{
0x49, // OP_DATA_73
0x30, 0x46, 0x02, 0x21, 0x00, 0xc3, 0x52, 0xd3,
0xdd, 0x99, 0x3a, 0x98, 0x1b, 0xeb, 0xa4, 0xa6,
0x3a, 0xd1, 0x5c, 0x20, 0x92, 0x75, 0xca, 0x94,
0x70, 0xab, 0xfc, 0xd5, 0x7d, 0xa9, 0x3b, 0x58,
0xe4, 0xeb, 0x5d, 0xce, 0x82, 0x02, 0x21, 0x00,
0x84, 0x07, 0x92, 0xbc, 0x1f, 0x45, 0x60, 0x62,
0x81, 0x9f, 0x15, 0xd3, 0x3e, 0xe7, 0x05, 0x5c,
0xf7, 0xb5, 0xee, 0x1a, 0xf1, 0xeb, 0xcc, 0x60,
0x28, 0xd9, 0xcd, 0xb1, 0xc3, 0xaf, 0x77, 0x48,
0x01, // 73-byte signature
0x41, // OP_DATA_65
0x04, 0xf4, 0x6d, 0xb5, 0xe9, 0xd6, 0x1a, 0x9d,
0xc2, 0x7b, 0x8d, 0x64, 0xad, 0x23, 0xe7, 0x38,
0x3a, 0x4e, 0x6c, 0xa1, 0x64, 0x59, 0x3c, 0x25,
0x27, 0xc0, 0x38, 0xc0, 0x85, 0x7e, 0xb6, 0x7e,
0xe8, 0xe8, 0x25, 0xdc, 0xa6, 0x50, 0x46, 0xb8,
0x2c, 0x93, 0x31, 0x58, 0x6c, 0x82, 0xe0, 0xfd,
0x1f, 0x63, 0x3f, 0x25, 0xf8, 0x7c, 0x16, 0x1b,
0xc6, 0xf8, 0xa6, 0x30, 0x12, 0x1d, 0xf2, 0xb3,
0xd3, // 65-byte pubkey
},
Sequence: 0xffffffff,
},
},
TxOut: []*btcwire.TxOut{
&btcwire.TxOut{
Value: 0x2123e300, // 556000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0xc3, 0x98, 0xef, 0xa9, 0xc3, 0x92, 0xba, 0x60,
0x13, 0xc5, 0xe0, 0x4e, 0xe7, 0x29, 0x75, 0x5e,
0xf7, 0xf5, 0x8b, 0x32,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
&btcwire.TxOut{
Value: 0x108e20f00, // 4444000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0x94, 0x8c, 0x76, 0x5a, 0x69, 0x14, 0xd4, 0x3f,
0x2a, 0x7a, 0xc1, 0x77, 0xda, 0x2c, 0x2f, 0x6b,
0x52, 0xde, 0x3d, 0x7c,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
},
LockTime: 0,
},
&btcwire.MsgTx{
Version: 1,
TxIn: []*btcwire.TxIn{
&btcwire.TxIn{
PreviousOutpoint: btcwire.OutPoint{
Hash: btcwire.ShaHash([32]byte{ // Make go vet happy.
0xc3, 0x3e, 0xbf, 0xf2, 0xa7, 0x09, 0xf1, 0x3d,
0x9f, 0x9a, 0x75, 0x69, 0xab, 0x16, 0xa3, 0x27,
0x86, 0xaf, 0x7d, 0x7e, 0x2d, 0xe0, 0x92, 0x65,
0xe4, 0x1c, 0x61, 0xd0, 0x78, 0x29, 0x4e, 0xcf,
}), // cf4e2978d0611ce46592e02d7e7daf8627a316ab69759a9f3df109a7f2bf3ec3
Index: 1,
},
SignatureScript: []byte{
0x47, // OP_DATA_71
0x30, 0x44, 0x02, 0x20, 0x03, 0x2d, 0x30, 0xdf,
0x5e, 0xe6, 0xf5, 0x7f, 0xa4, 0x6c, 0xdd, 0xb5,
0xeb, 0x8d, 0x0d, 0x9f, 0xe8, 0xde, 0x6b, 0x34,
0x2d, 0x27, 0x94, 0x2a, 0xe9, 0x0a, 0x32, 0x31,
0xe0, 0xba, 0x33, 0x3e, 0x02, 0x20, 0x3d, 0xee,
0xe8, 0x06, 0x0f, 0xdc, 0x70, 0x23, 0x0a, 0x7f,
0x5b, 0x4a, 0xd7, 0xd7, 0xbc, 0x3e, 0x62, 0x8c,
0xbe, 0x21, 0x9a, 0x88, 0x6b, 0x84, 0x26, 0x9e,
0xae, 0xb8, 0x1e, 0x26, 0xb4, 0xfe, 0x01,
0x41, // OP_DATA_65
0x04, 0xae, 0x31, 0xc3, 0x1b, 0xf9, 0x12, 0x78,
0xd9, 0x9b, 0x83, 0x77, 0xa3, 0x5b, 0xbc, 0xe5,
0xb2, 0x7d, 0x9f, 0xff, 0x15, 0x45, 0x68, 0x39,
0xe9, 0x19, 0x45, 0x3f, 0xc7, 0xb3, 0xf7, 0x21,
0xf0, 0xba, 0x40, 0x3f, 0xf9, 0x6c, 0x9d, 0xee,
0xb6, 0x80, 0xe5, 0xfd, 0x34, 0x1c, 0x0f, 0xc3,
0xa7, 0xb9, 0x0d, 0xa4, 0x63, 0x1e, 0xe3, 0x95,
0x60, 0x63, 0x9d, 0xb4, 0x62, 0xe9, 0xcb, 0x85,
0x0f, // 65-byte pubkey
},
Sequence: 0xffffffff,
},
},
TxOut: []*btcwire.TxOut{
&btcwire.TxOut{
Value: 0xf4240, // 1000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0xb0, 0xdc, 0xbf, 0x97, 0xea, 0xbf, 0x44, 0x04,
0xe3, 0x1d, 0x95, 0x24, 0x77, 0xce, 0x82, 0x2d,
0xad, 0xbe, 0x7e, 0x10,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
&btcwire.TxOut{
Value: 0x11d260c0, // 299000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0x6b, 0x12, 0x81, 0xee, 0xc2, 0x5a, 0xb4, 0xe1,
0xe0, 0x79, 0x3f, 0xf4, 0xe0, 0x8a, 0xb1, 0xab,
0xb3, 0x40, 0x9c, 0xd9,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
},
LockTime: 0,
},
&btcwire.MsgTx{
Version: 1,
TxIn: []*btcwire.TxIn{
&btcwire.TxIn{
PreviousOutpoint: btcwire.OutPoint{
Hash: btcwire.ShaHash([32]byte{ // Make go vet happy.
0x0b, 0x60, 0x72, 0xb3, 0x86, 0xd4, 0xa7, 0x73,
0x23, 0x52, 0x37, 0xf6, 0x4c, 0x11, 0x26, 0xac,
0x3b, 0x24, 0x0c, 0x84, 0xb9, 0x17, 0xa3, 0x90,
0x9b, 0xa1, 0xc4, 0x3d, 0xed, 0x5f, 0x51, 0xf4,
}), // f4515fed3dc4a19b90a317b9840c243bac26114cf637522373a7d486b372600b
Index: 0,
},
SignatureScript: []byte{
0x49, // OP_DATA_73
0x30, 0x46, 0x02, 0x21, 0x00, 0xbb, 0x1a, 0xd2,
0x6d, 0xf9, 0x30, 0xa5, 0x1c, 0xce, 0x11, 0x0c,
0xf4, 0x4f, 0x7a, 0x48, 0xc3, 0xc5, 0x61, 0xfd,
0x97, 0x75, 0x00, 0xb1, 0xae, 0x5d, 0x6b, 0x6f,
0xd1, 0x3d, 0x0b, 0x3f, 0x4a, 0x02, 0x21, 0x00,
0xc5, 0xb4, 0x29, 0x51, 0xac, 0xed, 0xff, 0x14,
0xab, 0xba, 0x27, 0x36, 0xfd, 0x57, 0x4b, 0xdb,
0x46, 0x5f, 0x3e, 0x6f, 0x8d, 0xa1, 0x2e, 0x2c,
0x53, 0x03, 0x95, 0x4a, 0xca, 0x7f, 0x78, 0xf3,
0x01, // 73-byte signature
0x41, // OP_DATA_65
0x04, 0xa7, 0x13, 0x5b, 0xfe, 0x82, 0x4c, 0x97,
0xec, 0xc0, 0x1e, 0xc7, 0xd7, 0xe3, 0x36, 0x18,
0x5c, 0x81, 0xe2, 0xaa, 0x2c, 0x41, 0xab, 0x17,
0x54, 0x07, 0xc0, 0x94, 0x84, 0xce, 0x96, 0x94,
0xb4, 0x49, 0x53, 0xfc, 0xb7, 0x51, 0x20, 0x65,
0x64, 0xa9, 0xc2, 0x4d, 0xd0, 0x94, 0xd4, 0x2f,
0xdb, 0xfd, 0xd5, 0xaa, 0xd3, 0xe0, 0x63, 0xce,
0x6a, 0xf4, 0xcf, 0xaa, 0xea, 0x4e, 0xa1, 0x4f,
0xbb, // 65-byte pubkey
},
Sequence: 0xffffffff,
},
},
TxOut: []*btcwire.TxOut{
&btcwire.TxOut{
Value: 0xf4240, // 1000000
PkScript: []byte{
0x76, // OP_DUP
0xa9, // OP_HASH160
0x14, // OP_DATA_20
0x39, 0xaa, 0x3d, 0x56, 0x9e, 0x06, 0xa1, 0xd7,
0x92, 0x6d, 0xc4, 0xbe, 0x11, 0x93, 0xc9, 0x9b,
0xf2, 0xeb, 0x9e, 0xe0,
0x88, // OP_EQUALVERIFY
0xac, // OP_CHECKSIG
},
},
},
LockTime: 0,
},
},
}

17
cov_report.sh Normal file
View file

@ -0,0 +1,17 @@
#!/bin/sh
# This script uses gocov to generate a test coverage report.
# The gocov tool my be obtained with the following command:
# go get github.com/axw/gocov/gocov
#
# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH.
# Check for gocov.
type gocov >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo >&2 "This script requires the gocov tool."
echo >&2 "You may obtain it with the following command:"
echo >&2 "go get github.com/axw/gocov/gocov"
exit 1
fi
gocov test | gocov report

15
doc.go Normal file
View file

@ -0,0 +1,15 @@
// Copyright (c) 2013 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
/*
Package btcutil provides bitcoin-specific convenience functions and types.
Block Overview
A Block defines a bitcoin block that provides easier and more efficient
manipulation of raw wire protocol blocks. It also memoizes hashes for the
block and its transactions on their first access so subsequent accesses don't
have to repeat the relatively expensive hashing operations.
*/
package btcutil

16
test_coverage.txt Normal file
View file

@ -0,0 +1,16 @@
github.com/conformal/btcutil/block.go Block.TxShas 100.00% (10/10)
github.com/conformal/btcutil/block.go Block.Sha 100.00% (5/5)
github.com/conformal/btcutil/block.go NewBlockFromBlockAndBytes 100.00% (1/1)
github.com/conformal/btcutil/block.go Block.MsgBlock 100.00% (1/1)
github.com/conformal/btcutil/block.go Block.ProtocolVersion 100.00% (1/1)
github.com/conformal/btcutil/block.go Block.Height 100.00% (1/1)
github.com/conformal/btcutil/block.go Block.SetHeight 100.00% (1/1)
github.com/conformal/btcutil/block.go NewBlock 100.00% (1/1)
github.com/conformal/btcutil/block.go Block.Bytes 88.89% (8/9)
github.com/conformal/btcutil/block.go NewBlockFromBytes 85.71% (6/7)
github.com/conformal/btcutil/block.go Block.TxSha 81.82% (9/11)
github.com/conformal/btcutil/block.go Block.TxLoc 0.00% (0/9)
github.com/conformal/btcutil/block.go OutOfRangeError.Error 0.00% (0/1)
github.com/conformal/btcutil ------------------------- 75.86% (44/58)