1
0
mirror of https://github.com/bitcoin/bips.git synced 2025-05-12 12:03:29 +00:00

Merge pull request #687 from Roasbeef/bip158-updates

BIP-0158: remove extended filter, remove txid from regular filter, reparameterize gcs params
This commit is contained in:
Luke Dashjr 2018-07-05 05:03:50 +00:00 committed by GitHub
commit 91bd69d29b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 225 additions and 277 deletions

View File

@ -65,11 +65,14 @@ For each block, compact filters are derived containing sets of items associated
with the block (eg. addresses sent to, outpoints spent, etc.). A set of such with the block (eg. addresses sent to, outpoints spent, etc.). A set of such
data objects is compressed into a probabilistic structure called a data objects is compressed into a probabilistic structure called a
''Golomb-coded set'' (GCS), which matches all items in the set with probability ''Golomb-coded set'' (GCS), which matches all items in the set with probability
1, and matches other items with probability <code>2^(-P)</code> for some integer 1, and matches other items with probability <code>2^(-P)</code> for some
parameter <code>P</code>. integer parameter <code>P</code>. We also introduce parameter <code>M</code>
which allows filter to uniquely tune the range that items are hashed onto
before compressing. Each defined filter also selects distinct parameters for P
and M.
At a high level, a GCS is constructed from a set of <code>N</code> items by: At a high level, a GCS is constructed from a set of <code>N</code> items by:
# hashing all items to 64-bit integers in the range <code>[0, N * 2^P)</code> # hashing all items to 64-bit integers in the range <code>[0, N * M)</code>
# sorting the hashed values in ascending order # sorting the hashed values in ascending order
# computing the differences between each value and the previous one # computing the differences between each value and the previous one
# writing the differences sequentially, compressed with Golomb-Rice coding # writing the differences sequentially, compressed with Golomb-Rice coding
@ -80,9 +83,13 @@ The following sections describe each step in greater detail.
The first step in the filter construction is hashing the variable-sized raw The first step in the filter construction is hashing the variable-sized raw
items in the set to the range <code>[0, F)</code>, where <code>F = N * items in the set to the range <code>[0, F)</code>, where <code>F = N *
2^P</code>. Set membership queries against the hash outputs will have a false M</code>. Customarily, <code>M</code> is set to <code>2^P</code>. However, if
positive rate of <code>2^(-P)</code>. To avoid integer overflow, the number of one is able to select both Parameters independently, then more optimal values
items <code>N</code> MUST be <2^32 and <code>P</code> MUST be <=32. can be
selected<ref>https://gist.github.com/sipa/576d5f09c3b86c3b1b75598d799fc845</ref>.
Set membership queries against the hash outputs will have a false positive rate
of <code>2^(-P)</code>. To avoid integer overflow, the
number of items <code>N</code> MUST be <2^32 and <code>M</code> MUST be <2^32.
The items are first passed through the pseudorandom function ''SipHash'', which The items are first passed through the pseudorandom function ''SipHash'', which
takes a 128-bit key <code>k</code> and a variable-sized byte vector and produces takes a 128-bit key <code>k</code> and a variable-sized byte vector and produces
@ -104,9 +111,9 @@ result.
hash_to_range(item: []byte, F: uint64, k: [16]byte) -> uint64: hash_to_range(item: []byte, F: uint64, k: [16]byte) -> uint64:
return (siphash(k, item) * F) >> 64 return (siphash(k, item) * F) >> 64
hashed_set_construct(raw_items: [][]byte, P: uint, k: [16]byte) -> []uint64: hashed_set_construct(raw_items: [][]byte, k: [16]byte, M: uint) -> []uint64:
let N = len(raw_items) let N = len(raw_items)
let F = N << P let F = N * M
let set_items = [] let set_items = []
@ -197,8 +204,8 @@ with Golomb-Rice coding. Finally, the bit stream is padded with 0's to the
nearest byte boundary and serialized to the output byte vector. nearest byte boundary and serialized to the output byte vector.
<pre> <pre>
construct_gcs(L: [][]byte, P: uint, k: [16]byte) -> []byte: construct_gcs(L: [][]byte, P: uint, k: [16]byte, M: uint) -> []byte:
let set_items = hashed_set_construct(L, P, k) let set_items = hashed_set_construct(L, k, M)
set_items.sort() set_items.sort()
@ -224,8 +231,8 @@ against the reconstructed values. Note that querying does not require the entire
decompressed set be held in memory at once. decompressed set be held in memory at once.
<pre> <pre>
gcs_match(key: [16]byte, compressed_set: []byte, target: []byte, P: uint, N: uint) -> bool: gcs_match(key: [16]byte, compressed_set: []byte, target: []byte, P: uint, N: uint, M: uint) -> bool:
let F = N << P let F = N * M
let target_hash = hash_to_range(target, F, k) let target_hash = hash_to_range(target, F, k)
stream = new_bit_stream(compressed_set) stream = new_bit_stream(compressed_set)
@ -258,49 +265,54 @@ against the decompressed GCS contents. See
=== Block Filters === === Block Filters ===
This BIP defines two initial filter types: This BIP defines one initial filter type:
* Basic (<code>0x00</code>) * Basic (<code>0x00</code>)
* Extended (<code>0x01</code>) * <code>M = 784931</code>
* <code>P = 19</code>
==== Contents ==== ==== Contents ====
The basic filter is designed to contain everything that a light client needs to The basic filter is designed to contain everything that a light client needs to
sync a regular Bitcoin wallet. A basic filter MUST contain exactly the following sync a regular Bitcoin wallet. A basic filter MUST contain exactly the
items for each transaction in a block: following items for each transaction in a block:
* The outpoint of each input, except for the coinbase transaction * The previous output script (the script being spent) for each input, except
* The scriptPubKey of each output for the coinbase transaction.
* The <code>txid</code> of the transaction itself * The scriptPubKey of each output, aside from all <code>OP_RETURN</code> output
scripts.
The extended filter contains extra data that is meant to enable applications Any "nil" items MUST NOT be included into the final set of filter elements.
with more advanced smart contracts. An extended filter MUST contain exactly the
following items for each transaction in a block ''except the coinbase'':
* Each item within the witness stack of each input (if the input has a witness)
* Each data push in the scriptSig of each input
Note that neither filter type interprets P2SH scripts or witness scripts to We exclude all <code>OP_RETURN</code> outputs in order to allow filters to
extract data pushes from them. If necessary, future filter types may be designed easily be committed to in the future via a soft-fork. A likely area for future
to do so. commitments is an additional <code>OP_RETURN</code> output in the coinbase
transaction similar to the current witness commitment
<ref>https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki</rev>. By
excluding all <code>OP_RETURN</code> outputs we avoid a circular dependency
between the commitment, and the item being committed to.
==== Construction ==== ==== Construction ====
Both the basic and extended filter types are constructed as Golomb-coded sets The basic type is constructed as Golomb-coded sets with the following
with the following parameters. parameters.
The parameter <code>P</code> MUST be set to <code>20</code>. This value was The parameter <code>P</code> MUST be set to <code>19</code>, and the parameter
chosen as simulations show that it minimizes the bandwidth utilized, considering <code>M</code> MUST be set to <code>784931</code>. Analysis has shown that if
both the expected number of blocks downloaded due to false positives and the one is able to select <code>P</code> and <code>M</code> independently, then
size of the filters themselves. The code along with a demo used for the setting <code>M=1.497137 * 2^P</code> is close to optimal
parameter tuning can be found <ref>https://gist.github.com/sipa/576d5f09c3b86c3b1b75598d799fc845</ref>.
[https://github.com/Roasbeef/bips/blob/83b83c78e189be898573e0bfe936dd0c9b99ecb9/gcs_light_client/gentestvectors.go here].
Empirical analysis also shows that was chosen as these parameters minimize the
bandwidth utilized, considering both the expected number of blocks downloaded
due to false positives and the size of the filters themselves.
The parameter <code>k</code> MUST be set to the first 16 bytes of the hash of The parameter <code>k</code> MUST be set to the first 16 bytes of the hash of
the block for which the filter is constructed. This ensures the key is the block for which the filter is constructed. This ensures the key is
deterministic while still varying from block to block. deterministic while still varying from block to block.
Since the value <code>N</code> is required to decode a GCS, a serialized GCS Since the value <code>N</code> is required to decode a GCS, a serialized GCS
includes it as a prefix, written as a CompactSize. Thus, the complete includes it as a prefix, written as a <code>CompactSize</code>. Thus, the
serialization of a filter is: complete serialization of a filter is:
* <code>N</code>, encoded as a CompactSize * <code>N</code>, encoded as a <code>CompactSize</code>
* The bytes of the compressed filter itself * The bytes of the compressed filter itself
==== Signaling ==== ==== Signaling ====
@ -323,7 +335,8 @@ though it requires implementation of the new filters.
We would like to thank bfd (from the bitcoin-dev mailing list) for bringing the We would like to thank bfd (from the bitcoin-dev mailing list) for bringing the
basis of this BIP to our attention, Greg Maxwell for pointing us in the basis of this BIP to our attention, Greg Maxwell for pointing us in the
direction of Golomb-Rice coding and fast range optimization, and Pedro direction of Golomb-Rice coding and fast range optimization, Pieter Wullie for
his analysis of optimal GCS parameters, and Pedro
Martelletto for writing the initial indexing code for <code>btcd</code>. Martelletto for writing the initial indexing code for <code>btcd</code>.
We would also like to thank Dave Collins, JJ Jeffrey, and Eric Lombrozo for We would also like to thank Dave Collins, JJ Jeffrey, and Eric Lombrozo for
@ -375,8 +388,8 @@ easier to understand.
=== Golomb-Coded Set Multi-Match === === Golomb-Coded Set Multi-Match ===
<pre> <pre>
gcs_match_any(key: [16]byte, compressed_set: []byte, targets: [][]byte, P: uint, N: uint) -> bool: gcs_match_any(key: [16]byte, compressed_set: []byte, targets: [][]byte, P: uint, N: uint, M: uint) -> bool:
let F = N << P let F = N * M
// Map targets to the same range as the set hashes. // Map targets to the same range as the set hashes.
let target_hashes = [] let target_hashes = []

View File

@ -15,13 +15,15 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"path" "path/filepath"
"github.com/roasbeef/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/blockchain"
"github.com/roasbeef/btcd/rpcclient" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/roasbeef/btcd/wire" "github.com/btcsuite/btcd/rpcclient"
"github.com/roasbeef/btcutil/gcs" "github.com/btcsuite/btcd/wire"
"github.com/roasbeef/btcutil/gcs/builder" "github.com/btcsuite/btcutil"
"github.com/btcsuite/btcutil/gcs/builder"
"github.com/davecgh/go-spew/spew"
) )
var ( var (
@ -29,13 +31,19 @@ var (
// vectors. Any new entries must be added in sorted order. // vectors. Any new entries must be added in sorted order.
testBlockHeights = []testBlockCase{ testBlockHeights = []testBlockCase{
{0, "Genesis block"}, {0, "Genesis block"},
{1, "Extended filter is empty"},
{2, ""}, {2, ""},
{3, ""}, {3, ""},
{926485, "Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"}, {926485, "Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"},
{987876, "Coinbase tx has unparseable output script"}, {987876, "Coinbase tx has unparseable output script"},
{1263442, "Includes witness data"}, {1263442, "Includes witness data"},
} }
defaultBtcdDir = btcutil.AppDataDir("btcd", false)
defaultBtcdRPCCertFile = filepath.Join(defaultBtcdDir, "rpc.cert")
)
const (
fp = 19
) )
type testBlockCase struct { type testBlockCase struct {
@ -86,41 +94,78 @@ func (w *JSONTestWriter) Close() error {
return err return err
} }
func fetchPrevOutputScripts(client *rpcclient.Client, block *wire.MsgBlock) ([][]byte, error) {
var prevScripts [][]byte
txCache := make(map[chainhash.Hash]*wire.MsgTx)
for _, tx := range block.Transactions {
if blockchain.IsCoinBaseTx(tx) {
continue
}
for _, txIn := range tx.TxIn {
prevOp := txIn.PreviousOutPoint
tx, ok := txCache[prevOp.Hash]
if !ok {
originTx, err := client.GetRawTransaction(
&prevOp.Hash,
)
if err != nil {
return nil, fmt.Errorf("unable to get "+
"txid=%v: %v", prevOp.Hash, err)
}
txCache[prevOp.Hash] = originTx.MsgTx()
tx = originTx.MsgTx()
}
index := prevOp.Index
prevScripts = append(
prevScripts, tx.TxOut[index].PkScript,
)
}
}
return prevScripts, nil
}
func main() { func main() {
err := os.Mkdir("gcstestvectors", os.ModeDir|0755) var (
if err != nil { // Don't overwrite existing output if any writerFile *JSONTestWriter
fmt.Println("Couldn't create directory: ", err) prevBasicHeader chainhash.Hash
)
fName := fmt.Sprintf("testnet-%02d.json", fp)
file, err := os.Create(fName)
if err != nil {
fmt.Println("Error creating output file: ", err.Error())
return return
} }
files := make([]*JSONTestWriter, 33) defer file.Close()
prevBasicHeaders := make([]chainhash.Hash, 33)
prevExtHeaders := make([]chainhash.Hash, 33)
for i := 1; i <= 32; i++ { // Min 1 bit of collision space, max 32
fName := fmt.Sprintf("gcstestvectors/testnet-%02d.json", i)
file, err := os.Create(fName)
if err != nil {
fmt.Println("Error creating output file: ", err.Error())
return
}
defer file.Close()
writer := &JSONTestWriter{writer: file} writer := &JSONTestWriter{
defer writer.Close() writer: file,
err = writer.WriteComment("Block Height,Block Hash,Block,Previous Basic Header,Previous Ext Header,Basic Filter,Ext Filter,Basic Header,Ext Header,Notes")
if err != nil {
fmt.Println("Error writing to output file: ", err.Error())
return
}
files[i] = writer
} }
cert, err := ioutil.ReadFile( defer writer.Close()
path.Join(os.Getenv("HOME"), "/.btcd/rpc.cert"))
err = writer.WriteComment("Block Height,Block Hash,Block," +
"[Prev Output Scripts for Block],Previous Basic Header," +
"Basic Filter,Basic Header,Notes")
if err != nil {
fmt.Println("Error writing to output file: ", err.Error())
return
}
writerFile = writer
cert, err := ioutil.ReadFile(defaultBtcdRPCCertFile)
if err != nil { if err != nil {
fmt.Println("Couldn't read RPC cert: ", err.Error()) fmt.Println("Couldn't read RPC cert: ", err.Error())
return return
} }
conf := rpcclient.ConnConfig{ conf := rpcclient.ConnConfig{
Host: "127.0.0.1:18334", Host: "127.0.0.1:18334",
Endpoint: "ws", Endpoint: "ws",
@ -134,19 +179,20 @@ func main() {
return return
} }
var testBlockIndex int = 0 var testBlockIndex int
for height := 0; testBlockIndex < len(testBlockHeights); height++ { for height := 0; testBlockIndex < len(testBlockHeights); height++ {
fmt.Printf("Height: %d\n", height)
blockHash, err := client.GetBlockHash(int64(height)) blockHash, err := client.GetBlockHash(int64(height))
if err != nil { if err != nil {
fmt.Println("Couldn't get block hash: ", err.Error()) fmt.Println("Couldn't get block hash: ", err.Error())
return return
} }
block, err := client.GetBlock(blockHash) block, err := client.GetBlock(blockHash)
if err != nil { if err != nil {
fmt.Println("Couldn't get block hash: ", err.Error()) fmt.Println("Couldn't get block hash: ", err.Error())
return return
} }
var blockBuf bytes.Buffer var blockBuf bytes.Buffer
err = block.Serialize(&blockBuf) err = block.Serialize(&blockBuf)
if err != nil { if err != nil {
@ -154,208 +200,98 @@ func main() {
return return
} }
blockBytes := blockBuf.Bytes() blockBytes := blockBuf.Bytes()
for i := 1; i <= 32; i++ {
basicFilter, err := buildBasicFilter(block, uint8(i)) prevOutputScripts, err := fetchPrevOutputScripts(client, block)
if err != nil {
fmt.Println("Couldn't fetch prev output scipts: ", err)
return
}
basicFilter, err := builder.BuildBasicFilter(block, prevOutputScripts)
if err != nil {
fmt.Println("Error generating basic filter: ", err.Error())
return
}
basicHeader, err := builder.MakeHeaderForFilter(basicFilter, prevBasicHeader)
if err != nil {
fmt.Println("Error generating header for filter: ", err.Error())
return
}
// We'll now ensure that we've constructed the same filter as
// the chain server we're fetching blocks form.
filter, err := client.GetCFilter(
blockHash, wire.GCSFilterRegular,
)
if err != nil {
fmt.Println("Error getting basic filter: ",
err.Error())
return
}
nBytes, err := basicFilter.NBytes()
if err != nil {
fmt.Println("Couldn't get NBytes(): ", err)
return
}
if !bytes.Equal(filter.Data, nBytes) {
// Don't error on empty filters
fmt.Printf("basic filter doesn't match: generated "+
"%x, rpc returns %x, block %v", nBytes,
filter.Data, spew.Sdump(block))
return
}
header, err := client.GetCFilterHeader(
blockHash, wire.GCSFilterRegular,
)
if err != nil {
fmt.Println("Error getting basic header: ", err.Error())
return
}
if !bytes.Equal(header.PrevFilterHeader[:], basicHeader[:]) {
fmt.Println("Basic header doesn't match!")
return
}
if height%1000 == 0 {
fmt.Printf("Verified height %v against server\n", height)
}
if uint32(height) == testBlockHeights[testBlockIndex].height {
var bfBytes []byte
bfBytes, err = basicFilter.NBytes()
if err != nil { if err != nil {
fmt.Println("Error generating basic filter: ", err.Error()) fmt.Println("Couldn't get NBytes(): ", err)
return return
} }
basicHeader, err := builder.MakeHeaderForFilter(basicFilter,
prevBasicHeaders[i])
if err != nil {
fmt.Println("Error generating header for filter: ", err.Error())
return
}
if basicFilter == nil {
basicFilter = &gcs.Filter{}
}
extFilter, err := buildExtFilter(block, uint8(i))
if err != nil {
fmt.Println("Error generating ext filter: ", err.Error())
return
}
extHeader, err := builder.MakeHeaderForFilter(extFilter,
prevExtHeaders[i])
if err != nil {
fmt.Println("Error generating header for filter: ", err.Error())
return
}
if extFilter == nil {
extFilter = &gcs.Filter{}
}
if i == builder.DefaultP { // This is the default filter size so we can check against the server's info
filter, err := client.GetCFilter(blockHash, wire.GCSFilterRegular)
if err != nil {
fmt.Println("Error getting basic filter: ", err.Error())
return
}
nBytes, err := basicFilter.NBytes()
if err != nil {
fmt.Println("Couldn't get NBytes(): ", err)
return
}
if !bytes.Equal(filter.Data, nBytes) {
// Don't error on empty filters
fmt.Println("Basic filter doesn't match!\n", filter.Data, "\n", nBytes)
return
}
filter, err = client.GetCFilter(blockHash, wire.GCSFilterExtended)
if err != nil {
fmt.Println("Error getting extended filter: ", err.Error())
return
}
nBytes, err = extFilter.NBytes()
if err != nil {
fmt.Println("Couldn't get NBytes(): ", err)
return
}
if !bytes.Equal(filter.Data, nBytes) {
fmt.Println("Extended filter doesn't match!")
return
}
header, err := client.GetCFilterHeader(blockHash, wire.GCSFilterRegular)
if err != nil {
fmt.Println("Error getting basic header: ", err.Error())
return
}
if !bytes.Equal(header.PrevFilterHeader[:], basicHeader[:]) {
fmt.Println("Basic header doesn't match!")
return
}
header, err = client.GetCFilterHeader(blockHash, wire.GCSFilterExtended)
if err != nil {
fmt.Println("Error getting extended header: ", err.Error())
return
}
if !bytes.Equal(header.PrevFilterHeader[:], extHeader[:]) {
fmt.Println("Extended header doesn't match!")
return
}
fmt.Println("Verified against server")
}
if uint32(height) == testBlockHeights[testBlockIndex].height { prevScriptStrings := make([]string, len(prevOutputScripts))
var bfBytes []byte for i, prevScript := range prevOutputScripts {
var efBytes []byte prevScriptStrings[i] = hex.EncodeToString(prevScript)
bfBytes, err = basicFilter.NBytes() }
if err != nil {
fmt.Println("Couldn't get NBytes(): ", err) row := []interface{}{
return height,
} blockHash.String(),
efBytes, err = extFilter.NBytes() hex.EncodeToString(blockBytes),
if err != nil { prevScriptStrings,
fmt.Println("Couldn't get NBytes(): ", err) prevBasicHeader.String(),
return hex.EncodeToString(bfBytes),
} basicHeader.String(),
row := []interface{}{ testBlockHeights[testBlockIndex].comment,
height, }
blockHash.String(), err = writerFile.WriteTestCase(row)
hex.EncodeToString(blockBytes), if err != nil {
prevBasicHeaders[i].String(), fmt.Println("Error writing test case to output: ", err.Error())
prevExtHeaders[i].String(), return
hex.EncodeToString(bfBytes),
hex.EncodeToString(efBytes),
basicHeader.String(),
extHeader.String(),
testBlockHeights[testBlockIndex].comment,
}
err = files[i].WriteTestCase(row)
if err != nil {
fmt.Println("Error writing test case to output: ", err.Error())
return
}
} }
prevBasicHeaders[i] = basicHeader
prevExtHeaders[i] = extHeader
} }
prevBasicHeader = basicHeader
if uint32(height) == testBlockHeights[testBlockIndex].height { if uint32(height) == testBlockHeights[testBlockIndex].height {
testBlockIndex++ testBlockIndex++
} }
} }
} }
// buildBasicFilter builds a basic GCS filter from a block. A basic GCS filter
// will contain all the previous outpoints spent within a block, as well as the
// data pushes within all the outputs created within a block. p is specified as
// an argument in order to create test vectors with various values for p.
func buildBasicFilter(block *wire.MsgBlock, p uint8) (*gcs.Filter, error) {
blockHash := block.BlockHash()
b := builder.WithKeyHashP(&blockHash, p)
// If the filter had an issue with the specified key, then we force it
// to bubble up here by calling the Key() function.
_, err := b.Key()
if err != nil {
return nil, err
}
// In order to build a basic filter, we'll range over the entire block,
// adding the outpoint data as well as the data pushes within the
// pkScript.
for i, tx := range block.Transactions {
// First we'll compute the bash of the transaction and add that
// directly to the filter.
txHash := tx.TxHash()
b.AddHash(&txHash)
// Skip the inputs for the coinbase transaction
if i != 0 {
// Each each txin, we'll add a serialized version of
// the txid:index to the filters data slices.
for _, txIn := range tx.TxIn {
b.AddOutPoint(txIn.PreviousOutPoint)
}
}
// For each output in a transaction, we'll add each of the
// individual data pushes within the script.
for _, txOut := range tx.TxOut {
b.AddEntry(txOut.PkScript)
}
}
return b.Build()
}
// buildExtFilter builds an extended GCS filter from a block. An extended
// filter supplements a regular basic filter by include all the _witness_ data
// found within a block. This includes all the data pushes within any signature
// scripts as well as each element of an input's witness stack. Additionally,
// the _hashes_ of each transaction are also inserted into the filter. p is
// specified as an argument in order to create test vectors with various values
// for p.
func buildExtFilter(block *wire.MsgBlock, p uint8) (*gcs.Filter, error) {
blockHash := block.BlockHash()
b := builder.WithKeyHashP(&blockHash, p)
// If the filter had an issue with the specified key, then we force it
// to bubble up here by calling the Key() function.
_, err := b.Key()
if err != nil {
return nil, err
}
// In order to build an extended filter, we add the hash of each
// transaction as well as each piece of witness data included in both
// the sigScript and the witness stack of an input.
for i, tx := range block.Transactions {
// Skip the inputs for the coinbase transaction
if i != 0 {
// Next, for each input, we'll add the sigScript (if
// it's present), and also the witness stack (if it's
// present)
for _, txIn := range tx.TxIn {
if txIn.SignatureScript != nil {
b.AddScript(txIn.SignatureScript)
}
if len(txIn.Witness) != 0 {
b.AddWitness(txIn.Witness)
}
}
}
}
return b.Build()
}

View File

@ -1,10 +1,9 @@
[ [
["Block Height,Block Hash,Block,Previous Basic Header,Previous Ext Header,Basic Filter,Ext Filter,Basic Header,Ext Header,Notes"], ["Block Height,Block Hash,Block,[Prev Output Scripts for Block],Previous Basic Header,Basic Filter,Basic Header,Notes"],
[0,"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943","0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000","0000000000000000000000000000000000000000000000000000000000000000","0000000000000000000000000000000000000000000000000000000000000000","0285c7cdbe33a0","00","c0589c7f567cffaf7bc0c9f6ad61710b78d3c1afef5d65a2a08e8a753173aa54","753e0d1c28585269ab770b166ca2cd1b32f9bc918750547941ed4849d5a80ba8","Genesis block"], [0,"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943","0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000",[],"0000000000000000000000000000000000000000000000000000000000000000","019dfca8","21584579b7eb08997773e5aeff3a7f932700042d0ed2a6129012b7d7ae81b750","Genesis block"],
[1,"00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206","0100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b6720101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0420e7494d017f062f503253482fffffffff0100f2052a010000002321021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac00000000","c0589c7f567cffaf7bc0c9f6ad61710b78d3c1afef5d65a2a08e8a753173aa54","753e0d1c28585269ab770b166ca2cd1b32f9bc918750547941ed4849d5a80ba8","026929d09bee00","00","81e4f3e934488be62758f0b88037aa558262da3190ca018329997a319a0f8b5b","31b674ab635e074717329dabdb25d3cb0e14cb2526000cc2cedac7b5f2595110","Extended filter is empty"], [2,"000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820","0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d235340101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0432e7494d010e062f503253482fffffffff0100f2052a010000002321038a7f6ef1c8ca0c588aa53fa860128077c9e6c11e6830f4d7ee4e763a56b7718fac00000000",[],"d7bdac13a59d745b1add0d2ce852f1a0442e8945fc1bf3848d3cbffd88c24fe1","0174a170","186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0",""],
[2,"000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820","0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d235340101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0432e7494d010e062f503253482fffffffff0100f2052a010000002321038a7f6ef1c8ca0c588aa53fa860128077c9e6c11e6830f4d7ee4e763a56b7718fac00000000","81e4f3e934488be62758f0b88037aa558262da3190ca018329997a319a0f8b5b","31b674ab635e074717329dabdb25d3cb0e14cb2526000cc2cedac7b5f2595110","0278fc41168ec0","00","ec48f9f8a625bd8adb2d2684867a05baafebf935553e0b78b386da98179dcf49","0dd53b407c3f242f1838e39e2fc0cfb89cdca27de07ec230568a08d1872f9e01",""], [3,"000000008b896e272758da5297bcd98fdc6d97c9b765ecec401e286dc1fdbe10","0100000020782a005255b657696ea057d5b98f34defcf75196f64f6eeac8026c0000000041ba5afc532aae03151b8aa87b65e1594f97504a768e010c98c0add79216247186e7494dffff001d058dc2b60101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0486e7494d0151062f503253482fffffffff0100f2052a01000000232103f6d9ff4c12959445ca5549c811683bf9c88e637b222dd2e0311154c4c85cf423ac00000000",[],"186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0","016cf7a0","8d63aadf5ab7257cb6d2316a57b16f517bff1c6388f124ec4c04af1212729d2a",""],
[3,"000000008b896e272758da5297bcd98fdc6d97c9b765ecec401e286dc1fdbe10","0100000020782a005255b657696ea057d5b98f34defcf75196f64f6eeac8026c0000000041ba5afc532aae03151b8aa87b65e1594f97504a768e010c98c0add79216247186e7494dffff001d058dc2b60101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0486e7494d0151062f503253482fffffffff0100f2052a01000000232103f6d9ff4c12959445ca5549c811683bf9c88e637b222dd2e0311154c4c85cf423ac00000000","ec48f9f8a625bd8adb2d2684867a05baafebf935553e0b78b386da98179dcf49","0dd53b407c3f242f1838e39e2fc0cfb89cdca27de07ec230568a08d1872f9e01","022ce4b3256540","00","060b7e1be150cc3cabd9e96b00af217132b387f31fd2bd9adfb0c7f5a09a3356","5b2a59bc476d52b45de1398ee34ed10d0cccd2a4b19ba502a456c7356b35be0d",""], [926485,"000000000000015d6077a411a8f5cc95caf775ccf11c54e27df75ce58d187313","0000002060bbab0edbf3ef8a49608ee326f8fd75c473b7e3982095e2d100000000000000c30134f8c9b6d2470488d7a67a888f6fa12f8692e0c3411fbfb92f0f68f67eedae03ca57ef13021acc22dc4105010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2f0315230e0004ae03ca57043e3d1e1d0c8796bf579aef0c0000000000122f4e696e6a61506f6f6c2f5345475749542fffffffff038427a112000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9ed5c748e121c0fe146d973a4ac26fa4a68b0549d46ee22d25f50a5e46fe1b377ee00000000000000002952534b424c4f434b3acd16772ad61a3c5f00287480b720f6035d5e54c9efc71be94bb5e3727f10909001200000000000000000000000000000000000000000000000000000000000000000000000000100000000010145310e878941a1b2bc2d33797ee4d89d95eaaf2e13488063a2aa9a74490f510a0100000023220020b6744de4f6ec63cc92f7c220cdefeeb1b1bed2b66c8e5706d80ec247d37e65a1ffffffff01002d3101000000001976a9143ebc40e411ed3c76f86711507ab952300890397288ac0400473044022001dd489a5d4e2fbd8a3ade27177f6b49296ba7695c40dbbe650ea83f106415fd02200b23a0602d8ff1bdf79dee118205fc7e9b40672bf31563e5741feb53fb86388501483045022100f88f040e90cc5dc6c6189d04718376ac19ed996bf9e4a3c29c3718d90ffd27180220761711f16c9e3a44f71aab55cbc0634907a1fa8bb635d971a9a01d368727bea10169522103b3623117e988b76aaabe3d63f56a4fc88b228a71e64c4cc551d1204822fe85cb2103dd823066e096f72ed617a41d3ca56717db335b1ea47a1b4c5c9dbdd0963acba621033d7c89bd9da29fa8d44db7906a9778b53121f72191184a9fee785c39180e4be153ae00000000010000000120925534261de4dcebb1ed5ab1b62bfe7a3ef968fb111dc2c910adfebc6e3bdf010000006b483045022100f50198f5ae66211a4f485190abe4dc7accdabe3bc214ebc9ea7069b97097d46e0220316a70a03014887086e335fc1b48358d46cd6bdc9af3b57c109c94af76fc915101210316cff587a01a2736d5e12e53551b18d73780b83c3bfb4fcf209c869b11b6415effffffff0220a10700000000001976a91450333046115eaa0ac9e0216565f945070e44573988ac2e7cd01a000000001976a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac00000000010000000203a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322010000006a47304402204efc3d70e4ca3049c2a425025edf22d5ca355f9ec899dbfbbeeb2268533a0f2b02204780d3739653035af4814ea52e1396d021953f948c29754edd0ee537364603dc012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff03a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322000000006a47304402202d96defdc5b4af71d6ba28c9a6042c2d5ee7bc6de565d4db84ef517445626e03022022da80320e9e489c8f41b74833dfb6a54a4eb5087cdb46eb663eef0b25caa526012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a914b7e6f7ff8658b2d1fb107e3d7be7af4742e6b1b3876f88fc00000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac0000000001000000043ffd60d3818431c495b89be84afac205d5d1ed663009291c560758bbd0a66df5010000006b483045022100f344607de9df42049688dcae8ff1db34c0c7cd25ec05516e30d2bc8f12ac9b2f022060b648f6a21745ea6d9782e17bcc4277b5808326488a1f40d41e125879723d3a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffffa5379401cce30f84731ef1ba65ce27edf2cc7ce57704507ebe8714aa16a96b92010000006a473044022020c37a63bf4d7f564c2192528709b6a38ab8271bd96898c6c2e335e5208661580220435c6f1ad4d9305d2c0a818b2feb5e45d443f2f162c0f61953a14d097fd07064012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff70e731e193235ff12c3184510895731a099112ffca4b00246c60003c40f843ce000000006a473044022053760f74c29a879e30a17b5f03a5bb057a5751a39f86fa6ecdedc36a1b7db04c022041d41c9b95f00d2d10a0373322a9025dba66c942196bc9d8adeb0e12d3024728012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff66b7a71b3e50379c8e85fc18fe3f1a408fc985f257036c34702ba205cef09f6f000000006a4730440220499bf9e2db3db6e930228d0661395f65431acae466634d098612fd80b08459ee022040e069fc9e3c60009f521cef54c38aadbd1251aee37940e6018aadb10f194d6a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a9148fc37ad460fdfbd2b44fe446f6e3071a4f64faa6878f447f0b000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac00000000",["a914feb8a29635c56d9cd913122f90678756bf23887687","76a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac"],"da49977ba1ee0d620a2c4f8f646b03cd0d230f5c6c994722e3ba884889f0be1a","09027acea61b6cc3fb33f5d52f7d088a6b2f75d234e89ca800","4cd9dd007a325199102f1fc0b7d77ca25ee3c84d46018c4353ecfcb56c0d3e7a","Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"],
[926485,"000000000000015d6077a411a8f5cc95caf775ccf11c54e27df75ce58d187313","0000002060bbab0edbf3ef8a49608ee326f8fd75c473b7e3982095e2d100000000000000c30134f8c9b6d2470488d7a67a888f6fa12f8692e0c3411fbfb92f0f68f67eedae03ca57ef13021acc22dc4105010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2f0315230e0004ae03ca57043e3d1e1d0c8796bf579aef0c0000000000122f4e696e6a61506f6f6c2f5345475749542fffffffff038427a112000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9ed5c748e121c0fe146d973a4ac26fa4a68b0549d46ee22d25f50a5e46fe1b377ee00000000000000002952534b424c4f434b3acd16772ad61a3c5f00287480b720f6035d5e54c9efc71be94bb5e3727f10909001200000000000000000000000000000000000000000000000000000000000000000000000000100000000010145310e878941a1b2bc2d33797ee4d89d95eaaf2e13488063a2aa9a74490f510a0100000023220020b6744de4f6ec63cc92f7c220cdefeeb1b1bed2b66c8e5706d80ec247d37e65a1ffffffff01002d3101000000001976a9143ebc40e411ed3c76f86711507ab952300890397288ac0400473044022001dd489a5d4e2fbd8a3ade27177f6b49296ba7695c40dbbe650ea83f106415fd02200b23a0602d8ff1bdf79dee118205fc7e9b40672bf31563e5741feb53fb86388501483045022100f88f040e90cc5dc6c6189d04718376ac19ed996bf9e4a3c29c3718d90ffd27180220761711f16c9e3a44f71aab55cbc0634907a1fa8bb635d971a9a01d368727bea10169522103b3623117e988b76aaabe3d63f56a4fc88b228a71e64c4cc551d1204822fe85cb2103dd823066e096f72ed617a41d3ca56717db335b1ea47a1b4c5c9dbdd0963acba621033d7c89bd9da29fa8d44db7906a9778b53121f72191184a9fee785c39180e4be153ae00000000010000000120925534261de4dcebb1ed5ab1b62bfe7a3ef968fb111dc2c910adfebc6e3bdf010000006b483045022100f50198f5ae66211a4f485190abe4dc7accdabe3bc214ebc9ea7069b97097d46e0220316a70a03014887086e335fc1b48358d46cd6bdc9af3b57c109c94af76fc915101210316cff587a01a2736d5e12e53551b18d73780b83c3bfb4fcf209c869b11b6415effffffff0220a10700000000001976a91450333046115eaa0ac9e0216565f945070e44573988ac2e7cd01a000000001976a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac00000000010000000203a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322010000006a47304402204efc3d70e4ca3049c2a425025edf22d5ca355f9ec899dbfbbeeb2268533a0f2b02204780d3739653035af4814ea52e1396d021953f948c29754edd0ee537364603dc012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff03a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322000000006a47304402202d96defdc5b4af71d6ba28c9a6042c2d5ee7bc6de565d4db84ef517445626e03022022da80320e9e489c8f41b74833dfb6a54a4eb5087cdb46eb663eef0b25caa526012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a914b7e6f7ff8658b2d1fb107e3d7be7af4742e6b1b3876f88fc00000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac0000000001000000043ffd60d3818431c495b89be84afac205d5d1ed663009291c560758bbd0a66df5010000006b483045022100f344607de9df42049688dcae8ff1db34c0c7cd25ec05516e30d2bc8f12ac9b2f022060b648f6a21745ea6d9782e17bcc4277b5808326488a1f40d41e125879723d3a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffffa5379401cce30f84731ef1ba65ce27edf2cc7ce57704507ebe8714aa16a96b92010000006a473044022020c37a63bf4d7f564c2192528709b6a38ab8271bd96898c6c2e335e5208661580220435c6f1ad4d9305d2c0a818b2feb5e45d443f2f162c0f61953a14d097fd07064012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff70e731e193235ff12c3184510895731a099112ffca4b00246c60003c40f843ce000000006a473044022053760f74c29a879e30a17b5f03a5bb057a5751a39f86fa6ecdedc36a1b7db04c022041d41c9b95f00d2d10a0373322a9025dba66c942196bc9d8adeb0e12d3024728012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff66b7a71b3e50379c8e85fc18fe3f1a408fc985f257036c34702ba205cef09f6f000000006a4730440220499bf9e2db3db6e930228d0661395f65431acae466634d098612fd80b08459ee022040e069fc9e3c60009f521cef54c38aadbd1251aee37940e6018aadb10f194d6a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a9148fc37ad460fdfbd2b44fe446f6e3071a4f64faa6878f447f0b000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac00000000","5c169b91332e661a4ebf684d6dffcf64aa139e1e736096ce462609b2e0783c55","5f3cd111e10ed28b7c2bc138fe4bc62e5df1cdc292c010b78c84e5111a5daaa6","16040c63f7ddea293f2d9c13690c0ba7b2910228c38b0fe542ce525021e49b598ada05f83bb9c37c711a02b1850265991c34c4fea6261d22a4b84596c0","0e6651beff00ee7a3be424a90e98450727b304558434c8d53781d469131ad21d399376c151ca28","c8f83ffbc9781c2bd4b7e3c055e888b00d3e2fea14e93b3c4f3adee86b063374","61f8ee615258981089be9f98337f53f44b14cc1532aa469a348fdee547117b80","Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"], [987876,"0000000000000c00901f2049055e2a437c819d79a3d54fd63e6af796cd7b8a79","000000202694f74969fdb542090e95a56bc8aa2d646e27033850e32f1c5f000000000000f7e53676b3f12d5beb524ed617f2d25f5a93b5f4f52c1ba2678260d72712f8dd0a6dfe5740257e1a4b1768960101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1603e4120ff9c30a1c216900002f424d4920546573742fffffff0001205fa012000000001e76a914c486de584a735ec2f22da7cd9681614681f92173d83d0aa68688ac00000000",[],"e9d729b72d533c29abe5276d5cf6c152f3723f10efe000b1e0c9ca5265a8beb6","010c0b40","e6137ae5a8424c40da1e5023c16975cc97b09300b4c050e6b1c713add3836c40","Coinbase tx has unparseable output script"],
[987876,"0000000000000c00901f2049055e2a437c819d79a3d54fd63e6af796cd7b8a79","000000202694f74969fdb542090e95a56bc8aa2d646e27033850e32f1c5f000000000000f7e53676b3f12d5beb524ed617f2d25f5a93b5f4f52c1ba2678260d72712f8dd0a6dfe5740257e1a4b1768960101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1603e4120ff9c30a1c216900002f424d4920546573742fffffff0001205fa012000000001e76a914c486de584a735ec2f22da7cd9681614681f92173d83d0aa68688ac00000000","37bf9e681888b3cd204ca4e0c995aad68cd0ecb86bdf19dd0fa2e72dbabcda28","c4c5051dd741c11840ef3f11fb4f372a16bb5aac1dc66576e89e8e6835d667e0","021016dc7a6a20","00","156e9bf3ec5be367f0a829858e9ee182cc3a6531bedced491a52fcfed841c6cb","cab50aab93410cb150fd761f2067a909d35c8a9c0114578efd9590e2d381ee02","Coinbase tx has unparseable output script"], [1263442,"000000006f27ddfe1dd680044a34548f41bed47eba9e6f0b310da21423bc5f33","000000201c8d1a529c39a396db2db234d5ec152fa651a2872966daccbde028b400000000083f14492679151dbfaa1a825ef4c18518e780c1f91044180280a7d33f4a98ff5f45765aaddc001d38333b9a02010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff230352471300fe5f45765afe94690a000963676d696e6572343208000000000000000000ffffffff024423a804000000001976a914f2c25ac3d59f3d674b1d1d0a25c27339aaac0ba688ac0000000000000000266a24aa21a9edcb26cb3052426b9ebb4d19c819ef87c19677bbf3a7c46ef0855bd1b2abe83491012000000000000000000000000000000000000000000000000000000000000000000000000002000000000101d20978463906ba4ff5e7192494b88dd5eb0de85d900ab253af909106faa22cc5010000000004000000014777ff000000000016001446c29eabe8208a33aa1023c741fa79aa92e881ff0347304402207d7ca96134f2bcfdd6b536536fdd39ad17793632016936f777ebb32c22943fda02206014d2fb8a6aa58279797f861042ba604ebd2f8f61e5bddbd9d3be5a245047b201004b632103eeaeba7ce5dc2470221e9517fb498e8d6bd4e73b85b8be655196972eb9ccd5566754b2752103a40b74d43df244799d041f32ce1ad515a6cd99501701540e38750d883ae21d3a68ac00000000",["002027a5000c7917f785d8fc6e5a55adfca8717ecb973ebb7743849ff956d896a7ed"],"a4a4d6c6034da8aa06f01fe71f1fffbd79e032006b07f6c7a2c60a66aa310c01","0385acb4f0fe889ef0","3588f34fbbc11640f9ed40b2a66a4e096215d50389691309c1dac74d4268aa81","Includes witness data"]
[1263442,"000000006f27ddfe1dd680044a34548f41bed47eba9e6f0b310da21423bc5f33","000000201c8d1a529c39a396db2db234d5ec152fa651a2872966daccbde028b400000000083f14492679151dbfaa1a825ef4c18518e780c1f91044180280a7d33f4a98ff5f45765aaddc001d38333b9a02010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff230352471300fe5f45765afe94690a000963676d696e6572343208000000000000000000ffffffff024423a804000000001976a914f2c25ac3d59f3d674b1d1d0a25c27339aaac0ba688ac0000000000000000266a24aa21a9edcb26cb3052426b9ebb4d19c819ef87c19677bbf3a7c46ef0855bd1b2abe83491012000000000000000000000000000000000000000000000000000000000000000000000000002000000000101d20978463906ba4ff5e7192494b88dd5eb0de85d900ab253af909106faa22cc5010000000004000000014777ff000000000016001446c29eabe8208a33aa1023c741fa79aa92e881ff0347304402207d7ca96134f2bcfdd6b536536fdd39ad17793632016936f777ebb32c22943fda02206014d2fb8a6aa58279797f861042ba604ebd2f8f61e5bddbd9d3be5a245047b201004b632103eeaeba7ce5dc2470221e9517fb498e8d6bd4e73b85b8be655196972eb9ccd5566754b2752103a40b74d43df244799d041f32ce1ad515a6cd99501701540e38750d883ae21d3a68ac00000000","da6984906c48525f1d800b0e9b480b5fde1a3a32ad7e4cac6a0566d86b9b01a5","7820f3d2397d77068f0f0c824c4f403db89682e5ab6e82d027cb84d7beb8a08c","06970f05e70c2ec63508cdf07609cb8434","03049063c6b4e9a028","5a369775edcb1dcde9bbc88f0897bd3fd9ab0317d2906e8c10b62641c2104c54","73cee3d4b37b689f5da7251f175ff4630f2c142d7399b407d5cac65bc593b68d","Includes witness data"]
] ]