forked from febe19/bazo-miner
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathblock_updatetx.go
148 lines (121 loc) · 4.43 KB
/
block_updatetx.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
package miner
import (
"errors"
"fmt"
"github.com/julwil/bazo-miner/crypto"
"github.com/julwil/bazo-miner/p2p"
"github.com/julwil/bazo-miner/protocol"
"github.com/julwil/bazo-miner/storage"
"time"
)
// Handles the processing of a UpdateTx.
// Updates the tx to delete referenced by tx.TxToUpdateHash from the
// local storage and increases the update counter from the block it was included in.
// Adds the UpdateTx to the UpdateTxData slice of the current block.
func addUpdateTx(b *protocol.Block, tx *protocol.UpdateTx) error {
// First we perform the update of the tx we want to update.
handleTxUpdate(tx)
// Then we can include the UpdateTx in the current block.
b.UpdateTxData = append(b.UpdateTxData, tx.Hash())
return nil
}
func handleTxUpdate(updateTx *protocol.UpdateTx) error {
txToUpdateHash := updateTx.TxToUpdateHash
// At this point we already verified that the transaction we want to update actually exists
// either in the open or closed transaction storage. Thus we can safely assume it exists and
// update it in our local storage.
updateLocalTx(txToUpdateHash, updateTx.TxToUpdateCheckString, updateTx.TxToUpdateData, updateTx.Data)
blockToUpdate := storage.ReadBlockByTxHash(txToUpdateHash)
if blockToUpdate == nil {
return errors.New(fmt.Sprintf("Can't find block of tx: %x", txToUpdateHash))
}
blockToUpdate.NrUpdates++
logger.Printf("\nUpdated Block:\n%s", blockToUpdate.String())
// Update the block in the local storage.
storage.DeleteOpenBlock(blockToUpdate.Hash)
storage.WriteClosedBlock(blockToUpdate)
go broadcastBlock(blockToUpdate)
return nil
}
// Updates the data field of a local tx identified by txHash
func updateLocalTx(
txHash [32]byte,
newCheckString *crypto.ChameleonHashCheckString,
newData []byte,
updateReason []byte, // This is the data field from update tx.
) error {
var txToUpdate protocol.Transaction
var oldData []byte
switch true {
case storage.ReadOpenTx(txHash) != nil:
txToUpdate = storage.ReadOpenTx(txHash)
oldData = txToUpdate.GetData()
txToUpdate.SetData(newData)
txToUpdate.SetCheckString(newCheckString)
storage.WriteOpenTx(txToUpdate)
case storage.ReadClosedTx(txHash) != nil:
txToUpdate = storage.ReadClosedTx(txHash)
oldData = txToUpdate.GetData()
txToUpdate.SetData(newData)
txToUpdate.SetCheckString(newCheckString)
storage.WriteClosedTx(txToUpdate)
default: // If we don't find the tx to update in the storage, we also can't update it.
return errors.New(fmt.Sprintf("Can't find TxToDelete: %x", txHash))
}
logger.Printf("\n"+
"=====================================================================================\n"+
" Updated TX: %x\n"+
" Old: %s\n"+
" New: %s\n\n"+
" Reason: %s\n"+
"=====================================================================================",
txToUpdate.Hash(), oldData, txToUpdate.GetData(), updateReason,
)
return nil
}
// Fetch UpdateTxData
func fetchUpdateTxData(block *protocol.Block, updateTxSlice []*protocol.UpdateTx, initialSetup bool, errChan chan error) {
for i, txHash := range block.UpdateTxData {
var tx protocol.Transaction
var updateTx *protocol.UpdateTx
closedTx := storage.ReadClosedTx(txHash)
if closedTx != nil {
logger.Printf("Tx was in closed")
if initialSetup {
updateTx = closedTx.(*protocol.UpdateTx)
updateTxSlice[i] = updateTx
continue
} else {
//Reject blocks that have txs which have already been validated.
errChan <- errors.New("Block validation had updateTx that was already in a previous block.")
return
}
}
//Tx is either in open storage or needs to be fetched from the network.
tx = storage.ReadOpenTx(txHash)
if tx != nil {
logger.Printf("Tx was in open")
updateTx = tx.(*protocol.UpdateTx)
} else {
err := p2p.TxReq(txHash, p2p.UPDATETX_REQ)
if err != nil {
errChan <- errors.New(fmt.Sprintf("UpdateTx could not be read: %v", err))
return
}
//Blocking Wait
select {
case updateTx = <-p2p.UpdateTxChan:
logger.Printf("Tx was fetched from network")
case <-time.After(TXFETCH_TIMEOUT * time.Second):
errChan <- errors.New("UpdateTx fetch timed out.")
}
//This check is important. A malicious miner might have sent us a tx whose hash is a different one
//from what we requested.
if updateTx.Hash() != txHash {
errChan <- errors.New("Received UpdateTx hash did not correspond to our request.")
}
}
updateTxSlice[i] = updateTx
}
errChan <- nil
}