Coverage Summary for Class: FederationMember (co.rsk.peg)

Class Method, % Line, %
FederationMember 45.5% (5/11) 34.5% (10/29)
FederationMember$1 100% (2/2) 55.6% (5/9)
FederationMember$2 0% (0/1) 0% (0/1)
FederationMember$KeyType 0% (0/4) 0% (0/12)
Total 38.9% (7/18) 29.4% (15/51)


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  19 package co.rsk.peg; 20  21 import co.rsk.bitcoinj.core.BtcECKey; 22 import com.google.common.primitives.UnsignedBytes; 23 import org.ethereum.crypto.ECKey; 24 import org.ethereum.util.ByteUtil; 25  26 import java.util.Arrays; 27 import java.util.Comparator; 28 import java.util.List; 29 import java.util.Objects; 30 import java.util.stream.Collectors; 31  32 /** 33  * Immutable representation of an RSK Federation member. 34  * 35  * It's composed of three public keys: one for the RSK network, one for the 36  * BTC network and one called MST of yet undefined usage. 37  * 38  * @author Ariel Mendelzon 39  */ 40 public final class FederationMember { 41  private final BtcECKey btcPublicKey; 42  private final ECKey rskPublicKey; 43  private final ECKey mstPublicKey; 44  45  public enum KeyType { 46  BTC("btc"), 47  RSK("rsk"), 48  MST("mst"); 49  50  private String value; 51  52  KeyType(String value) { 53  this.value = value; 54  } 55  56  public String getValue() { 57  return value; 58  } 59  60  public static KeyType byValue(String value) { 61  switch (value) { 62  case "rsk": 63  return KeyType.RSK; 64  case "mst": 65  return KeyType.MST; 66  case "btc": 67  return KeyType.BTC; 68  default: 69  throw new IllegalArgumentException(String.format("Invalid value for FederationMember.KeyType: %s", value)); 70  } 71  } 72  } 73  74  // To be removed when different keys per federation member feature is implemented. These are just helper 75  // methods to make it easier w.r.t. compatibility with the current approach 76  77  public static FederationMember getFederationMemberFromKey(BtcECKey pk) { 78  ECKey ethKey = ECKey.fromPublicOnly(pk.getPubKey()); 79  return new FederationMember(pk, ethKey, ethKey); 80  } 81  82  public static List<FederationMember> getFederationMembersFromKeys(List<BtcECKey> pks) { 83  return pks.stream().map(pk -> getFederationMemberFromKey(pk)).collect(Collectors.toList()); 84  } 85  86  /** 87  * Compares federation members based on their underlying keys. 88  * 89  * The total ordering is defined such that, for any two members M1, M2, 90  * 1) M1 < M2 iff BTC_PUB_KEY(M1) <lex BTC_PUB_KEY(M2) OR 91  * (BTC_PUB_KEY(M1) ==lex BTC_PUB_KEY(M2) AND 92  * RSK_PUB_KEY(M1) <lex RSK_PUB_KEY(M2)) OR 93  * (BTC_PUB_KEY(M1) ==lex BTC_PUB_KEY(M2) AND 94  * RSK_PUB_KEY(M1) ==lex RSK_PUB_KEY(M2) AND 95  * MST_PUB_KEY(M1) <lex MST_PUB_KEY(M2)) 96  * 2) M1 == M2 iff BTC_PUB_KEY(M1) ==lex BTC_PUB_KEY(M2) AND 97  * RSK_PUB_KEY(M1) ==lex RSK_PUB_KEY(M2) AND 98  * MST_PUB_KEY(M1) ==lex MST_PUB_KEY(M2) AND 99  * 3) M1 > M2 otherwise 100  * 101  * where <lex and ==lex is given by negative and zero values (resp.) of the 102  * UnsignedBytes.lexicographicalComparator() comparator. 103  */ 104  public static final Comparator<FederationMember> BTC_RSK_MST_PUBKEYS_COMPARATOR = new Comparator<FederationMember>() { 105  private Comparator<byte[]> comparator = UnsignedBytes.lexicographicalComparator(); 106  107  @Override 108  public int compare(FederationMember m1, FederationMember m2) { 109  int btcKeysComparison = comparator.compare(m1.getBtcPublicKey().getPubKey(), m2.getBtcPublicKey().getPubKey()); 110  if (btcKeysComparison == 0) { 111  int rskKeysComparison = comparator.compare(m1.getRskPublicKey().getPubKey(), m2.getRskPublicKey().getPubKey()); 112  if (rskKeysComparison == 0) { 113  return comparator.compare(m1.getMstPublicKey().getPubKey(), m2.getMstPublicKey().getPubKey()); 114  } 115  return rskKeysComparison; 116  } 117  return btcKeysComparison; 118  } 119  }; 120  121  public FederationMember(BtcECKey btcPublicKey, ECKey rskPublicKey, ECKey mstPublicKey) { 122  // Copy public keys to ensure effective immutability 123  // Make sure we always use compressed versions of public keys 124  this.btcPublicKey = BtcECKey.fromPublicOnly(btcPublicKey.getPubKeyPoint().getEncoded(true)); 125  this.rskPublicKey = ECKey.fromPublicOnly(rskPublicKey.getPubKey(true)); 126  this.mstPublicKey = ECKey.fromPublicOnly(mstPublicKey.getPubKey(true)); 127  } 128  129  public BtcECKey getBtcPublicKey() { 130  // Return a copy 131  return BtcECKey.fromPublicOnly(btcPublicKey.getPubKey()); 132  } 133  134  public ECKey getRskPublicKey() { 135  // Return a copy 136  return ECKey.fromPublicOnly(rskPublicKey.getPubKey()); 137  } 138  139  public ECKey getMstPublicKey() { 140  // Return a copy 141  return ECKey.fromPublicOnly(mstPublicKey.getPubKey()); 142  } 143  144  public ECKey getPublicKey(KeyType keyType) { 145  switch (keyType) { 146  case RSK: 147  return getRskPublicKey(); 148  case MST: 149  return getMstPublicKey(); 150  case BTC: 151  default: 152  return ECKey.fromPublicOnly(btcPublicKey.getPubKey()); 153  } 154  } 155  156  @Override 157  public String toString() { 158  return String.format( 159  "<BTC-%s, RSK-%s, MST-%s> federation member", 160  ByteUtil.toHexString(btcPublicKey.getPubKey()), 161  ByteUtil.toHexString(rskPublicKey.getPubKey()), 162  ByteUtil.toHexString(mstPublicKey.getPubKey()) 163  ); 164  } 165  166  @Override 167  public boolean equals(Object other) { 168  if (this == other) { 169  return true; 170  } 171  172  if (other == null || this.getClass() != other.getClass()) { 173  return false; 174  } 175  176  FederationMember otherFederationMember = (FederationMember) other; 177  178  return Arrays.equals(btcPublicKey.getPubKey(), otherFederationMember.btcPublicKey.getPubKey()) && 179  Arrays.equals(rskPublicKey.getPubKey(), otherFederationMember.rskPublicKey.getPubKey()) && 180  Arrays.equals(mstPublicKey.getPubKey(), otherFederationMember.mstPublicKey.getPubKey()); 181  } 182  183  @Override 184  public int hashCode() { 185  // Can use java.util.Objects.hash since both BtcECKey and ECKey have 186  // well-defined hashCode(s). 187  return Objects.hash( 188  btcPublicKey, 189  rskPublicKey, 190  mstPublicKey 191  ); 192  } 193 }