Exemplo n.º 1
0
		/**
		 * This is required for signatures which use a sigHashType which cannot be represented using SigHash and anyoneCanPay
		 * See transaction c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73, which has sigHashType 0
		 * throws ScriptException
		 */
		private Sha256Hash hashTransactionForSignature(int inputIndex,byte[] connectedScript,byte sigHashType)
		{
			lock(this)
			{
				// TODO: This whole separate method should be un-necessary if we fix how we deserialize sighash flags.
				// The SIGHASH flags are used in the design of contracts, please see this page for a further understanding of
				// the purposes of the code in this method:
				//
				//   https://en.bitcoin.it/wiki/Contracts
			
				try
				{
					// Store all the input scripts and clear them in preparation for signing. If we're signing a fresh
					// transaction that step isn't very helpful, but it doesn't add much cost relative to the actual
					// EC math so we'll do it anyway.
					//
					// Also store the input sequence numbers in case we are clearing them with SigHash.NONE/SINGLE
				
					byte[][] inputScripts = new byte[inputs.size()][];
					long[] inputSequenceNumbers = new long[inputs.size()];
					for (int i = 0; i < inputs.size(); i++)
					{
						inputScripts[i] = inputs[i].getScriptBytes();
						inputSequenceNumbers[i] = inputs[i].getSequenceNumber();
						inputs[i].setScriptBytes(TransactionInput.EMPTY_ARRAY);
					}
				
					// This step has no purpose beyond being synchronized with the reference clients bugs. OP_CODESEPARATOR
					// is a legacy holdover from a previous, broken design of executing scripts that shipped in Bitcoin 0.1.
					// It was seriously flawed and would have let anyone take anyone elses money. Later versions switched to
					// the design we use today where scripts are executed independently but share a stack. This left the
					// OP_CODESEPARATOR instruction having no purpose as it was only meant to be used internally, not actually
					// ever put into scripts. Deleting OP_CODESEPARATOR is a step that should never be required but if we don't
					// do it, we could split off the main chain.
				
					connectedScript = Script.removeAllInstancesOfOp(connectedScript, Script.OP_CODESEPARATOR);
				
					// Set the input to the script of its output. Satoshi does this but the step has no obvious purpose as
					// the signature covers the hash of the prevout transaction which obviously includes the output script
					// already. Perhaps it felt safer to him in some way, or is another leftover from how the code was written.
				
					TransactionInput input = inputs.get(inputIndex);
					input.setScriptBytes(connectedScript);
					ArrayList<TransactionOutput> outputs = this.outputs;
					if((sigHashType & 0x1f) == (SigHash.NONE.ordinal() + 1))
					{
						// SIGHASH_NONE means no outputs are signed at all - the signature is effectively for a "blank cheque".
						this.outputs = new ArrayList<TransactionOutput>(0);
					
						// The signature isn't broken by new versions of the transaction issued by other parties.
					
						for(int i=0;i<inputs.size();i++)
						{
							if (i != inputIndex)
							{ inputs[i].setSequenceNumber(0); }
						}
					}
					else if((sigHashType & 0x1f) == (SigHash.SINGLE.ordinal() + 1))
					{
						// SIGHASH_SINGLE means only sign the output at the same index as the input (ie, my output).
					
						if (inputIndex >= this.outputs.size())
						{
							// The input index is beyond the number of outputs, it's a buggy signature made by a broken
							// Bitcoin implementation. The reference client also contains a bug in handling this case:
							// any transaction output that is signed in this case will result in both the signed output
							// and any future outputs to this public key being steal-able by anyone who has
							// the resulting signature and the public key (both of which are part of the signed tx input).
							// Put the transaction back to how we found it.
							// TODO: Only allow this to happen if we are checking a signature, not signing a transactions
						
							for(int i=0;i<inputs.size();i++)
							{
								inputs[i].setScriptBytes(inputScripts[i]);
								inputs[i].setSequenceNumber(inputSequenceNumbers[i]);
							}
						
							this.outputs = outputs;
						
							// Satoshis bug is that SignatureHash was supposed to return a hash and on this codepath it
							// actually returns the constant "1" to indicate an error, which is never checked for. Oops.
							return new Sha256Hash("0100000000000000000000000000000000000000000000000000000000000000");
						}
					
						// In SIGHASH_SINGLE the outputs after the matching input index are deleted, and the outputs before
						// that position are "nulled out". Unintuitively, the value in a "null" transaction is set to -1.
					
						this.outputs = new ArrayList<TransactionOutput>(this.outputs.subList(0, inputIndex + 1));
						for (int i = 0; i < inputIndex; i++)
						{ this.outputs.set(i, new TransactionOutput(params, this, BigInteger.valueOf(-1), new byte[] {})); }
					
						// The signature isn't broken by new versions of the transaction issued by other parties.
						for(int i=0;i<inputs.size();i++)
						{
							if (i != inputIndex)
							{ inputs[i].setSequenceNumber(0); }
						}
					}
				
					ArrayList<TransactionInput> inputs = this.inputs;
				
					if((sigHashType & 0x80) == 0x80)
					{
						// SIGHASH_ANYONECANPAY means the signature in the input is not broken by changes/additions/removals
						// of other inputs. For example, this is useful for building assurance contracts.
					
						this.inputs = new ArrayList<TransactionInput>();
						this.inputs.add(input);
					}
				
					ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(length == UNKNOWN_LENGTH ? 256 : length + 4);
					bitcoinSerialize(bos);
				
					// We also have to write a hash type (sigHashType is actually an unsigned char)
					uint32ToByteStreamLE(0x000000ff & sigHashType, bos);
				
					// Note that this is NOT reversed to ensure it will be signed correctly. If it were to be printed out
					// however then we would expect that it is IS reversed.
					Sha256Hash hash = new Sha256Hash(doubleDigest(bos.toByteArray()));
					bos.close();
				
					// Put the transaction back to how we found it.
					this.inputs = inputs;
					for (int i = 0; i < inputs.size(); i++)
					{
						inputs[i].setScriptBytes(inputScripts[i]);
						inputs[i].setSequenceNumber(inputSequenceNumbers[i]);
					}
				
					this.outputs = outputs;
					return hash;
				}
				catch(IOException e)
				{
					throw new RuntimeException(e);  // Cannot happen.
				}
			}
		}