Coverage Summary for Class: FederationSupport (co.rsk.peg)
Class |
Method, %
|
Line, %
|
FederationSupport |
0%
(0/13)
|
0%
(0/47)
|
FederationSupport$1 |
0%
(0/1)
|
0%
(0/1)
|
FederationSupport$StorageFederationReference |
0%
(0/1)
|
0%
(0/1)
|
Total |
0%
(0/15)
|
0%
(0/49)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2018 RSK Labs Ltd.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 package co.rsk.peg;
19
20 import co.rsk.bitcoinj.core.BtcECKey;
21 import co.rsk.bitcoinj.core.UTXO;
22 import co.rsk.config.BridgeConstants;
23 import org.ethereum.core.Block;
24
25 import javax.annotation.Nullable;
26 import java.io.IOException;
27 import java.util.Collections;
28 import java.util.List;
29
30 public class FederationSupport {
31
32 private enum StorageFederationReference { NONE, NEW, OLD, GENESIS }
33
34 private final BridgeStorageProvider provider;
35 private final BridgeConstants bridgeConstants;
36 private final Block executionBlock;
37
38 public FederationSupport(BridgeConstants bridgeConstants, BridgeStorageProvider provider, Block executionBlock) {
39 this.provider = provider;
40 this.bridgeConstants = bridgeConstants;
41 this.executionBlock = executionBlock;
42 }
43
44 /**
45 * Returns the federation's size
46 * @return the federation size
47 */
48 public int getFederationSize() {
49 return getActiveFederation().getBtcPublicKeys().size();
50 }
51
52 /**
53 * Returns the BTC public key of the federation's federator at the given index
54 * @param index the federator's index (zero-based)
55 * @return the federator's public key
56 */
57 public byte[] getFederatorBtcPublicKey(int index) {
58 List<BtcECKey> publicKeys = getActiveFederation().getBtcPublicKeys();
59
60 if (index < 0 || index >= publicKeys.size()) {
61 throw new IndexOutOfBoundsException(String.format("Federator index must be between 0 and %d", publicKeys.size() - 1));
62 }
63
64 return publicKeys.get(index).getPubKey();
65 }
66
67 /**
68 * Returns the public key of given type of the federation's federator at the given index
69 * @param index the federator's index (zero-based)
70 * @param keyType the key type
71 * @return the federator's public key
72 */
73 public byte[] getFederatorPublicKeyOfType(int index, FederationMember.KeyType keyType) {
74 return getMemberPublicKeyOfType(getActiveFederation().getMembers(), index, keyType, "Federator");
75 }
76
77 /**
78 * Returns the compressed public key of given type of the member list at the given index
79 * Throws a custom index out of bounds exception when appropiate
80 * @param members the list of federation members
81 * @param index the federator's index (zero-based)
82 * @param keyType the key type
83 * @param errorPrefix the index out of bounds error prefix
84 * @return the federation member's public key
85 */
86 public byte[] getMemberPublicKeyOfType(List<FederationMember> members, int index, FederationMember.KeyType keyType, String errorPrefix) {
87 if (index < 0 || index >= members.size()) {
88 throw new IndexOutOfBoundsException(String.format("%s index must be between 0 and %d", errorPrefix, members.size() - 1));
89 }
90
91 return members.get(index).getPublicKey(keyType).getPubKey(true);
92 }
93
94 /**
95 * Returns the currently active federation.
96 * See getActiveFederationReference() for details.
97 *
98 * @return the currently active federation.
99 */
100 public Federation getActiveFederation() {
101 switch (getActiveFederationReference()) {
102 case NEW:
103 return provider.getNewFederation();
104 case OLD:
105 return provider.getOldFederation();
106 case GENESIS:
107 default:
108 return bridgeConstants.getGenesisFederation();
109 }
110 }
111
112 /**
113 * Returns the currently retiring federation.
114 * See getRetiringFederationReference() for details.
115 *
116 * @return the retiring federation.
117 */
118 @Nullable
119 public Federation getRetiringFederation() {
120 switch (getRetiringFederationReference()) {
121 case OLD:
122 return provider.getOldFederation();
123 case NONE:
124 default:
125 return null;
126 }
127 }
128
129 public List<UTXO> getActiveFederationBtcUTXOs() throws IOException {
130 switch (getActiveFederationReference()) {
131 case OLD:
132 return provider.getOldFederationBtcUTXOs();
133 case NEW:
134 case GENESIS:
135 default:
136 return provider.getNewFederationBtcUTXOs();
137 }
138 }
139
140 public List<UTXO> getRetiringFederationBtcUTXOs() throws IOException {
141 switch (getRetiringFederationReference()) {
142 case OLD:
143 return provider.getOldFederationBtcUTXOs();
144 case NONE:
145 default:
146 return Collections.emptyList();
147 }
148 }
149
150 public boolean amAwaitingFederationActivation() {
151 Federation newFederation = provider.getNewFederation();
152 Federation oldFederation = provider.getOldFederation();
153
154 return newFederation != null && oldFederation != null && !shouldFederationBeActive(newFederation);
155 }
156
157 /**
158 * Returns the currently active federation reference.
159 * Logic is as follows:
160 * When no "new" federation is recorded in the blockchain, then return GENESIS
161 * When a "new" federation is present and no "old" federation is present, then return NEW
162 * When both "new" and "old" federations are present, then
163 * 1) If the "new" federation is at least bridgeConstants::getFederationActivationAge() blocks old,
164 * return the NEW
165 * 2) Otherwise, return OLD
166 *
167 * @return a reference to where the currently active federation is stored.
168 */
169 private StorageFederationReference getActiveFederationReference() {
170 Federation newFederation = provider.getNewFederation();
171
172 // No new federation in place, then the active federation
173 // is the genesis federation
174 if (newFederation == null) {
175 return StorageFederationReference.GENESIS;
176 }
177
178 Federation oldFederation = provider.getOldFederation();
179
180 // No old federation in place, then the active federation
181 // is the new federation
182 if (oldFederation == null) {
183 return StorageFederationReference.NEW;
184 }
185
186 // Both new and old federations in place
187 // If the minimum age has gone by for the new federation's
188 // activation, then that federation is the currently active.
189 // Otherwise, the old federation is still the currently active.
190 if (shouldFederationBeActive(newFederation)) {
191 return StorageFederationReference.NEW;
192 }
193
194 return StorageFederationReference.OLD;
195 }
196
197 /**
198 * Returns the currently retiring federation reference.
199 * Logic is as follows:
200 * When no "new" or "old" federation is recorded in the blockchain, then return empty.
201 * When both "new" and "old" federations are present, then
202 * 1) If the "new" federation is at least bridgeConstants::getFederationActivationAge() blocks old,
203 * return OLD
204 * 2) Otherwise, return empty
205 *
206 * @return the retiring federation.
207 */
208 private StorageFederationReference getRetiringFederationReference() {
209 Federation newFederation = provider.getNewFederation();
210 Federation oldFederation = provider.getOldFederation();
211
212 if (oldFederation == null || newFederation == null) {
213 return StorageFederationReference.NONE;
214 }
215
216 // Both new and old federations in place
217 // If the minimum age has gone by for the new federation's
218 // activation, then the old federation is the currently retiring.
219 // Otherwise, there is no retiring federation.
220 if (shouldFederationBeActive(newFederation)) {
221 return StorageFederationReference.OLD;
222 }
223
224 return StorageFederationReference.NONE;
225 }
226
227 private boolean shouldFederationBeActive(Federation federation) {
228 long federationAge = executionBlock.getNumber() - federation.getCreationBlockNumber();
229 return federationAge >= bridgeConstants.getFederationActivationAge();
230 }
231 }