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 }