Пример #1
0
// loadUtxoView returns a utxo view loaded from a file.
func loadUtxoView(filename string) (*blockchain.UtxoViewpoint, error) {
	// The utxostore file format is:
	// <tx hash><serialized utxo len><serialized utxo>
	//
	// The serialized utxo len is a little endian uint32 and the serialized
	// utxo uses the format described in chainio.go.

	filename = filepath.Join("testdata", filename)
	fi, err := os.Open(filename)
	if err != nil {
		return nil, err
	}

	// Choose read based on whether the file is compressed or not.
	var r io.Reader
	if strings.HasSuffix(filename, ".bz2") {
		r = bzip2.NewReader(fi)
	} else {
		r = fi
	}
	defer fi.Close()

	view := blockchain.NewUtxoViewpoint()
	for {
		// Hash of the utxo entry.
		var hash chainhash.Hash
		_, err := io.ReadAtLeast(r, hash[:], len(hash[:]))
		if err != nil {
			// Expected EOF at the right offset.
			if err == io.EOF {
				break
			}
			return nil, err
		}

		// Num of serialize utxo entry bytes.
		var numBytes uint32
		err = binary.Read(r, binary.LittleEndian, &numBytes)
		if err != nil {
			return nil, err
		}

		// Serialized utxo entry.
		serialized := make([]byte, numBytes)
		_, err = io.ReadAtLeast(r, serialized, int(numBytes))
		if err != nil {
			return nil, err
		}

		// Deserialize it and add it to the view.
		utxoEntry, err := blockchain.TstDeserializeUtxoEntry(serialized)
		if err != nil {
			return nil, err
		}
		view.Entries()[hash] = utxoEntry
	}

	return view, nil
}
Пример #2
0
// makeUtxoView creates a mock unspent transaction output view by using the
// transaction index in order to look up all inputs referenced by the
// transactions in the block.  This is sometimes needed when catching indexes up
// because many of the txouts could actually already be spent however the
// associated scripts are still required to index them.
func makeUtxoView(dbTx database.Tx, block, parent *dcrutil.Block) (*blockchain.UtxoViewpoint, error) {
	view := blockchain.NewUtxoViewpoint()
	regularTxTreeValid := dcrutil.IsFlagSet16(block.MsgBlock().Header.VoteBits,
		dcrutil.BlockValid)
	if regularTxTreeValid {
		for txIdx, tx := range parent.Transactions() {
			// Coinbases do not reference any inputs.  Since the block is
			// required to have already gone through full validation, it has
			// already been proven on the first transaction in the block is
			// a coinbase.
			if txIdx == 0 {
				continue
			}

			// Use the transaction index to load all of the referenced
			// inputs and add their outputs to the view.
			for _, txIn := range tx.MsgTx().TxIn {
				// Skip already fetched outputs.
				originOut := &txIn.PreviousOutPoint
				if view.LookupEntry(&originOut.Hash) != nil {
					continue
				}

				originTx, err := dbFetchTx(dbTx, originOut.Hash)
				if err != nil {
					return nil, err
				}

				view.AddTxOuts(dcrutil.NewTx(originTx),
					int64(wire.NullBlockHeight), wire.NullBlockIndex)
			}
		}
	}

	for _, tx := range block.STransactions() {
		msgTx := tx.MsgTx()
		isSSGen, _ := stake.IsSSGen(msgTx)

		// Use the transaction index to load all of the referenced
		// inputs and add their outputs to the view.
		for i, txIn := range msgTx.TxIn {
			// Skip stakebases.
			if isSSGen && i == 0 {
				continue
			}

			originOut := &txIn.PreviousOutPoint
			if view.LookupEntry(&originOut.Hash) != nil {
				continue
			}

			originTx, err := dbFetchTx(dbTx, originOut.Hash)
			if err != nil {
				return nil, err
			}

			view.AddTxOuts(dcrutil.NewTx(originTx), int64(wire.NullBlockHeight),
				wire.NullBlockIndex)
		}
	}

	return view, nil
}