-
Notifications
You must be signed in to change notification settings - Fork 82
/
verification.go
123 lines (114 loc) · 3.43 KB
/
verification.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
// Copyright 2018 Shift Devices AG
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package transactions
import (
"fmt"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/btc/blockchain"
"github.com/digitalbitbox/bitbox-wallet-app/backend/coins/btc/headers"
)
func (transactions *Transactions) onHeadersEvent(event headers.Event) {
switch event {
case headers.EventSynced:
transactions.verifyTransactions()
case headers.EventNewTip:
done := transactions.synchronizer.IncRequestsCounter()
transactions.headersTipHeight = transactions.headers.TipHeight()
done()
}
}
func (transactions *Transactions) unverifiedTransactions() map[chainhash.Hash]int {
defer transactions.RLock()()
dbTx, err := transactions.db.Begin()
if err != nil {
// TODO
panic(err)
}
defer dbTx.Rollback()
unverifiedTransactions, err := dbTx.UnverifiedTransactions()
if err != nil {
// TODO
panic(err)
}
result := map[chainhash.Hash]int{}
for _, txHash := range unverifiedTransactions {
_, _, height, _, err := dbTx.TxInfo(txHash)
if err != nil {
// TODO
panic(err)
}
result[txHash] = height
}
return result
}
func hashMerkleRoot(merkle []blockchain.TXHash, start chainhash.Hash, pos int) chainhash.Hash {
for i := 0; i < len(merkle); i++ {
if (uint32(pos)>>uint32(i))&1 == 0 {
start = chainhash.DoubleHashH(append(start[:], merkle[i][:]...))
} else {
start = chainhash.DoubleHashH(append(merkle[i][:], start[:]...))
}
}
return start
}
func (transactions *Transactions) verifyTransactions() {
unverifiedTransactions := transactions.unverifiedTransactions()
transactions.log.Debugf("verifying %d transactions", len(unverifiedTransactions))
for txHash, height := range unverifiedTransactions {
transactions.verifyTransaction(txHash, height)
}
}
func (transactions *Transactions) verifyTransaction(txHash chainhash.Hash, height int) {
if height <= 0 {
return
}
header, err := transactions.headers.HeaderByHeight(height)
if err != nil {
// TODO
panic(err)
}
if header == nil {
transactions.log.Warningf("Header not yet synced to %d, couldn't verify tx", height)
return
}
done := transactions.synchronizer.IncRequestsCounter()
transactions.blockchain.GetMerkle(
txHash, height,
func(merkle []blockchain.TXHash, pos int) error {
expectedMerkleRoot := hashMerkleRoot(merkle, txHash, pos)
if expectedMerkleRoot != header.MerkleRoot {
transactions.log.Warning(
fmt.Sprintf("Merkle root verification failed for %s", txHash))
return nil
}
transactions.log.Debugf("Merkle root verification succeeded for %s", txHash)
defer transactions.Lock()()
dbTx, err := transactions.db.Begin()
if err != nil {
// TODO
panic(err)
}
defer dbTx.Rollback()
if err := dbTx.MarkTxVerified(txHash, header.Timestamp); err != nil {
return err
}
return dbTx.Commit()
},
func(err error) {
done()
if err != nil {
panic(err)
}
})
}