Coverage Summary for Class: PendingFederation (co.rsk.peg)
Class |
Class, %
|
Method, %
|
Line, %
|
PendingFederation |
0%
(0/1)
|
0%
(0/11)
|
0%
(0/28)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 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 co.rsk.config.BridgeConstants;
23 import co.rsk.crypto.Keccak256;
24 import org.ethereum.config.blockchain.upgrades.ActivationConfig;
25 import org.ethereum.config.blockchain.upgrades.ConsensusRule;
26 import org.ethereum.crypto.HashUtil;
27
28 import java.time.Instant;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.List;
32 import java.util.Objects;
33 import java.util.stream.Collectors;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38 * Immutable representation of an RSK Pending Federation.
39 * A pending federation is one that is being actively
40 * voted by the current federation to potentially become
41 * the new active federation.
42 *
43 * @author Ariel Mendelzon
44 */
45 public final class PendingFederation {
46 private static final Logger logger = LoggerFactory.getLogger("PendingFederation");
47 private static final int MIN_MEMBERS_REQUIRED = 2;
48
49 private final List<FederationMember> members;
50
51 public PendingFederation(List<FederationMember> members) {
52 // Sorting members ensures same order for members
53 // Immutability provides protection against unwanted modification, thus making the Pending Federation instance
54 // effectively immutable
55 this.members = Collections.unmodifiableList(members.stream().sorted(FederationMember.BTC_RSK_MST_PUBKEYS_COMPARATOR).collect(Collectors.toList()));
56 }
57
58 public List<FederationMember> getMembers() {
59 // Safe to return instance since both the list and instances are immutable
60 return members;
61 }
62
63 public List<BtcECKey> getBtcPublicKeys() {
64 // Copy keys since we don't control immutability of BtcECKey(s)
65 return members.stream().map(FederationMember::getBtcPublicKey).collect(Collectors.toList());
66 }
67
68 public boolean isComplete() {
69 return this.members.size() >= MIN_MEMBERS_REQUIRED;
70 }
71
72 /**
73 * Creates a new PendingFederation with the additional specified member
74 * @param member the new federation member
75 * @return a new PendingFederation with the added member
76 */
77 public PendingFederation addMember(FederationMember member) {
78 List<FederationMember> newMembers = new ArrayList<>(members);
79 newMembers.add(member);
80 return new PendingFederation(newMembers);
81 }
82
83 /**
84 * Builds a Federation from this PendingFederation
85 * @param creationTime the creation time for the new Federation
86 * @param bridgeConstants to get the bitcoin parameters for the new Federation,
87 * and the keys for creating an ERP Federation
88 * @param activations Activation configuration to check hard fork
89 * @return a Federation
90 */
91 public Federation buildFederation(
92 Instant creationTime,
93 long blockNumber,
94 BridgeConstants bridgeConstants,
95 ActivationConfig.ForBlock activations
96 ) {
97 if (!this.isComplete()) {
98 throw new IllegalStateException("PendingFederation is incomplete");
99 }
100
101 if (activations.isActive(ConsensusRule.RSKIP201)) {
102 logger.info("[buildFederation] Going to create an ERP Federation");
103 return new ErpFederation(
104 members,
105 creationTime,
106 blockNumber,
107 bridgeConstants.getBtcParams(),
108 bridgeConstants.getErpFedPubKeysList(),
109 bridgeConstants.getErpFedActivationDelay()
110 );
111 }
112
113 return new Federation(
114 members,
115 creationTime,
116 blockNumber,
117 bridgeConstants.getBtcParams()
118 );
119 }
120
121 @Override
122 public String toString() {
123 return String.format("%d signatures pending federation (%s)", members.size(), isComplete() ? "complete" : "incomplete");
124 }
125
126 @Override
127 public boolean equals(Object other) {
128 if (this == other) {
129 return true;
130 }
131
132 if (other == null || this.getClass() != other.getClass()) {
133 return false;
134 }
135
136 return this.members.equals(((PendingFederation) other).members);
137 }
138
139 public Keccak256 getHash() {
140 byte[] encoded = BridgeSerializationUtils.serializePendingFederationOnlyBtcKeys(this);
141 return new Keccak256(HashUtil.keccak256(encoded));
142 }
143
144 @Override
145 public int hashCode() {
146 // Can use java.util.Objects.hash since List<BtcECKey> has a
147 // well-defined hashCode()
148 return Objects.hash(getBtcPublicKeys());
149 }
150 }