/** * Creates a new transaction using the provided inputs * * @param inputs List of signed inputs * @param outputs List of outputs * @throws ECException Unable to sign transaction * @throws ScriptException Script processing error * @throws VerificationException Transaction verification failure */ public Transaction(List<SignedInput> inputs, List<TransactionOutput> outputs) throws ECException, ScriptException, VerificationException { SerializedBuffer outBuffer = new SerializedBuffer(1024); txVersion = 1; txOutputs = outputs; txLockTime = 0; coinBase = false; // // Create the transaction inputs // txInputs = new ArrayList<>(inputs.size()); for (int i = 0; i < inputs.size(); i++) txInputs.add(new TransactionInput(this, i, inputs.get(i).getOutPoint())); // // Now sign each input and create the input scripts // for (int i = 0; i < inputs.size(); i++) { SignedInput input = inputs.get(i); ECKey key = input.getKey(); byte[] contents; // // Serialize the transaction for signing using the SIGHASH_ALL hash type // outBuffer.rewind(); serializeForSignature(i, ScriptOpCodes.SIGHASH_ALL, input.getScriptBytes(), outBuffer); outBuffer.putInt(ScriptOpCodes.SIGHASH_ALL); contents = outBuffer.toByteArray(); // // Create the DER-encoded signature // ECDSASignature sig = key.createSignature(contents); byte[] encodedSig = sig.encodeToDER(); // // Create the input script using the SIGHASH_ALL hash type // <sig> <pubKey> // byte[] pubKey = key.getPubKey(); byte[] scriptBytes = new byte[1 + encodedSig.length + 1 + 1 + pubKey.length]; scriptBytes[0] = (byte) (encodedSig.length + 1); System.arraycopy(encodedSig, 0, scriptBytes, 1, encodedSig.length); int offset = encodedSig.length + 1; scriptBytes[offset++] = (byte) ScriptOpCodes.SIGHASH_ALL; scriptBytes[offset++] = (byte) pubKey.length; System.arraycopy(pubKey, 0, scriptBytes, offset, pubKey.length); txInputs.get(i).setScriptBytes(scriptBytes); } // // Serialize the entire transaction // outBuffer.rewind(); getBytes(outBuffer); txData = outBuffer.toByteArray(); // // Calculate the transaction hash using the serialized data // txHash = new Sha256Hash(Utils.reverseBytes(Utils.doubleDigest(txData))); // // Calculate the normalized transaction ID // List<byte[]> bufferList = new ArrayList<>(txInputs.size() + txOutputs.size()); txInputs .stream() .forEach( (txInput) -> { bufferList.add(txInput.getOutPoint().getBytes()); }); txOutputs .stream() .forEach( (txOutput) -> { bufferList.add(txOutput.getBytes()); }); normID = new Sha256Hash(Utils.reverseBytes(Utils.doubleDigest(bufferList))); }