diff --git a/rskj-core/src/main/java/co/rsk/config/BridgeConstants.java b/rskj-core/src/main/java/co/rsk/config/BridgeConstants.java index 8b8046b18dc..554c6dbd268 100644 --- a/rskj-core/src/main/java/co/rsk/config/BridgeConstants.java +++ b/rskj-core/src/main/java/co/rsk/config/BridgeConstants.java @@ -21,7 +21,7 @@ import co.rsk.bitcoinj.core.BtcECKey; import co.rsk.bitcoinj.core.Coin; import co.rsk.bitcoinj.core.NetworkParameters; -import co.rsk.peg.AddressBasedAuthorizer; +import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.federation.Federation; import java.util.List; diff --git a/rskj-core/src/main/java/co/rsk/config/BridgeDevNetConstants.java b/rskj-core/src/main/java/co/rsk/config/BridgeDevNetConstants.java index f7fbf2ac168..f5843e8cded 100644 --- a/rskj-core/src/main/java/co/rsk/config/BridgeDevNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/config/BridgeDevNetConstants.java @@ -21,7 +21,7 @@ import co.rsk.bitcoinj.core.BtcECKey; import co.rsk.bitcoinj.core.Coin; import co.rsk.bitcoinj.core.NetworkParameters; -import co.rsk.peg.AddressBasedAuthorizer; +import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.federation.FederationArgs; import co.rsk.peg.federation.FederationMember; import co.rsk.peg.federation.FederationFactory; diff --git a/rskj-core/src/main/java/co/rsk/config/BridgeMainNetConstants.java b/rskj-core/src/main/java/co/rsk/config/BridgeMainNetConstants.java index 95e3e981219..c8e90640141 100644 --- a/rskj-core/src/main/java/co/rsk/config/BridgeMainNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/config/BridgeMainNetConstants.java @@ -3,7 +3,7 @@ import co.rsk.bitcoinj.core.BtcECKey; import co.rsk.bitcoinj.core.Coin; import co.rsk.bitcoinj.core.NetworkParameters; -import co.rsk.peg.AddressBasedAuthorizer; +import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.federation.FederationArgs; import co.rsk.peg.federation.FederationMember; import co.rsk.peg.federation.FederationFactory; diff --git a/rskj-core/src/main/java/co/rsk/config/BridgeRegTestConstants.java b/rskj-core/src/main/java/co/rsk/config/BridgeRegTestConstants.java index 211f7dbdd6d..43edf91c11f 100644 --- a/rskj-core/src/main/java/co/rsk/config/BridgeRegTestConstants.java +++ b/rskj-core/src/main/java/co/rsk/config/BridgeRegTestConstants.java @@ -21,7 +21,7 @@ import co.rsk.bitcoinj.core.BtcECKey; import co.rsk.bitcoinj.core.Coin; import co.rsk.bitcoinj.core.NetworkParameters; -import co.rsk.peg.AddressBasedAuthorizer; +import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.federation.FederationArgs; import co.rsk.peg.federation.FederationMember; import co.rsk.peg.federation.FederationFactory; diff --git a/rskj-core/src/main/java/co/rsk/config/BridgeTestNetConstants.java b/rskj-core/src/main/java/co/rsk/config/BridgeTestNetConstants.java index 19fbc10b12e..86447a5cebf 100644 --- a/rskj-core/src/main/java/co/rsk/config/BridgeTestNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/config/BridgeTestNetConstants.java @@ -21,7 +21,7 @@ import co.rsk.bitcoinj.core.BtcECKey; import co.rsk.bitcoinj.core.Coin; import co.rsk.bitcoinj.core.NetworkParameters; -import co.rsk.peg.AddressBasedAuthorizer; +import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.federation.FederationArgs; import co.rsk.peg.federation.FederationMember; import co.rsk.peg.federation.FederationFactory; diff --git a/rskj-core/src/main/java/co/rsk/peg/Bridge.java b/rskj-core/src/main/java/co/rsk/peg/Bridge.java index 68f9e4d5cba..0e2d73266a5 100644 --- a/rskj-core/src/main/java/co/rsk/peg/Bridge.java +++ b/rskj-core/src/main/java/co/rsk/peg/Bridge.java @@ -27,6 +27,7 @@ import co.rsk.crypto.Keccak256; import co.rsk.panic.PanicProcessor; import co.rsk.peg.BridgeMethods.BridgeMethodExecutor; +import co.rsk.peg.vote.ABICallSpec; import co.rsk.peg.bitcoin.MerkleBranch; import co.rsk.peg.federation.Federation; import co.rsk.peg.federation.FederationMember; diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeSerializationUtils.java b/rskj-core/src/main/java/co/rsk/peg/BridgeSerializationUtils.java index 2faf18dcaea..e055c9b84af 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSerializationUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSerializationUtils.java @@ -23,9 +23,12 @@ import co.rsk.config.BridgeConstants; import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; +import co.rsk.peg.vote.ABICallElection; +import co.rsk.peg.vote.ABICallSpec; import co.rsk.peg.bitcoin.CoinbaseInformation; import co.rsk.peg.federation.*; import co.rsk.peg.flyover.FlyoverFederationInformation; +import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.whitelist.OneOffWhiteListEntry; import co.rsk.peg.whitelist.UnlimitedWhiteListEntry; import org.apache.commons.lang3.tuple.Pair; diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeStorageProvider.java b/rskj-core/src/main/java/co/rsk/peg/BridgeStorageProvider.java index e1891e4850b..2962e83ece8 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeStorageProvider.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeStorageProvider.java @@ -23,10 +23,12 @@ import co.rsk.config.BridgeConstants; import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; +import co.rsk.peg.vote.ABICallElection; import co.rsk.peg.bitcoin.CoinbaseInformation; import co.rsk.peg.federation.Federation; import co.rsk.peg.federation.PendingFederation; import co.rsk.peg.flyover.FlyoverFederationInformation; +import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.whitelist.LockWhitelist; import co.rsk.peg.whitelist.LockWhitelistEntry; import co.rsk.peg.whitelist.OneOffWhiteListEntry; diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java index 9a037612fc2..cee4baf5ca6 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -20,37 +20,11 @@ import static co.rsk.peg.BridgeUtils.getRegularPegoutTxSize; import static co.rsk.peg.ReleaseTransactionBuilder.BTC_TX_VERSION_2; import static co.rsk.peg.pegin.RejectedPeginReason.INVALID_AMOUNT; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP186; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP219; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP271; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP293; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP294; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP377; - -import co.rsk.bitcoinj.core.Address; -import co.rsk.bitcoinj.core.AddressFormatException; -import co.rsk.bitcoinj.core.BtcBlock; -import co.rsk.bitcoinj.core.BtcBlockChain; -import co.rsk.bitcoinj.core.BtcECKey; -import co.rsk.bitcoinj.core.BtcTransaction; -import co.rsk.bitcoinj.core.CheckpointManager; -import co.rsk.bitcoinj.core.Coin; -import co.rsk.bitcoinj.core.Context; -import co.rsk.bitcoinj.core.InsufficientMoneyException; -import co.rsk.bitcoinj.core.NetworkParameters; -import co.rsk.bitcoinj.core.PartialMerkleTree; -import co.rsk.bitcoinj.core.Sha256Hash; -import co.rsk.bitcoinj.core.StoredBlock; -import co.rsk.bitcoinj.core.TransactionInput; -import co.rsk.bitcoinj.core.TransactionOutput; -import co.rsk.bitcoinj.core.UTXO; -import co.rsk.bitcoinj.core.UTXOProviderException; -import co.rsk.bitcoinj.core.VerificationException; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.*; + +import co.rsk.bitcoinj.core.*; import co.rsk.bitcoinj.crypto.TransactionSignature; -import co.rsk.bitcoinj.script.FastBridgeRedeemScriptParser; -import co.rsk.bitcoinj.script.Script; -import co.rsk.bitcoinj.script.ScriptBuilder; -import co.rsk.bitcoinj.script.ScriptChunk; +import co.rsk.bitcoinj.script.*; import co.rsk.bitcoinj.store.BlockStoreException; import co.rsk.bitcoinj.wallet.SendRequest; import co.rsk.bitcoinj.wallet.Wallet; @@ -58,29 +32,18 @@ import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; import co.rsk.panic.PanicProcessor; -import co.rsk.peg.bitcoin.BitcoinUtils; -import co.rsk.peg.bitcoin.CoinbaseInformation; -import co.rsk.peg.bitcoin.MerkleBranch; -import co.rsk.peg.bitcoin.RskAllowUnconfirmedCoinSelector; +import co.rsk.peg.bitcoin.*; import co.rsk.peg.btcLockSender.BtcLockSender.TxSenderAddressType; import co.rsk.peg.btcLockSender.BtcLockSenderProvider; import co.rsk.peg.federation.*; import co.rsk.peg.flyover.FlyoverFederationInformation; import co.rsk.peg.flyover.FlyoverTxResponseCodes; -import co.rsk.peg.pegin.PeginEvaluationResult; -import co.rsk.peg.pegin.PeginProcessAction; -import co.rsk.peg.pegin.RejectedPeginReason; +import co.rsk.peg.pegin.*; import co.rsk.peg.pegininstructions.PeginInstructionsException; import co.rsk.peg.pegininstructions.PeginInstructionsProvider; -import co.rsk.peg.utils.BridgeEventLogger; -import co.rsk.peg.utils.BtcTransactionFormatUtils; -import co.rsk.peg.utils.PartialMerkleTreeFormatUtils; -import co.rsk.peg.utils.RejectedPegoutReason; -import co.rsk.peg.utils.UnrefundablePeginReason; -import co.rsk.peg.whitelist.LockWhitelist; -import co.rsk.peg.whitelist.LockWhitelistEntry; -import co.rsk.peg.whitelist.OneOffWhiteListEntry; -import co.rsk.peg.whitelist.UnlimitedWhiteListEntry; +import co.rsk.peg.utils.*; +import co.rsk.peg.vote.*; +import co.rsk.peg.whitelist.*; import co.rsk.rpc.modules.trace.CallType; import co.rsk.rpc.modules.trace.ProgramSubtrace; import com.google.common.annotations.VisibleForTesting; @@ -88,23 +51,14 @@ import java.io.InputStream; import java.math.BigInteger; import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; import javax.annotation.Nullable; import org.apache.commons.lang3.tuple.Pair; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; -import org.ethereum.core.Block; -import org.ethereum.core.Repository; -import org.ethereum.core.SignatureCache; -import org.ethereum.core.Transaction; +import org.ethereum.core.*; import org.ethereum.crypto.ECKey; import org.ethereum.crypto.HashUtil; import org.ethereum.util.ByteUtil; @@ -153,7 +107,7 @@ public class BridgeSupport { // (6 blocks/hour, 24 hours/day, 30 days/month) public static final Integer BTC_TRANSACTION_CONFIRMATION_MAX_DEPTH = 4320; - private static final Logger logger = LoggerFactory.getLogger("BridgeSupport"); + private static final Logger logger = LoggerFactory.getLogger(BridgeSupport.class); private static final PanicProcessor panicProcessor = new PanicProcessor(); private static final String INVALID_ADDRESS_FORMAT_MESSAGE = "invalid address format"; @@ -2298,8 +2252,9 @@ public Integer voteFederationChange(Transaction tx, ABICallSpec callSpec) throws } // If enough votes have been reached, then actually execute the function - ABICallSpec winnerSpec = election.getWinner(); - if (winnerSpec != null) { + Optional winnerSpecOptional = election.getWinner(); + if (winnerSpecOptional.isPresent()) { + ABICallSpec winnerSpec = winnerSpecOptional.get(); try { result = executeVoteFederationChangeFunction(false, winnerSpec); } catch (IOException e) { @@ -2601,12 +2556,13 @@ public Integer voteFeePerKbChange(Transaction tx, Coin feePerKb) { return -1; } - ABICallSpec winner = feePerKbElection.getWinner(); - if (winner == null) { + Optional winnerOptional = feePerKbElection.getWinner(); + if (!winnerOptional.isPresent()) { logger.info("Successful fee per kb vote for {}", feePerKb); return 1; } + ABICallSpec winner = winnerOptional.get(); Coin winnerFee; try { winnerFee = BridgeSerializationUtils.deserializeCoin(winner.getArguments()[0]); diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java b/rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java index 9ded4b80afc..acd39675783 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java @@ -32,6 +32,7 @@ import co.rsk.peg.federation.Federation; import co.rsk.peg.flyover.FlyoverTxResponseCodes; import co.rsk.peg.utils.BtcTransactionFormatUtils; +import co.rsk.peg.vote.AddressBasedAuthorizer; import org.ethereum.config.Constants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; diff --git a/rskj-core/src/main/java/co/rsk/peg/ABICallElection.java b/rskj-core/src/main/java/co/rsk/peg/vote/ABICallElection.java similarity index 61% rename from rskj-core/src/main/java/co/rsk/peg/ABICallElection.java rename to rskj-core/src/main/java/co/rsk/peg/vote/ABICallElection.java index 1916c85fa7d..c6e8f802ea7 100644 --- a/rskj-core/src/main/java/co/rsk/peg/ABICallElection.java +++ b/rskj-core/src/main/java/co/rsk/peg/vote/ABICallElection.java @@ -16,11 +16,15 @@ * along with this program. If not, see . */ -package co.rsk.peg; +package co.rsk.peg.vote; import co.rsk.core.RskAddress; import java.util.*; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Representation of a given state of the election @@ -30,22 +34,28 @@ * @author Ariel Mendelzon */ public class ABICallElection { - private AddressBasedAuthorizer authorizer; + private static final Logger logger = LoggerFactory.getLogger(ABICallElection.class); + private final AddressBasedAuthorizer authorizer; private Map> votes; + public ABICallElection(AddressBasedAuthorizer authorizer) { + this.authorizer = authorizer; + this.votes = new HashMap<>(); + } + public ABICallElection(AddressBasedAuthorizer authorizer, Map> votes) { this.authorizer = authorizer; - this.votes = votes; + this.votes = clone(votes); validate(); } - public ABICallElection(AddressBasedAuthorizer authorizer) { - this.authorizer = authorizer; - this.votes = new HashMap<>(); + private Map> clone(Map> originalMap) { + return originalMap.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> new ArrayList<>(e.getValue()))); } public Map> getVotes() { - return votes; + return clone(votes); } public void clear() { @@ -59,47 +69,57 @@ public void clear() { * @return whether the voting succeeded */ public boolean vote(ABICallSpec callSpec, RskAddress voter) { + logger.info("[vote] Trying to register voter's {} vote ", voter); + if (!authorizer.isAuthorized(voter)) { + logger.info("[vote] Voter is not authorized."); return false; } - if (!votes.containsKey(callSpec)) { - votes.put(callSpec, new ArrayList<>()); - } - + votes.computeIfAbsent(callSpec, k -> new ArrayList<>()); List callVoters = votes.get(callSpec); if (callVoters.contains(voter)) { + logger.info("[vote] Vote has already been registered."); return false; } callVoters.add(voter); + logger.info("[vote] Vote registered successfully."); return true; } /** - * Returns the election winner abi call spec, or null if there's none + * Returns the election winner abi call spec, or empty if there's none * The vote authorizer determines the number of participants, * whereas this class determines the number of votes that * conforms a win - * @return the winner abi call spec + * @return the (optional) winner abi call spec */ - public ABICallSpec getWinner() { + public Optional getWinner() { for (Map.Entry> specVotes : votes.entrySet()) { - if (specVotes.getValue().size() >= authorizer.getRequiredAuthorizedKeys()) { - return specVotes.getKey(); + int votesSize = specVotes.getValue().size(); + if (areEnoughVotes(votesSize)) { + ABICallSpec winner = specVotes.getKey(); + logger.info("[getWinner] Winner is {} ", winner); + return Optional.of(winner); } } - return null; + return Optional.empty(); + } + + private boolean areEnoughVotes(int votesSize) { + return votesSize >= authorizer.getRequiredAuthorizedKeys(); } /** * Removes the entry votes for the current winner of the election */ public void clearWinners() { - ABICallSpec winner = getWinner(); - if (winner != null) { + Optional winnerOptional = getWinner(); + if (winnerOptional.isPresent()) { + ABICallSpec winner = winnerOptional.get(); votes.remove(winner); } } @@ -109,7 +129,7 @@ private void validate() { for (Map.Entry> specVotes : votes.entrySet()) { for (RskAddress vote : specVotes.getValue()) { if (!authorizer.isAuthorized(vote)) { - throw new RuntimeException("Unauthorized voter"); + throw new UnauthorizedVoterException("Unauthorized voter"); } } } diff --git a/rskj-core/src/main/java/co/rsk/peg/ABICallSpec.java b/rskj-core/src/main/java/co/rsk/peg/vote/ABICallSpec.java similarity index 87% rename from rskj-core/src/main/java/co/rsk/peg/ABICallSpec.java rename to rskj-core/src/main/java/co/rsk/peg/vote/ABICallSpec.java index a52ed9dde71..facc0067a13 100644 --- a/rskj-core/src/main/java/co/rsk/peg/ABICallSpec.java +++ b/rskj-core/src/main/java/co/rsk/peg/vote/ABICallSpec.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package co.rsk.peg; +package co.rsk.peg.vote; import com.google.common.primitives.SignedBytes; @@ -34,18 +34,11 @@ * @author Ariel Mendelzon */ public final class ABICallSpec { - public static final Comparator byBytesComparator = new Comparator() { - @Override - public int compare(ABICallSpec specA, ABICallSpec specB) { - return SignedBytes.lexicographicalComparator().compare( - specA.getEncoded(), - specB.getEncoded() - ); - } - }; + public static final Comparator byBytesComparator = (specA, specB) + -> SignedBytes.lexicographicalComparator().compare(specA.getEncoded(), specB.getEncoded()); - private String function; - private byte[][] arguments; + private final String function; + private final byte[][] arguments; public ABICallSpec(String function, byte[][] arguments) { this.function = function; @@ -100,7 +93,12 @@ public boolean equals(Object other) { @Override public int hashCode() { - int[] argumentsHashes = Arrays.stream(arguments).map(argument -> Arrays.hashCode(argument)).mapToInt(Integer::intValue).toArray(); + int[] argumentsHashes = Arrays + .stream(arguments) + .map(Arrays::hashCode) + .mapToInt(Integer::intValue) + .toArray(); + return Objects.hash(function, Arrays.hashCode(argumentsHashes)); } diff --git a/rskj-core/src/main/java/co/rsk/peg/ABICallVoteResult.java b/rskj-core/src/main/java/co/rsk/peg/vote/ABICallVoteResult.java similarity index 93% rename from rskj-core/src/main/java/co/rsk/peg/ABICallVoteResult.java rename to rskj-core/src/main/java/co/rsk/peg/vote/ABICallVoteResult.java index fda1416f98d..0693028a316 100644 --- a/rskj-core/src/main/java/co/rsk/peg/ABICallVoteResult.java +++ b/rskj-core/src/main/java/co/rsk/peg/vote/ABICallVoteResult.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package co.rsk.peg; +package co.rsk.peg.vote; /** * Immutable representation of the result of a vote @@ -27,8 +27,8 @@ * @author Ariel Mendelzon */ public final class ABICallVoteResult { - private boolean successful; - private Object result; + private final boolean successful; + private final Object result; public ABICallVoteResult(boolean successful, Object result) { this.successful = successful; diff --git a/rskj-core/src/main/java/co/rsk/peg/AddressBasedAuthorizer.java b/rskj-core/src/main/java/co/rsk/peg/vote/AddressBasedAuthorizer.java similarity index 94% rename from rskj-core/src/main/java/co/rsk/peg/AddressBasedAuthorizer.java rename to rskj-core/src/main/java/co/rsk/peg/vote/AddressBasedAuthorizer.java index 3ef1101b0ce..5333e94e7e3 100644 --- a/rskj-core/src/main/java/co/rsk/peg/AddressBasedAuthorizer.java +++ b/rskj-core/src/main/java/co/rsk/peg/vote/AddressBasedAuthorizer.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ -package co.rsk.peg; +package co.rsk.peg.vote; import co.rsk.core.RskAddress; import org.ethereum.core.SignatureCache; @@ -33,13 +33,13 @@ * @author Ariel Mendelzon */ public class AddressBasedAuthorizer { - public enum MinimumRequiredCalculation { ONE, MAJORITY, ALL }; + public enum MinimumRequiredCalculation { ONE, MAJORITY, ALL } protected List authorizedAddresses; protected MinimumRequiredCalculation requiredCalculation; public AddressBasedAuthorizer(List authorizedKeys, MinimumRequiredCalculation requiredCalculation) { - this.authorizedAddresses = authorizedKeys.stream().map(key -> key.getAddress()).collect(Collectors.toList()); + this.authorizedAddresses = authorizedKeys.stream().map(ECKey::getAddress).collect(Collectors.toList()); this.requiredCalculation = requiredCalculation; } diff --git a/rskj-core/src/main/java/co/rsk/peg/vote/UnauthorizedVoterException.java b/rskj-core/src/main/java/co/rsk/peg/vote/UnauthorizedVoterException.java new file mode 100644 index 00000000000..20c1a9a7e38 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/vote/UnauthorizedVoterException.java @@ -0,0 +1,7 @@ +package co.rsk.peg.vote; + +public class UnauthorizedVoterException extends RuntimeException { + + public UnauthorizedVoterException(String message) { super(message); } + +} diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSerializationUtilsTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSerializationUtilsTest.java index 1c1a1c8aa1d..345c0f70401 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSerializationUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSerializationUtilsTest.java @@ -25,11 +25,14 @@ import co.rsk.config.BridgeMainNetConstants; import co.rsk.config.BridgeTestNetConstants; import co.rsk.core.RskAddress; +import co.rsk.peg.vote.ABICallElection; +import co.rsk.peg.vote.ABICallSpec; import co.rsk.peg.bitcoin.CoinbaseInformation; import co.rsk.peg.federation.*; import co.rsk.peg.resources.TestConstants; import co.rsk.peg.utils.MerkleTreeUtils; import co.rsk.peg.flyover.FlyoverFederationInformation; +import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.whitelist.LockWhitelist; import co.rsk.peg.whitelist.LockWhitelistEntry; import co.rsk.peg.whitelist.OneOffWhiteListEntry; diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeStorageProviderTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeStorageProviderTest.java index e26affbfeab..072ebd8a2a7 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeStorageProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeStorageProviderTest.java @@ -27,9 +27,12 @@ import co.rsk.crypto.Keccak256; import co.rsk.db.MutableTrieCache; import co.rsk.db.MutableTrieImpl; +import co.rsk.peg.vote.ABICallElection; +import co.rsk.peg.vote.ABICallSpec; import co.rsk.peg.bitcoin.*; import co.rsk.peg.federation.*; import co.rsk.peg.flyover.FlyoverFederationInformation; +import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.whitelist.LockWhitelist; import co.rsk.peg.whitelist.LockWhitelistEntry; import co.rsk.peg.whitelist.OneOffWhiteListEntry; @@ -68,7 +71,6 @@ import static co.rsk.peg.federation.FederationFormatVersion.*; import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static co.rsk.peg.BridgeStorageIndexKey.*; @@ -1847,7 +1849,7 @@ void getFeePerKbElection_emptyVotes() { ABICallElection result = storageProvider.getFeePerKbElection(authorizerMock); MatcherAssert.assertThat(result.getVotes().isEmpty(), is(true)); - MatcherAssert.assertThat(result.getWinner(), nullValue()); + Assertions.assertFalse(result.getWinner().isPresent()); } @Test @@ -1879,7 +1881,7 @@ void getFeePerKbElection_withVotes() { ABICallElection result = storageProvider.getFeePerKbElection(authorizerMock); MatcherAssert.assertThat(result.getVotes(), is(electionVotes)); - MatcherAssert.assertThat(result.getWinner(), is(expectedWinner)); + Assertions.assertEquals(expectedWinner, result.getWinner().get()); } @Test diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java index b15b588f6e4..b0d30abd04b 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -30,6 +30,7 @@ import co.rsk.config.BridgeTestNetConstants; import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; +import co.rsk.peg.vote.ABICallElection; import co.rsk.peg.bitcoin.BitcoinTestUtils; import co.rsk.peg.bitcoin.CoinbaseInformation; import co.rsk.peg.bitcoin.MerkleBranch; @@ -45,6 +46,7 @@ import co.rsk.peg.utils.MerkleTreeUtils; import co.rsk.peg.pegin.RejectedPeginReason; import co.rsk.peg.utils.UnrefundablePeginReason; +import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.whitelist.LockWhitelist; import co.rsk.peg.whitelist.OneOffWhiteListEntry; import co.rsk.test.builders.BridgeSupportBuilder; diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestIntegration.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestIntegration.java index b0af957e074..5f84e1f873b 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestIntegration.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestIntegration.java @@ -22,16 +22,7 @@ import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.collection.IsCollectionWithSize.hasSize; import static org.hamcrest.core.Is.is; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyBoolean; -import static org.mockito.Mockito.anyInt; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import co.rsk.bitcoinj.core.Address; import co.rsk.bitcoinj.core.AddressFormatException; @@ -64,12 +55,15 @@ import co.rsk.crypto.Keccak256; import co.rsk.db.MutableTrieCache; import co.rsk.db.MutableTrieImpl; +import co.rsk.peg.vote.ABICallElection; +import co.rsk.peg.vote.ABICallSpec; import co.rsk.peg.bitcoin.MerkleBranch; import co.rsk.peg.btcLockSender.BtcLockSenderProvider; import co.rsk.peg.federation.*; import co.rsk.peg.pegininstructions.PeginInstructionsProvider; import co.rsk.peg.simples.SimpleBlockChain; import co.rsk.peg.utils.BridgeEventLogger; +import co.rsk.peg.vote.AddressBasedAuthorizer; import co.rsk.peg.whitelist.LockWhitelist; import co.rsk.peg.whitelist.LockWhitelistEntry; import co.rsk.peg.whitelist.OneOffWhiteListEntry; @@ -2165,8 +2159,12 @@ public Transaction getTx() { return tx; } - public ABICallSpec getWinner() { - return winner; + public Optional getWinner() { + if (winner == null) { + return Optional.empty(); + } + + return Optional.of(winner); } public void setWinner(ABICallSpec winner) { @@ -3987,15 +3985,15 @@ public void setFederationElection(ABICallElection federationElection) { return holder.getFederationElection(); }); - Mockito.doAnswer((InvocationOnMock m) -> { + doAnswer((InvocationOnMock m) -> { holder.setActiveFederation(m.getArgument(0)); return null; }).when(providerMock).setNewFederation(any()); - Mockito.doAnswer((InvocationOnMock m) -> { + doAnswer((InvocationOnMock m) -> { holder.setRetiringFederation(m.getArgument(0)); return null; }).when(providerMock).setOldFederation(any()); - Mockito.doAnswer((InvocationOnMock m) -> { + doAnswer((InvocationOnMock m) -> { holder.setPendingFederation(m.getArgument(0)); return null; }).when(providerMock).setPendingFederation(any()); diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeTestIntegration.java b/rskj-core/src/test/java/co/rsk/peg/BridgeTestIntegration.java index 384f8d354fb..2a06c2cd3f5 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeTestIntegration.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeTestIntegration.java @@ -50,6 +50,7 @@ import java.util.Set; import java.util.function.BiFunction; +import co.rsk.peg.vote.ABICallSpec; import co.rsk.peg.federation.Federation; import co.rsk.peg.federation.FederationMember; import co.rsk.test.builders.BlockChainBuilder; diff --git a/rskj-core/src/test/java/co/rsk/peg/PowpegMigrationTest.java b/rskj-core/src/test/java/co/rsk/peg/PowpegMigrationTest.java index 77d9b07f412..66750a928a0 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PowpegMigrationTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PowpegMigrationTest.java @@ -10,6 +10,7 @@ import co.rsk.crypto.Keccak256; import co.rsk.db.MutableTrieCache; import co.rsk.db.MutableTrieImpl; +import co.rsk.peg.vote.ABICallSpec; import co.rsk.peg.bitcoin.BitcoinUtils; import co.rsk.peg.bitcoin.NonStandardErpRedeemScriptBuilder; import co.rsk.peg.bitcoin.P2shErpRedeemScriptBuilder; @@ -221,7 +222,7 @@ private void testChangePowpeg( // Trying to create a new powpeg again should fail // -2 corresponds to a new powpeg was elected and the Bridge is waiting for this new powpeg to activate - attemptToCreateNewFederation(bridgeSupport, bridgeConstants, -2); + attemptToCreateNewFederation(bridgeSupport, -2); // No change in active powpeg assertEquals(oldPowPegAddress, bridgeSupport.getFederationAddress()); @@ -333,7 +334,7 @@ private void testChangePowpeg( // Trying to create a new powpeg again should fail // -3 corresponds to a new powpeg was elected and the Bridge is waiting for this new powpeg to migrate - attemptToCreateNewFederation(bridgeSupport, bridgeConstants, -3); + attemptToCreateNewFederation(bridgeSupport, -3); // peg-in after new fed activates testPegins( @@ -386,7 +387,7 @@ private void testChangePowpeg( // Trying to create a new powpeg again should fail // -3 corresponds to a new powpeg was elected and the Bridge is waiting for this new powpeg to migrate - attemptToCreateNewFederation(bridgeSupport, bridgeConstants, -3); + attemptToCreateNewFederation(bridgeSupport, -3); // Migration should start ! assertTrue(bridgeStorageProvider.getPegoutsWaitingForConfirmations().getEntries().isEmpty()); @@ -875,14 +876,14 @@ private void testPegins( private void attemptToCreateNewFederation( BridgeSupport bridgeSupport, - BridgeConstants bridgeConstants, int expectedResult) throws BridgeIllegalArgumentException { ABICallSpec createSpec = new ABICallSpec("create", new byte[][]{}); Transaction voteTx = mock(Transaction.class); - RskAddress federationChangeAuthorizer = new RskAddress( - bridgeConstants.getFederationChangeAuthorizer().authorizedAddresses.get(0) - ); + + // Known authorized address to vote the federation change + RskAddress federationChangeAuthorizer = new RskAddress("56bc5087ac97bc85a877bd20dfef910b78b1dc5a"); + when(voteTx.getSender(any())).thenReturn(federationChangeAuthorizer); int federationChangeResult = bridgeSupport.voteFederationChange(voteTx, createSpec); diff --git a/rskj-core/src/test/java/co/rsk/peg/performance/FederationChangeTest.java b/rskj-core/src/test/java/co/rsk/peg/performance/FederationChangeTest.java index ff444375388..b51089b30b9 100644 --- a/rskj-core/src/test/java/co/rsk/peg/performance/FederationChangeTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/performance/FederationChangeTest.java @@ -22,6 +22,8 @@ import co.rsk.bitcoinj.store.BtcBlockStore; import co.rsk.core.RskAddress; import co.rsk.peg.*; +import co.rsk.peg.vote.ABICallElection; +import co.rsk.peg.vote.ABICallSpec; import co.rsk.peg.federation.FederationMember; import co.rsk.peg.federation.PendingFederation; import org.ethereum.core.Repository; diff --git a/rskj-core/src/test/java/co/rsk/peg/ABICallElectionTest.java b/rskj-core/src/test/java/co/rsk/peg/vote/ABICallElectionTest.java similarity index 83% rename from rskj-core/src/test/java/co/rsk/peg/ABICallElectionTest.java rename to rskj-core/src/test/java/co/rsk/peg/vote/ABICallElectionTest.java index 47a30f21dcb..c61259ced0b 100644 --- a/rskj-core/src/test/java/co/rsk/peg/ABICallElectionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/vote/ABICallElectionTest.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package co.rsk.peg; +package co.rsk.peg.vote; import co.rsk.core.RskAddress; import org.bouncycastle.util.encoders.Hex; @@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test; import java.util.*; +import java.util.stream.Collectors; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -73,8 +74,28 @@ void emptyVotesConstructor() { } @Test - void getVotes() { - Assertions.assertSame(votes, election.getVotes()); + void getVotes_shouldNotBeSame_ButEqual_votes() { + Assertions.assertNotSame(votes, election.getVotes()); + Assertions.assertEquals(votes, election.getVotes()); + } + + @Test + void modify_votes_shouldNotChange_electionVotes() { + votes.put( + spec_fnb, + new ArrayList<>(Arrays.asList( + createVoter("cc"), + createVoter("dd") + )) + ); + + Assertions.assertNotEquals(votes, election.getVotes()); + } + + @Test + void clear_electionVotes_shouldNotChange_votes() { + election.clear(); + Assertions.assertNotEquals(votes, election.getVotes()); } @Test @@ -126,13 +147,13 @@ void vote_existingFn() { @Test void getWinnerAndClearWinners_existingFn() { - Assertions.assertNull(election.getWinner()); + Assertions.assertFalse(election.getWinner().isPresent()); Assertions.assertTrue(election.vote(spec_fnb, createVoter("ee"))); - Assertions.assertEquals(spec_fnb, election.getWinner()); + Assertions.assertEquals(spec_fnb, election.getWinner().get()); election.clearWinners(); - Assertions.assertNull(election.getWinner()); + Assertions.assertFalse(election.getWinner().isPresent()); Assertions.assertEquals(1, election.getVotes().size()); Assertions.assertEquals(Collections.emptyList(), election.getVotes().get(spec_fna)); } @@ -140,17 +161,17 @@ void getWinnerAndClearWinners_existingFn() { @Test void getWinnerAndClearWinners_newFn() { ABICallSpec spec_fnc = new ABICallSpec("fn-c", new byte[][]{ Hex.decode("44") }); - Assertions.assertNull(election.getWinner()); + Assertions.assertFalse(election.getWinner().isPresent()); Assertions.assertTrue(election.vote(spec_fnc, createVoter("ee"))); - Assertions.assertNull(election.getWinner()); + Assertions.assertFalse(election.getWinner().isPresent()); Assertions.assertTrue(election.vote(spec_fnc, createVoter("cc"))); - Assertions.assertNull(election.getWinner()); + Assertions.assertFalse(election.getWinner().isPresent()); Assertions.assertTrue(election.vote(spec_fnc, createVoter("aa"))); - Assertions.assertEquals(spec_fnc, election.getWinner()); + Assertions.assertEquals(spec_fnc, election.getWinner().get()); election.clearWinners(); - Assertions.assertNull(election.getWinner()); + Assertions.assertFalse(election.getWinner().isPresent()); Assertions.assertEquals(2, election.getVotes().size()); Assertions.assertEquals(Collections.emptyList(), election.getVotes().get(spec_fna)); Assertions.assertEquals(Arrays.asList(createVoter("aa"), createVoter("bb")), election.getVotes().get(spec_fnb)); diff --git a/rskj-core/src/test/java/co/rsk/peg/ABICallSpecTest.java b/rskj-core/src/test/java/co/rsk/peg/vote/ABICallSpecTest.java similarity index 99% rename from rskj-core/src/test/java/co/rsk/peg/ABICallSpecTest.java rename to rskj-core/src/test/java/co/rsk/peg/vote/ABICallSpecTest.java index 9bf2eba6f75..3527197f153 100644 --- a/rskj-core/src/test/java/co/rsk/peg/ABICallSpecTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/vote/ABICallSpecTest.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package co.rsk.peg; +package co.rsk.peg.vote; import org.bouncycastle.util.encoders.Hex; import org.ethereum.TestUtils; diff --git a/rskj-core/src/test/java/co/rsk/peg/AddressBasedAuthorizerTest.java b/rskj-core/src/test/java/co/rsk/peg/vote/AddressBasedAuthorizerTest.java similarity index 99% rename from rskj-core/src/test/java/co/rsk/peg/AddressBasedAuthorizerTest.java rename to rskj-core/src/test/java/co/rsk/peg/vote/AddressBasedAuthorizerTest.java index 4909b4e1d0a..761a506f024 100644 --- a/rskj-core/src/test/java/co/rsk/peg/AddressBasedAuthorizerTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/vote/AddressBasedAuthorizerTest.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package co.rsk.peg; +package co.rsk.peg.vote; import co.rsk.core.RskAddress; import org.ethereum.core.BlockTxSignatureCache;