/** * Copyright 2011 Google Inc. * * 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 com.google.bitcoin.core; import java.io.IOException; import java.io.OutputStream; import java.io.Serializable; /** * A transfer of coins from one address to another creates a transaction in which the outputs * can be claimed by the recipient in the input of another transaction. You can imagine a * transaction as being a module which is wired up to others, the inputs of one have to be wired * to the outputs of another. The exceptions are coinbase transactions, which create new coins. */ public class TransactionInput extends Message implements Serializable { private static final long serialVersionUID = -7687665228438202968L; // An apparently unused field intended for altering transactions after they were broadcast. long sequence; // The output of the transaction we're gathering coins from. TransactionOutPoint outpoint; // The "script bytes" might not actually be a script. In coinbase transactions where new coins are minted there // is no input transaction, so instead the scriptBytes contains some extra stuff (like a rollover nonce) that we // don't care about much. The bytes are turned into a Script object (cached below) on demand via a getter. byte[] scriptBytes; // The Script object obtained from parsing scriptBytes. Only filled in on demand and if the transaction is not // coinbase. transient private Script scriptSig; static public final byte[] EMPTY_ARRAY = new byte[0]; /** Used only in creation of the genesis block. */ TransactionInput(NetworkParameters params, byte[] scriptBytes) { super(params); this.scriptBytes = scriptBytes; this.outpoint = new TransactionOutPoint(params, -1, null); this.sequence = 0xFFFFFFFFL; } /** Creates an UNSIGNED input that links to the given output */ TransactionInput(NetworkParameters params, TransactionOutput output) { super(params); long outputIndex = output.getIndex(); outpoint = new TransactionOutPoint(params, outputIndex, output.parentTransaction); scriptBytes = EMPTY_ARRAY; this.sequence = 0xFFFFFFFFL; } /** Deserializes an input message. This is usually part of a transaction message. */ public TransactionInput(NetworkParameters params, byte[] payload, int offset) throws ProtocolException { super(params, payload, offset); } void parse() throws ProtocolException { outpoint = new TransactionOutPoint(params, bytes, cursor); cursor += outpoint.getMessageSize(); int scriptLen = (int) readVarInt(); scriptBytes = readBytes(scriptLen); sequence = readUint32(); } @Override public void bitcoinSerializeToStream(OutputStream stream) throws IOException { outpoint.bitcoinSerializeToStream(stream); stream.write(new VarInt(scriptBytes.length).encode()); stream.write(scriptBytes); Utils.uint32ToByteStreamLE(sequence, stream); } /** * Coinbase transactions have special inputs with hashes of zero. If this is such an input, returns true. */ public boolean isCoinBase() { for (int i = 0; i < outpoint.hash.length; i++) if (outpoint.hash[i] != 0) return false; return true; } /** * Returns the input script. */ public Script getScriptSig() throws ScriptException { // Transactions that generate new coins don't actually have a script. Instead this // parameter is overloaded to be something totally different. if (scriptSig == null) { assert scriptBytes != null; scriptSig = new Script(params, scriptBytes, 0, scriptBytes.length); } return scriptSig; } /** * Convenience method that returns the from address of this input by parsing the scriptSig. * @throws ScriptException if the scriptSig could not be understood (eg, if this is a coinbase transaction). */ public Address getFromAddress() throws ScriptException { assert !isCoinBase(); return getScriptSig().getFromAddress(); } /** Returns a human readable debug string. */ public String toString() { if (isCoinBase()) return "TxIn: COINBASE"; try { return "TxIn from " + Utils.bytesToHexString(getScriptSig().getPubKey()) + " script:" + getScriptSig().toString(); } catch (ScriptException e) { throw new RuntimeException(e); } } }