/
transactions.go
184 lines (142 loc) · 6.24 KB
/
transactions.go
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// jeffCoin 1. BLOCKCHAIN transactions.go
package blockchain
import (
"crypto/ecdsa"
"crypto/sha256"
"crypto/x509"
"encoding/hex"
"encoding/json"
"encoding/pem"
"fmt"
"math/big"
"strconv"
log "github.com/sirupsen/logrus"
)
// TRANSACTIONS **********************************************************************************************************
// processTxRequestMessage - Request to transfer jeffCoins to a jeffCoin Address
func (trms txRequestMessageSignedStruct) processTxRequestMessage() string {
s := "START processTxRequestMessage() - Request to transfer jeffCoins to a jeffCoin Address"
log.Debug("TRANSACTION: " + s)
// PRINT OUT TX REQUEST MESSAGE
s = "The theTxRequestMessageSignedStruct (-loglevel trace to display)"
log.Info("TRANSACTION: " + s)
js, _ := json.MarshalIndent(trms, "", " ")
log.Trace("\n\n" + string(js) + "\n\n")
// EXTRACT WHAT YOU NEED
signature := trms.Signature
publicKeyHex := trms.TxRequestMessage.SourceAddress
theTxRequestMessageStruct := trms.TxRequestMessage
theTxRequestMessageByte, err := json.Marshal(theTxRequestMessageStruct)
checkErr(err)
theTxRequestMessage := string(theTxRequestMessageByte)
// ---------------------------------------------------------------------------
// STEP 1 - VERIFY SIGNATURE
s = "STEP 1 - VERIFY SIGNATURE"
log.Info("TRANSACTION: " + s)
verifyStatus := verifySignature(publicKeyHex, signature, theTxRequestMessage)
if !(verifyStatus) {
s = "Signature Failed"
log.Warn("TRANSACTION: " + s)
return "Signature Failed"
}
// ---------------------------------------------------------------------------
// STEP 2 - GET BALANCE AND A LIST OF UNSPENT OUTPUTS
s = "STEP 2 - GET BALANCE AND A LIST OF UNSPENT OUTPUTS"
log.Info("TRANSACTION: " + s)
balance, unspentOutput := getAddressBalance(trms.TxRequestMessage.SourceAddress)
// ---------------------------------------------------------------------------
// STEP 3 - CHECK IF YOU HAVE ENOUGH jeffCoins
s = "STEP 3 - CHECK IF YOU HAVE ENOUGH jeffCoins"
log.Info("TRANSACTION: " + s)
var value int64
for _, destinations := range trms.TxRequestMessage.Destinations {
value = value + destinations.Value
}
s = "The balance for " + trms.TxRequestMessage.SourceAddress[0:50] + "... " + "is " + strconv.FormatInt(balance, 10)
log.Info("TRANSACTION: " + s)
s = "The value to remove is " + strconv.FormatInt(value, 10) + " from " + fmt.Sprint(unspentOutput)
log.Info("TRANSACTION: " + s)
if balance < value {
s = "Not Enough jeffCoins/Value"
log.Warn("TRANSACTION: " + s)
return "Not Enough jeffCoins/Value"
}
// ---------------------------------------------------------------------------
// STEP 4 - PICK THE UNSPENT OUTPUTS TO USE AND PROVIDE CHANGE
s = "STEP 4 - PICK THE UNSPENT OUTPUTS TO USE AND PROVIDE CHANGE"
log.Info("TRANSACTION: " + s)
useUnspentOutput, change := pickUnspentOutputs(unspentOutput, value)
s = "You are using unspent outputs " + fmt.Sprint(useUnspentOutput)
log.Info("TRANSACTION: " + s)
s = "The change will be " + strconv.FormatInt(change, 10)
log.Info("TRANSACTION: " + s)
// ---------------------------------------------------------------------------
// STEP 5 - ADD TRANSACTION to pendingBlock and MAKE CHANGE
s = "STEP 5 - ADD TRANSACTION to pendingBlock and MAKE CHANGE"
log.Info("TRANSACTION: " + s)
trms.addTransactionToPendingBlock(useUnspentOutput, change)
s = "END processTxRequestMessage() - Request to transfer jeffCoins to a jeffCoin Address"
log.Debug("TRANSACTION: " + s)
return "Pending Transaction"
}
// SIGNATURE *************************************************************************************************************
// verifySignature - Verifies a ECDSA Digital Signature
func verifySignature(publicKeyHex string, signature string, plainText string) bool {
s := "START verifySignature() - Verifies a ECDSA Digital Signature"
log.Debug("TRANSACTION: " + s)
// DECODE PUBLIC KEY
publicKeyPEM, _ := hex.DecodeString(publicKeyHex)
blockPub, _ := pem.Decode([]byte(publicKeyPEM))
publicKeyx509Encoded := blockPub.Bytes
genericPublicKey, _ := x509.ParsePKIXPublicKey(publicKeyx509Encoded)
publicKeyRaw := genericPublicKey.(*ecdsa.PublicKey)
// HASH plainText
hashedPlainText := sha256.Sum256([]byte(plainText))
hashedPlainTextByte := hashedPlainText[:]
// DECODE signature
signatureByte, _ := hex.DecodeString(signature)
// EXTRACT R & S
r := big.NewInt(0)
ss := big.NewInt(0)
sigLen := len(signatureByte)
r.SetBytes(signatureByte[:(sigLen / 2)])
ss.SetBytes(signatureByte[(sigLen / 2):])
// VERIFY SIGNATURE
verifyStatus := ecdsa.Verify(
publicKeyRaw,
hashedPlainTextByte,
r,
ss,
)
s = "Verified status is: " + strconv.FormatBool(verifyStatus)
log.Info("TRANSACTION: " + s)
s = "END verifySignature() - Verifies a ECDSA Digital Signature"
log.Debug("TRANSACTION: " + s)
return verifyStatus
}
// UNSPENT OUTPUTS *******************************************************************************************************
// pickUnspentOutputs - Pick the Unspent Outputs to use and provide change
func pickUnspentOutputs(pickUnspentOutputSlice []unspentOutputStruct, value int64) ([]unspentOutputStruct, int64) {
s := "START pickUnspentOutputs() - Pick the Unspent Outputs to use and provide change"
log.Debug("TRANSACTION: " + s)
var unspentOutputStructTemp = unspentOutputStruct{}
var useUnspentOutputSlice []unspentOutputStruct
var change int64
var runningTotal int64
// Once you hit the value, stop
for _, unspentOutput := range pickUnspentOutputSlice {
unspentOutputStructTemp.TxID = unspentOutput.TxID
unspentOutputStructTemp.Value = unspentOutput.Value
// Place in slice
useUnspentOutputSlice = append(useUnspentOutputSlice, unspentOutputStructTemp)
runningTotal = runningTotal + unspentOutput.Value
// did you get enough - If yes, provide change
if value < runningTotal {
change = runningTotal - value
break
}
}
s = "END pickUnspentOutputs() - Pick the Unspent Outputs to use and provide change"
log.Debug("TRANSACTION: " + s)
return useUnspentOutputSlice, change
}