-
Notifications
You must be signed in to change notification settings - Fork 0
/
Transaction.java
101 lines (82 loc) · 3.78 KB
/
Transaction.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package silverchain;
import java.security.*;
import java.util.ArrayList;
public class Transaction {
public String transactionId; //Contains a hash of transaction*
public PublicKey sender; //Senders address/public key.
public PublicKey reciepient; //Recipients address/public key.
public float value; //Contains the amount we wish to send to the recipient.
public byte[] signature; //This is to prevent anybody else from spending funds in our wallet.
public ArrayList<TransactionInput> inputs = new ArrayList<TransactionInput>();
public ArrayList<TransactionOutput> outputs = new ArrayList<TransactionOutput>();
private static int sequence = 0; //A rough count of how many transactions have been generated
// Constructor:
public Transaction(PublicKey from, PublicKey to, float value, ArrayList<TransactionInput> inputs) {
this.sender = from;
this.reciepient = to;
this.value = value;
this.inputs = inputs;
}
public boolean processTransaction() {
if(verifySignature() == false) {
System.out.println("#Transaction Signature failed to verify");
return false;
}
//Gathers transaction inputs (Making sure they are unspent):
for(TransactionInput i : inputs) {
i.UTXO = SilverChain.UTXOs.get(i.transactionOutputId);
}
//Checks if transaction is valid:
if(getInputsValue() < SilverChain.minimumTransaction) {
System.out.println("Transaction Inputs too small: " + getInputsValue());
System.out.println("Please enter the amount greater than " + SilverChain.minimumTransaction);
return false;
}
//Generate transaction outputs:
float leftOver = getInputsValue() - value; //get value of inputs then the left over change:
transactionId = calulateHash();
outputs.add(new TransactionOutput( this.reciepient, value,transactionId)); //send value to recipient
outputs.add(new TransactionOutput( this.sender, leftOver,transactionId)); //send the left over 'change' back to sender
//Add outputs to Unspent list
for(TransactionOutput o : outputs) {
SilverChain.UTXOs.put(o.id , o);
}
//Remove transaction inputs from UTXO lists as spent:
for(TransactionInput i : inputs) {
if(i.UTXO == null) continue; //if Transaction can't be found skip it
SilverChain.UTXOs.remove(i.UTXO.id);
}
return true;
}
public float getInputsValue() {
float total = 0;
for(TransactionInput i : inputs) {
if(i.UTXO == null) continue; //if Transaction can't be found skip it, This behavior may not be optimal.
total += i.UTXO.value;
}
return total;
}
public void generateSignature(PrivateKey privateKey) {
String data = StringUtil.getStringFromKey(sender) + StringUtil.getStringFromKey(reciepient) + Float.toString(value) ;
signature = StringUtil.applyECDSASig(privateKey,data);
}
public boolean verifySignature() {
String data = StringUtil.getStringFromKey(sender) + StringUtil.getStringFromKey(reciepient) + Float.toString(value) ;
return StringUtil.verifyECDSASig(sender, data, signature);
}
public float getOutputsValue() {
float total = 0;
for(TransactionOutput o : outputs) {
total += o.value;
}
return total;
}
private String calulateHash() {
sequence++; //increase the sequence to avoid 2 identical transactions having the same hash
return StringUtil.applySha256(
StringUtil.getStringFromKey(sender) +
StringUtil.getStringFromKey(reciepient) +
Float.toString(value) + sequence
);
}
}