-
Notifications
You must be signed in to change notification settings - Fork 7
/
bitcoin.go
99 lines (89 loc) · 2.46 KB
/
bitcoin.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
package client
import (
"fmt"
"math"
"time"
"github.com/BlockchainSource/go-opentimestamps/opentimestamps"
"github.com/btcsuite/btcrpcclient"
)
// A BitcoinAttestationVerifier uses a bitcoin RPC connection to verify bitcoin
// headers.
type BitcoinAttestationVerifier struct {
btcrpcClient *btcrpcclient.Client
}
func NewBitcoinAttestationVerifier(
c *btcrpcclient.Client,
) *BitcoinAttestationVerifier {
return &BitcoinAttestationVerifier{c}
}
// VerifyAttestation checks a BitcoinAttestation using a given hash digest. It
// returns the time of the block if the verification succeeds, an error
// otherwise.
func (v *BitcoinAttestationVerifier) VerifyAttestation(
digest []byte, a *opentimestamps.BitcoinAttestation,
) (*time.Time, error) {
if a.Height > math.MaxInt64 {
return nil, fmt.Errorf("illegal block height")
}
blockHash, err := v.btcrpcClient.GetBlockHash(int64(a.Height))
if err != nil {
return nil, err
}
h, err := v.btcrpcClient.GetBlockHeader(blockHash)
if err != nil {
return nil, err
}
merkleRootBytes := h.MerkleRoot[:]
err = a.VerifyAgainstBlockHash(digest, merkleRootBytes)
if err != nil {
return nil, err
}
utc := h.Timestamp.UTC()
return &utc, nil
}
// A BitcoinVerification is the result of verifying a BitcoinAttestation
type BitcoinVerification struct {
Timestamp *opentimestamps.Timestamp
Attestation *opentimestamps.BitcoinAttestation
AttestationTime *time.Time
Error error
}
// BitcoinVerifications returns the all bitcoin attestation results for the
// timestamp.
func (v *BitcoinAttestationVerifier) BitcoinVerifications(
t *opentimestamps.Timestamp,
) (res []BitcoinVerification) {
t.Walk(func(ts *opentimestamps.Timestamp) {
for _, att := range ts.Attestations {
btcAtt, ok := att.(*opentimestamps.BitcoinAttestation)
if !ok {
continue
}
attTime, err := v.VerifyAttestation(ts.Message, btcAtt)
res = append(res, BitcoinVerification{
Timestamp: ts,
Attestation: btcAtt,
AttestationTime: attTime,
Error: err,
})
}
})
return res
}
// Verify returns the earliest bitcoin-attested time, or nil if none can be
// found or verified successfully.
func (v *BitcoinAttestationVerifier) Verify(
t *opentimestamps.Timestamp,
) (ret *time.Time, err error) {
res := v.BitcoinVerifications(t)
for _, r := range res {
if r.Error != nil {
err = r.Error
continue
}
if ret == nil || r.AttestationTime.Before(*ret) {
ret = r.AttestationTime
}
}
return
}