package com.ripple.core.types.known.tx.signed;
import com.ripple.core.coretypes.Amount;
import com.ripple.core.coretypes.Blob;
import com.ripple.core.coretypes.PathSet;
import com.ripple.core.coretypes.hash.HalfSha512;
import com.ripple.core.coretypes.hash.Hash256;
import com.ripple.core.coretypes.hash.prefixes.HashPrefix;
import com.ripple.core.coretypes.uint.UInt32;
import com.ripple.core.fields.Field;
import com.ripple.core.serialized.BytesList;
import com.ripple.core.serialized.MultiSink;
import com.ripple.core.serialized.SerializedType;
import com.ripple.core.serialized.enums.TransactionType;
import com.ripple.core.types.known.tx.Transaction;
import com.ripple.crypto.ecdsa.IKeyPair;
import com.ripple.crypto.ecdsa.Seed;
public class SignedTransaction {
private SignedTransaction(Transaction of) {
// TODO: is this just over kill ?
// TODO: do we want to -> binary -> Transaction ?
// Shallow copy the transaction. Child fields
// are practically immutable, except perhaps PathSet.
txn = new Transaction(of.transactionType());
for (Field field : of) {
SerializedType st = of.get(field);
// Deep copy Paths
if (field == Field.Paths) {
st = PathSet.translate.fromBytes(st.toBytes());
}
txn.put(field, st);
}
}
// This will eventually be private
@Deprecated
public SignedTransaction() {}
public Transaction txn;
public Hash256 hash;
public Hash256 signingHash;
public Hash256 previousSigningHash;
public String tx_blob;
public void sign(String base58Secret) {
sign(Seed.fromBase58(base58Secret).keyPair());
}
public static SignedTransaction fromTx(Transaction tx) {
return new SignedTransaction(tx);
}
public void sign(IKeyPair keyPair) {
prepare(keyPair, null, null, null);
}
public void prepare(IKeyPair keyPair,
Amount fee,
UInt32 Sequence,
UInt32 lastLedgerSequence) {
Blob pubKey = new Blob(keyPair.pubBytes());
// This won't always be specified
if (lastLedgerSequence != null) {
txn.put(UInt32.LastLedgerSequence, lastLedgerSequence);
}
if (Sequence != null) {
txn.put(UInt32.Sequence, Sequence);
}
if (fee != null) {
txn.put(Amount.Fee, fee);
}
txn.signingPubKey(pubKey);
if (Transaction.CANONICAL_FLAG_DEPLOYED) {
txn.setCanonicalSignatureFlag();
}
txn.checkFormat();
signingHash = txn.signingHash();
if (previousSigningHash != null && signingHash.equals(previousSigningHash)) {
return;
}
try {
txn.txnSignature(new Blob(keyPair.sign(signingHash.bytes())));
BytesList blob = new BytesList();
HalfSha512 id = HalfSha512.prefixed256(HashPrefix.transactionID);
txn.toBytesSink(new MultiSink(blob, id));
tx_blob = blob.bytesHex();
hash = id.finish();
} catch (Exception e) {
// electric paranoia
previousSigningHash = null;
throw new RuntimeException(e);
} /*else {*/
previousSigningHash = signingHash;
// }
}
public TransactionType transactionType() {
return txn.transactionType();
}
}