-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathfeatures.go
140 lines (102 loc) · 3.61 KB
/
features.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
package libwallet
import (
"fmt"
)
const (
BackendFeatureTaproot = "TAPROOT"
BackendFeatureTaprootPreactivation = "TAPROOT_PREACTIVATION"
BackendFeatureApolloBiometrics = "APOLLO_BIOMETRICS"
UserActivatedFeatureStatusOff = "off"
UserActivatedFeatureStatusCanPreactivate = "can_preactivate"
UserActivatedFeatureStatusCanActivate = "can_activate"
UserActivatedFeatureStatusPreactivated = "preactivated"
UserActivatedFeatureStatusScheduledActivation = "scheduled_activation"
UserActivatedFeatureStatusActive = "active"
)
var UserActivatedFeatureTaproot UserActivatedFeature = &taprootUserActivatedFeature{}
type UserActivatedFeature interface {
Blockheight(*Network) int
RequiredKitVersion() int
BackendFeature() string
BackendPreactivationFeature() string
}
type taprootUserActivatedFeature struct {}
func (t *taprootUserActivatedFeature) Blockheight(network *Network) int {
switch network.Name() {
case Mainnet().Name():
// 709_632 is defined in the BIP and we use a 6 block safety margin
return 709_632 + 6
case Regtest().Name():
// A nice low value for testing
return 100
case Testnet().Name():
// A nice low value for testing
return 100
}
panic(fmt.Sprintf("Unexpected network: %v", network.Name()))
}
func (t *taprootUserActivatedFeature) RequiredKitVersion() int {
return EKVersionMusig
}
func (t *taprootUserActivatedFeature) BackendFeature() string {
return BackendFeatureTaproot
}
func (t *taprootUserActivatedFeature) BackendPreactivationFeature() string {
return BackendFeatureTaprootPreactivation
}
func DetermineUserActivatedFeatureStatus(
feature UserActivatedFeature,
blockHeight int,
exportedKitVersions *IntList,
backendFeatures *StringList,
network *Network,
) string {
// If the feature is turned off by houston, two things can happen:
// 1. The (pre)activation event is not enabled: ie kill switch
// 2. Activation is held-off and the status is frozen as if the network
// never activated.: ie backend feature toggle
if len(feature.BackendFeature()) > 0 &&
!backendFeatures.Contains(feature.BackendPreactivationFeature()) {
return UserActivatedFeatureStatusOff
}
activatedByHouston := len(feature.BackendFeature()) > 0 &&
backendFeatures.Contains(feature.BackendFeature())
activatedByNetwork := blockHeight >= feature.Blockheight(network)
// If the user never exported a kit, they have the feature implicitly active
if exportedKitVersions.Length() == 0 {
if activatedByNetwork && activatedByHouston {
return UserActivatedFeatureStatusActive
} else if activatedByHouston {
return UserActivatedFeatureStatusScheduledActivation
} else {
return UserActivatedFeatureStatusOff
}
}
var maxKitVersion int
for i := 0; i < exportedKitVersions.Length(); i++ {
if exportedKitVersions.Get(i) > maxKitVersion {
maxKitVersion = exportedKitVersions.Get(i)
}
}
if maxKitVersion >= feature.RequiredKitVersion() {
// If the user activated already, it's up to the network
if activatedByNetwork && activatedByHouston {
return UserActivatedFeatureStatusActive
} else if exportedKitVersions.Length() > 1 {
// If the user had pre-existing kits, then they updated
return UserActivatedFeatureStatusPreactivated
} else {
// Otherwise they just happened to export during the activation
return UserActivatedFeatureStatusScheduledActivation
}
} else {
// Otherwise it's up to the user
if !activatedByHouston {
return UserActivatedFeatureStatusOff
} else if activatedByNetwork {
return UserActivatedFeatureStatusCanActivate
} else {
return UserActivatedFeatureStatusCanPreactivate
}
}
}