All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bitcoinj.core.UTXOsMessage Maven / Gradle / Ivy

There is a newer version: 0.15-cm06
Show newest version
/*
 * Copyright 2014 the bitcoinj authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.bitcoinj.core;

import com.google.common.base.Objects;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 

Message representing a list of unspent transaction outputs ("utxos"), returned in response to sending a * {@link GetUTXOsMessage} ("getutxos"). Note that both this message and the query that generates it are not * supported by Bitcoin Core. An implementation is available in Bitcoin XT, * a patch set on top of Core. Thus if you want to use it, you must find some XT peers to connect to. This can be done * using a {@link org.bitcoinj.net.discovery.HttpDiscovery} class combined with an HTTP/Cartographer seed.

* *

The getutxos/utxos protocol is defined in BIP 65. * In that document you can find a discussion of the security of this protocol (briefly, there is none). Because the * data found in this message is not authenticated it should be used carefully. Places where it can be useful are if * you're querying your own trusted node, if you're comparing answers from multiple nodes simultaneously and don't * believe there is a MITM on your connection, or if you're only using the returned data as a UI hint and it's OK * if the data is occasionally wrong. Bear in mind that the answer can be wrong even in the absence of malicious intent * just through the nature of querying an ever changing data source: the UTXO set may be updated by a new transaction * immediately after this message is returned.

* *

Instances of this class are not safe for use by multiple threads.

*/ public class UTXOsMessage extends Message { private long height; private Sha256Hash chainHead; private byte[] hits; // little-endian bitset indicating whether an output was found or not. private List outputs; private long[] heights; /** This is a special sentinel value that can appear in the heights field if the given tx is in the mempool. */ public static long MEMPOOL_HEIGHT = 0x7FFFFFFFL; public UTXOsMessage(NetworkParameters params, byte[] payloadBytes) { super(params, payloadBytes, 0); } /** * Provide an array of output objects, with nulls indicating that the output was missing. The bitset will * be calculated from this. */ public UTXOsMessage(NetworkParameters params, List outputs, long[] heights, Sha256Hash chainHead, long height) { super(params); hits = new byte[(int) Math.ceil(outputs.size() / 8.0)]; for (int i = 0; i < outputs.size(); i++) { if (outputs.get(i) != null) Utils.setBitLE(hits, i); } this.outputs = new ArrayList<>(outputs.size()); for (TransactionOutput output : outputs) { if (output != null) this.outputs.add(output); } this.chainHead = chainHead; this.height = height; this.heights = Arrays.copyOf(heights, heights.length); } @Override protected void bitcoinSerializeToStream(OutputStream stream) throws IOException { Utils.uint32ToByteStreamLE(height, stream); stream.write(chainHead.getBytes()); stream.write(new VarInt(hits.length).encode()); stream.write(hits); stream.write(new VarInt(outputs.size()).encode()); for (int i = 0; i < outputs.size(); i++) { TransactionOutput output = outputs.get(i); Transaction tx = output.getParentTransaction(); Utils.uint32ToByteStreamLE(tx != null ? tx.getVersion() : 0L, stream); // Version Utils.uint32ToByteStreamLE(heights[i], stream); // Height output.bitcoinSerializeToStream(stream); } } @Override protected void parse() throws ProtocolException { // Format is: // uint32 chainHeight // uint256 chainHeadHash // vector hitsBitmap; // vector outs; // // A CCoin is { int nVersion, int nHeight, CTxOut output } // The bitmap indicates which of the requested TXOs were found in the UTXO set. height = readUint32(); chainHead = readHash(); int numBytes = (int) readVarInt(); if (numBytes < 0 || numBytes > InventoryMessage.MAX_INVENTORY_ITEMS / 8) throw new ProtocolException("hitsBitmap out of range: " + numBytes); hits = readBytes(numBytes); int numOuts = (int) readVarInt(); if (numOuts < 0 || numOuts > InventoryMessage.MAX_INVENTORY_ITEMS) throw new ProtocolException("numOuts out of range: " + numOuts); outputs = new ArrayList<>(numOuts); heights = new long[numOuts]; for (int i = 0; i < numOuts; i++) { long version = readUint32(); long height = readUint32(); if (version > 1) throw new ProtocolException("Unknown tx version in getutxo output: " + version); TransactionOutput output = new TransactionOutput(params, null, payload, cursor); outputs.add(output); heights[i] = height; cursor += output.length; } length = cursor; } /** * Returns a bit map indicating which of the queried outputs were found in the UTXO set. */ public byte[] getHitMap() { return Arrays.copyOf(hits, hits.length); } /** Returns the list of outputs that matched the query. */ public List getOutputs() { return new ArrayList<>(outputs); } /** Returns the block heights of each output returned in getOutputs(), or MEMPOOL_HEIGHT if not confirmed yet. */ public long[] getHeights() { return Arrays.copyOf(heights, heights.length); } @Override public String toString() { return "UTXOsMessage{" + "height=" + height + ", chainHead=" + chainHead + ", hitMap=" + Arrays.toString(hits) + ", outputs=" + outputs + ", heights=" + Arrays.toString(heights) + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; UTXOsMessage other = (UTXOsMessage) o; return height == other.height && chainHead.equals(other.chainHead) && Arrays.equals(heights, other.heights) && Arrays.equals(hits, other.hits) && outputs.equals(other.outputs); } @Override public int hashCode() { return Objects.hashCode(height, chainHead, Arrays.hashCode(heights), Arrays.hashCode(hits), outputs); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy