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 }