-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTransaction.java
More file actions
161 lines (139 loc) · 4.64 KB
/
Transaction.java
File metadata and controls
161 lines (139 loc) · 4.64 KB
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import java.security.*;
import java.util.ArrayList;
import java.util.Base64;
public class Transaction {
public String transactionId; // Hash of the transaction
private PublicKey sender; // Senders Public Key
private PublicKey reciever; // Recievers public key
private float amount; // Amount to send
private byte[] signature; // Our signatutre
private ArrayList<TransactionInput> inputs;
public ArrayList<TransactionOutput> outputs;
private static int number; // approximate number of transactions
public Transaction(
PublicKey from, PublicKey to, float amount, ArrayList<TransactionInput> inputs) {
outputs = new ArrayList<TransactionOutput>();
this.sender = from;
this.reciever = to;
this.amount = amount;
this.inputs = inputs;
number = 0;
}
private String calulateHash() {
number++; // increase the number to avoid 2 identical transactions having the same hash
return StringUtil.applySha256(
StringUtil.getStringFromKey(sender)
+ StringUtil.getStringFromKey(reciever)
+ Float.toString(getAmount())
+ number);
}
// Applies ECDSA Signature and returns the result ( as bytes ).
public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
Signature dsa;
byte[] output = new byte[0];
try {
dsa = Signature.getInstance("ECDSA", "BC");
dsa.initSign(privateKey);
byte[] strByte = input.getBytes();
dsa.update(strByte);
byte[] realSig = dsa.sign();
output = realSig;
} catch (Exception e) {
throw new RuntimeException(e);
}
return output;
}
// Verifies a String signature
public static boolean verifyECDSASig(PublicKey publicKey, String data, byte[] signature) {
try {
Signature ecdsaVerify = Signature.getInstance("ECDSA", "BC");
ecdsaVerify.initVerify(publicKey);
ecdsaVerify.update(data.getBytes());
return ecdsaVerify.verify(signature);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String getStringFromKey(Key key) {
return Base64.getEncoder().encodeToString(key.getEncoded());
}
// Signs all the data we dont wish to be tampered with.
public void generateSignature(PrivateKey privateKey) {
String data =
StringUtil.getStringFromKey(getSender())
+ StringUtil.getStringFromKey(getReciever())
+ Float.toString(getAmount());
signature = StringUtil.applyECDSASig(privateKey, data);
}
// Verifies the data we signed hasnt been tampered with
public boolean verifiySignature() {
String data =
StringUtil.getStringFromKey(getSender())
+ StringUtil.getStringFromKey(getReciever())
+ Float.toString(getAmount());
return StringUtil.verifyECDSASig(getSender(), data, getSignature());
}
public boolean processTransaction() {
if (!verifiySignature()) {
System.out.println("# Failed to verify transaction signature");
return false;
}
for (TransactionInput i : inputs) {
i.UTXO = BlockChain.UTXOs.get(i.transactionOutputId);
}
if (getInputsValue() < BlockChain.minimumTransaction) {
System.out.println("Transaction too small: " + getInputsValue());
return false;
}
float leftOver = getInputsValue() - getAmount();
transactionId = calulateHash();
outputs.add(new TransactionOutput(this.getReciever(), getAmount(), getTransactionId()));
outputs.add(new TransactionOutput(this.getSender(), leftOver, getTransactionId()));
for (TransactionOutput out : outputs) {
BlockChain.UTXOs.put(out.id, out);
}
for (TransactionInput i : inputs) {
if (i.UTXO != null) {
BlockChain.UTXOs.remove(i.UTXO.id);
}
}
return true;
}
public float getInputsValue() {
float total = 0;
for (TransactionInput i : inputs) {
if (i.UTXO != null) {
total += i.UTXO.value;
}
}
return total;
}
public float getOutputsValue() {
float total = 0;
for (TransactionOutput o : outputs) {
total += o.value;
}
return total;
}
public String getTransactionId() {
return transactionId;
}
public PublicKey getSender() {
return sender;
}
public PublicKey getReciever() {
return reciever;
}
public float getAmount() {
return amount;
}
public byte[] getSignature() {
return signature;
}
public ArrayList<TransactionOutput> getOutputs() {
return outputs;
}
public ArrayList<TransactionInput> getInputs() {
return inputs;
}
}