package com.yoghurt.crypto.transactions.client.util.transaction; import com.yoghurt.crypto.transactions.shared.domain.RawTransactionContainer; import com.yoghurt.crypto.transactions.shared.domain.ScriptType; import com.yoghurt.crypto.transactions.shared.domain.Transaction; import com.yoghurt.crypto.transactions.shared.domain.TransactionInput; import com.yoghurt.crypto.transactions.shared.domain.TransactionOutput; import com.yoghurt.crypto.transactions.shared.domain.TransactionPartType; import com.yoghurt.crypto.transactions.shared.domain.VariableLengthInteger; import com.yoghurt.crypto.transactions.shared.util.NumberEncodeUtil; import com.yoghurt.crypto.transactions.shared.util.ScriptEncodeUtil; public final class TransactionEncodeUtil extends TransactionUtil { private TransactionEncodeUtil() {} public static RawTransactionContainer encodeTransaction(final Transaction transaction) { return encodeTransaction(transaction, new RawTransactionContainer()); } public static RawTransactionContainer encodeTransaction(final Transaction transaction, final RawTransactionContainer container) { // Encode the version container.add(TransactionPartType.VERSION, encodeVersion(transaction)); // Encode the input length container.add(TransactionPartType.INPUT_SIZE, encodeNumInputs(transaction)); // Encode the inputs encodeTransactionInputs(transaction, container); // Encode the output length container.add(TransactionPartType.OUTPUT_SIZE, encodeNumOutputs(transaction)); // Encode the outputs encodeTransactionOutputs(transaction, container); // Encode the lock time container.add(TransactionPartType.LOCK_TIME, encodeLockTime(transaction)); return container; } private static void encodeTransactionInputs(final Transaction transaction, final RawTransactionContainer container) { for (int i = 0; i < transaction.getInputSize().getValue(); i++) { encodeInput(transaction.getInputs().get(i), container); } } private static void encodeTransactionOutputs(final Transaction transaction, final RawTransactionContainer container) { for (int i = 0; i < transaction.getOutputs().size(); i++) { encodeOutput(transaction.getOutputs().get(i), container); } } private static void encodeInput(final TransactionInput input, final RawTransactionContainer container) { // Encode the outpoint hash final byte[] outpointHash = input.getOutPoint().getReferenceTransaction(); container.add(TransactionPartType.INPUT_PREVIOUS_TRANSACTION_HASH, outpointHash); // Encode the outpoint index final byte[] indexBytes = NumberEncodeUtil.encodeUint32(input.getOutPoint().getIndex()); container.add(TransactionPartType.INPUT_OUTPOINT_INDEX, indexBytes); // Encode the signature length final byte[] scriptSizeBytes = encodeVariableInteger(input.getScriptSize()); container.add(TransactionPartType.INPUT_SCRIPT_LENGTH, scriptSizeBytes); // Encode the signature script ScriptEncodeUtil.encodeScript(input, container, ScriptType.SCRIPT_SIG); // Encode the sequence bytes final byte[] sequenceBytes = NumberEncodeUtil.encodeUint32(input.getTransactionSequence()); container.add(TransactionPartType.INPUT_SEQUENCE, sequenceBytes); } private static void encodeOutput(final TransactionOutput output, final RawTransactionContainer container) { // Encode the output value final byte[] outputValueBytes = NumberEncodeUtil.encodeUint64(output.getTransactionValue()); container.add(TransactionPartType.OUTPUT_VALUE, outputValueBytes); // Encode the output script length final byte[] scriptSizeBytes = encodeVariableInteger(output.getScriptSize()); container.add(TransactionPartType.OUTPUT_SCRIPT_LENGTH, scriptSizeBytes); // Encode the output script ScriptEncodeUtil.encodeScript(output, container, ScriptType.SCRIPT_PUB_KEY); } private static byte[] encodeLockTime(final Transaction transaction) { return NumberEncodeUtil.encodeUint32(transaction.getLockTime()); } private static byte[] encodeNumOutputs(final Transaction transaction) { return encodeVariableInteger(transaction.getOutputSize()); } private static byte[] encodeNumInputs(final Transaction transaction) { return encodeVariableInteger(transaction.getInputSize()); } private static byte[] encodeVariableInteger(final VariableLengthInteger varInt) { return varInt.getBytes(); } private static byte[] encodeVersion(final Transaction t) { return NumberEncodeUtil.encodeUint32(t.getVersion()); } }