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 f5671f66edd..1c5cfb82024 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.feeperkb.FeePerKbResponseCode; import co.rsk.peg.vote.ABICallSpec; import co.rsk.peg.bitcoin.MerkleBranch; import co.rsk.peg.federation.Federation; @@ -1128,7 +1129,7 @@ public Integer voteFeePerKbChange(Object[] args) { feePerKb = Coin.valueOf(((BigInteger) args[0]).longValueExact()); } catch (Exception e) { logger.warn("Exception in voteFeePerKbChange", e); - return -10; + return FeePerKbResponseCode.GENERIC_ERROR.getCode(); } return bridgeSupport.voteFeePerKbChange(rskTx, feePerKb); diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeStorageIndexKey.java b/rskj-core/src/main/java/co/rsk/peg/BridgeStorageIndexKey.java index 5b2f30cf4e5..b4f777d1c37 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeStorageIndexKey.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeStorageIndexKey.java @@ -17,8 +17,6 @@ public enum BridgeStorageIndexKey { FEDERATION_ELECTION_KEY("federationElection"), LOCK_ONE_OFF_WHITELIST_KEY("lockWhitelist"), LOCK_UNLIMITED_WHITELIST_KEY("unlimitedLockWhitelist"), - FEE_PER_KB_KEY("feePerKb"), - FEE_PER_KB_ELECTION_KEY("feePerKbElection"), LOCKING_CAP_KEY("lockingCap"), RELEASE_REQUEST_QUEUE_WITH_TXHASH("releaseRequestQueueWithTxHash"), PEGOUTS_WAITING_FOR_CONFIRMATIONS_WITH_TXHASH_KEY("releaseTransactionSetWithTxHash"), 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 7a66814ac4a..ba85bfc198b 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeStorageProvider.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeStorageProvider.java @@ -88,9 +88,6 @@ public class BridgeStorageProvider { private LockWhitelist lockWhitelist; - private Coin feePerKb; - private ABICallElection feePerKbElection; - private Coin lockingCap; private HashMap> storageVersionEntries; @@ -547,47 +544,6 @@ public LockWhitelist getLockWhitelist() { return lockWhitelist; } - public Coin getFeePerKb() { - if (feePerKb != null) { - return feePerKb; - } - - feePerKb = safeGetFromRepository(FEE_PER_KB_KEY, BridgeSerializationUtils::deserializeCoin); - return feePerKb; - } - - public void setFeePerKb(Coin feePerKb) { - this.feePerKb = feePerKb; - } - - public void saveFeePerKb() { - if (feePerKb == null) { - return; - } - - safeSaveToRepository(FEE_PER_KB_KEY, feePerKb, BridgeSerializationUtils::serializeCoin); - } - - /** - * Save the fee per kb election - */ - public void saveFeePerKbElection() { - if (feePerKbElection == null) { - return; - } - - safeSaveToRepository(FEE_PER_KB_ELECTION_KEY, feePerKbElection, BridgeSerializationUtils::serializeElection); - } - - public ABICallElection getFeePerKbElection(AddressBasedAuthorizer authorizer) { - if (feePerKbElection != null) { - return feePerKbElection; - } - - feePerKbElection = safeGetFromRepository(FEE_PER_KB_ELECTION_KEY, data -> BridgeSerializationUtils.deserializeElection(data, authorizer)); - return feePerKbElection; - } - public void saveLockingCap() { if (activations.isActive(RSKIP134)) { safeSaveToRepository(LOCKING_CAP_KEY, this.getLockingCap(), BridgeSerializationUtils::serializeCoin); @@ -982,9 +938,6 @@ public void save() throws IOException { saveLockWhitelist(); - saveFeePerKb(); - saveFeePerKbElection(); - saveLockingCap(); saveHeightBtcTxHashAlreadyProcessed(); 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 b291258a0e3..65a1fe491d6 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -33,10 +33,14 @@ import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; import co.rsk.panic.PanicProcessor; -import co.rsk.peg.bitcoin.*; +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.btcLockSender.BtcLockSender.TxSenderAddressType; import co.rsk.peg.btcLockSender.BtcLockSenderProvider; import co.rsk.peg.federation.*; +import co.rsk.peg.feeperkb.FeePerKbSupport; import co.rsk.peg.flyover.FlyoverFederationInformation; import co.rsk.peg.flyover.FlyoverTxResponseCodes; import co.rsk.peg.pegin.*; @@ -88,9 +92,6 @@ public class BridgeSupport { public static final Integer LOCK_WHITELIST_ALREADY_EXISTS_ERROR_CODE = -1; public static final Integer LOCK_WHITELIST_UNKNOWN_ERROR_CODE = 0; public static final Integer LOCK_WHITELIST_SUCCESS_CODE = 1; - public static final Integer FEE_PER_KB_GENERIC_ERROR_CODE = -10; - public static final Integer NEGATIVE_FEE_PER_KB_ERROR_CODE = -1; - public static final Integer EXCESSIVE_FEE_PER_KB_ERROR_CODE = -2; public static final Integer BTC_TRANSACTION_CONFIRMATION_INEXISTENT_BLOCK_HASH_ERROR_CODE = -1; public static final Integer BTC_TRANSACTION_CONFIRMATION_BLOCK_NOT_IN_BEST_CHAIN_ERROR_CODE = -2; @@ -121,6 +122,7 @@ public class BridgeSupport { "rollback" )); + private final FeePerKbSupport feePerKbSupport; private final BridgeConstants bridgeConstants; private final BridgeStorageProvider provider; private final Repository rskRepository; @@ -150,6 +152,7 @@ public BridgeSupport( Block executionBlock, Context btcContext, FederationSupport federationSupport, + FeePerKbSupport feePerKbSupport, BtcBlockStoreWithCache.Factory btcBlockStoreFactory, ActivationConfig.ForBlock activations, SignatureCache signatureCache) { @@ -162,6 +165,7 @@ public BridgeSupport( this.peginInstructionsProvider = peginInstructionsProvider; this.btcContext = btcContext; this.federationSupport = federationSupport; + this.feePerKbSupport = feePerKbSupport; this.btcBlockStoreFactory = btcBlockStoreFactory; this.activations = activations; this.signatureCache = signatureCache; @@ -190,6 +194,7 @@ ActivationConfig.ForBlock getActivations() { public void save() throws IOException { provider.save(); + feePerKbSupport.save(); } /** @@ -916,19 +921,6 @@ private void requestRelease(Address destinationAddress, Coin value, Transaction } } - /** - * @return Current fee per kb in BTC. - */ - public Coin getFeePerKb() { - Coin currentFeePerKb = provider.getFeePerKb(); - - if (currentFeePerKb == null) { - currentFeePerKb = bridgeConstants.getGenesisFeePerKb(); - } - - return currentFeePerKb; - } - /** * Executed every now and then. * Performs a few tasks: processing of any pending btc funds @@ -2548,61 +2540,12 @@ public Integer removeLockWhitelistAddress(Transaction tx, String addressBase58) } } - /** - * Votes for a fee per kb value. - * - * @return 1 upon successful vote, -1 when the vote was unsuccessful, - * FEE_PER_KB_GENERIC_ERROR_CODE when there was an un expected error. - */ - public Integer voteFeePerKbChange(Transaction tx, Coin feePerKb) { - AddressBasedAuthorizer authorizer = bridgeConstants.getFeePerKbChangeAuthorizer(); - if (!authorizer.isAuthorized(tx, signatureCache)) { - return FEE_PER_KB_GENERIC_ERROR_CODE; - } - - if(!feePerKb.isPositive()){ - return NEGATIVE_FEE_PER_KB_ERROR_CODE; - } - - if(feePerKb.isGreaterThan(bridgeConstants.getMaxFeePerKb())) { - return EXCESSIVE_FEE_PER_KB_ERROR_CODE; - } - - ABICallElection feePerKbElection = provider.getFeePerKbElection(authorizer); - ABICallSpec feeVote = new ABICallSpec("setFeePerKb", new byte[][]{BridgeSerializationUtils.serializeCoin(feePerKb)}); - boolean successfulVote = feePerKbElection.vote(feeVote, tx.getSender(signatureCache)); - if (!successfulVote) { - return -1; - } - - 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]); - } catch (Exception e) { - logger.warn("Exception deserializing winner feePerKb", e); - return FEE_PER_KB_GENERIC_ERROR_CODE; - } - - if (winnerFee == null) { - logger.warn("Invalid winner feePerKb: feePerKb can't be null"); - return FEE_PER_KB_GENERIC_ERROR_CODE; - } - - if (!winnerFee.equals(feePerKb)) { - logger.debug("Winner fee is different than the last vote: maybe you forgot to clear winners"); - } + public Coin getFeePerKb() { + return feePerKbSupport.getFeePerKb(); + } - logger.info("Fee per kb changed to {}", winnerFee); - provider.setFeePerKb(winnerFee); - feePerKbElection.clear(); - return 1; + public Integer voteFeePerKbChange(Transaction tx, Coin feePerKb) { + return feePerKbSupport.voteFeePerKbChange(tx, feePerKb, signatureCache); } /** diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeSupportFactory.java b/rskj-core/src/main/java/co/rsk/peg/BridgeSupportFactory.java index eedfb287b49..1b8236a354b 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupportFactory.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupportFactory.java @@ -22,6 +22,13 @@ import co.rsk.core.RskAddress; import co.rsk.peg.BtcBlockStoreWithCache.Factory; import co.rsk.peg.btcLockSender.BtcLockSenderProvider; +import co.rsk.peg.feeperkb.FeePerKbStorageProvider; +import co.rsk.peg.feeperkb.FeePerKbSupport; +import co.rsk.peg.feeperkb.constants.FeePerKbConstants; +import co.rsk.peg.storage.StorageAccessor; +import co.rsk.peg.storage.BridgeStorageAccessorImpl; +import co.rsk.peg.feeperkb.FeePerKbStorageProviderImpl; +import co.rsk.peg.feeperkb.FeePerKbSupportImpl; import co.rsk.peg.pegininstructions.PeginInstructionsProvider; import co.rsk.peg.utils.BridgeEventLogger; import co.rsk.peg.utils.BridgeEventLoggerImpl; @@ -59,6 +66,8 @@ public BridgeSupport newInstance(Repository repository, Block executionBlock, ActivationConfig.ForBlock activations = activationConfig.forBlock(executionBlock.getNumber()); Context btcContext = new Context(bridgeConstants.getBtcParams()); + StorageAccessor bridgeStorageAccessor = new BridgeStorageAccessorImpl(repository); + BridgeStorageProvider provider = new BridgeStorageProvider( repository, contractAddress, @@ -67,6 +76,7 @@ public BridgeSupport newInstance(Repository repository, Block executionBlock, ); FederationSupport federationSupport = new FederationSupport(bridgeConstants, provider, executionBlock, activations); + FeePerKbSupport feePerKbSupport = newFeePerKbSupportInstance(bridgeStorageAccessor, bridgeConstants); BridgeEventLogger eventLogger; if (logs == null) { @@ -92,9 +102,16 @@ public BridgeSupport newInstance(Repository repository, Block executionBlock, executionBlock, btcContext, federationSupport, + feePerKbSupport, btcBlockStoreFactory, activations, signatureCache ); } + + private FeePerKbSupport newFeePerKbSupportInstance(StorageAccessor bridgeStorageAccessor, BridgeConstants bridgeConstants) { + FeePerKbConstants feePerKbConstants = bridgeConstants.getFeePerKbConstants(); + FeePerKbStorageProvider feePerKbStorageProvider = new FeePerKbStorageProviderImpl(bridgeStorageAccessor); + return new FeePerKbSupportImpl(feePerKbConstants, feePerKbStorageProvider); + } } 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 89979f5c14f..7a791b68197 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java @@ -30,6 +30,7 @@ import co.rsk.peg.bitcoin.RskAllowUnconfirmedCoinSelector; import co.rsk.peg.btcLockSender.BtcLockSender.TxSenderAddressType; import co.rsk.peg.federation.Federation; +import co.rsk.peg.feeperkb.constants.FeePerKbConstants; import co.rsk.peg.flyover.FlyoverTxResponseCodes; import co.rsk.peg.utils.BtcTransactionFormatUtils; import co.rsk.peg.vote.AddressBasedAuthorizer; @@ -402,14 +403,20 @@ public static boolean isFreeBridgeTx(Transaction rskTx, Constants constants, Act // must be the genesis federation. // Once the original federation changes, txs are always paid. return PrecompiledContracts.BRIDGE_ADDR.equals(receiveAddress) && - !activations.isActive(ConsensusRule.ARE_BRIDGE_TXS_PAID) && - rskTx.acceptTransactionSignature(constants.getChainId()) && - ( - isFromGenesisFederation(senderAddress, bridgeConstants.getGenesisFederationPublicKeys()) || - isFromFederationChangeAuthorizedSender(rskTx, bridgeConstants, signatureCache) || - isFromLockWhitelistChangeAuthorizedSender(rskTx, bridgeConstants, signatureCache) || - isFromFeePerKbChangeAuthorizedSender(rskTx, bridgeConstants, signatureCache) - ); + !activations.isActive(ConsensusRule.ARE_BRIDGE_TXS_PAID) && + rskTx.acceptTransactionSignature(constants.getChainId()) && + ( + isFromGenesisFederation(senderAddress, bridgeConstants.getGenesisFederationPublicKeys()) || + isFromAuthorizedSender(rskTx, bridgeConstants, signatureCache) + ); + } + + private static boolean isFromAuthorizedSender(Transaction rskTx, BridgeConstants bridgeConstants, SignatureCache signatureCache) { + FeePerKbConstants feePerKbConstants = bridgeConstants.getFeePerKbConstants(); + + return isFromFederationChangeAuthorizedSender(rskTx, bridgeConstants, signatureCache) || + isFromLockWhitelistChangeAuthorizedSender(rskTx, bridgeConstants, signatureCache) || + isFromFeePerKbChangeAuthorizedSender(rskTx, feePerKbConstants, signatureCache); } /** @@ -462,8 +469,8 @@ private static boolean isFromLockWhitelistChangeAuthorizedSender(Transaction rsk return authorizer.isAuthorized(rskTx, signatureCache); } - private static boolean isFromFeePerKbChangeAuthorizedSender(Transaction rskTx, BridgeConstants bridgeConfiguration, SignatureCache signatureCache) { - AddressBasedAuthorizer authorizer = bridgeConfiguration.getFeePerKbChangeAuthorizer(); + private static boolean isFromFeePerKbChangeAuthorizedSender(org.ethereum.core.Transaction rskTx, FeePerKbConstants feePerKbConstants, SignatureCache signatureCache) { + AddressBasedAuthorizer authorizer = feePerKbConstants.getFeePerKbChangeAuthorizer(); return authorizer.isAuthorized(rskTx, signatureCache); } diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeConstants.java index 579890fac06..0a629ec7431 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeConstants.java @@ -24,6 +24,7 @@ import co.rsk.peg.vote.AddressBasedAuthorizer; import java.util.List; +import co.rsk.peg.feeperkb.constants.FeePerKbConstants; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; @@ -31,8 +32,12 @@ public abstract class BridgeConstants { protected String btcParamsString; + + protected FeePerKbConstants feePerKbConstants; + protected List genesisFederationPublicKeys; protected Instant genesisFederationCreationTime; + protected int btc2RskMinimumAcceptableConfirmations; protected int btc2RskMinimumAcceptableConfirmationsOnRsk; protected int rsk2BtcMinimumAcceptableConfirmations; @@ -57,11 +62,6 @@ public abstract class BridgeConstants { protected AddressBasedAuthorizer lockWhitelistChangeAuthorizer; - protected AddressBasedAuthorizer feePerKbChangeAuthorizer; - - protected Coin genesisFeePerKb; - protected Coin maxFeePerKb; - protected AddressBasedAuthorizer increaseLockingCapAuthorizer; protected Coin initialLockingCap; @@ -92,6 +92,8 @@ public NetworkParameters getBtcParams() { return NetworkParameters.fromID(btcParamsString); } + public FeePerKbConstants getFeePerKbConstants() { return feePerKbConstants; } + public String getBtcParamsString() { return btcParamsString; } @@ -148,18 +150,12 @@ public long getFundsMigrationAgeSinceActivationEnd(ActivationConfig.ForBlock act public AddressBasedAuthorizer getLockWhitelistChangeAuthorizer() { return lockWhitelistChangeAuthorizer; } - public AddressBasedAuthorizer getFeePerKbChangeAuthorizer() { return feePerKbChangeAuthorizer; } - public AddressBasedAuthorizer getIncreaseLockingCapAuthorizer() { return increaseLockingCapAuthorizer; } public int getLockingCapIncrementsMultiplier() { return lockingCapIncrementsMultiplier; } public Coin getInitialLockingCap() { return initialLockingCap; } - public Coin getGenesisFeePerKb() { return genesisFeePerKb; } - - public Coin getMaxFeePerKb() { return maxFeePerKb; } - public Coin getMaxRbtc() { return Coin.valueOf(21_000_000, 0); } public int getBtcHeightWhenBlockIndexActivates() { return btcHeightWhenBlockIndexActivates; } diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeDevNetConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeDevNetConstants.java index 34ef167cf1f..5f730c6969b 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeDevNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeDevNetConstants.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; + import org.bouncycastle.util.encoders.Hex; import org.ethereum.crypto.ECKey; @@ -98,19 +99,6 @@ public BridgeDevNetConstants(List federationPublicKeys) { fundsMigrationAgeSinceActivationEnd = 100L; specialCaseFundsMigrationAgeSinceActivationEnd = 100L; - // Key generated with GenNodeKey using generator 'auth-fee-per-kb' - List feePerKbAuthorizedKeys = Arrays.stream(new String[]{ - "0430c7d0146029db553d60cf11e8d39df1c63979ee2e4cd1e4d4289a5d88cfcbf3a09b06b5cbc88b5bfeb4b87a94cefab81c8d44655e7e813fc3e18f51cfe7e8a0" - }).map(hex -> ECKey.fromPublicOnly(Hex.decode(hex))).collect(Collectors.toList()); - - feePerKbChangeAuthorizer = new AddressBasedAuthorizer( - feePerKbAuthorizedKeys, - AddressBasedAuthorizer.MinimumRequiredCalculation.MAJORITY - ); - - genesisFeePerKb = Coin.MILLICOIN; - maxFeePerKb = Coin.valueOf(5_000_000L); - // Key generated with GenNodeKey using generator 'auth-increase_locking_cap' List increaseLockingCapAuthorizedKeys = Arrays.stream(new String[]{ "04450bbaab83ec48b3cb8fbb077c950ee079733041c039a8c4f1539e5181ca1a27589eeaf0fbf430e49d2909f14c767bf6909ad6845831f683416ee12b832e36ed" diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeMainNetConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeMainNetConstants.java index 23a929ca823..1a023ac24af 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeMainNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeMainNetConstants.java @@ -3,6 +3,7 @@ import co.rsk.bitcoinj.core.BtcECKey; import co.rsk.bitcoinj.core.Coin; import co.rsk.bitcoinj.core.NetworkParameters; +import co.rsk.peg.feeperkb.constants.FeePerKbMainNetConstants; import co.rsk.peg.vote.AddressBasedAuthorizer; import com.google.common.collect.Lists; import java.time.ZonedDateTime; @@ -15,8 +16,9 @@ public class BridgeMainNetConstants extends BridgeConstants { private static final BridgeMainNetConstants instance = new BridgeMainNetConstants(); - BridgeMainNetConstants() { + private BridgeMainNetConstants() { btcParamsString = NetworkParameters.ID_MAINNET; + feePerKbConstants = FeePerKbMainNetConstants.getInstance(); BtcECKey federator0PublicKey = BtcECKey.fromPublicOnly(Hex.decode("03b53899c390573471ba30e5054f78376c5f797fda26dde7a760789f02908cbad2")); BtcECKey federator1PublicKey = BtcECKey.fromPublicOnly(Hex.decode("027319afb15481dbeb3c426bcc37f9a30e7f51ceff586936d85548d9395bcc2344")); @@ -83,20 +85,6 @@ public class BridgeMainNetConstants extends BridgeConstants { fundsMigrationAgeSinceActivationEnd = 10585L; specialCaseFundsMigrationAgeSinceActivationEnd = 172_800L; // 60 days, considering 1 block every 30 seconds - List feePerKbAuthorizedKeys = Arrays.stream(new String[]{ - "0448f51638348b034995b1fd934fe14c92afde783e69f120a46ee16eb6bdc2e4f6b5e37772094c68c0dea2b1be3d96ea9651a9eebda7304914c8047f4e3e251378", - "0484c66f75548baf93e322574adac4e4579b6a53f8d11fab640e14c90118e6983ef24b0de349a3e88f72e81e771ae1c897cef446fd7f4da71778c532aee3b6c41b", - "04bb6435dc1ea12da843ebe213893d136c1624acd681fff82551498ae00bf28e9323164b00daf925fa75177463b8254a2aae8a1713e4d851a84ea369c193e9ce51" - }).map(hex -> ECKey.fromPublicOnly(Hex.decode(hex))).collect(Collectors.toList()); - - feePerKbChangeAuthorizer = new AddressBasedAuthorizer( - feePerKbAuthorizedKeys, - AddressBasedAuthorizer.MinimumRequiredCalculation.MAJORITY - ); - - genesisFeePerKb = Coin.MILLICOIN.multiply(5); - maxFeePerKb = Coin.valueOf(5_000_000L); - List increaseLockingCapAuthorizedKeys = Arrays.stream(new String[]{ "0448f51638348b034995b1fd934fe14c92afde783e69f120a46ee16eb6bdc2e4f6b5e37772094c68c0dea2b1be3d96ea9651a9eebda7304914c8047f4e3e251378", "0484c66f75548baf93e322574adac4e4579b6a53f8d11fab640e14c90118e6983ef24b0de349a3e88f72e81e771ae1c897cef446fd7f4da71778c532aee3b6c41b", diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeRegTestConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeRegTestConstants.java index 489450bf6cb..38d58ab24f0 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeRegTestConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeRegTestConstants.java @@ -28,6 +28,7 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import co.rsk.peg.feeperkb.constants.FeePerKbRegTestConstants; import org.bouncycastle.util.encoders.Hex; import org.ethereum.crypto.ECKey; import org.ethereum.crypto.HashUtil; @@ -48,6 +49,7 @@ public class BridgeRegTestConstants extends BridgeConstants { public BridgeRegTestConstants(List federationPublicKeys) { btcParamsString = NetworkParameters.ID_REGTEST; + feePerKbConstants = FeePerKbRegTestConstants.getInstance(); genesisFederationPublicKeys = federationPublicKeys; genesisFederationCreationTime = ZonedDateTime.parse("2016-01-01T00:00:00Z").toInstant(); @@ -96,20 +98,6 @@ public BridgeRegTestConstants(List federationPublicKeys) { AddressBasedAuthorizer.MinimumRequiredCalculation.ONE ); - // Key generated with GenNodeKey using generator 'auth-fee-per-kb' - List feePerKbAuthorizedKeys = Arrays.stream(new String[]{ - "0430c7d0146029db553d60cf11e8d39df1c63979ee2e4cd1e4d4289a5d88cfcbf3a09b06b5cbc88b5bfeb4b87a94cefab81c8d44655e7e813fc3e18f51cfe7e8a0" - }).map(hex -> ECKey.fromPublicOnly(Hex.decode(hex))).collect(Collectors.toList()); - - feePerKbChangeAuthorizer = new AddressBasedAuthorizer( - feePerKbAuthorizedKeys, - AddressBasedAuthorizer.MinimumRequiredCalculation.MAJORITY - ); - - genesisFeePerKb = Coin.MILLICOIN; - - maxFeePerKb = Coin.valueOf(5_000_000L); - initialLockingCap = Coin.COIN.multiply(1_000L); // 1_000 BTC lockingCapIncrementsMultiplier = 2; diff --git a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNetConstants.java b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNetConstants.java index 9c66118bcca..0b51e75feee 100644 --- a/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/peg/constants/BridgeTestNetConstants.java @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import co.rsk.peg.feeperkb.constants.FeePerKbTestNetConstants; import org.bouncycastle.util.encoders.Hex; import org.ethereum.crypto.ECKey; @@ -34,6 +35,7 @@ public class BridgeTestNetConstants extends BridgeConstants { BridgeTestNetConstants() { btcParamsString = NetworkParameters.ID_TESTNET; + feePerKbConstants = FeePerKbTestNetConstants.getInstance(); BtcECKey federator0PublicKey = BtcECKey.fromPublicOnly( Hex.decode("039a060badbeb24bee49eb2063f616c0f0f0765d4ca646b20a88ce828f259fcdb9") @@ -99,20 +101,6 @@ public class BridgeTestNetConstants extends BridgeConstants { fundsMigrationAgeSinceActivationEnd = 900L; specialCaseFundsMigrationAgeSinceActivationEnd = 900L; - List feePerKbAuthorizedKeys = Arrays.stream(new String[]{ - "04701d1d27f8c2ae97912d96fb1f82f10c2395fd320e7a869049268c6b53d2060dfb2e22e3248955332d88cd2ae29a398f8f3858e48dd6d8ffbc37dfd6d1aa4934", - "045ef89e4a5645dc68895dbc33b4c966c3a0a52bb837ecdd2ba448604c4f47266456d1191420e1d32bbe8741f8315fde4d1440908d400e5998dbed6549d499559b", - "0455db9b3867c14e84a6f58bd2165f13bfdba0703cb84ea85788373a6a109f3717e40483aa1f8ef947f435ccdf10e530dd8b3025aa2d4a7014f12180ee3a301d27" - }).map(hex -> ECKey.fromPublicOnly(Hex.decode(hex))).collect(Collectors.toList()); - - feePerKbChangeAuthorizer = new AddressBasedAuthorizer( - feePerKbAuthorizedKeys, - AddressBasedAuthorizer.MinimumRequiredCalculation.MAJORITY - ); - - genesisFeePerKb = Coin.MILLICOIN; - maxFeePerKb = Coin.valueOf(5_000_000L); - List increaseLockingCapAuthorizedKeys = Arrays.stream(new String[]{ "04701d1d27f8c2ae97912d96fb1f82f10c2395fd320e7a869049268c6b53d2060dfb2e22e3248955332d88cd2ae29a398f8f3858e48dd6d8ffbc37dfd6d1aa4934", "045ef89e4a5645dc68895dbc33b4c966c3a0a52bb837ecdd2ba448604c4f47266456d1191420e1d32bbe8741f8315fde4d1440908d400e5998dbed6549d499559b", diff --git a/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbResponseCode.java b/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbResponseCode.java new file mode 100644 index 00000000000..a4953c45163 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbResponseCode.java @@ -0,0 +1,20 @@ +package co.rsk.peg.feeperkb; + +public enum FeePerKbResponseCode { + SUCCESSFUL_VOTE(1), + UNSUCCESSFUL_VOTE(-1), + EXCESSIVE_FEE_VOTED(-2), + NEGATIVE_FEE_VOTED(-1), + UNAUTHORIZED_CALLER(-10), + GENERIC_ERROR(-10); + + private final int code; + + FeePerKbResponseCode(int code) { + this.code = code; + } + + public int getCode() { + return code; + } +} diff --git a/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbStorageProvider.java b/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbStorageProvider.java new file mode 100644 index 00000000000..22a4366bf9e --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbStorageProvider.java @@ -0,0 +1,19 @@ +package co.rsk.peg.feeperkb; + +import co.rsk.bitcoinj.core.Coin; +import co.rsk.peg.vote.ABICallElection; +import co.rsk.peg.vote.AddressBasedAuthorizer; + +import java.util.Optional; + +public interface FeePerKbStorageProvider { + + void setFeePerKb(Coin feePerKb); + + Optional getFeePerKb(); + + ABICallElection getFeePerKbElection(AddressBasedAuthorizer authorizer); + + void save(); + +} diff --git a/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbStorageProviderImpl.java b/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbStorageProviderImpl.java new file mode 100644 index 00000000000..fd2f715ae12 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbStorageProviderImpl.java @@ -0,0 +1,69 @@ +package co.rsk.peg.feeperkb; + +import co.rsk.bitcoinj.core.Coin; +import co.rsk.peg.BridgeSerializationUtils; +import co.rsk.peg.storage.StorageAccessor; +import co.rsk.peg.vote.ABICallElection; +import co.rsk.peg.vote.AddressBasedAuthorizer; + +import java.util.Optional; + +import static co.rsk.peg.storage.FeePerKbStorageIndexKey.FEE_PER_KB_ELECTION; +import static co.rsk.peg.storage.FeePerKbStorageIndexKey.FEE_PER_KB; + +public class FeePerKbStorageProviderImpl implements FeePerKbStorageProvider { + private final StorageAccessor bridgeStorageAccessor; + private Coin feePerKb; + private ABICallElection feePerKbElection; + + public FeePerKbStorageProviderImpl(StorageAccessor bridgeStorageAccessor) { + this.bridgeStorageAccessor = bridgeStorageAccessor; + } + + @Override + public void setFeePerKb(Coin feePerKb) { + this.feePerKb = feePerKb; + } + + private void saveFeePerKb() { + if (feePerKb == null) { + return; + } + + bridgeStorageAccessor.safeSaveToRepository(FEE_PER_KB.getKey(), feePerKb, BridgeSerializationUtils::serializeCoin); + } + + @Override + public Optional getFeePerKb() { + if (feePerKb != null) { + return Optional.of(feePerKb); + } + + feePerKb = bridgeStorageAccessor.safeGetFromRepository(FEE_PER_KB.getKey(), BridgeSerializationUtils::deserializeCoin); + return Optional.ofNullable(feePerKb); + } + + private void saveFeePerKbElection() { + if (feePerKbElection == null) { + return; + } + + bridgeStorageAccessor.safeSaveToRepository(FEE_PER_KB_ELECTION.getKey(), feePerKbElection, BridgeSerializationUtils::serializeElection); + } + + @Override + public ABICallElection getFeePerKbElection(AddressBasedAuthorizer authorizer) { + if (feePerKbElection != null) { + return feePerKbElection; + } + + feePerKbElection = bridgeStorageAccessor.safeGetFromRepository(FEE_PER_KB_ELECTION.getKey(), data -> BridgeSerializationUtils.deserializeElection(data, authorizer)); + return feePerKbElection; + } + + @Override + public void save() { + saveFeePerKb(); + saveFeePerKbElection(); + } +} diff --git a/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbSupport.java b/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbSupport.java new file mode 100644 index 00000000000..3bc5a63a475 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbSupport.java @@ -0,0 +1,30 @@ +package co.rsk.peg.feeperkb; + +import co.rsk.bitcoinj.core.Coin; +import org.ethereum.core.SignatureCache; +import org.ethereum.core.Transaction; + +public interface FeePerKbSupport { + + /** + * @return Current fee per kb in BTC. + */ + Coin getFeePerKb(); + + /** + * Votes for a fee per kb value. + * + * @return + * UNAUTHORIZED fee per kb response code when the signature is not authorized to vote. + * NEGATIVE fee per kb response code when fee is not positive. + * EXCESSIVE fee per kb response code when fee is greater than the maximum fee allowed. + * UNSUCCESSFUL fee per kb response code when the vote was unsuccessful. + * GENERIC fee per kb response code when there was an unexpected error. + * SUCCESSFUL fee per kb response code when the vote was successful. + */ + Integer voteFeePerKbChange(Transaction tx, Coin feePerKb, SignatureCache signatureCache); + + + void save(); + +} diff --git a/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbSupportImpl.java b/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbSupportImpl.java new file mode 100644 index 00000000000..4c9448b5af2 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/feeperkb/FeePerKbSupportImpl.java @@ -0,0 +1,100 @@ +package co.rsk.peg.feeperkb; + +import co.rsk.peg.vote.*; +import co.rsk.bitcoinj.core.Coin; +import co.rsk.peg.BridgeSerializationUtils; +import co.rsk.peg.feeperkb.constants.*; +import org.ethereum.core.SignatureCache; +import org.ethereum.core.Transaction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Optional; + +public class FeePerKbSupportImpl implements FeePerKbSupport { + + private static final Logger logger = LoggerFactory.getLogger(FeePerKbSupportImpl.class); + private static final String SET_FEE_PER_KB_ABI_FUNCTION = "setFeePerKb"; + + private final FeePerKbStorageProvider provider; + private final FeePerKbConstants feePerKbConstants; + + public FeePerKbSupportImpl(FeePerKbConstants feePerKbConstants, FeePerKbStorageProvider provider) { + this.provider = provider; + this.feePerKbConstants = feePerKbConstants; + } + + @Override + public Coin getFeePerKb() { + Optional currentFeePerKb = provider.getFeePerKb(); + + return currentFeePerKb.orElseGet(feePerKbConstants::getGenesisFeePerKb); + } + + @Override + public Integer voteFeePerKbChange(Transaction tx, Coin feePerKb, SignatureCache signatureCache) { + + logger.info("[voteFeePerKbChange] Voting new fee per kb value: {}", feePerKb); + + AddressBasedAuthorizer authorizer = feePerKbConstants.getFeePerKbChangeAuthorizer(); + Coin maxFeePerKb = feePerKbConstants.getMaxFeePerKb(); + + if (!authorizer.isAuthorized(tx, signatureCache)) { + logger.warn("[voteFeePerKbChange] Unauthorized signature."); + return FeePerKbResponseCode.UNAUTHORIZED_CALLER.getCode(); + } + + if (!feePerKb.isPositive()){ + logger.warn("[voteFeePerKbChange] Negative fee."); + return FeePerKbResponseCode.NEGATIVE_FEE_VOTED.getCode(); + } + + if (feePerKb.isGreaterThan(maxFeePerKb)) { + logger.warn("[voteFeePerKbChange] Fee greater than maximum."); + return FeePerKbResponseCode.EXCESSIVE_FEE_VOTED.getCode(); + } + + ABICallElection feePerKbElection = provider.getFeePerKbElection(authorizer); + ABICallSpec feeVote = new ABICallSpec(SET_FEE_PER_KB_ABI_FUNCTION, new byte[][]{BridgeSerializationUtils.serializeCoin(feePerKb)}); + boolean successfulVote = feePerKbElection.vote(feeVote, tx.getSender(signatureCache)); + if (!successfulVote) { + logger.warn("[voteFeePerKbChange] Unsuccessful {} vote", feeVote); + return FeePerKbResponseCode.UNSUCCESSFUL_VOTE.getCode(); + } + + Optional winnerOptional = feePerKbElection.getWinner(); + if (!winnerOptional.isPresent()) { + logger.info("[voteFeePerKbChange] Successful fee per kb vote for {}", feePerKb); + return FeePerKbResponseCode.SUCCESSFUL_VOTE.getCode(); + } + + ABICallSpec winner = winnerOptional.get(); + Coin winnerFee; + try { + winnerFee = BridgeSerializationUtils.deserializeCoin(winner.getArguments()[0]); + } catch (Exception e) { + logger.warn("[voteFeePerKbChange] Exception deserializing winner feePerKb", e); + return FeePerKbResponseCode.GENERIC_ERROR.getCode(); + } + + if (winnerFee == null) { + logger.warn("[voteFeePerKbChange] Invalid winner feePerKb: feePerKb can't be null"); + return FeePerKbResponseCode.GENERIC_ERROR.getCode(); + } + + if (!winnerFee.equals(feePerKb)) { + logger.debug("[voteFeePerKbChange] Winner fee is different than the last vote: maybe you forgot to clear winners"); + } + + logger.info("[voteFeePerKbChange] Fee per kb changed to {}", winnerFee); + provider.setFeePerKb(winnerFee); + feePerKbElection.clear(); + + return FeePerKbResponseCode.SUCCESSFUL_VOTE.getCode(); + } + + @Override + public void save() { + provider.save(); + } +} diff --git a/rskj-core/src/main/java/co/rsk/peg/feeperkb/constants/FeePerKbConstants.java b/rskj-core/src/main/java/co/rsk/peg/feeperkb/constants/FeePerKbConstants.java new file mode 100644 index 00000000000..9832deea8ff --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/feeperkb/constants/FeePerKbConstants.java @@ -0,0 +1,19 @@ +package co.rsk.peg.feeperkb.constants; + +import co.rsk.bitcoinj.core.Coin; +import co.rsk.peg.vote.AddressBasedAuthorizer; + +public class FeePerKbConstants { + + protected Coin genesisFeePerKb; + + protected Coin maxFeePerKb; + + protected AddressBasedAuthorizer feePerKbChangeAuthorizer; + + public Coin getGenesisFeePerKb() { return genesisFeePerKb; } + + public Coin getMaxFeePerKb() { return maxFeePerKb; } + + public AddressBasedAuthorizer getFeePerKbChangeAuthorizer() { return feePerKbChangeAuthorizer; } +} diff --git a/rskj-core/src/main/java/co/rsk/peg/feeperkb/constants/FeePerKbMainNetConstants.java b/rskj-core/src/main/java/co/rsk/peg/feeperkb/constants/FeePerKbMainNetConstants.java new file mode 100644 index 00000000000..1d4ef3f4340 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/feeperkb/constants/FeePerKbMainNetConstants.java @@ -0,0 +1,36 @@ +package co.rsk.peg.feeperkb.constants; + +import co.rsk.bitcoinj.core.Coin; +import co.rsk.peg.vote.AddressBasedAuthorizer; +import org.bouncycastle.util.encoders.Hex; +import org.ethereum.crypto.ECKey; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class FeePerKbMainNetConstants extends FeePerKbConstants { + + private static final FeePerKbMainNetConstants instance = new FeePerKbMainNetConstants(); + + private FeePerKbMainNetConstants() { + List feePerKbAuthorizedKeys = Arrays.stream(new String[]{ + "0448f51638348b034995b1fd934fe14c92afde783e69f120a46ee16eb6bdc2e4f6b5e37772094c68c0dea2b1be3d96ea9651a9eebda7304914c8047f4e3e251378", + "0484c66f75548baf93e322574adac4e4579b6a53f8d11fab640e14c90118e6983ef24b0de349a3e88f72e81e771ae1c897cef446fd7f4da71778c532aee3b6c41b", + "04bb6435dc1ea12da843ebe213893d136c1624acd681fff82551498ae00bf28e9323164b00daf925fa75177463b8254a2aae8a1713e4d851a84ea369c193e9ce51" + }).map(hex -> ECKey.fromPublicOnly(Hex.decode(hex))).collect(Collectors.toList()); + + feePerKbChangeAuthorizer = new AddressBasedAuthorizer( + feePerKbAuthorizedKeys, + AddressBasedAuthorizer.MinimumRequiredCalculation.MAJORITY + ); + + genesisFeePerKb = Coin.MILLICOIN.multiply(5); + + maxFeePerKb = Coin.valueOf(5_000_000L); + } + + public static FeePerKbMainNetConstants getInstance() { + return instance; + } +} diff --git a/rskj-core/src/main/java/co/rsk/peg/feeperkb/constants/FeePerKbRegTestConstants.java b/rskj-core/src/main/java/co/rsk/peg/feeperkb/constants/FeePerKbRegTestConstants.java new file mode 100644 index 00000000000..c4df2904823 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/feeperkb/constants/FeePerKbRegTestConstants.java @@ -0,0 +1,35 @@ +package co.rsk.peg.feeperkb.constants; + +import co.rsk.bitcoinj.core.Coin; +import co.rsk.peg.vote.AddressBasedAuthorizer; +import org.bouncycastle.util.encoders.Hex; +import org.ethereum.crypto.ECKey; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class FeePerKbRegTestConstants extends FeePerKbConstants { + + private static final FeePerKbRegTestConstants instance = new FeePerKbRegTestConstants(); + + private FeePerKbRegTestConstants() { + // Key generated with GenNodeKey using generator 'auth-fee-per-kb' + List feePerKbAuthorizedKeys = Arrays.stream(new String[]{ + "0430c7d0146029db553d60cf11e8d39df1c63979ee2e4cd1e4d4289a5d88cfcbf3a09b06b5cbc88b5bfeb4b87a94cefab81c8d44655e7e813fc3e18f51cfe7e8a0" + }).map(hex -> ECKey.fromPublicOnly(Hex.decode(hex))).collect(Collectors.toList()); + + feePerKbChangeAuthorizer = new AddressBasedAuthorizer( + feePerKbAuthorizedKeys, + AddressBasedAuthorizer.MinimumRequiredCalculation.MAJORITY + ); + + genesisFeePerKb = Coin.MILLICOIN; + + maxFeePerKb = Coin.valueOf(5_000_000L); + } + + public static FeePerKbRegTestConstants getInstance() { + return instance; + } +} diff --git a/rskj-core/src/main/java/co/rsk/peg/feeperkb/constants/FeePerKbTestNetConstants.java b/rskj-core/src/main/java/co/rsk/peg/feeperkb/constants/FeePerKbTestNetConstants.java new file mode 100644 index 00000000000..ffd4d1bd134 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/feeperkb/constants/FeePerKbTestNetConstants.java @@ -0,0 +1,36 @@ +package co.rsk.peg.feeperkb.constants; + +import co.rsk.bitcoinj.core.Coin; +import co.rsk.peg.vote.AddressBasedAuthorizer; +import org.bouncycastle.util.encoders.Hex; +import org.ethereum.crypto.ECKey; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class FeePerKbTestNetConstants extends FeePerKbConstants { + + private static final FeePerKbTestNetConstants instance = new FeePerKbTestNetConstants(); + + private FeePerKbTestNetConstants() { + List feePerKbAuthorizedKeys = Arrays.stream(new String[]{ + "04701d1d27f8c2ae97912d96fb1f82f10c2395fd320e7a869049268c6b53d2060dfb2e22e3248955332d88cd2ae29a398f8f3858e48dd6d8ffbc37dfd6d1aa4934", + "045ef89e4a5645dc68895dbc33b4c966c3a0a52bb837ecdd2ba448604c4f47266456d1191420e1d32bbe8741f8315fde4d1440908d400e5998dbed6549d499559b", + "0455db9b3867c14e84a6f58bd2165f13bfdba0703cb84ea85788373a6a109f3717e40483aa1f8ef947f435ccdf10e530dd8b3025aa2d4a7014f12180ee3a301d27" + }).map(hex -> ECKey.fromPublicOnly(Hex.decode(hex))).collect(Collectors.toList()); + + feePerKbChangeAuthorizer = new AddressBasedAuthorizer( + feePerKbAuthorizedKeys, + AddressBasedAuthorizer.MinimumRequiredCalculation.MAJORITY + ); + + genesisFeePerKb = Coin.MILLICOIN; + + maxFeePerKb = Coin.valueOf(5_000_000L); + } + + public static FeePerKbTestNetConstants getInstance() { + return instance; + } +} diff --git a/rskj-core/src/main/java/co/rsk/peg/storage/BridgeStorageAccessorImpl.java b/rskj-core/src/main/java/co/rsk/peg/storage/BridgeStorageAccessorImpl.java new file mode 100644 index 00000000000..b666be187c2 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/storage/BridgeStorageAccessorImpl.java @@ -0,0 +1,49 @@ +package co.rsk.peg.storage; + +import co.rsk.core.RskAddress; +import org.ethereum.core.Repository; +import org.ethereum.vm.DataWord; +import org.ethereum.vm.PrecompiledContracts; + +import java.io.IOException; + +public class BridgeStorageAccessorImpl implements StorageAccessor { + + private static final RskAddress CONTRACT_ADDRESS = PrecompiledContracts.BRIDGE_ADDR; + private final Repository repository; + + public BridgeStorageAccessorImpl(Repository repository) { + this.repository = repository; + } + + @Override + public T safeGetFromRepository(DataWord keyAddress, RepositoryDeserializer deserializer) { + try { + return getFromRepository(keyAddress, deserializer); + } catch (IOException ioe) { + throw new StorageAccessException("Unable to get from repository: " + keyAddress, ioe); + } + } + + private T getFromRepository(DataWord keyAddress, RepositoryDeserializer deserializer) throws IOException { + byte[] data = repository.getStorageBytes(CONTRACT_ADDRESS, keyAddress); + return deserializer.deserialize(data); + } + + @Override + public void safeSaveToRepository(DataWord addressKey, T object, RepositorySerializer serializer) { + try { + saveToRepository(addressKey, object, serializer); + } catch (IOException ioe) { + throw new StorageAccessException("Unable to save to repository: " + addressKey, ioe); + } + } + + private void saveToRepository(DataWord addressKey, T object, RepositorySerializer serializer) throws IOException { + byte[] data = null; + if (object != null) { + data = serializer.serialize(object); + } + repository.addStorageBytes(CONTRACT_ADDRESS, addressKey, data); + } +} diff --git a/rskj-core/src/main/java/co/rsk/peg/storage/FeePerKbStorageIndexKey.java b/rskj-core/src/main/java/co/rsk/peg/storage/FeePerKbStorageIndexKey.java new file mode 100644 index 00000000000..eabac1b0166 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/storage/FeePerKbStorageIndexKey.java @@ -0,0 +1,20 @@ +package co.rsk.peg.storage; + +import org.ethereum.vm.DataWord; + +public enum FeePerKbStorageIndexKey { + FEE_PER_KB("feePerKb"), + FEE_PER_KB_ELECTION("feePerKbElection") + ; + + private final String key; + + FeePerKbStorageIndexKey(String key) { + this.key = key; + } + + public DataWord getKey() { + return DataWord.fromString(key); + } + +} diff --git a/rskj-core/src/main/java/co/rsk/peg/storage/StorageAccessException.java b/rskj-core/src/main/java/co/rsk/peg/storage/StorageAccessException.java new file mode 100644 index 00000000000..aa52041e8ea --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/storage/StorageAccessException.java @@ -0,0 +1,15 @@ +package co.rsk.peg.storage; + +public class StorageAccessException extends RuntimeException { + public StorageAccessException() { + super(); + } + + public StorageAccessException(String s) { + super(s); + } + + public StorageAccessException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/rskj-core/src/main/java/co/rsk/peg/storage/StorageAccessor.java b/rskj-core/src/main/java/co/rsk/peg/storage/StorageAccessor.java new file mode 100644 index 00000000000..7bd2510e429 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/storage/StorageAccessor.java @@ -0,0 +1,18 @@ +package co.rsk.peg.storage; + +import org.ethereum.vm.DataWord; + +public interface StorageAccessor { + + T safeGetFromRepository(DataWord key, RepositoryDeserializer deserializer); + + void safeSaveToRepository(DataWord key, T value, RepositorySerializer serializer); + + interface RepositoryDeserializer { + T deserialize(byte[] value); + } + + interface RepositorySerializer { + byte[] serialize(T value); + } +} diff --git a/rskj-core/src/main/java/co/rsk/peg/vote/ABICallSpec.java b/rskj-core/src/main/java/co/rsk/peg/vote/ABICallSpec.java index facc0067a13..c41516a1f8b 100644 --- a/rskj-core/src/main/java/co/rsk/peg/vote/ABICallSpec.java +++ b/rskj-core/src/main/java/co/rsk/peg/vote/ABICallSpec.java @@ -88,16 +88,16 @@ public boolean equals(Object other) { ABICallSpec otherSpec = ((ABICallSpec) other); return otherSpec.getFunction().equals(getFunction()) && - areEqual(arguments, otherSpec.arguments); + areEqual(arguments, otherSpec.arguments); } @Override public int hashCode() { int[] argumentsHashes = Arrays - .stream(arguments) - .map(Arrays::hashCode) - .mapToInt(Integer::intValue) - .toArray(); + .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/vote/ABICallVoteResult.java b/rskj-core/src/main/java/co/rsk/peg/vote/ABICallVoteResult.java index 0693028a316..cfbacda876f 100644 --- a/rskj-core/src/main/java/co/rsk/peg/vote/ABICallVoteResult.java +++ b/rskj-core/src/main/java/co/rsk/peg/vote/ABICallVoteResult.java @@ -42,4 +42,4 @@ public boolean wasSuccessful() { public Object getResult() { return result; } -} \ No newline at end of file +} diff --git a/rskj-core/src/main/java/co/rsk/peg/vote/AddressBasedAuthorizer.java b/rskj-core/src/main/java/co/rsk/peg/vote/AddressBasedAuthorizer.java index 5333e94e7e3..de8cb2594d3 100644 --- a/rskj-core/src/main/java/co/rsk/peg/vote/AddressBasedAuthorizer.java +++ b/rskj-core/src/main/java/co/rsk/peg/vote/AddressBasedAuthorizer.java @@ -45,7 +45,7 @@ public AddressBasedAuthorizer(List authorizedKeys, MinimumRequiredCalcula public boolean isAuthorized(RskAddress sender) { return authorizedAddresses.stream() - .anyMatch(address -> Arrays.equals(address, sender.getBytes())); + .anyMatch(address -> Arrays.equals(address, sender.getBytes())); } public boolean isAuthorized(Transaction tx, SignatureCache signatureCache) { 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 6b83d9955fa..05b6b2c896d 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeStorageProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeStorageProviderTest.java @@ -28,7 +28,6 @@ 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.constants.BridgeConstants; import co.rsk.peg.constants.BridgeMainNetConstants; @@ -1333,7 +1332,7 @@ void getLockWhitelist_nonNullBytes() { NetworkParameters parameters = invocation.getArgument(1); assertEquals(NetworkParameters.fromID(NetworkParameters.ID_TESTNET), parameters); // Make sure we're deserializing what just came from the repo with the correct AddressBasedAuthorizer - assertTrue(Arrays.equals(new byte[]{(byte) 0xaa}, data)); + assertArrayEquals(new byte[]{(byte) 0xaa}, data); HashMap map = new HashMap<>(); map.put(oneOffEntry.address(), oneOffEntry); return Pair.of(map, 0); @@ -1346,7 +1345,7 @@ void getLockWhitelist_nonNullBytes() { NetworkParameters parameters = invocation.getArgument(1); assertEquals(NetworkParameters.fromID(NetworkParameters.ID_TESTNET), parameters); // Make sure we're deserializing what just came from the repo with the correct AddressBasedAuthorizer - assertTrue(Arrays.equals(new byte[]{(byte) 0xbb}, unlimitedData)); + assertArrayEquals(new byte[]{(byte) 0xbb}, unlimitedData); HashMap map = new HashMap<>(); map.put(unlimitedEntry.address(), unlimitedEntry); return map; @@ -1671,12 +1670,6 @@ void getPegoutsWaitingForConfirmations_after_rskip_146_activation() throws IOExc new PegoutsWaitingForConfirmations.Entry(new BtcTransaction(networkParameters), 1L) )); - Set newEntriesSet = new HashSet<>(Collections.singletonList( - new PegoutsWaitingForConfirmations.Entry(new BtcTransaction(networkParameters), - 1L, - PegTestUtils.createHash3(0) - ))); - Repository repositoryMock = mock(Repository.class); when(repositoryMock.getStorageBytes(any(RskAddress.class), eq(PEGOUTS_WAITING_FOR_CONFIRMATIONS.getKey()))) @@ -1803,91 +1796,6 @@ void getReleaseTransaction_after_rskip_146_activations() throws IOException { Assertions.assertEquals(0, provider.getPegoutsWaitingForSignatures().size()); } - @Test - void setFeePerKb_savedAndRecreated() { - Repository repository = createRepository(); - Repository track = repository.startTracking(); - - BridgeStorageProvider provider0 = new BridgeStorageProvider( - track, - PrecompiledContracts.BRIDGE_ADDR, - bridgeTestnetInstance, - activationsBeforeFork - ); - - Coin expectedCoin = Coin.valueOf(5325); - provider0.setFeePerKb(expectedCoin); - provider0.saveFeePerKb(); - track.commit(); - - track = repository.startTracking(); - - BridgeStorageProvider provider = new BridgeStorageProvider( - track, - PrecompiledContracts.BRIDGE_ADDR, - bridgeTestnetInstance, - activationsBeforeFork - ); - - MatcherAssert.assertThat(provider.getFeePerKb(), is(expectedCoin)); - } - - @Test - void getFeePerKbElection_emptyVotes() { - AddressBasedAuthorizer authorizerMock = mock(AddressBasedAuthorizer.class); - Repository repositoryMock = mock(Repository.class); - BridgeStorageProvider storageProvider = new BridgeStorageProvider( - repositoryMock, - mockAddress("aabbccdd"), - bridgeTestnetInstance, - activationsBeforeFork - ); - - HashMap> electionVotes = new HashMap<>(); - byte[] serializedElection = BridgeSerializationUtils.serializeElection( - new ABICallElection(authorizerMock, electionVotes)); - when(repositoryMock.getStorageBytes( - any(RskAddress.class), - any(DataWord.class) - )).thenReturn(serializedElection); - - ABICallElection result = storageProvider.getFeePerKbElection(authorizerMock); - MatcherAssert.assertThat(result.getVotes().isEmpty(), is(true)); - Assertions.assertFalse(result.getWinner().isPresent()); - } - - @Test - void getFeePerKbElection_withVotes() { - AddressBasedAuthorizer authorizerMock = mock(AddressBasedAuthorizer.class); - Repository repositoryMock = mock(Repository.class); - when(authorizerMock.getRequiredAuthorizedKeys()).thenReturn(1); - when(authorizerMock.isAuthorized(any(RskAddress.class))).thenReturn(true); - BridgeStorageProvider storageProvider = new BridgeStorageProvider( - repositoryMock, - mockAddress("aabbccdd"), - bridgeTestnetInstance, - activationsBeforeFork - ); - - byte[] electionFee = new byte[] {0x43, 0x19}; - ABICallSpec expectedWinner = new ABICallSpec("setFeePerKb", new byte[][]{electionFee}); - List voters = new ArrayList<>(); - voters.add(new RskAddress("0000000000000000000000000000000000001321")); - voters.add(new RskAddress("0000000000000000000000000000000000004049")); - HashMap> electionVotes = new HashMap<>(); - electionVotes.put(expectedWinner, voters); - byte[] serializedElection = BridgeSerializationUtils.serializeElection( - new ABICallElection(authorizerMock, electionVotes)); - when(repositoryMock.getStorageBytes( - any(RskAddress.class), - any(DataWord.class) - )).thenReturn(serializedElection); - - ABICallElection result = storageProvider.getFeePerKbElection(authorizerMock); - MatcherAssert.assertThat(result.getVotes(), is(electionVotes)); - Assertions.assertEquals(expectedWinner, result.getWinner().get()); - } - @Test void setLockingCap_before_fork() { Repository repository = mock(Repository.class); @@ -2164,7 +2072,7 @@ void getCoinBaseInformation_before_RSKIP143() { CoinbaseInformation result = provider.getCoinbaseInformation(hash); assertNull(result); - verify(repository, never()).getStorageBytes(PrecompiledContracts.BRIDGE_ADDR, DataWord.fromLongString("coinbaseInformation-" + hash.toString())); + verify(repository, never()).getStorageBytes(PrecompiledContracts.BRIDGE_ADDR, DataWord.fromLongString("coinbaseInformation-" + hash)); } @Test @@ -2174,7 +2082,7 @@ void getCoinBaseInformation_after_RSKIP143() { Sha256Hash hash = Sha256Hash.ZERO_HASH; CoinbaseInformation coinbaseInformation = new CoinbaseInformation(Sha256Hash.ZERO_HASH); - when(repository.getStorageBytes(PrecompiledContracts.BRIDGE_ADDR, DataWord.fromLongString("coinbaseInformation-" + hash.toString()))) + when(repository.getStorageBytes(PrecompiledContracts.BRIDGE_ADDR, DataWord.fromLongString("coinbaseInformation-" + hash))) .thenReturn(BridgeSerializationUtils.serializeCoinbaseInformation(coinbaseInformation)); BridgeStorageProvider provider = new BridgeStorageProvider( @@ -2283,7 +2191,7 @@ void saveCoinBaseInformation_after_RSKIP143() throws IOException { verify(repository, times(1)).addStorageBytes( PrecompiledContracts.BRIDGE_ADDR, - DataWord.fromLongString("coinbaseInformation-" + hash.toString()), + DataWord.fromLongString("coinbaseInformation-" + hash), BridgeSerializationUtils.serializeCoinbaseInformation(coinbaseInformation) ); } @@ -2607,7 +2515,7 @@ void isFlyoverFederationDerivationHashUsed_afterRSKIP176_returnTrue() { when(repository.getStorageBytes( PrecompiledContracts.BRIDGE_ADDR, - DataWord.fromLongString("fastBridgeHashUsedInBtcTx-" + btcTxHash.toString() + derivationHash.toString())) + DataWord.fromLongString("fastBridgeHashUsedInBtcTx-" + btcTxHash + derivationHash)) ).thenReturn(new byte[]{FAST_BRIDGE_FEDERATION_SCRIPT_HASH_TRUE_VALUE_TEST}); BridgeStorageProvider provider = new BridgeStorageProvider( @@ -2651,7 +2559,7 @@ void isFlyoverFederationDerivationHashUsed_storageReturnsNull_returnFalse() { when(repository.getStorageBytes( PrecompiledContracts.BRIDGE_ADDR, - DataWord.fromLongString("fastBridgeHashUsedInBtcTx-" + btcTxHash.toString() + derivationHash.toString())) + DataWord.fromLongString("fastBridgeHashUsedInBtcTx-" + btcTxHash + derivationHash)) ).thenReturn(null); ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); @@ -2677,7 +2585,7 @@ void isFlyoverFederationDerivationHashUsed_storageReturnsEmpty_returnFalse() { when(repository.getStorageBytes( PrecompiledContracts.BRIDGE_ADDR, - DataWord.fromLongString("fastBridgeHashUsedInBtcTx-" + btcTxHash.toString() + derivationHash.toString())) + DataWord.fromLongString("fastBridgeHashUsedInBtcTx-" + btcTxHash + derivationHash)) ).thenReturn(new byte[]{}); ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); @@ -2703,7 +2611,7 @@ void isFlyoverFederationDerivationHashUsed_storageReturnsWrongValue_returnFalse( when(repository.getStorageBytes( PrecompiledContracts.BRIDGE_ADDR, - DataWord.fromLongString("fastBridgeHashUsedInBtcTx-" + btcTxHash.toString() + derivationHash.toString())) + DataWord.fromLongString("fastBridgeHashUsedInBtcTx-" + btcTxHash + derivationHash)) ).thenReturn(new byte[]{(byte) 0}); ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); @@ -3272,7 +3180,7 @@ void saveReceiveHeadersLastTimestamp_after_RSKIP200() throws IOException { bridgeTestnetInstance, activationsAllForks ); - Long timeInMillis = System.currentTimeMillis(); + long timeInMillis = System.currentTimeMillis(); provider.setReceiveHeadersLastTimestamp(timeInMillis); provider.save(); @@ -3509,13 +3417,12 @@ void getReleaseRequestQueueSize_when_releaseRequestQueue_is_not_null() throws IO } private void testGetOldFederation(Federation oldFederation, ActivationConfig.ForBlock activations) { - BridgeConstants bridgeConstants = bridgeTestnetInstance; List storageCalls = new ArrayList<>(); Repository repositoryMock = mock(Repository.class); BridgeStorageProvider storageProvider = new BridgeStorageProvider( repositoryMock, mockAddress("aabbccdd"), - bridgeConstants, + bridgeTestnetInstance, activations ); @@ -3599,11 +3506,10 @@ private void testSaveOldFederation(Federation oldFederation, int version, Activa private void testGetNewFederationPostMultiKey(Federation federation) { List storageCalls = new ArrayList<>(); Repository repositoryMock = mock(Repository.class); - BridgeConstants bridgeConstants = bridgeTestnetInstance; BridgeStorageProvider storageProvider = new BridgeStorageProvider( repositoryMock, mockAddress("aabbccdd"), - bridgeConstants, + bridgeTestnetInstance, mock(ActivationConfig.ForBlock.class) ); diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportAddSignatureTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportAddSignatureTest.java index f1966ab576d..d0b7e26836e 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportAddSignatureTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportAddSignatureTest.java @@ -1,5 +1,6 @@ package co.rsk.peg; +import co.rsk.peg.feeperkb.FeePerKbSupport; import java.time.Instant; import java.math.BigInteger; import java.util.*; @@ -96,6 +97,7 @@ void addSignature_fedPubKey_belongs_to_active_federation() throws Exception { Federation activeFederation = FederationFactory.buildStandardMultiSigFederation(activeFedArgs); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); BridgeSupport bridgeSupport = new BridgeSupport( bridgeRegTestConstants, provider, @@ -106,6 +108,7 @@ void addSignature_fedPubKey_belongs_to_active_federation() throws Exception { mock(Block.class), new Context(bridgeRegTestConstants.getBtcParams()), mockFederationSupport, + feePerKbSupport, null, null, null @@ -128,6 +131,7 @@ void addSignature_fedPubKey_belongs_to_retiring_federation() throws Exception { //Setup FederationSupport mockFederationSupport = mock(FederationSupport.class); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); BridgeSupport bridgeSupport = new BridgeSupport( bridgeRegTestConstants, provider, @@ -138,6 +142,7 @@ void addSignature_fedPubKey_belongs_to_retiring_federation() throws Exception { mock(Block.class), new Context(bridgeRegTestConstants.getBtcParams()), mockFederationSupport, + feePerKbSupport, null, null, null @@ -191,6 +196,7 @@ void addSignature_fedPubKey_no_belong_to_retiring_or_active_federation() throws //Setup FederationSupport mockFederationSupport = mock(FederationSupport.class); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); BridgeSupport bridgeSupport = new BridgeSupport( bridgeRegTestConstants, provider, @@ -201,6 +207,7 @@ void addSignature_fedPubKey_no_belong_to_retiring_or_active_federation() throws mock(Block.class), new Context(bridgeRegTestConstants.getBtcParams()), mockFederationSupport, + feePerKbSupport, null, null, null diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportFlyoverTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportFlyoverTest.java index 3b771f6a7de..2c4ece49930 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportFlyoverTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportFlyoverTest.java @@ -17,32 +17,24 @@ */ package co.rsk.peg; -import co.rsk.bitcoinj.core.Address; -import co.rsk.bitcoinj.core.BtcECKey; -import co.rsk.bitcoinj.core.BtcTransaction; -import co.rsk.bitcoinj.core.Coin; -import co.rsk.bitcoinj.core.Context; -import co.rsk.bitcoinj.core.NetworkParameters; -import co.rsk.bitcoinj.core.PartialMerkleTree; -import co.rsk.bitcoinj.core.ScriptException; -import co.rsk.bitcoinj.core.Sha256Hash; -import co.rsk.bitcoinj.core.TransactionWitness; -import co.rsk.bitcoinj.core.UTXO; +import co.rsk.bitcoinj.core.*; import co.rsk.bitcoinj.script.FastBridgeRedeemScriptParser; import co.rsk.bitcoinj.script.Script; import co.rsk.bitcoinj.script.ScriptBuilder; import co.rsk.bitcoinj.store.BlockStoreException; import co.rsk.bitcoinj.wallet.Wallet; +import co.rsk.peg.bitcoin.BitcoinTestUtils; +import co.rsk.peg.btcLockSender.BtcLockSender; import co.rsk.peg.constants.BridgeConstants; import co.rsk.peg.constants.BridgeMainNetConstants; import co.rsk.peg.constants.BridgeRegTestConstants; import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; import co.rsk.peg.bitcoin.CoinbaseInformation; -import co.rsk.peg.btcLockSender.BtcLockSender; import co.rsk.peg.btcLockSender.BtcLockSenderProvider; import co.rsk.peg.federation.Federation; import co.rsk.peg.federation.FederationTestUtils; +import co.rsk.peg.feeperkb.FeePerKbSupport; import co.rsk.peg.flyover.FlyoverFederationInformation; import co.rsk.peg.flyover.FlyoverTxResponseCodes; import co.rsk.peg.pegininstructions.PeginInstructionsProvider; @@ -63,28 +55,18 @@ import java.io.IOException; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; import static co.rsk.peg.PegTestUtils.createBech32Output; import static co.rsk.peg.PegTestUtils.createP2pkhOutput; import static co.rsk.peg.PegTestUtils.createP2shOutput; -import static co.rsk.peg.PegTestUtils.createRandomP2PKHBtcAddress; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import static co.rsk.peg.BridgeSupportTestUtil.*; class BridgeSupportFlyoverTest { @@ -107,7 +89,7 @@ void setUpOnEachTest() { } private BtcTransaction createBtcTransactionWithOutputToAddress(Coin amount, Address btcAddress) { - return PegTestUtils.createBtcTransactionWithOutputToAddress(btcRegTestParams, amount, btcAddress); + return BitcoinTestUtils.createBtcTransactionWithOutputToAddress(btcRegTestParams, amount, btcAddress); } private BigInteger sendFundsToActiveFederation( @@ -131,8 +113,8 @@ private BigInteger sendFundsToActiveFederation( BridgeStorageProvider provider = mock(BridgeStorageProvider.class); when(provider.getNewFederation()).thenReturn(activeFederation); - Address userRefundBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); - Address lpBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); + Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "refund"); + Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "lp"); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); @@ -182,7 +164,7 @@ private BigInteger sendFundsToActiveFederation( co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( bridgeConstants.getBtcParams(), 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), merkleRoot, 1, 1, @@ -273,8 +255,8 @@ private BigInteger sendFundsToRetiringFederation( when(provider.getNewFederation()).thenReturn(activeFederation); when(provider.getOldFederation()).thenReturn(retiringFederation); - Address userRefundBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); - Address lpBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); + Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "refund"); + Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "lp"); Repository repository = createRepository(); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); @@ -325,7 +307,7 @@ private BigInteger sendFundsToRetiringFederation( co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( bridgeConstants.getBtcParams(), 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), merkleRoot, 1, 1, @@ -417,8 +399,8 @@ private BigInteger sendFundsToActiveAndRetiringFederation( when(provider.getNewFederation()).thenReturn(activeFederation); when(provider.getOldFederation()).thenReturn(retiringFederation); - Address userRefundBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); - Address lpBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); + Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "refund"); + Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "lp"); Repository repository = createRepository(); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); @@ -477,7 +459,7 @@ private BigInteger sendFundsToActiveAndRetiringFederation( co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( bridgeConstants.getBtcParams(), 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), merkleRoot, 1, 1, @@ -585,8 +567,8 @@ private BigInteger sendFundsToAnyAddress( when(provider.getNewFederation()).thenReturn(activeFederation); when(provider.getOldFederation()).thenReturn(retiringFederation); - Address userRefundBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); - Address lpBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); + Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "refund"); + Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "lp"); Repository repository = createRepository(); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); @@ -641,7 +623,7 @@ private BigInteger sendFundsToAnyAddress( co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( bridgeConstants.getBtcParams(), 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), merkleRoot, 1, 1, @@ -695,13 +677,11 @@ private BigInteger sendFundsSurpassesLockingCapToAnyAddress( when(activations.isActive(ConsensusRule.RSKIP176)).thenReturn(true); when(activations.isActive(ConsensusRule.RSKIP293)).thenReturn(isRskip293Active); - BridgeConstants bridgeConstants = spy(this.bridgeConstantsRegtest); - Context btcContext = mock(Context.class); - doReturn(bridgeConstants.getBtcParams()).when(btcContext).getParams(); + doReturn(bridgeConstantsRegtest.getBtcParams()).when(btcContext).getParams(); - Federation activeFederation = PegTestUtils.createFederation(bridgeConstants, "fa03", "fa04"); - Federation retiringFederation = PegTestUtils.createFederation(bridgeConstants, "fa01", "fa02"); + Federation activeFederation = PegTestUtils.createFederation(bridgeConstantsRegtest, "fa03", "fa04"); + Federation retiringFederation = PegTestUtils.createFederation(bridgeConstantsRegtest, "fa01", "fa02"); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); when(provider.getNewFederation()).thenReturn(activeFederation); @@ -711,27 +691,32 @@ private BigInteger sendFundsSurpassesLockingCapToAnyAddress( PegoutsWaitingForConfirmations pegoutsWaitingForConfirmations = new PegoutsWaitingForConfirmations(new HashSet<>()); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(pegoutsWaitingForConfirmations); - Address userRefundBtcAddress = createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); - Address lpBtcAddress = createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); + Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstantsRegtest.getBtcParams(), "refund"); + Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstantsRegtest.getBtcParams(), "lp"); Repository repository = createRepository(); // For simplicity of this test, the max rbtc value is set as the current balance for the repository // This simulates that no pegin has ever been processed - repository.addBalance(PrecompiledContracts.BRIDGE_ADDR, co.rsk.core.Coin.fromBitcoin(bridgeConstantsRegtest.getMaxRbtc())); + repository.addBalance(PrecompiledContracts.BRIDGE_ADDR, co.rsk.core.Coin.fromBitcoin( + this.bridgeConstantsRegtest.getMaxRbtc())); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); - when(mockFactory.newInstance(repository, bridgeConstants, provider, activations)).thenReturn(btcBlockStore); + when(mockFactory.newInstance(repository, bridgeConstantsRegtest, provider, activations)).thenReturn(btcBlockStore); Block executionBlock = Mockito.mock(Block.class); when(executionBlock.getNumber()).thenReturn(10L); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = bridgeSupportBuilder .withProvider(provider) - .withBridgeConstants(bridgeConstants) + .withBridgeConstants(bridgeConstantsRegtest) .withActivations(activations) .withBtcBlockStoreFactory(mockFactory) .withExecutionBlock(executionBlock) .withRepository(repository) + .withFeePerKbSupport(feePerKbSupport) .build(); Keccak256 derivationArgumentsHash = PegTestUtils.createHash3(0); @@ -744,21 +729,22 @@ private BigInteger sendFundsSurpassesLockingCapToAnyAddress( ); Address activeFederationAddress = PegTestUtils.getFlyoverAddressFromRedeemScript( - bridgeConstants, + bridgeConstantsRegtest, activeFederation.getRedeemScript(), Sha256Hash.wrap(flyoverDerivationHash.getBytes()) ); Address retiringFederationAddress = PegTestUtils.getFlyoverAddressFromRedeemScript( - bridgeConstants, + bridgeConstantsRegtest, retiringFederation.getRedeemScript(), Sha256Hash.wrap(flyoverDerivationHash.getBytes()) ); - BtcTransaction btcTx = btcTransactionProvider.provide(bridgeConstants, activeFederationAddress, retiringFederationAddress); + BtcTransaction btcTx = btcTransactionProvider.provide(bridgeConstantsRegtest, activeFederationAddress, retiringFederationAddress); btcTx.addInput( Sha256Hash.ZERO_HASH, - 0, ScriptBuilder.createInputScript(null, new BtcECKey()) + 0, + ScriptBuilder.createInputScript(null, new BtcECKey()) ); List hashes = new ArrayList<>(); @@ -766,12 +752,12 @@ private BigInteger sendFundsSurpassesLockingCapToAnyAddress( // Create header and PMT byte[] bits = new byte[1]; bits[0] = 0x3f; - PartialMerkleTree pmt = new PartialMerkleTree(bridgeConstants.getBtcParams(), bits, hashes, 1); + PartialMerkleTree pmt = new PartialMerkleTree(bridgeConstantsRegtest.getBtcParams(), bits, hashes, 1); Sha256Hash merkleRoot = pmt.getTxnHashAndMerkleRoot(new ArrayList<>()); co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( - bridgeConstants.getBtcParams(), + bridgeConstantsRegtest.getBtcParams(), 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), merkleRoot, 1, 1, @@ -783,7 +769,7 @@ private BigInteger sendFundsSurpassesLockingCapToAnyAddress( mockChainOfStoredBlocks( btcBlockStore, registerHeader, - height + bridgeConstants.getBtc2RskMinimumAcceptableConfirmations(), + height + bridgeConstantsRegtest.getBtc2RskMinimumAcceptableConfirmations(), height ); @@ -825,14 +811,14 @@ private BigInteger sendFundsSurpassesLockingCapToAnyAddress( Assertions.assertEquals(1, releaseTx.getOutputs().size()); Coin amountSent = BridgeUtils.getAmountSentToAddresses(activations, - bridgeConstants.getBtcParams(), + bridgeConstantsRegtest.getBtcParams(), btcContext, btcTx, isRskip293Active? Arrays.asList(activeFederationAddress, retiringFederationAddress): Collections.singletonList(activeFederationAddress) ); Coin amountToRefund = BridgeUtils.getAmountSentToAddresses(activations, - bridgeConstants.getBtcParams(), + bridgeConstantsRegtest.getBtcParams(), btcContext, releaseTx, Collections.singletonList( @@ -844,7 +830,7 @@ private BigInteger sendFundsSurpassesLockingCapToAnyAddress( Coin estimatedFee = amountSent.divide(10); Coin estimatedAmountToRefund = amountSent.minus(estimatedFee); - Assertions.assertTrue(amountToRefund.isGreaterThan(estimatedAmountToRefund) && + assertTrue(amountToRefund.isGreaterThan(estimatedAmountToRefund) && amountToRefund.isLessThan(amountSent), "Pegout value should be bigger than the estimated amount to refund(" + estimatedAmountToRefund + ") and " + "smaller than the amount sent(" + amountSent + ")" ); @@ -1516,7 +1502,7 @@ void registerFlyoverBtcTransaction_funds_sent_to_active_and_retiring_fed_surpass }, true ); - Assertions.assertEquals(FlyoverTxResponseCodes.REFUNDED_LP_ERROR.value(), result.longValue()); + assertEquals(FlyoverTxResponseCodes.REFUNDED_LP_ERROR.value(), result.longValue()); } @Test @@ -1575,7 +1561,7 @@ void registerFlyoverBtcTransaction_sum_of_all_utxos_surpass_locking_cap_but_not_ BtcTransaction tx = new BtcTransaction(bridgeConstants.getBtcParams()); tx.addOutput(Coin.COIN, activeFederationAddress); tx.addOutput(Coin.COIN, retiringFederationAddress); - tx.addOutput(Coin.FIFTY_COINS, createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams())); + tx.addOutput(Coin.FIFTY_COINS, BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "rndm")); return tx; }, false @@ -1590,8 +1576,8 @@ void registerFlyoverBtcTransaction_funds_sent_to_random_addresses_surpass_lockin Coin.FIFTY_COINS, (bridgeConstants, activeFederationAddress, retiringFederationAddress) -> { BtcTransaction tx = new BtcTransaction(bridgeConstants.getBtcParams()); - tx.addOutput(Coin.FIFTY_COINS, createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams())); - tx.addOutput(Coin.COIN, createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams())); + tx.addOutput(Coin.FIFTY_COINS, BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "rndm1")); + tx.addOutput(Coin.COIN, BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "rndm2")); return tx; }, false @@ -1621,8 +1607,8 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_already_saved_in_ BridgeStorageProvider provider = spy(new BridgeStorageProvider(repository, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants, activations)); provider.setNewFederation(activeFederation); - Address userRefundBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); - Address lpBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); + Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "refund"); + Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "lp"); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); @@ -1630,6 +1616,9 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_already_saved_in_ Block executionBlock = Mockito.mock(Block.class); when(executionBlock.getNumber()).thenReturn(10L); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = bridgeSupportBuilder .withProvider(provider) .withBridgeConstants(bridgeConstants) @@ -1637,6 +1626,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_already_saved_in_ .withBtcBlockStoreFactory(mockFactory) .withExecutionBlock(executionBlock) .withRepository(repository) + .withFeePerKbSupport(feePerKbSupport) .build(); Keccak256 derivationArgumentsHash = PegTestUtils.createHash3(0); @@ -1675,7 +1665,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_already_saved_in_ co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( bridgeConstants.getBtcParams(), 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), merkleRoot, 1, 1, @@ -1734,7 +1724,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_already_saved_in_ assertEquals(co.rsk.core.Coin.fromBitcoin(Coin.COIN).asBigInteger(), result); // Transaction includes a witness making its txId != wTxId - Assertions.assertNotEquals(btcTx.getHash(), btcTx.getHash(true)); + assertNotEquals(btcTx.getHash(), btcTx.getHash(true)); verify(provider).isFlyoverDerivationHashUsed(btcTx.getHash(true), derivationHash); verify(provider).isFlyoverDerivationHashUsed(btcTx.getHash(false), derivationHash); @@ -1815,8 +1805,8 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_surpassing_lockin PegoutsWaitingForConfirmations pegoutsWaitingForConfirmations = new PegoutsWaitingForConfirmations(new HashSet<>()); doReturn(pegoutsWaitingForConfirmations).when(provider).getPegoutsWaitingForConfirmations(); - Address userRefundBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); - Address lpBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); + Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "refund"); + Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "lp"); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); @@ -1824,6 +1814,9 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_surpassing_lockin Block executionBlock = Mockito.mock(Block.class); when(executionBlock.getNumber()).thenReturn(10L); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = bridgeSupportBuilder .withProvider(provider) .withBridgeConstants(bridgeConstants) @@ -1831,6 +1824,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_surpassing_lockin .withBtcBlockStoreFactory(mockFactory) .withExecutionBlock(executionBlock) .withRepository(repository) + .withFeePerKbSupport(feePerKbSupport) .build(); Keccak256 derivationArgumentsHash = PegTestUtils.createHash3(0); @@ -1869,7 +1863,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_surpassing_lockin co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( bridgeConstants.getBtcParams(), 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), merkleRoot, 1, 1, @@ -1928,7 +1922,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_surpassing_lockin assertEquals(FlyoverTxResponseCodes.REFUNDED_USER_ERROR.value(), result.longValue()); // Transaction includes a witness making its txId != wTxId - Assertions.assertNotEquals(btcTx.getHash(), btcTx.getHash(true)); + assertNotEquals(btcTx.getHash(), btcTx.getHash(true)); // The verified derivation hash should be the computed one verify(provider).isFlyoverDerivationHashUsed(btcTx.getHash(true), derivationHash); @@ -2009,8 +2003,8 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_surpassing_lockin PegoutsWaitingForConfirmations pegoutsWaitingForConfirmations = new PegoutsWaitingForConfirmations(new HashSet<>()); doReturn(pegoutsWaitingForConfirmations).when(provider).getPegoutsWaitingForConfirmations(); - Address userRefundBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); - Address lpBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); + Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "refund"); + Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "lp"); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); @@ -2018,6 +2012,9 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_surpassing_lockin Block executionBlock = Mockito.mock(Block.class); when(executionBlock.getNumber()).thenReturn(10L); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = bridgeSupportBuilder .withProvider(provider) .withBridgeConstants(bridgeConstants) @@ -2025,6 +2022,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_surpassing_lockin .withBtcBlockStoreFactory(mockFactory) .withExecutionBlock(executionBlock) .withRepository(repository) + .withFeePerKbSupport(feePerKbSupport) .build(); Keccak256 derivationArgumentsHash = PegTestUtils.createHash3(0); @@ -2063,7 +2061,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_surpassing_lockin co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( bridgeConstants.getBtcParams(), 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), merkleRoot, 1, 1, @@ -2089,8 +2087,12 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_surpassing_lockin CoinbaseInformation coinbaseInformation = new CoinbaseInformation(witnessMerkleRoot); provider.setCoinbaseInformation(registerHeader.getHash(), coinbaseInformation); - Keccak256 derivationHash = - bridgeSupport.getFlyoverDerivationHash(derivationArgumentsHash, userRefundBtcAddress, lpBtcAddress, lbcAddress); + Keccak256 derivationHash = bridgeSupport.getFlyoverDerivationHash( + derivationArgumentsHash, + userRefundBtcAddress, + lpBtcAddress, + lbcAddress + ); InternalTransaction rskTx = new InternalTransaction( Keccak256.ZERO_HASH.getBytes(), @@ -2122,7 +2124,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_surpassing_lockin assertEquals(FlyoverTxResponseCodes.REFUNDED_USER_ERROR.value(), result.longValue()); // Transaction includes a witness making its txId != wTxId - Assertions.assertNotEquals(btcTx.getHash(), btcTx.getHash(true)); + assertNotEquals(btcTx.getHash(), btcTx.getHash(true)); // The verified derivation hash should be the computed one verify(provider).isFlyoverDerivationHashUsed(btcTx.getHash(true), derivationHash); @@ -2162,7 +2164,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_with_witness_surpassing_lockin assertEquals(FlyoverTxResponseCodes.UNPROCESSABLE_TX_ALREADY_PROCESSED_ERROR.value(), result.longValue()); // Transaction does not include a witness making its txId == wTxId - Assertions.assertEquals(btcTx.getHash(), btcTx.getHash(true)); + assertEquals(btcTx.getHash(), btcTx.getHash(true)); verify(provider).isFlyoverDerivationHashUsed(btcTx.getHash(false), derivationHash); verify(provider, never()).isFlyoverDerivationHashUsed(btcTx.getHash(false), derivationArgumentsHash); @@ -2202,8 +2204,8 @@ void registerFlyoverBtcTransaction_failed_when_tx_without_witness_surpassing_loc PegoutsWaitingForConfirmations pegoutsWaitingForConfirmations = new PegoutsWaitingForConfirmations(new HashSet<>()); doReturn(pegoutsWaitingForConfirmations).when(provider).getPegoutsWaitingForConfirmations(); - Address userRefundBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); - Address lpBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); + Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "refund"); + Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "lp"); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); @@ -2211,6 +2213,9 @@ void registerFlyoverBtcTransaction_failed_when_tx_without_witness_surpassing_loc Block executionBlock = Mockito.mock(Block.class); when(executionBlock.getNumber()).thenReturn(10L); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = bridgeSupportBuilder .withProvider(provider) .withBridgeConstants(bridgeConstants) @@ -2218,6 +2223,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_without_witness_surpassing_loc .withBtcBlockStoreFactory(mockFactory) .withExecutionBlock(executionBlock) .withRepository(repository) + .withFeePerKbSupport(feePerKbSupport) .build(); Keccak256 derivationArgumentsHash = PegTestUtils.createHash3(0); @@ -2253,7 +2259,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_without_witness_surpassing_loc co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( bridgeConstants.getBtcParams(), 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), merkleRoot, 1, 1, @@ -2269,8 +2275,12 @@ void registerFlyoverBtcTransaction_failed_when_tx_without_witness_surpassing_loc height ); - Keccak256 derivationHash = - bridgeSupport.getFlyoverDerivationHash(derivationArgumentsHash, userRefundBtcAddress, lpBtcAddress, lbcAddress); + Keccak256 derivationHash = bridgeSupport.getFlyoverDerivationHash( + derivationArgumentsHash, + userRefundBtcAddress, + lpBtcAddress, + lbcAddress + ); InternalTransaction rskTx = new InternalTransaction( Keccak256.ZERO_HASH.getBytes(), @@ -2369,8 +2379,8 @@ void registerFlyoverBtcTransaction_failed_when_tx_without_witness_surpassing_loc PegoutsWaitingForConfirmations pegoutsWaitingForConfirmations = new PegoutsWaitingForConfirmations(new HashSet<>()); doReturn(pegoutsWaitingForConfirmations).when(provider).getPegoutsWaitingForConfirmations(); - Address userRefundBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); - Address lpBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); + Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "refund"); + Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "lp"); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); @@ -2378,6 +2388,9 @@ void registerFlyoverBtcTransaction_failed_when_tx_without_witness_surpassing_loc Block executionBlock = Mockito.mock(Block.class); when(executionBlock.getNumber()).thenReturn(10L); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = bridgeSupportBuilder .withProvider(provider) .withBridgeConstants(bridgeConstants) @@ -2385,6 +2398,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_without_witness_surpassing_loc .withBtcBlockStoreFactory(mockFactory) .withExecutionBlock(executionBlock) .withRepository(repository) + .withFeePerKbSupport(feePerKbSupport) .build(); Keccak256 derivationArgumentsHash = PegTestUtils.createHash3(0); @@ -2420,7 +2434,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_without_witness_surpassing_loc co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( bridgeConstants.getBtcParams(), 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), merkleRoot, 1, 1, @@ -2436,8 +2450,12 @@ void registerFlyoverBtcTransaction_failed_when_tx_without_witness_surpassing_loc height ); - Keccak256 derivationHash = - bridgeSupport.getFlyoverDerivationHash(derivationArgumentsHash, userRefundBtcAddress, lpBtcAddress, lbcAddress); + Keccak256 derivationHash = bridgeSupport.getFlyoverDerivationHash( + derivationArgumentsHash, + userRefundBtcAddress, + lpBtcAddress, + lbcAddress + ); InternalTransaction rskTx = new InternalTransaction( Keccak256.ZERO_HASH.getBytes(), @@ -2542,8 +2560,8 @@ void registerFlyoverBtcTransaction_failed_when_tx_without_witness_already_saved_ BridgeStorageProvider provider = spy(new BridgeStorageProvider(repository, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants, activations)); provider.setNewFederation(activeFederation); - Address userRefundBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); - Address lpBtcAddress = PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()); + Address userRefundBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "refund"); + Address lpBtcAddress = BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "lp"); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); @@ -2593,7 +2611,7 @@ void registerFlyoverBtcTransaction_failed_when_tx_without_witness_already_saved_ co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( bridgeConstants.getBtcParams(), 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), merkleRoot, 1, 1, @@ -2698,7 +2716,7 @@ void registerFlyoverBtcTransaction_is_not_contract() false ); - Assertions.assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.UNPROCESSABLE_TX_NOT_CONTRACT_ERROR.value()), result); + assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.UNPROCESSABLE_TX_NOT_CONTRACT_ERROR.value()), result); } @Test @@ -2744,7 +2762,7 @@ void registerFlyoverBtcTransaction_sender_is_not_lbc() false ); - Assertions.assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.UNPROCESSABLE_TX_INVALID_SENDER_ERROR.value()), result); + assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.UNPROCESSABLE_TX_INVALID_SENDER_ERROR.value()), result); } @Test @@ -2795,7 +2813,7 @@ void registerFlyoverBtcTransaction_validationsForRegisterBtcTransaction_returns_ false ); - Assertions.assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.UNPROCESSABLE_TX_VALIDATIONS_ERROR.value()), result); + assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.UNPROCESSABLE_TX_VALIDATIONS_ERROR.value()), result); } @Test @@ -2809,6 +2827,7 @@ void registerFlyoverBtcTransaction_amount_sent_is_0() RskAddress lbcAddress = PegTestUtils.createRandomRskAddress(); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); BridgeSupport bridgeSupport = spy(new BridgeSupport( bridgeConstantsMainnet, mock(BridgeStorageProvider.class), @@ -2819,6 +2838,7 @@ void registerFlyoverBtcTransaction_amount_sent_is_0() mock(Block.class), btcContext, mock(FederationSupport.class), + feePerKbSupport, mock(BtcBlockStoreWithCache.Factory.class), activations, signatureCache @@ -2863,7 +2883,7 @@ void registerFlyoverBtcTransaction_amount_sent_is_0() false ); - Assertions.assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.UNPROCESSABLE_TX_VALUE_ZERO_ERROR.value()), result); + assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.UNPROCESSABLE_TX_VALUE_ZERO_ERROR.value()), result); } @Test @@ -2887,6 +2907,9 @@ void registerFlyoverBtcTransaction_surpasses_locking_cap_and_shouldTransfer_is_t Context btcContext = mock(Context.class); when(btcContext.getParams()).thenReturn(bridgeConstantsRegtest.getBtcParams()); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = spy(new BridgeSupport( bridgeConstantsRegtest, provider, @@ -2897,6 +2920,7 @@ void registerFlyoverBtcTransaction_surpasses_locking_cap_and_shouldTransfer_is_t mock(Block.class), btcContext, mock(FederationSupport.class), + feePerKbSupport, mock(BtcBlockStoreWithCache.Factory.class), activations, signatureCache @@ -2949,7 +2973,7 @@ void registerFlyoverBtcTransaction_surpasses_locking_cap_and_shouldTransfer_is_t true ); - Assertions.assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.REFUNDED_LP_ERROR.value()), result); + assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.REFUNDED_LP_ERROR.value()), result); } @Test @@ -2975,6 +2999,9 @@ void registerFlyoverBtcTransaction_surpasses_locking_cap_and_shouldTransfer_is_f Context btcContext = mock(Context.class); when(btcContext.getParams()).thenReturn(bridgeConstantsRegtest.getBtcParams()); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = spy(new BridgeSupport( bridgeConstantsRegtest, provider, @@ -2985,6 +3012,7 @@ void registerFlyoverBtcTransaction_surpasses_locking_cap_and_shouldTransfer_is_f mock(Block.class), btcContext, mock(FederationSupport.class), + feePerKbSupport, mock(BtcBlockStoreWithCache.Factory.class), activations, signatureCache @@ -3038,7 +3066,7 @@ void registerFlyoverBtcTransaction_surpasses_locking_cap_and_shouldTransfer_is_f false ); - Assertions.assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.REFUNDED_USER_ERROR.value()), result); + assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.REFUNDED_USER_ERROR.value()), result); } @Test @@ -3065,6 +3093,9 @@ void registerFlyoverBtcTransaction_surpasses_locking_cap_and_tries_to_register_a Context btcContext = mock(Context.class); when(btcContext.getParams()).thenReturn(bridgeConstantsRegtest.getBtcParams()); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = spy(new BridgeSupport( bridgeConstantsRegtest, provider, @@ -3075,6 +3106,7 @@ void registerFlyoverBtcTransaction_surpasses_locking_cap_and_tries_to_register_a mock(Block.class), btcContext, mock(FederationSupport.class), + feePerKbSupport, mock(BtcBlockStoreWithCache.Factory.class), activations, signatureCache @@ -3132,7 +3164,7 @@ void registerFlyoverBtcTransaction_surpasses_locking_cap_and_tries_to_register_a false ); - Assertions.assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.REFUNDED_USER_ERROR.value()), result); + assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.REFUNDED_USER_ERROR.value()), result); // Update repository bridgeSupport.save(); @@ -3149,7 +3181,7 @@ void registerFlyoverBtcTransaction_surpasses_locking_cap_and_tries_to_register_a false ); - Assertions.assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.UNPROCESSABLE_TX_ALREADY_PROCESSED_ERROR.value()), result); + assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.UNPROCESSABLE_TX_ALREADY_PROCESSED_ERROR.value()), result); } @Test @@ -3172,6 +3204,7 @@ void registerFlyoverBtcTransaction_OK() FederationSupport federationSupportMock = mock(FederationSupport.class); doReturn(provider.getNewFederationBtcUTXOs()).when(federationSupportMock).getActiveFederationBtcUTXOs(); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); BridgeSupport bridgeSupport = spy(new BridgeSupport( bridgeConstantsRegtest, provider, @@ -3182,6 +3215,7 @@ void registerFlyoverBtcTransaction_OK() mock(Block.class), btcContext, federationSupportMock, + feePerKbSupport, mock(BtcBlockStoreWithCache.Factory.class), activations, signatureCache @@ -3247,13 +3281,13 @@ void registerFlyoverBtcTransaction_OK() bridgeSupport.save(); - Assertions.assertTrue( + assertTrue( provider.isFlyoverDerivationHashUsed( tx.getHash(), bridgeSupport.getFlyoverDerivationHash(PegTestUtils.createHash3(0), btcAddress, btcAddress, lbcAddress) ) ); - Assertions.assertEquals(1, provider.getNewFederationBtcUTXOs().size()); + assertEquals(1, provider.getNewFederationBtcUTXOs().size()); // Trying to register the same transaction again fails result = bridgeSupport.registerFlyoverBtcTransaction( @@ -3268,7 +3302,7 @@ void registerFlyoverBtcTransaction_OK() true ); - Assertions.assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.UNPROCESSABLE_TX_ALREADY_PROCESSED_ERROR.value()), result); + assertEquals(BigInteger.valueOf(FlyoverTxResponseCodes.UNPROCESSABLE_TX_ALREADY_PROCESSED_ERROR.value()), result); } @Test @@ -3280,6 +3314,7 @@ void createFlyoverFederationInformation_OK() { FederationSupport federationSupport = mock(FederationSupport.class); when(federationSupport.getActiveFederation()).thenReturn(activeFederation); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); BridgeSupport bridgeSupport = new BridgeSupport( bridgeConstantsRegtest, mock(BridgeStorageProvider.class), @@ -3290,6 +3325,7 @@ void createFlyoverFederationInformation_OK() { mock(Block.class), mock(Context.class), federationSupport, + feePerKbSupport, mock(BtcBlockStoreWithCache.Factory.class), activations, signatureCache @@ -3300,7 +3336,7 @@ void createFlyoverFederationInformation_OK() { Script flyoverRedeemScript = FastBridgeRedeemScriptParser.createMultiSigFastBridgeRedeemScript( federationRedeemScript, - PegTestUtils.createHash(1) + BitcoinTestUtils.createHash(1) ); Script flyoverP2SH = ScriptBuilder.createP2SHOutputScript(flyoverRedeemScript); @@ -3315,7 +3351,7 @@ void createFlyoverFederationInformation_OK() { FlyoverFederationInformation obtainedFlyoverFedInfo = bridgeSupport.createFlyoverFederationInformation(derivationHash); - Assertions.assertEquals( + assertEquals( expectedFlyoverFederationInformation.getFlyoverFederationAddress(bridgeConstantsRegtest.getBtcParams()), obtainedFlyoverFedInfo.getFlyoverFederationAddress(bridgeConstantsRegtest.getBtcParams()) ); @@ -3329,6 +3365,7 @@ void getFlyoverWallet_ok() { Context btcContext = mock(Context.class); when(btcContext.getParams()).thenReturn(bridgeConstantsRegtest.getBtcParams()); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); BridgeSupport bridgeSupport = new BridgeSupport( bridgeConstantsRegtest, mock(BridgeStorageProvider.class), @@ -3339,6 +3376,7 @@ void getFlyoverWallet_ok() { mock(Block.class), btcContext, mock(FederationSupport.class), + feePerKbSupport, mock(BtcBlockStoreWithCache.Factory.class), activations, signatureCache @@ -3429,7 +3467,7 @@ void saveFlyoverDataInStorage_OK() throws IOException { .withActivations(activations) .build(); - Sha256Hash btcTxHash = PegTestUtils.createHash(1); + Sha256Hash btcTxHash = BitcoinTestUtils.createHash(1); Keccak256 derivationHash = PegTestUtils.createHash3(1); byte[] flyoverScriptHash = new byte[]{0x1}; @@ -3440,7 +3478,7 @@ void saveFlyoverDataInStorage_OK() throws IOException { ); List utxos = new ArrayList<>(); - Sha256Hash utxoHash = PegTestUtils.createHash(1); + Sha256Hash utxoHash = BitcoinTestUtils.createHash(1); UTXO utxo = new UTXO(utxoHash, 0, Coin.COIN.multiply(2), 0, false, new Script(new byte[]{})); utxos.add(utxo); @@ -3451,9 +3489,9 @@ void saveFlyoverDataInStorage_OK() throws IOException { Assertions.assertEquals(1, provider.getNewFederationBtcUTXOs().size()); assertEquals(utxo, provider.getNewFederationBtcUTXOs().get(0)); - Assertions.assertTrue(provider.isFlyoverDerivationHashUsed(btcTxHash, derivationHash)); + assertTrue(provider.isFlyoverDerivationHashUsed(btcTxHash, derivationHash)); Optional optionalFlyoverFederationInformation = provider.getFlyoverFederationInformation(flyoverScriptHash); - Assertions.assertTrue(optionalFlyoverFederationInformation.isPresent()); + assertTrue(optionalFlyoverFederationInformation.isPresent()); FlyoverFederationInformation obtainedFlyoverFederationInformation = optionalFlyoverFederationInformation.get(); Assertions.assertEquals(flyoverFederationInformation.getDerivationHash(), obtainedFlyoverFederationInformation.getDerivationHash()); Assertions.assertArrayEquals(flyoverFederationInformation.getFederationRedeemScriptHash(), obtainedFlyoverFederationInformation.getFederationRedeemScriptHash()); @@ -3465,7 +3503,7 @@ private Address getFlyoverFederationAddress() { Script flyoverRedeemScript = FastBridgeRedeemScriptParser.createMultiSigFastBridgeRedeemScript( federationRedeemScript, - PegTestUtils.createHash(1) + BitcoinTestUtils.createHash(1) ); Script flyoverP2SH = ScriptBuilder.createP2SHOutputScript(flyoverRedeemScript); diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportPegoutTransactionCreatedEventTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportPegoutTransactionCreatedEventTest.java index 4c4cf1a9491..b9b13232994 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportPegoutTransactionCreatedEventTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportPegoutTransactionCreatedEventTest.java @@ -5,19 +5,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -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 co.rsk.bitcoinj.core.BtcTransaction; -import co.rsk.bitcoinj.core.Coin; -import co.rsk.bitcoinj.core.Context; -import co.rsk.bitcoinj.core.NetworkParameters; -import co.rsk.bitcoinj.core.Sha256Hash; -import co.rsk.bitcoinj.core.TransactionOutput; -import co.rsk.bitcoinj.core.UTXO; +import static org.mockito.Mockito.*; + +import co.rsk.bitcoinj.core.*; import co.rsk.bitcoinj.wallet.Wallet; import co.rsk.blockchain.utils.BlockGenerator; import co.rsk.crypto.Keccak256; @@ -29,15 +19,14 @@ import co.rsk.peg.federation.FederationArgs; import co.rsk.peg.federation.FederationFactory; import co.rsk.peg.federation.FederationTestUtils; +import co.rsk.peg.feeperkb.FeePerKbStorageProvider; +import co.rsk.peg.feeperkb.FeePerKbSupport; +import co.rsk.peg.feeperkb.FeePerKbSupportImpl; import co.rsk.peg.utils.BridgeEventLogger; import co.rsk.test.builders.BridgeSupportBuilder; import java.io.IOException; import java.time.Instant; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.TreeMap; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; import org.ethereum.config.blockchain.upgrades.ActivationConfig; @@ -57,6 +46,7 @@ class BridgeSupportPegoutTransactionCreatedEventTest { private static final ErpFederation ERP_FEDERATION = FederationTestUtils.getErpFederation(btcMainnetParams); private BridgeStorageProvider provider; + private FeePerKbSupport feePerKbSupport; private BridgeEventLogger eventLogger; private Block rskCurrentBlock; private Keccak256 pegoutCreationRskTxHash; @@ -64,26 +54,23 @@ class BridgeSupportPegoutTransactionCreatedEventTest { @BeforeEach void init() throws IOException { - provider = mock(BridgeStorageProvider.class); - eventLogger = mock(BridgeEventLogger.class); - - when(provider.getFeePerKb()) - .thenReturn(Coin.MILLICOIN); - - when(provider.getPegoutsWaitingForSignatures()) - .thenReturn(new TreeMap<>()); - - when(provider.getPegoutsWaitingForConfirmations()) - .thenReturn(new PegoutsWaitingForConfirmations(new HashSet<>())); - List fedUTXOs = createUTXOs( 10, ERP_FEDERATION.getAddress() ); - when(provider.getNewFederationBtcUTXOs()) - .thenReturn(fedUTXOs); - when(provider.getNewFederation()) - .thenReturn(ERP_FEDERATION); + + provider = mock(BridgeStorageProvider.class); + when(provider.getPegoutsWaitingForSignatures()).thenReturn(new TreeMap<>()); + when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(new HashSet<>())); + when(provider.getNewFederationBtcUTXOs()).thenReturn(fedUTXOs); + when(provider.getNewFederation()).thenReturn(ERP_FEDERATION); + + FeePerKbStorageProvider feePerKbStorageProvider = mock(FeePerKbStorageProvider.class); + when(feePerKbStorageProvider.getFeePerKb()).thenReturn(Optional.of(Coin.MILLICOIN)); + feePerKbSupport = new FeePerKbSupportImpl( + bridgeMainnetConstants.getFeePerKbConstants(), + feePerKbStorageProvider + ); BlockGenerator blockGenerator = new BlockGenerator(); rskCurrentBlock = blockGenerator.createBlock(ERP_FEDERATION.getCreationBlockNumber(), 1); @@ -91,6 +78,8 @@ void init() throws IOException { pegoutCreationRskTxHash = PegTestUtils.createHash3(1); executionRskTx = mock(Transaction.class); when(executionRskTx.getHash()).thenReturn(pegoutCreationRskTxHash); + + eventLogger = mock(BridgeEventLogger.class); } private static Stream activationsProvider() { @@ -105,8 +94,7 @@ private static Stream activationsProvider() { void updateCollections_whenPegoutBatchIsCreated_shouldLogPegoutTransactionCreatedEvent(ActivationConfig.ForBlock activations) throws IOException { // Arrange List pegoutRequests = PegTestUtils.createReleaseRequestQueueEntries(3); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(pegoutRequests)); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(pegoutRequests)); PegoutsWaitingForConfirmations pegoutsWaitingForConfirmations = provider.getPegoutsWaitingForConfirmations(); @@ -116,6 +104,7 @@ void updateCollections_whenPegoutBatchIsCreated_shouldLogPegoutTransactionCreate .withEventLogger(eventLogger) .withExecutionBlock(rskCurrentBlock) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); // Act @@ -129,8 +118,7 @@ void updateCollections_whenPegoutBatchIsCreated_shouldLogPegoutTransactionCreate BtcTransaction pegoutBatchTransaction = pegoutEntry.getBtcTransaction(); Sha256Hash pegoutTxHash = pegoutBatchTransaction.getHash(); List outpointValues = extractOutpointValues(pegoutBatchTransaction); - List pegoutRequestRskTxHashes = pegoutRequests.stream().map(Entry::getRskTxHash).collect( - Collectors.toList()); + List pegoutRequestRskTxHashes = pegoutRequests.stream().map(Entry::getRskTxHash).collect(Collectors.toList()); Coin totalTransactionAmount = pegoutRequests.stream().map(Entry::getAmount).reduce(Coin.ZERO, Coin::add); verify(eventLogger, times(1)).logBatchPegoutCreated(pegoutTxHash, pegoutRequestRskTxHashes); @@ -147,34 +135,33 @@ void updateCollections_whenPegoutBatchIsCreated_shouldLogPegoutTransactionCreate @MethodSource("activationsProvider") void updateCollections_whenPegoutMigrationIsCreated_shouldLogPegoutTransactionCreatedEvent(ActivationConfig.ForBlock activations) throws IOException { // Arrange - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(Collections.emptyList())); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Collections.emptyList())); PegoutsWaitingForConfirmations pegoutsWaitingForConfirmations = provider.getPegoutsWaitingForConfirmations(); Federation oldFederation = ERP_FEDERATION; - when(provider.getOldFederation()) - .thenReturn(oldFederation); - + when(provider.getOldFederation()).thenReturn(oldFederation); long newFedCreationBlockNumber = 5L; - FederationArgs newFederationArgs = new FederationArgs(FederationTestUtils.getFederationMembers(1), - Instant.EPOCH, newFedCreationBlockNumber, btcMainnetParams); + FederationArgs newFederationArgs = new FederationArgs( + FederationTestUtils.getFederationMembers(1), + Instant.EPOCH, + newFedCreationBlockNumber, + btcMainnetParams + ); Federation newFederation = FederationFactory.buildStandardMultiSigFederation(newFederationArgs); - when(provider.getNewFederation()) - .thenReturn(newFederation); + when(provider.getNewFederation()).thenReturn(newFederation); // Utxos to migrate List utxosToMigrate = createUTXOs(10, oldFederation.getAddress()); Coin totalTransactionInputAmount = utxosToMigrate.stream().map(UTXO::getValue).reduce(Coin.ZERO, Coin::add); - when(provider.getOldFederationBtcUTXOs()) - .thenReturn(utxosToMigrate); + when(provider.getOldFederationBtcUTXOs()).thenReturn(utxosToMigrate); // Advance blockchain to migration phase. Migration phase starts 1 block after migration age is reached. long migrationAge = bridgeMainnetConstants.getFederationActivationAge(activations) + - bridgeMainnetConstants.getFundsMigrationAgeSinceActivationBegin() + - newFedCreationBlockNumber + 1; + bridgeMainnetConstants.getFundsMigrationAgeSinceActivationBegin() + + newFedCreationBlockNumber + 1; BlockGenerator blockGenerator = new BlockGenerator(); rskCurrentBlock = blockGenerator.createBlock(migrationAge, 1); @@ -185,6 +172,7 @@ void updateCollections_whenPegoutMigrationIsCreated_shouldLogPegoutTransactionCr .withEventLogger(eventLogger) .withExecutionBlock(rskCurrentBlock) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); // Act @@ -223,36 +211,34 @@ void updateCollections_whenPegoutMigrationAndBatchAreCreated_shouldLogPegoutTran PegoutsWaitingForConfirmations pegoutsWaitingForConfirmations = provider.getPegoutsWaitingForConfirmations(); List pegoutRequests = PegTestUtils.createReleaseRequestQueueEntries(3); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(pegoutRequests)); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(pegoutRequests)); Federation oldFederation = ERP_FEDERATION; - when(provider.getOldFederation()) - .thenReturn(oldFederation); + when(provider.getOldFederation()).thenReturn(oldFederation); long newFedCreationBlockNumber = 5L; - FederationArgs newFederationArgs = new FederationArgs(FederationTestUtils.getFederationMembers(1), - Instant.EPOCH, newFedCreationBlockNumber, btcMainnetParams); - Federation newFederation = FederationFactory.buildStandardMultiSigFederation( - newFederationArgs); + FederationArgs newFederationArgs = new FederationArgs( + FederationTestUtils.getFederationMembers(1), + Instant.EPOCH, + newFedCreationBlockNumber, + btcMainnetParams + ); + Federation newFederation = FederationFactory.buildStandardMultiSigFederation(newFederationArgs); - when(provider.getNewFederation()) - .thenReturn(newFederation); + when(provider.getNewFederation()).thenReturn(newFederation); // Utxos to migrate List utxosToMigrate = createUTXOs(10, oldFederation.getAddress()); - when(provider.getOldFederationBtcUTXOs()) - .thenReturn(utxosToMigrate); + when(provider.getOldFederationBtcUTXOs()).thenReturn(utxosToMigrate); Coin migrationTotalAmount = utxosToMigrate.stream().map(UTXO::getValue).reduce(Coin.ZERO, Coin::add); List utxosNewFederation = createUTXOs(10, newFederation.getAddress()); - when(provider.getNewFederationBtcUTXOs()) - .thenReturn(utxosNewFederation); + when(provider.getNewFederationBtcUTXOs()).thenReturn(utxosNewFederation); // Advance blockchain to migration phase. Migration phase starts 1 block after migration age is reached. long migrationAge = bridgeMainnetConstants.getFederationActivationAge(activations) + - bridgeMainnetConstants.getFundsMigrationAgeSinceActivationBegin() + - newFedCreationBlockNumber + 1; + bridgeMainnetConstants.getFundsMigrationAgeSinceActivationBegin() + + newFedCreationBlockNumber + 1; BlockGenerator blockGenerator = new BlockGenerator(); rskCurrentBlock = blockGenerator.createBlock(migrationAge, 1); @@ -263,6 +249,7 @@ void updateCollections_whenPegoutMigrationAndBatchAreCreated_shouldLogPegoutTran .withEventLogger(eventLogger) .withExecutionBlock(rskCurrentBlock) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); Transaction rskTx = mock(Transaction.class); @@ -306,8 +293,7 @@ void updateCollections_whenPegoutMigrationAndBatchAreCreated_shouldLogPegoutTran Coin pegoutBatchTotalAmount = pegoutRequests.stream().map(Entry::getAmount).reduce(Coin.ZERO, Coin::add); List pegoutBatchTxOutpointValues = extractOutpointValues(pegoutBatchTx); - List pegoutRequestRskTxHashes = pegoutRequests.stream().map(Entry::getRskTxHash).collect( - Collectors.toList()); + List pegoutRequestRskTxHashes = pegoutRequests.stream().map(Entry::getRskTxHash).collect(Collectors.toList()); verify(eventLogger, times(1)).logBatchPegoutCreated(pegoutBatchBtcTxHash, pegoutRequestRskTxHashes); verify(eventLogger, times(1)).logReleaseBtcRequested(pegoutBatchCreationRskTxHash.getBytes(), pegoutBatchTx, pegoutBatchTotalAmount); diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportProcessFundsMigrationTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportProcessFundsMigrationTest.java index 13f65527818..cd999aad0d2 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportProcessFundsMigrationTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportProcessFundsMigrationTest.java @@ -11,6 +11,7 @@ import co.rsk.peg.federation.FederationArgs; import co.rsk.peg.federation.FederationFactory; import co.rsk.peg.federation.FederationTestUtils; +import co.rsk.peg.feeperkb.FeePerKbSupport; import co.rsk.peg.utils.BridgeEventLogger; import co.rsk.test.builders.BridgeSupportBuilder; import org.bouncycastle.util.encoders.Hex; @@ -19,7 +20,6 @@ import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.Transaction; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -35,6 +35,8 @@ import static co.rsk.peg.PegTestUtils.BTC_TX_LEGACY_VERSION; import static co.rsk.peg.ReleaseTransactionBuilder.BTC_TX_VERSION_2; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -76,7 +78,6 @@ private static Stream processFundMigrationArgsProvider() { Arguments.of(bridgeMainNetConstants, hopActivations, true) ); - ActivationConfig.ForBlock hop401Activations = ActivationConfigsForTest.hop401().forBlock(0); Stream hop401Tests = Stream.of( Arguments.of(bridgeTestNetConstants, hop401Activations, false), @@ -137,9 +138,7 @@ void test_processFundsMigration( federationCreationBlockNumber, bridgeConstants.getBtcParams() ); - Federation newFederation = FederationFactory.buildStandardMultiSigFederation( - newFederationArgs - ); + Federation newFederation = FederationFactory.buildStandardMultiSigFederation(newFederationArgs); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Collections.emptyList())); @@ -152,12 +151,16 @@ void test_processFundsMigration( long updateCollectionsCallHeight = inMigrationAge ? federationInMigrationAgeHeight : federationPastMigrationAgeHeight; org.ethereum.core.Block rskCurrentBlock = blockGenerator.createBlock(updateCollectionsCallHeight, 1); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = new BridgeSupportBuilder() .withBridgeConstants(bridgeConstants) .withProvider(provider) .withEventLogger(bridgeEventLogger) .withExecutionBlock(rskCurrentBlock) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); List sufficientUTXOsForMigration = new ArrayList<>(); @@ -172,10 +175,10 @@ void test_processFundsMigration( Transaction updateCollectionsTx = buildUpdateCollectionsTransaction(); bridgeSupport.updateCollections(updateCollectionsTx); - Assertions.assertEquals(activations.isActive(ConsensusRule.RSKIP146)? 0 : 1, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); - Assertions.assertEquals(activations.isActive(ConsensusRule.RSKIP146)? 1 : 0, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); + assertEquals(activations.isActive(ConsensusRule.RSKIP146)? 0 : 1, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); + assertEquals(activations.isActive(ConsensusRule.RSKIP146)? 1 : 0, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); - Assertions.assertTrue(sufficientUTXOsForMigration.isEmpty()); + assertTrue(sufficientUTXOsForMigration.isEmpty()); if (inMigrationAge){ verify(provider, never()).setOldFederation(null); } else { @@ -194,9 +197,9 @@ void test_processFundsMigration( ); if (activations.isActive(ConsensusRule.RSKIP376)){ - Assertions.assertEquals(BTC_TX_VERSION_2, entry.getBtcTransaction().getVersion()); + assertEquals(BTC_TX_VERSION_2, entry.getBtcTransaction().getVersion()); } else { - Assertions.assertEquals(BTC_TX_LEGACY_VERSION, entry.getBtcTransaction().getVersion()); + assertEquals(BTC_TX_LEGACY_VERSION, entry.getBtcTransaction().getVersion()); } } else { verify(bridgeEventLogger, never()).logReleaseBtcRequested( diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java index 92acfaec9ba..c908f539721 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportRegisterBtcTransactionTest.java @@ -9,27 +9,15 @@ import static co.rsk.peg.pegin.RejectedPeginReason.LEGACY_PEGIN_MULTISIG_SENDER; import static co.rsk.peg.pegin.RejectedPeginReason.PEGIN_V1_INVALID_PAYLOAD; import static co.rsk.peg.utils.UnrefundablePeginReason.LEGACY_PEGIN_UNDETERMINED_SENDER; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -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 co.rsk.bitcoinj.core.Address; -import co.rsk.bitcoinj.core.BtcECKey; -import co.rsk.bitcoinj.core.BtcTransaction; -import co.rsk.bitcoinj.core.Coin; -import co.rsk.bitcoinj.core.Context; -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.TransactionWitness; -import co.rsk.bitcoinj.core.UTXO; +import static org.mockito.Mockito.*; + +import co.rsk.bitcoinj.core.*; import co.rsk.bitcoinj.script.Script; import co.rsk.bitcoinj.script.ScriptBuilder; import co.rsk.bitcoinj.store.BlockStoreException; @@ -42,13 +30,12 @@ import co.rsk.peg.constants.BridgeConstants; import co.rsk.peg.constants.BridgeMainNetConstants; import co.rsk.peg.constants.BridgeRegTestConstants; -import co.rsk.peg.federation.Federation; -import co.rsk.peg.federation.FederationArgs; -import co.rsk.peg.federation.FederationFactory; -import co.rsk.peg.federation.FederationMember; -import co.rsk.peg.federation.FederationTestUtils; +import co.rsk.peg.federation.*; +import co.rsk.peg.feeperkb.*; import co.rsk.peg.pegin.RejectedPeginReason; import co.rsk.peg.pegininstructions.PeginInstructionsProvider; +import co.rsk.peg.storage.BridgeStorageAccessorImpl; +import co.rsk.peg.storage.StorageAccessor; import co.rsk.peg.utils.BridgeEventLogger; import co.rsk.peg.utils.UnrefundablePeginReason; import co.rsk.peg.whitelist.LockWhitelist; @@ -56,23 +43,13 @@ import java.io.IOException; import java.math.BigInteger; import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.stream.Stream; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; import org.ethereum.config.blockchain.upgrades.ConsensusRule; -import org.ethereum.core.Block; -import org.ethereum.core.BlockTxSignatureCache; -import org.ethereum.core.ReceivedTxSignatureCache; -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.vm.PrecompiledContracts; import org.junit.jupiter.api.Assertions; @@ -130,8 +107,8 @@ private void assertInvalidPeginIsIgnored() throws IOException { verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); } // After peg-out tx index gets in use @@ -140,8 +117,8 @@ private void assertInvalidPeginIsRejectedWithInvalidAmountReason(BtcTransaction verify(bridgeEventLogger, times(1)).logUnrefundablePegin(btcTransaction, UnrefundablePeginReason.INVALID_AMOUNT); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); } // fingerroot @@ -150,8 +127,8 @@ private void assertUnknownTxIsProcessedAsPegin(RskAddress expectedRskAddressToBe verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); } // After arrowhead600Activations but before grace period @@ -160,8 +137,8 @@ private void assertUnknownTxIsRejectedWithInvalidAmountReason(BtcTransaction btc verify(bridgeEventLogger, times(1)).logUnrefundablePegin(btcTransaction, UnrefundablePeginReason.INVALID_AMOUNT); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); } // After arrowhead600Activations and grace period @@ -170,17 +147,17 @@ private void assertUnknownTxIsIgnored() throws IOException { verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); } private void assertPeginIsRejectedAndRefunded(ActivationConfig.ForBlock activations, BtcTransaction btcTransaction, Coin sentAmount, RejectedPeginReason expectedRejectedPeginReason) throws IOException { verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); verify(bridgeEventLogger, never()).logUnrefundablePegin(any(), any()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); - Assertions.assertEquals(1, pegoutsWaitingForConfirmations.getEntries().size()); + assertEquals(1, pegoutsWaitingForConfirmations.getEntries().size()); Entry pegoutWaitingForConfirmationEntry = pegoutsWaitingForConfirmations.getEntries().stream().findFirst().get(); BtcTransaction refundPegout = pegoutWaitingForConfirmationEntry.getBtcTransaction(); Sha256Hash refundPegoutHash = refundPegout.getHash(); @@ -215,9 +192,9 @@ private void assertLegacyUndeterminedSenderPeginIsRejectedAsPeginV1InvalidPayloa verify(bridgeEventLogger, never()).logReleaseBtcRequested(any(), any(), any()); verify(bridgeEventLogger, never()).logPegoutTransactionCreated(any(), any()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); - Assertions.assertTrue(pegoutsWaitingForConfirmations.getEntries().isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(pegoutsWaitingForConfirmations.getEntries().isEmpty()); } // After arrowhead600Activations is activated @@ -253,9 +230,9 @@ private void assertInvalidPeginV1UndeterminedSenderIsRejected(BtcTransaction btc verify(bridgeEventLogger, never()).logPegoutTransactionCreated(any(), any()); verify(provider, never()).setHeightBtcTxhashAlreadyProcessed(any(), anyLong()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); - Assertions.assertTrue(pegoutsWaitingForConfirmations.getEntries().isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(pegoutsWaitingForConfirmations.getEntries().isEmpty()); } private static Stream common_args() { @@ -545,6 +522,13 @@ private BridgeSupport buildBridgeSupport(ActivationConfig.ForBlock activations) when(repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)).thenReturn(co.rsk.core.Coin.fromBitcoin(bridgeMainnetConstants.getMaxRbtc())); when(provider.getLockingCap()).thenReturn(bridgeMainnetConstants.getMaxRbtc()); + StorageAccessor bridgeStorageAccessor = new BridgeStorageAccessorImpl(repository); + FeePerKbStorageProvider feePerKbStorageProvider = new FeePerKbStorageProviderImpl(bridgeStorageAccessor); + FeePerKbSupport feePerKbSupport = new FeePerKbSupportImpl( + bridgeMainnetConstants.getFeePerKbConstants(), + feePerKbStorageProvider + ); + return new BridgeSupportBuilder() .withBtcBlockStoreFactory(mockFactory) .withBridgeConstants(bridgeMainnetConstants) @@ -556,6 +540,7 @@ private BridgeSupport buildBridgeSupport(ActivationConfig.ForBlock activations) .withBtcLockSenderProvider(btcLockSenderProvider) .withPeginInstructionsProvider(peginInstructionsProvider) .withExecutionBlock(rskExecutionBlock) + .withFeePerKbSupport(feePerKbSupport) .build(); } @@ -766,8 +751,8 @@ void pegin_legacy_to_active_fed( verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(amountToSend), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertEquals(1, activeFederationUtxos.size()); + assertTrue(retiringFederationUtxos.isEmpty()); } @ParameterizedTest @@ -807,7 +792,7 @@ void pegin_multiple_outputs_to_active_fed( verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(minimumPeginTxValue.multiply(10)), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(10, activeFederationUtxos.size()); + assertEquals(10, activeFederationUtxos.size()); } @ParameterizedTest @@ -847,7 +832,7 @@ void pegin_to_active_fed_with_bech32_output( verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(amountToSend), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); + assertEquals(1, activeFederationUtxos.size()); } @ParameterizedTest @@ -887,7 +872,7 @@ void pegin_to_active_fed_equal_to_minimum_with_other_random_outputs_below_minimu verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(minimumPeginTxValue), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); + assertEquals(1, activeFederationUtxos.size()); } @ParameterizedTest @@ -1040,8 +1025,8 @@ void pegin_to_active_and_retiring_fed( verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(minimumPeginTxValue.multiply(2)), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); - Assertions.assertEquals(1, retiringFederationUtxos.size()); + assertEquals(1, activeFederationUtxos.size()); + assertEquals(1, retiringFederationUtxos.size()); } @ParameterizedTest @@ -1114,8 +1099,8 @@ void pegin_to_active_and_retiring_fed_and_unknown_address( verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(minimumPeginTxValue.multiply(2)), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); - Assertions.assertEquals(1, retiringFederationUtxos.size()); + assertEquals(1, activeFederationUtxos.size()); + assertEquals(1, retiringFederationUtxos.size()); } @ParameterizedTest @@ -1215,7 +1200,7 @@ void pegin_v1_two_rsk_op_return_cannot_be_registered( verify(bridgeEventLogger, times(1)).logRejectedPegin(btcTransaction, PEGIN_V1_INVALID_PAYLOAD); } verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); } @ParameterizedTest @@ -1258,7 +1243,7 @@ void pegin_v1_invalid_protocol_legacy_sender_to_active_fed_( verify(bridgeEventLogger, times(1)).logRejectedPegin(btcTransaction, PEGIN_V1_INVALID_PAYLOAD); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); } @ParameterizedTest @@ -1300,8 +1285,8 @@ void pegin_v1_invalid_prefix_to_active_fed_can_be_registered( verify(bridgeEventLogger, times(1)).logPeginBtc(any(), eq(btcTransaction), eq(amountToSend), eq(0)); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertEquals(1, activeFederationUtxos.size()); + assertTrue(retiringFederationUtxos.isEmpty()); } @ParameterizedTest @@ -1637,8 +1622,8 @@ void pegout_no_change_output( // assert verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); } @Test @@ -1679,8 +1664,8 @@ void pegout_sighash_no_exists_in_provider() throws BlockStoreException, BridgeIl verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); } @ParameterizedTest @@ -1762,8 +1747,8 @@ void pegout_many_outputs_and_inputs_with_change_output( // assert verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertEquals(1, activeFederationUtxos.size()); + assertTrue(retiringFederationUtxos.isEmpty()); } @ParameterizedTest @@ -1843,8 +1828,8 @@ void pegout_many_outputs_and_one_input( // assert verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertEquals(1, activeFederationUtxos.size()); + assertTrue(retiringFederationUtxos.isEmpty()); } @ParameterizedTest @@ -1909,8 +1894,8 @@ void pegout_one_output_and_many_input( // assert verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); } // Migration tests @@ -1961,8 +1946,8 @@ void migration_ok( // assert verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertEquals(1, activeFederationUtxos.size()); + assertTrue(retiringFederationUtxos.isEmpty()); } @Test @@ -2002,8 +1987,8 @@ void migration_sighash_no_exists_in_provider() throws BlockStoreException, Bridg verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(activeFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); } @ParameterizedTest @@ -2070,8 +2055,8 @@ void migration_many_outputs_and_inputs( // assert verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(40, activeFederationUtxos.size()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertEquals(40, activeFederationUtxos.size()); + assertTrue(retiringFederationUtxos.isEmpty()); } @ParameterizedTest @@ -2139,8 +2124,8 @@ void migration_many_outputs_and_one_input( // assert verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(40, activeFederationUtxos.size()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertEquals(40, activeFederationUtxos.size()); + assertTrue(retiringFederationUtxos.isEmpty()); } @ParameterizedTest @@ -2192,8 +2177,8 @@ void migration_one_outputs_and_many_input( // assert verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertEquals(1, activeFederationUtxos.size()); + assertTrue(retiringFederationUtxos.isEmpty()); } // flyover pegin @@ -2411,8 +2396,8 @@ void flyover_segwit_as_migration_utxo( // assert verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertEquals(1, activeFederationUtxos.size()); + assertTrue(retiringFederationUtxos.isEmpty()); } @ParameterizedTest @@ -2496,8 +2481,8 @@ void flyover_segwit_as_migration_utxo_with_many_outputs_and_inputs( // assert verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(10, activeFederationUtxos.size()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertEquals(10, activeFederationUtxos.size()); + assertTrue(retiringFederationUtxos.isEmpty()); } // old fed @@ -2526,8 +2511,7 @@ void old_fed_migration( when(lockWhitelist.isWhitelistedFor(any(Address.class), any(Coin.class), any(int.class))).thenReturn(true); when(provider.getLockWhitelist()).thenReturn(lockWhitelist); - when(provider.getNewFederationBtcUTXOs()) - .thenReturn(activeFederationUtxos); + when(provider.getNewFederationBtcUTXOs()).thenReturn(activeFederationUtxos); pegoutsWaitingForConfirmations = new PegoutsWaitingForConfirmations(new HashSet<>()); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(pegoutsWaitingForConfirmations); @@ -2566,7 +2550,7 @@ void old_fed_migration( co.rsk.bitcoinj.core.BtcBlock headBlock = new co.rsk.bitcoinj.core.BtcBlock( btcRegTestsParams, 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), Sha256Hash.of(new byte[]{1}), 1, 1, @@ -2574,17 +2558,36 @@ void old_fed_migration( new ArrayList<>() ); - StoredBlock chainHead = new StoredBlock(headBlock, new BigInteger("0"), height + BridgeSupportRegisterBtcTransactionTest.bridgeMainnetConstants.getBtc2RskMinimumAcceptableConfirmations()); + StoredBlock chainHead = new StoredBlock( + headBlock, + new BigInteger("0"), + height + BridgeSupportRegisterBtcTransactionTest.bridgeMainnetConstants.getBtc2RskMinimumAcceptableConfirmations() + ); when(btcBlockStore.getChainHead()).thenReturn(chainHead); when(btcBlockStore.getStoredBlockAtMainChainHeight(block.getHeight())).thenReturn(block); when(mockFactory.newInstance(any(), any(), any(), any())).thenReturn(btcBlockStore); - co.rsk.bitcoinj.core.BtcBlock btcBlock = - new co.rsk.bitcoinj.core.BtcBlock(btcRegTestsParams, 1, BitcoinTestUtils.createHash(1), blockMerkleRoot, - 1, 1, 1, new ArrayList<>()); + co.rsk.bitcoinj.core.BtcBlock btcBlock = new co.rsk.bitcoinj.core.BtcBlock( + btcRegTestsParams, + 1, + BitcoinTestUtils.createHash(1), + blockMerkleRoot, + 1, + 1, + 1, + new ArrayList<>() + ); - mockChainOfStoredBlocks(btcBlockStore, btcBlock, height + BridgeSupportRegisterBtcTransactionTest.bridgeMainnetConstants.getBtc2RskMinimumAcceptableConfirmations(), height); + mockChainOfStoredBlocks( + btcBlockStore, + btcBlock, + height + BridgeSupportRegisterBtcTransactionTest.bridgeMainnetConstants.getBtc2RskMinimumAcceptableConfirmations(), + height + ); + + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); // act BridgeSupport bridgeSupport = new BridgeSupportBuilder() @@ -2597,6 +2600,7 @@ void old_fed_migration( .withBtcLockSenderProvider(btcLockSenderProvider) .withPeginInstructionsProvider(peginInstructionsProvider) .withExecutionBlock(rskExecutionBlock) + .withFeePerKbSupport(feePerKbSupport) .build(); bridgeSupport.registerBtcTransaction( @@ -2609,7 +2613,7 @@ void old_fed_migration( // assert verify(bridgeEventLogger, never()).logUnrefundablePegin(migrationTx, LEGACY_PEGIN_UNDETERMINED_SENDER); verify(bridgeEventLogger, never()).logPeginBtc(any(), any(), any(), anyInt()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertTrue(retiringFederationUtxos.isEmpty()); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(migrationTx.getHash(false), rskExecutionBlock.getNumber()); if (shouldUsePegoutTxIndex) { @@ -2621,8 +2625,8 @@ void old_fed_migration( any(BtcTransaction.class), eq(Coin.COIN) ); - Assertions.assertEquals(1, pegoutsWaitingForConfirmations.getEntries().size()); - Assertions.assertTrue(activeFederationUtxos.isEmpty()); + assertEquals(1, pegoutsWaitingForConfirmations.getEntries().size()); + assertTrue(activeFederationUtxos.isEmpty()); } else { verify(bridgeEventLogger, never()).logRejectedPegin( any(), any() @@ -2632,7 +2636,7 @@ void old_fed_migration( any(), any() ); - Assertions.assertEquals(1, activeFederationUtxos.size()); + assertEquals(1, activeFederationUtxos.size()); } } @@ -2683,8 +2687,8 @@ void last_retired_fed_to_active_fed( // assert verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertEquals(1, activeFederationUtxos.size()); + assertTrue(retiringFederationUtxos.isEmpty()); } @ParameterizedTest @@ -2735,8 +2739,8 @@ void no_last_retired_fed_in_storage_sending_funds_to_active_fed( verify(bridgeEventLogger, never()).logRejectedPegin(any(), any()); verify(bridgeEventLogger, never()).logReleaseBtcRequested(any(), any(), any()); verify(provider, times(1)).setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(false), rskExecutionBlock.getNumber()); - Assertions.assertEquals(1, activeFederationUtxos.size()); - Assertions.assertTrue(retiringFederationUtxos.isEmpty()); + assertEquals(1, activeFederationUtxos.size()); + assertTrue(retiringFederationUtxos.isEmpty()); } else { assertPeginIsRejectedAndRefunded(activations, btcTransaction, Coin.COIN, RejectedPeginReason.LEGACY_PEGIN_MULTISIG_SENDER); } diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportReleaseBtcTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportReleaseBtcTest.java index 1ce3339998e..bdd414e577b 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportReleaseBtcTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportReleaseBtcTest.java @@ -29,6 +29,8 @@ import co.rsk.peg.federation.FederationArgs; import co.rsk.peg.federation.FederationFactory; import co.rsk.peg.federation.FederationTestUtils; +import co.rsk.peg.feeperkb.FeePerKbSupport; +import co.rsk.peg.feeperkb.FeePerKbSupportImpl; import co.rsk.peg.utils.BridgeEventLogger; import co.rsk.peg.utils.BridgeEventLoggerImpl; import co.rsk.peg.utils.RejectedPegoutReason; @@ -48,10 +50,14 @@ import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.program.InternalTransaction; import org.ethereum.vm.program.Program; -import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.fail; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; import java.io.IOException; import java.math.BigInteger; @@ -78,7 +84,7 @@ class BridgeSupportReleaseBtcTest { private BridgeConstants bridgeConstants; private ActivationConfig.ForBlock activationsBeforeForks; - private ActivationConfig.ForBlock activationMock = mock(ActivationConfig.ForBlock.class); + private final ActivationConfig.ForBlock activationMock = mock(ActivationConfig.ForBlock.class); private Federation activeFederation; private Repository repository; private BridgeEventLogger eventLogger; @@ -88,6 +94,7 @@ class BridgeSupportReleaseBtcTest { private Transaction releaseTx; private BridgeSupportBuilder bridgeSupportBuilder; private SignatureCache signatureCache; + private FeePerKbSupport feePerKbSupport; @BeforeEach void setUpOnEachTest() throws IOException { @@ -100,6 +107,8 @@ void setUpOnEachTest() throws IOException { utxo = buildUTXO(); provider = initProvider(repository, activationMock); bridgeSupportBuilder = new BridgeSupportBuilder(); + feePerKbSupport = mock(FeePerKbSupportImpl.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(bridgeConstants.getFeePerKbConstants().getGenesisFeePerKb()); bridgeSupport = spy(initBridgeSupport(eventLogger, activationMock)); releaseTx = buildReleaseRskTx(); } @@ -201,8 +210,8 @@ void handmade_release_before_rskip_146_185() throws IOException { bridgeSupport.updateCollections(rskTx); verify(repository, never()).transfer(any(), any(), any()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); verify(eventLogger, never()).logReleaseBtcRequested(any(byte[].class), any(BtcTransaction.class), any(Coin.class)); verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); @@ -225,8 +234,8 @@ void handmade_release_after_rskip_146() throws IOException { bridgeSupport.updateCollections(rskTx); verify(repository, never()).transfer(any(), any(), any()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); verify(eventLogger, times(1)).logReleaseBtcRequested( any(byte[].class), any(BtcTransaction.class), @@ -252,10 +261,10 @@ void handmade_release_after_rskip_146_185() throws IOException { verify(repository, never()).transfer(any(), any(), any()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(3, logInfo.size()); + assertEquals(3, logInfo.size()); verify(eventLogger, times(1)).logReleaseBtcRequested( any(byte[].class), any(BtcTransaction.class), @@ -267,7 +276,7 @@ void handmade_release_after_rskip_146_185() throws IOException { LogInfo logInfo1 = logInfo.get(0); CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED_LEGACY.getEvent(); Object btcDestinationAddress = event.decodeEventData(logInfo1.getData())[0]; - Assertions.assertTrue(btcDestinationAddress instanceof byte[]); + assertInstanceOf(byte[].class, btcDestinationAddress); } @Test @@ -289,10 +298,10 @@ void handmade_release_after_rskip_146_185_326() throws IOException { verify(repository, never()).transfer(any(), any(), any()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(3, logInfo.size()); + assertEquals(3, logInfo.size()); verify(eventLogger, times(1)).logReleaseBtcRequested( any(byte[].class), any(BtcTransaction.class), @@ -305,7 +314,7 @@ void handmade_release_after_rskip_146_185_326() throws IOException { LogInfo logInfo1 = logInfo.get(0); CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED.getEvent(); Object btcDestinationAddress = event.decodeEventData(logInfo1.getData())[0]; - Assertions.assertTrue(btcDestinationAddress instanceof String); + assertInstanceOf(String.class, btcDestinationAddress); } @Test @@ -327,11 +336,11 @@ void handmade_release_after_rskip_146_rejected_lowAmount() throws IOException { verify(repository, never()).transfer(any(), any(), any()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); verify(eventLogger, never()).logReleaseBtcRequestRejected(any(), any(), any()); - Assertions.assertEquals(1, logInfo.size()); + assertEquals(1, logInfo.size()); verify(eventLogger, times(1)).logUpdateCollections(any()); } @@ -354,15 +363,15 @@ void handmade_release_after_rskip_146_185_rejected_lowAmount() throws IOExceptio bridgeSupport.updateCollections(rskTx); verify(repository, times(1)).transfer( - argThat((a) -> a.equals(PrecompiledContracts.BRIDGE_ADDR)), - argThat((a) -> a.equals(new RskAddress(SENDER.getAddress()))), - argThat((a) -> a.equals(co.rsk.core.Coin.fromBitcoin(Coin.ZERO))) + argThat(a -> a.equals(PrecompiledContracts.BRIDGE_ADDR)), + argThat(a -> a.equals(new RskAddress(SENDER.getAddress()))), + argThat(a -> a.equals(co.rsk.core.Coin.fromBitcoin(Coin.ZERO))) ); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(2, logInfo.size()); + assertEquals(2, logInfo.size()); verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); verify(eventLogger, times(1)).logReleaseBtcRequestRejected(any(), any(), any()); verify(eventLogger, times(1)).logUpdateCollections(any()); @@ -391,10 +400,10 @@ void handmade_release_after_rskip_146_185_rejected_contractCaller() throws IOExc any(), any(), any() ); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); - Assertions.assertEquals(2, logInfo.size()); + assertEquals(2, logInfo.size()); verify(eventLogger, times(1)).logReleaseBtcRequestRejected(any(), any(), any()); verify(eventLogger, times(1)).logUpdateCollections(any()); @@ -413,9 +422,9 @@ void handmade_release_after_rskip_146_rejected_contractCaller() throws IOExcepti releaseTx = buildReleaseRskTx_fromContract(Coin.COIN); try { bridgeSupport.releaseBtc(releaseTx); - Assertions.fail(); + fail(); } catch (Program.OutOfGasException e) { - Assertions.assertTrue(e.getMessage().contains("Contract calling releaseBTC")); + assertTrue(e.getMessage().contains("Contract calling releaseBTC")); } } @@ -432,8 +441,8 @@ void release_after_rskip_219() throws IOException { // Get a value between old and new minimum pegout values Coin middle = bridgeConstants.getLegacyMinimumPegoutTxValue().subtract(bridgeConstants.getMinimumPegoutTxValue()).div(2); Coin value = bridgeConstants.getMinimumPegoutTxValue().add(middle); - Assertions.assertTrue(value.isLessThan(bridgeConstants.getLegacyMinimumPegoutTxValue())); - Assertions.assertTrue(value.isGreaterThan(bridgeConstants.getMinimumPegoutTxValue())); + assertTrue(value.isLessThan(bridgeConstants.getLegacyMinimumPegoutTxValue())); + assertTrue(value.isGreaterThan(bridgeConstants.getMinimumPegoutTxValue())); bridgeSupport.releaseBtc(buildReleaseRskTx(value)); Transaction rskTx = buildUpdateTx(); @@ -441,16 +450,15 @@ void release_after_rskip_219() throws IOException { verify(repository, never()).transfer(any(), any(), any()); - Assertions.assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, logInfo.size()); + assertEquals(1, logInfo.size()); verify(eventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); LogInfo logInfo1 = logInfo.get(0); CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED_LEGACY.getEvent(); Object btcDestinationAddress = event.decodeEventData(logInfo1.getData())[0]; - Assertions.assertTrue(btcDestinationAddress instanceof byte[]); - + assertInstanceOf(byte[].class, btcDestinationAddress); } @Test @@ -467,8 +475,8 @@ void release_after_rskip_219_326() throws IOException { // Get a value between old and new minimum pegout values Coin middle = bridgeConstants.getLegacyMinimumPegoutTxValue().subtract(bridgeConstants.getMinimumPegoutTxValue()).div(2); Coin value = bridgeConstants.getMinimumPegoutTxValue().add(middle); - Assertions.assertTrue(value.isLessThan(bridgeConstants.getLegacyMinimumPegoutTxValue())); - Assertions.assertTrue(value.isGreaterThan(bridgeConstants.getMinimumPegoutTxValue())); + assertTrue(value.isLessThan(bridgeConstants.getLegacyMinimumPegoutTxValue())); + assertTrue(value.isGreaterThan(bridgeConstants.getMinimumPegoutTxValue())); bridgeSupport.releaseBtc(buildReleaseRskTx(value)); Transaction rskTx = buildUpdateTx(); @@ -476,15 +484,15 @@ void release_after_rskip_219_326() throws IOException { verify(repository, never()).transfer(any(), any(), any()); - Assertions.assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, logInfo.size()); + assertEquals(1, logInfo.size()); verify(eventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); LogInfo logInfo1 = logInfo.get(0); CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED.getEvent(); Object btcDestinationAddress = event.decodeEventData(logInfo1.getData())[0]; - Assertions.assertTrue(btcDestinationAddress instanceof String); + assertInstanceOf(String.class, btcDestinationAddress); } @Test @@ -500,16 +508,16 @@ void release_before_rskip_219() throws IOException { // Get a value between old and new minimum pegout values Coin middle = bridgeConstants.getLegacyMinimumPegoutTxValue().subtract(bridgeConstants.getMinimumPegoutTxValue()).div(2); Coin value = bridgeConstants.getMinimumPegoutTxValue().add(middle); - Assertions.assertTrue(value.isLessThan(bridgeConstants.getLegacyMinimumPegoutTxValue())); - Assertions.assertTrue(value.isGreaterThan(bridgeConstants.getMinimumPegoutTxValue())); + assertTrue(value.isLessThan(bridgeConstants.getLegacyMinimumPegoutTxValue())); + assertTrue(value.isGreaterThan(bridgeConstants.getMinimumPegoutTxValue())); bridgeSupport.releaseBtc(buildReleaseRskTx(value)); Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, logInfo.size()); + assertEquals(1, logInfo.size()); verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); verify(eventLogger, times(1)).logReleaseBtcRequestRejected(any(), any(), any()); } @@ -531,9 +539,9 @@ void release_before_rskip_219_minimum_exclusive() throws IOException { Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, logInfo.size()); + assertEquals(1, logInfo.size()); verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); verify(eventLogger, times(1)).logReleaseBtcRequestRejected(any(), any(), any()); } @@ -557,15 +565,15 @@ void release_after_rskip_219_minimum_inclusive() throws IOException { verify(repository, never()).transfer(any(), any(), any()); - Assertions.assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, logInfo.size()); + assertEquals(1, logInfo.size()); verify(eventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); LogInfo logInfo1 = logInfo.get(0); CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED_LEGACY.getEvent(); Object btcDestinationAddress = event.decodeEventData(logInfo1.getData())[0]; - Assertions.assertTrue(btcDestinationAddress instanceof byte[]); + assertInstanceOf(byte[].class, btcDestinationAddress); } @Test @@ -588,23 +596,22 @@ void release_after_rskip_219_326_minimum_inclusive() throws IOException { verify(repository, never()).transfer(any(), any(), any()); - Assertions.assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, logInfo.size()); + assertEquals(1, logInfo.size()); verify(eventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); LogInfo logInfo1 = logInfo.get(0); CallTransaction.Function event = BridgeEvents.RELEASE_REQUEST_RECEIVED.getEvent(); Object btcDestinationAddress = event.decodeEventData(logInfo1.getData())[0]; - Assertions.assertTrue(btcDestinationAddress instanceof String); + assertInstanceOf(String.class, btcDestinationAddress); } @Test void release_verify_fee_below_fee_is_rejected() throws IOException { Coin value = bridgeConstants.getMinimumPegoutTxValue().add(Coin.SATOSHI); - - testPegoutMinimumWithFeeVerification(Coin.COIN, value, false); + testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(Coin.COIN, value); } @Test @@ -614,8 +621,7 @@ void release_verify_fee_above_fee_but_below_gap_is_rejected_before_rskip_271() t int pegoutSize = BridgeUtils.getRegularPegoutTxSize(activationMock, provider.getNewFederation()); Coin value = feePerKB.div(1000).times(pegoutSize); - - testPegoutMinimumWithFeeVerification(feePerKB, value, false); + testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(feePerKB, value); } @Test @@ -625,22 +631,20 @@ void release_verify_fee_above_fee_but_below_gap_is_rejected_after_rskip_271() th int pegoutSize = BridgeUtils.getRegularPegoutTxSize(activationMock, provider.getNewFederation()); Coin value = feePerKB.div(1000).times(pegoutSize); - - testPegoutMinimumWithFeeVerification(feePerKB, value, false); + testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(feePerKB, value); } @Test void release_verify_fee_above_fee_but_below_minimum_is_rejected() throws IOException { - testPegoutMinimumWithFeeVerification( + testPegoutMinimumWithFeeVerificationRejectedByLowAmount( Coin.MILLICOIN, - bridgeConstants.getMinimumPegoutTxValue().minus(Coin.SATOSHI), - false + bridgeConstants.getMinimumPegoutTxValue().minus(Coin.SATOSHI) ); } @Test void release_verify_fee_above_fee_and_minimum_is_accepted() throws IOException { - testPegoutMinimumWithFeeVerification(Coin.COIN, Coin.FIFTY_COINS, true); + testPegoutMinimumWithFeeVerificationPass(Coin.COIN, Coin.FIFTY_COINS); } @Test @@ -653,10 +657,10 @@ void test_processPegoutsIndividually_before_RSKIP271_activation() throws IOExcep BridgeStorageProvider provider = mock(BridgeStorageProvider.class); when(provider.getNewFederationBtcUTXOs()).thenReturn(utxos); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN)))); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN)) + )); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); BridgeSupport bridgeSupport = bridgeSupportBuilder @@ -669,8 +673,8 @@ void test_processPegoutsIndividually_before_RSKIP271_activation() throws IOExcep bridgeSupport.updateCollections(rskTx); // assert pegouts were not batched - Assertions.assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); verify(provider, never()).getNextPegoutHeight(); verify(provider, never()).setNextPegoutHeight(any(Long.class)); @@ -685,11 +689,11 @@ void test_processPegoutsInBatch_after_RSKIP271() throws IOException { List utxos = new ArrayList<>(); utxos.add(PegTestUtils.createUTXO(1, 0, Coin.COIN.multiply(4), genesisFederation.getAddress())); - ReleaseRequestQueue pegoutRequests = new ReleaseRequestQueue( - Arrays.asList( - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.MILLICOIN), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.MILLICOIN), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.MILLICOIN))); + ReleaseRequestQueue pegoutRequests = new ReleaseRequestQueue(Arrays.asList( + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.MILLICOIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.MILLICOIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "three"), Coin.MILLICOIN) + )); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); when(provider.getNewFederationBtcUTXOs()).thenReturn(utxos); @@ -716,8 +720,8 @@ void test_processPegoutsInBatch_after_RSKIP271() throws IOException { Transaction rskTx = buildUpdateTx(); bridgeSupport.updateCollections(rskTx); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); BtcTransaction generatedTransaction = provider.getPegoutsWaitingForConfirmations().getEntries().iterator().next().getBtcTransaction(); @@ -740,11 +744,10 @@ void test_processPegoutsInBatch_after_RSKIP271_activation_next_pegout_height_not BridgeStorageProvider provider = mock(BridgeStorageProvider.class); when(provider.getNextPegoutHeight()).thenReturn(Optional.of(executionBlockNumber + bridgeConstants.getNumberOfBlocksBetweenPegouts() - 1)); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue( - Arrays.asList( - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.MILLICOIN), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.MILLICOIN)))); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.MILLICOIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.MILLICOIN) + ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); BridgeSupport bridgeSupport = bridgeSupportBuilder @@ -760,8 +763,8 @@ void test_processPegoutsInBatch_after_RSKIP271_activation_next_pegout_height_not verify(provider, times(1)).getNextPegoutHeight(); verify(provider, never()).setNextPegoutHeight(any(Long.class)); - Assertions.assertEquals(2, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(2, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); } @Test @@ -804,14 +807,13 @@ void test_processPegoutsInBatch_after_rskip_271_Insufficient_Money() throws IOEx BridgeStorageProvider provider = mock(BridgeStorageProvider.class); when(provider.getNewFederationBtcUTXOs()).thenReturn(utxos); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue( - Arrays.asList( - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN)))); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "three"), Coin.COIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "four"), Coin.COIN), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "five"), Coin.COIN) + ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); BridgeSupport bridgeSupport = bridgeSupportBuilder @@ -825,8 +827,8 @@ void test_processPegoutsInBatch_after_rskip_271_Insufficient_Money() throws IOEx // Insufficient_Money i.e 4 BTC UTXO Available For 5 BTC Transaction. // Pegout requests can't be processed and remains in the queue - Assertions.assertEquals(5, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(5, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); } @Test @@ -852,15 +854,15 @@ void test_processPegoutsInBatch_after_rskip_271_divide_transaction_when_max_size bridgeSupport.updateCollections(rskTx); // First Half of the PegoutRequests 600 / 2 = 300 Is Batched For The First Time - Assertions.assertEquals(300, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(300, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); rskTx = buildUpdateTx(); bridgeSupport.updateCollections(rskTx); // The Rest PegoutRequests 600 / 2 = 300 Is Batched The 2nd Time updateCollections Is Called - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(2, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(2, provider.getPegoutsWaitingForConfirmations().getEntries().size()); } @Test @@ -873,9 +875,9 @@ void test_processPegoutsInBatch_after_rskip_271_when_max_size_exceeded_for_one_p BridgeStorageProvider provider = mock(BridgeStorageProvider.class); when(provider.getNewFederationBtcUTXOs()).thenReturn(utxos); - when(provider.getReleaseRequestQueue()).thenReturn( - new ReleaseRequestQueue(Collections.singletonList( - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(700))))); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Collections.singletonList( + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN.multiply(700)) + ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); BridgeSupport bridgeSupport = bridgeSupportBuilder @@ -887,8 +889,8 @@ void test_processPegoutsInBatch_after_rskip_271_when_max_size_exceeded_for_one_p Transaction rskTx = buildUpdateTx(); bridgeSupport.updateCollections(rskTx); - Assertions.assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); } @Test @@ -902,8 +904,9 @@ void test_processPegoutsInBatch_after_rskip_271_when_max_size_exceeded_for_two_p when(provider.getNewFederationBtcUTXOs()).thenReturn(utxos); when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(700)), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(700))))); + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN.multiply(700)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN.multiply(700)) + ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); BridgeSupport bridgeSupport = bridgeSupportBuilder @@ -915,8 +918,8 @@ void test_processPegoutsInBatch_after_rskip_271_when_max_size_exceeded_for_two_p Transaction rskTx = buildUpdateTx(); bridgeSupport.updateCollections(rskTx); - Assertions.assertEquals(2, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(2, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); } @Test @@ -929,9 +932,9 @@ void test_processPegoutsIndividually_before_rskip_271_no_funds_to_process_any_re utxos.add(PegTestUtils.createUTXO(2, 1, Coin.COIN, genesisFederation.getAddress())); List entries = Arrays.asList( - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(5)), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(4)), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(3)) + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN.multiply(5)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN.multiply(4)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "three"), Coin.COIN.multiply(3)) ); ReleaseRequestQueue originalPegoutRequests = new ReleaseRequestQueue(entries); @@ -952,8 +955,8 @@ void test_processPegoutsIndividually_before_rskip_271_no_funds_to_process_any_re Transaction rskTx = buildUpdateTx(); bridgeSupport.updateCollections(rskTx); - Assertions.assertEquals(originalPegoutRequests, provider.getReleaseRequestQueue()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(originalPegoutRequests, provider.getReleaseRequestQueue()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); } @Test @@ -999,11 +1002,11 @@ void test_processPegoutsIndividually_before_rskip_271_no_funds_to_process_any_re Transaction rskTx = buildUpdateTx(); bridgeSupport.updateCollections(rskTx); - Assertions.assertNotEquals(originalPegoutRequests, provider.getReleaseRequestQueue()); + assertNotEquals(originalPegoutRequests, provider.getReleaseRequestQueue()); - Assertions.assertEquals(expectedPegoutRequests, provider.getReleaseRequestQueue()); + assertEquals(expectedPegoutRequests, provider.getReleaseRequestQueue()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); } @Test @@ -1016,11 +1019,11 @@ void test_check_wallet_balance_before_rskip_271_process_at_least_one_request() t BridgeStorageProvider provider = mock(BridgeStorageProvider.class); when(provider.getNewFederationBtcUTXOs()).thenReturn(utxos); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(4)), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(3)), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(2))))); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN.multiply(4)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN.multiply(3)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "three"), Coin.COIN.multiply(2)) + ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); BridgeSupport bridgeSupport = bridgeSupportBuilder @@ -1033,8 +1036,8 @@ void test_check_wallet_balance_before_rskip_271_process_at_least_one_request() t bridgeSupport.updateCollections(rskTx); // 2 remains in queue, 1 is processed to the transaction set - Assertions.assertEquals(2, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(2, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); } @Test @@ -1049,11 +1052,11 @@ void test_check_wallet_balance_after_rskip_271_process_no_requests() throws IOEx BridgeStorageProvider provider = mock(BridgeStorageProvider.class); when(provider.getNewFederationBtcUTXOs()).thenReturn(utxos); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(5)), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(4)), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(3))))); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN.multiply(5)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN.multiply(4)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "three"), Coin.COIN.multiply(3)) + ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); BridgeSupport bridgeSupport = bridgeSupportBuilder @@ -1066,8 +1069,8 @@ void test_check_wallet_balance_after_rskip_271_process_no_requests() throws IOEx Transaction rskTx = buildUpdateTx(); bridgeSupport.updateCollections(rskTx); - Assertions.assertEquals(3, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(3, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); verify(eventLogger, never()).logBatchPegoutCreated(any(), any()); verify(provider, never()).setNextPegoutHeight(any(Long.class)); @@ -1085,11 +1088,11 @@ void test_check_wallet_balance_after_rskip_271_process_all_requests_when_utxos_a BridgeStorageProvider provider = mock(BridgeStorageProvider.class); when(provider.getNewFederationBtcUTXOs()).thenReturn(utxos); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(Arrays.asList( - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(5)), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(4)), - new ReleaseRequestQueue.Entry(PegTestUtils.createRandomP2PKHBtcAddress(bridgeConstants.getBtcParams()), Coin.COIN.multiply(3))))); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Arrays.asList( + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "one"), Coin.COIN.multiply(5)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "two"), Coin.COIN.multiply(4)), + new ReleaseRequestQueue.Entry(BitcoinTestUtils.createP2PKHAddress(bridgeConstants.getBtcParams(), "three"), Coin.COIN.multiply(3)) + ))); when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); BridgeSupport bridgeSupport = bridgeSupportBuilder @@ -1103,8 +1106,8 @@ void test_check_wallet_balance_after_rskip_271_process_all_requests_when_utxos_a Transaction rskTx = buildUpdateTx(); bridgeSupport.updateCollections(rskTx); - Assertions.assertEquals(3, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(3, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntries().size()); verify(eventLogger, never()).logBatchPegoutCreated(any(), any()); verify(provider, never()).setNextPegoutHeight(any(Long.class)); @@ -1122,14 +1125,14 @@ void test_check_wallet_balance_after_rskip_271_process_all_requests_when_utxos_a Transaction rskTx2 = buildUpdateTx(); bridgeSupport.updateCollections(rskTx2); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); verify(eventLogger, times(1)).logBatchPegoutCreated(any(), any()); verify(provider, times(1)).setNextPegoutHeight(any(Long.class)); } - private void testPegoutMinimumWithFeeVerification(Coin feePerKB, Coin value, boolean shouldPegout) + private void testPegoutMinimumWithFeeVerificationPass(Coin feePerKB, Coin value) throws IOException { when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); @@ -1138,15 +1141,13 @@ private void testPegoutMinimumWithFeeVerification(Coin feePerKB, Coin value, boo List logInfo = new ArrayList<>(); BridgeEventLoggerImpl eventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); bridgeSupport = initBridgeSupport(eventLogger, activationMock); - - provider.setFeePerKb(feePerKB); + when(feePerKbSupport.getFeePerKb()).thenReturn(feePerKB); int pegoutSize = BridgeUtils.getRegularPegoutTxSize(activationMock, provider.getNewFederation()); - Coin minValueAccordingToFee = provider.getFeePerKb().div(1000).times(pegoutSize); + Coin minValueAccordingToFee = feePerKbSupport.getFeePerKb().div(1000).times(pegoutSize); Coin minValueWithGapAboveFee = minValueAccordingToFee.add(minValueAccordingToFee.times(bridgeConstants.getMinimumPegoutValuePercentageToReceiveAfterFee()).div(100)); - // if shouldPegout true then value should be greater or equals than both required fee plus gap and min pegout value - // if shouldPegout false then value should be smaller than any of those minimums - Assertions.assertEquals(!shouldPegout, value.isLessThan(minValueWithGapAboveFee) || + + assertFalse(value.isLessThan(minValueWithGapAboveFee) || value.isLessThan(bridgeConstants.getMinimumPegoutTxValue())); bridgeSupport.releaseBtc(buildReleaseRskTx(value)); @@ -1154,23 +1155,97 @@ private void testPegoutMinimumWithFeeVerification(Coin feePerKB, Coin value, boo Transaction rskTx = buildUpdateTx(); rskTx.sign(SENDER.getPrivKeyBytes()); - verify(repository, shouldPegout ? never() : times(1)).transfer(any(), any(), any()); - - Assertions.assertEquals(shouldPegout ? 1 : 0, provider.getReleaseRequestQueue().getEntries().size()); - - Assertions.assertEquals(1, logInfo.size()); - verify(eventLogger, shouldPegout ? times(1) : never()).logReleaseBtcRequestReceived(any(), any(), any()); - ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(RejectedPegoutReason.class); - verify(eventLogger, shouldPegout ? never() : times(1)).logReleaseBtcRequestRejected(any(), any(), argumentCaptor.capture()); - if (!shouldPegout) { - // Verify rejected pegout reason using value in comparison with fee and pegout minimum - Assertions.assertEquals( - value.isLessThan(minValueWithGapAboveFee) ? - RejectedPegoutReason.FEE_ABOVE_VALUE : - RejectedPegoutReason.LOW_AMOUNT, - argumentCaptor.getValue() - ); - } + verify(repository, never()).transfer(any(), any(), any()); + + assertEquals(1, provider.getReleaseRequestQueue().getEntries().size()); + + assertEquals(1, logInfo.size()); + verify(eventLogger, times(1)).logReleaseBtcRequestReceived(any(), any(), any()); + verify(eventLogger, never()).logReleaseBtcRequestRejected(any(), any(), any()); + } + + private void testPegoutMinimumWithFeeVerificationRejectedByLowAmount(Coin feePerKB, Coin value) + throws IOException { + when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); + when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); + when(activationMock.isActive(ConsensusRule.RSKIP219)).thenReturn(true); + + RskAddress bridgeAddress = PrecompiledContracts.BRIDGE_ADDR; + + List logInfo = new ArrayList<>(); + BridgeEventLoggerImpl eventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); + bridgeSupport = initBridgeSupport(eventLogger, activationMock); + when(feePerKbSupport.getFeePerKb()).thenReturn(feePerKB); + + int pegoutSize = BridgeUtils.getRegularPegoutTxSize(activationMock, provider.getNewFederation()); + Coin minValueAccordingToFee = feePerKbSupport.getFeePerKb().div(1000).times(pegoutSize); + Coin minValueWithGapAboveFee = minValueAccordingToFee.add(minValueAccordingToFee.times(bridgeConstants.getMinimumPegoutValuePercentageToReceiveAfterFee()).div(100)); + + assertTrue(value.isGreaterThan(minValueWithGapAboveFee)); + + bridgeSupport.releaseBtc(buildReleaseRskTx(value)); + + RskAddress senderAddress = new RskAddress(SENDER.getAddress()); + + Transaction rskTx = buildUpdateTx(); + rskTx.sign(SENDER.getPrivKeyBytes()); + + co.rsk.core.Coin coin = co.rsk.core.Coin.fromBitcoin(value); + + verify(repository, times(1)).transfer(bridgeAddress, senderAddress, coin); + + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + + assertEquals(1, logInfo.size()); + + verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); + + verify(eventLogger, times(1)) + .logReleaseBtcRequestRejected(senderAddress.toHexString(), value, RejectedPegoutReason.LOW_AMOUNT); + + } + + private void testPegoutMinimumWithFeeVerificationRejectedByFeeAboveValue(Coin feePerKB, Coin value) + throws IOException { + when(activationMock.isActive(ConsensusRule.RSKIP146)).thenReturn(true); + when(activationMock.isActive(ConsensusRule.RSKIP185)).thenReturn(true); + when(activationMock.isActive(ConsensusRule.RSKIP219)).thenReturn(true); + + RskAddress bridgeAddress = PrecompiledContracts.BRIDGE_ADDR; + + List logInfo = new ArrayList<>(); + BridgeEventLoggerImpl eventLogger = spy(new BridgeEventLoggerImpl(bridgeConstants, activationMock, logInfo, signatureCache)); + bridgeSupport = initBridgeSupport(eventLogger, activationMock); + when(feePerKbSupport.getFeePerKb()).thenReturn(feePerKB); + + int pegoutSize = BridgeUtils.getRegularPegoutTxSize(activationMock, provider.getNewFederation()); + Coin minValueAccordingToFee = feePerKbSupport.getFeePerKb().div(1000).times(pegoutSize); + Coin minValueWithGapAboveFee = minValueAccordingToFee.add(minValueAccordingToFee.times(bridgeConstants.getMinimumPegoutValuePercentageToReceiveAfterFee()).div(100)); + + assertTrue(value.isLessThan(minValueWithGapAboveFee)); + + bridgeSupport.releaseBtc(buildReleaseRskTx(value)); + + RskAddress senderAddress = new RskAddress(SENDER.getAddress()); + + Transaction rskTx = buildUpdateTx(); + rskTx.sign(SENDER.getPrivKeyBytes()); + + co.rsk.core.Coin coin = co.rsk.core.Coin.fromBitcoin(value); + + verify(repository, times(1)).transfer(bridgeAddress, senderAddress, coin); + + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + + assertEquals(1, logInfo.size()); + + verify(eventLogger, never()).logReleaseBtcRequestReceived(any(), any(), any()); + + verify(eventLogger, times(1)).logReleaseBtcRequestRejected( + senderAddress.toHexString(), + value, + RejectedPegoutReason.FEE_ABOVE_VALUE + ); } /********************************** @@ -1239,6 +1314,7 @@ private BridgeSupport initBridgeSupport(BridgeEventLogger eventLogger, Activatio .withEventLogger(eventLogger) .withActivations(activationMock) .withSignatureCache(signatureCache) + .withFeePerKbSupport(feePerKbSupport) .build(); } diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSigHashTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSigHashTest.java index a0dfede33e9..ee8d1edd9d1 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSigHashTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportSigHashTest.java @@ -10,6 +10,7 @@ import co.rsk.peg.federation.FederationArgs; import co.rsk.peg.federation.FederationFactory; import co.rsk.peg.federation.FederationTestUtils; +import co.rsk.peg.feeperkb.FeePerKbSupport; import co.rsk.test.builders.BridgeSupportBuilder; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; @@ -41,9 +42,6 @@ class BridgeSupportSigHashTest { void init() throws IOException { provider = mock(BridgeStorageProvider.class); - when(provider.getFeePerKb()) - .thenReturn(Coin.MILLICOIN); - when(provider.getPegoutsWaitingForSignatures()) .thenReturn(new TreeMap<>()); @@ -67,18 +65,22 @@ void test_pegoutTxIndex_when_pegout_batch_is_created(ActivationConfig.ForBlock a 10, federationAddress ); - when(provider.getNewFederationBtcUTXOs()) - .thenReturn(fedUTXOs); + when(provider.getNewFederationBtcUTXOs()).thenReturn(fedUTXOs); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(PegTestUtils.createReleaseRequestQueueEntries(3))); + when(provider.getReleaseRequestQueue()).thenReturn( + new ReleaseRequestQueue(PegTestUtils.createReleaseRequestQueueEntries(3)) + ); PegoutsWaitingForConfirmations pegoutsWaitingForConfirmations = provider.getPegoutsWaitingForConfirmations(); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = new BridgeSupportBuilder() .withBridgeConstants(bridgeMainnetConstants) .withProvider(provider) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); // Act @@ -105,39 +107,43 @@ void test_pegoutTxIndex_when_pegout_batch_is_created(ActivationConfig.ForBlock a @MethodSource("pegoutTxIndexArgsProvider") void test_pegoutTxIndex_when_migration_tx_is_created(ActivationConfig.ForBlock activations) throws IOException { // Arrange - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(Collections.emptyList())); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Collections.emptyList())); PegoutsWaitingForConfirmations pegoutsWaitingForConfirmations = provider.getPegoutsWaitingForConfirmations(); Federation oldFederation = FederationTestUtils.getGenesisFederation(bridgeMainnetConstants); long newFedCreationBlockNumber = 5L; - FederationArgs newFederationArgs = new FederationArgs(FederationTestUtils.getFederationMembers(1), - Instant.EPOCH, newFedCreationBlockNumber, btcMainnetParams); + FederationArgs newFederationArgs = new FederationArgs( + FederationTestUtils.getFederationMembers(1), + Instant.EPOCH, + newFedCreationBlockNumber, + btcMainnetParams + ); Federation newFederation = FederationFactory.buildStandardMultiSigFederation(newFederationArgs); - when(provider.getOldFederation()) - .thenReturn(oldFederation); - when(provider.getNewFederation()) - .thenReturn(newFederation); + when(provider.getOldFederation()).thenReturn(oldFederation); + when(provider.getNewFederation()).thenReturn(newFederation); // Utxos to migrate List utxos = PegTestUtils.createUTXOs(10, oldFederation.getAddress()); - when(provider.getOldFederationBtcUTXOs()) - .thenReturn(utxos); + when(provider.getOldFederationBtcUTXOs()).thenReturn(utxos); // Advance blockchain to migration phase. Migration phase starts 1 block after migration age is reached. long migrationAge = bridgeMainnetConstants.getFederationActivationAge(activations) + - bridgeMainnetConstants.getFundsMigrationAgeSinceActivationBegin() + - newFedCreationBlockNumber + 1; + bridgeMainnetConstants.getFundsMigrationAgeSinceActivationBegin() + + newFedCreationBlockNumber + 1; BlockGenerator blockGenerator = new BlockGenerator(); org.ethereum.core.Block rskCurrentBlock = blockGenerator.createBlock(migrationAge, 1); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = new BridgeSupportBuilder() .withBridgeConstants(bridgeMainnetConstants) .withProvider(provider) .withExecutionBlock(rskCurrentBlock) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); Transaction rskTx = mock(Transaction.class); @@ -179,37 +185,40 @@ void test_pegoutTxIndex_when_migration_and_pegout_batch_tx_are_created(Activatio Federation oldFederation = FederationTestUtils.getGenesisFederation(bridgeMainnetConstants); long newFedCreationBlockNumber = 5L; - FederationArgs newFederationArgs = new FederationArgs(FederationTestUtils.getFederationMembers(1), - Instant.EPOCH, newFedCreationBlockNumber, btcMainnetParams); - Federation newFederation = FederationFactory.buildStandardMultiSigFederation( - newFederationArgs); - when(provider.getOldFederation()) - .thenReturn(oldFederation); - when(provider.getNewFederation()) - .thenReturn(newFederation); + FederationArgs newFederationArgs = new FederationArgs( + FederationTestUtils.getFederationMembers(1), + Instant.EPOCH, + newFedCreationBlockNumber, + btcMainnetParams + ); + Federation newFederation = FederationFactory.buildStandardMultiSigFederation(newFederationArgs); + when(provider.getOldFederation()).thenReturn(oldFederation); + when(provider.getNewFederation()).thenReturn(newFederation); // Utxos to migrate List utxos = PegTestUtils.createUTXOs(10, oldFederation.getAddress()); - when(provider.getOldFederationBtcUTXOs()) - .thenReturn(utxos); + when(provider.getOldFederationBtcUTXOs()).thenReturn(utxos); List utxosNew = PegTestUtils.createUTXOs(10, newFederation.getAddress()); - when(provider.getNewFederationBtcUTXOs()) - .thenReturn(utxosNew); + when(provider.getNewFederationBtcUTXOs()).thenReturn(utxosNew); // Advance blockchain to migration phase. Migration phase starts 1 block after migration age is reached. long migrationAge = bridgeMainnetConstants.getFederationActivationAge(activations) + - bridgeMainnetConstants.getFundsMigrationAgeSinceActivationBegin() + - newFedCreationBlockNumber + 1; + bridgeMainnetConstants.getFundsMigrationAgeSinceActivationBegin() + + newFedCreationBlockNumber + 1; BlockGenerator blockGenerator = new BlockGenerator(); org.ethereum.core.Block rskCurrentBlock = blockGenerator.createBlock(migrationAge, 1); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = new BridgeSupportBuilder() .withBridgeConstants(bridgeMainnetConstants) .withProvider(provider) .withExecutionBlock(rskCurrentBlock) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); Transaction rskTx = mock(Transaction.class); 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 956b39641b8..ed1aac76bb5 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -24,13 +24,11 @@ import co.rsk.bitcoinj.store.BlockStoreException; import co.rsk.bitcoinj.wallet.Wallet; import co.rsk.blockchain.utils.BlockGenerator; -import co.rsk.peg.constants.BridgeConstants; -import co.rsk.peg.constants.BridgeMainNetConstants; -import co.rsk.peg.constants.BridgeRegTestConstants; -import co.rsk.peg.constants.BridgeTestNetConstants; +import co.rsk.peg.constants.*; import co.rsk.core.RskAddress; import co.rsk.crypto.Keccak256; -import co.rsk.peg.vote.ABICallElection; +import co.rsk.peg.feeperkb.FeePerKbResponseCode; +import co.rsk.peg.feeperkb.FeePerKbSupport; import co.rsk.peg.bitcoin.BitcoinTestUtils; import co.rsk.peg.bitcoin.CoinbaseInformation; import co.rsk.peg.bitcoin.MerkleBranch; @@ -38,10 +36,7 @@ import co.rsk.peg.btcLockSender.BtcLockSender.TxSenderAddressType; import co.rsk.peg.btcLockSender.BtcLockSenderProvider; import co.rsk.peg.federation.*; -import co.rsk.peg.pegininstructions.PeginInstructions; -import co.rsk.peg.pegininstructions.PeginInstructionsException; -import co.rsk.peg.pegininstructions.PeginInstructionsProvider; -import co.rsk.peg.pegininstructions.PeginInstructionsVersion1; +import co.rsk.peg.pegininstructions.*; import co.rsk.peg.utils.BridgeEventLogger; import co.rsk.peg.utils.MerkleTreeUtils; import co.rsk.peg.pegin.RejectedPeginReason; @@ -59,10 +54,8 @@ import org.ethereum.core.*; import org.ethereum.crypto.ECKey; import org.ethereum.crypto.HashUtil; -import org.ethereum.util.ByteUtil; import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.exception.VMException; -import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -81,14 +74,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.hamcrest.core.Is.is; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.*; @@ -133,179 +122,34 @@ void activations_is_set() { } @Test - void voteFeePerKbChange_nullFeeThrows() { - BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - Transaction tx = mock(Transaction.class); - BridgeConstants constants = mock(BridgeConstants.class); - AddressBasedAuthorizer authorizer = mock(AddressBasedAuthorizer.class); - - when(provider.getFeePerKbElection(any())).thenReturn(new ABICallElection(null)); - when(tx.getSender(any(SignatureCache.class))).thenReturn(new RskAddress(ByteUtil.leftPadBytes(new byte[]{0x43}, 20))); - when(constants.getFeePerKbChangeAuthorizer()).thenReturn(authorizer); - when(authorizer.isAuthorized(eq(tx), any())).thenReturn(true); + void getFeePerKb() { + Coin feePerKb = Coin.valueOf(10_000L); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(feePerKb); BridgeSupport bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(constants) - .withProvider(provider) + .withFeePerKbSupport(feePerKbSupport) .build(); - assertThrows(NullPointerException.class, () -> bridgeSupport.voteFeePerKbChange(tx, null)); + Coin result = bridgeSupport.getFeePerKb(); - verify(provider, never()).setFeePerKb(any()); + assertEquals(feePerKb, result); } @Test - void voteFeePerKbChange_unsuccessfulVote_unauthorized() { - BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - Transaction tx = mock(Transaction.class); - BridgeConstants constants = mock(BridgeConstants.class); - AddressBasedAuthorizer authorizer = mock(AddressBasedAuthorizer.class); - byte[] senderBytes = ByteUtil.leftPadBytes(new byte[]{0x43}, 20); - - when(provider.getFeePerKbElection(any())).thenReturn(new ABICallElection(authorizer)); - when(tx.getSender(any(SignatureCache.class))).thenReturn(new RskAddress(senderBytes)); - when(constants.getFeePerKbChangeAuthorizer()).thenReturn(authorizer); - when(authorizer.isAuthorized(eq(tx), any())).thenReturn(false); - - BridgeSupport bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(constants) - .withProvider(provider) - .build(); - - MatcherAssert.assertThat(bridgeSupport.voteFeePerKbChange(tx, Coin.CENT), is(-10)); - verify(provider, never()).setFeePerKb(any()); - } - - @Test - void voteFeePerKbChange_unsuccessfulVote_negativeFeePerKb() { - BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - Transaction tx = mock(Transaction.class); - BridgeConstants constants = mock(BridgeConstants.class); - AddressBasedAuthorizer authorizer = mock(AddressBasedAuthorizer.class); - - when(provider.getFeePerKbElection(any())) - .thenReturn(new ABICallElection(authorizer)); - when(constants.getFeePerKbChangeAuthorizer()) - .thenReturn(authorizer); - when(authorizer.isAuthorized(eq(tx), any())) - .thenReturn(true); - when(authorizer.getRequiredAuthorizedKeys()) - .thenReturn(2); + void voteFeePerKbChange_success() { + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.voteFeePerKbChange(any(), any(), any())).thenReturn(1); BridgeSupport bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(constants) - .withProvider(provider) + .withFeePerKbSupport(feePerKbSupport) .build(); - MatcherAssert.assertThat(bridgeSupport.voteFeePerKbChange(tx, Coin.NEGATIVE_SATOSHI), is(-1)); - MatcherAssert.assertThat(bridgeSupport.voteFeePerKbChange(tx, Coin.ZERO), is(-1)); - verify(provider, never()).setFeePerKb(any()); - } - - @Test - void voteFeePerKbChange_unsuccessfulVote_excessiveFeePerKb() { - final long MAX_FEE_PER_KB = 5_000_000L; - BridgeStorageProvider provider = mock(BridgeStorageProvider.class); Transaction tx = mock(Transaction.class); - BridgeConstants constants = mock(BridgeConstants.class); - AddressBasedAuthorizer authorizer = mock(AddressBasedAuthorizer.class); - byte[] senderBytes = ByteUtil.leftPadBytes(new byte[]{0x43}, 20); - - RskAddress sender = new RskAddress(senderBytes); - - when(provider.getFeePerKbElection(any())) - .thenReturn(new ABICallElection(authorizer)); - when(tx.getSender(any(SignatureCache.class))) - .thenReturn(sender); - when(constants.getFeePerKbChangeAuthorizer()) - .thenReturn(authorizer); - when(authorizer.isAuthorized(eq(tx), any())) - .thenReturn(true); - when(authorizer.isAuthorized(sender)) - .thenReturn(true); - when(authorizer.getRequiredAuthorizedKeys()) - .thenReturn(2); - when(constants.getMaxFeePerKb()) - .thenReturn(Coin.valueOf(MAX_FEE_PER_KB)); + Coin feePerKbVote = Coin.CENT; + int result = bridgeSupport.voteFeePerKbChange(tx, feePerKbVote); - BridgeSupport bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(constants) - .withProvider(provider) - .build(); - - MatcherAssert.assertThat(bridgeSupport.voteFeePerKbChange(tx, Coin.valueOf(MAX_FEE_PER_KB)), is(1)); - MatcherAssert.assertThat(bridgeSupport.voteFeePerKbChange(tx, Coin.valueOf(MAX_FEE_PER_KB + 1)), is(-2)); - verify(provider, never()).setFeePerKb(any()); - } - - @Test - void voteFeePerKbChange_successfulVote() { - final long MAX_FEE_PER_KB = 5_000_000L; - BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - Transaction tx = mock(Transaction.class); - BridgeConstants constants = mock(BridgeConstants.class); - AddressBasedAuthorizer authorizer = mock(AddressBasedAuthorizer.class); - byte[] senderBytes = ByteUtil.leftPadBytes(new byte[]{0x43}, 20); - - RskAddress sender = new RskAddress(senderBytes); - - when(provider.getFeePerKbElection(any())) - .thenReturn(new ABICallElection(authorizer)); - when(tx.getSender(any(SignatureCache.class))) - .thenReturn(sender); - when(constants.getFeePerKbChangeAuthorizer()) - .thenReturn(authorizer); - when(authorizer.isAuthorized(eq(tx), any())) - .thenReturn(true); - when(authorizer.isAuthorized(sender)) - .thenReturn(true); - when(authorizer.getRequiredAuthorizedKeys()) - .thenReturn(2); - when(constants.getMaxFeePerKb()) - .thenReturn(Coin.valueOf(MAX_FEE_PER_KB)); - - BridgeSupport bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(constants) - .withProvider(provider) - .build(); - - MatcherAssert.assertThat(bridgeSupport.voteFeePerKbChange(tx, Coin.CENT), is(1)); - verify(provider, never()).setFeePerKb(any()); - } - - @Test - void voteFeePerKbChange_successfulVoteWithFeeChange() { - final long MAX_FEE_PER_KB = 5_000_000L; - BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - Transaction tx = mock(Transaction.class); - BridgeConstants constants = mock(BridgeConstants.class); - AddressBasedAuthorizer authorizer = mock(AddressBasedAuthorizer.class); - byte[] senderBytes = ByteUtil.leftPadBytes(new byte[]{0x43}, 20); - - RskAddress sender = new RskAddress(senderBytes); - - when(provider.getFeePerKbElection(any())) - .thenReturn(new ABICallElection(authorizer)); - when(tx.getSender(any(SignatureCache.class))) - .thenReturn(sender); - when(constants.getFeePerKbChangeAuthorizer()) - .thenReturn(authorizer); - when(authorizer.isAuthorized(eq(tx), any())) - .thenReturn(true); - when(authorizer.isAuthorized(sender)) - .thenReturn(true); - when(authorizer.getRequiredAuthorizedKeys()) - .thenReturn(1); - when(constants.getMaxFeePerKb()) - .thenReturn(Coin.valueOf(MAX_FEE_PER_KB)); - - BridgeSupport bridgeSupport = bridgeSupportBuilder - .withBridgeConstants(constants) - .withProvider(provider) - .build(); - - MatcherAssert.assertThat(bridgeSupport.voteFeePerKbChange(tx, Coin.CENT), is(1)); - verify(provider).setFeePerKb(Coin.CENT); + assertEquals(FeePerKbResponseCode.SUCCESSFUL_VOTE.getCode(), result); } @Test @@ -987,15 +831,14 @@ void registerBtcTransactionLockTxNotWhitelisted_before_rskip_146_activation() th 0L, btcParams ); - Federation newFederation = FederationFactory.buildStandardMultiSigFederation( - newFederationArgs - ); + Federation newFederation = FederationFactory.buildStandardMultiSigFederation(newFederationArgs); // Creates retiring federation List retiringFederationKeys = Arrays.asList( BtcECKey.fromPrivate(Hex.decode("fb01")), BtcECKey.fromPrivate(Hex.decode("fb02")), - BtcECKey.fromPrivate(Hex.decode("fb03"))); + BtcECKey.fromPrivate(Hex.decode("fb03")) + ); FederationArgs retiringFederationArgs = new FederationArgs( FederationTestUtils.getFederationMembersWithBtcKeys(retiringFederationKeys), @@ -1003,9 +846,7 @@ void registerBtcTransactionLockTxNotWhitelisted_before_rskip_146_activation() th 0L, btcParams ); - Federation retiringFederation = FederationFactory.buildStandardMultiSigFederation( - retiringFederationArgs - ); + Federation retiringFederation = FederationFactory.buildStandardMultiSigFederation(retiringFederationArgs); Repository repository = createRepository(); repository.addBalance(PrecompiledContracts.BRIDGE_ADDR, LIMIT_MONETARY_BASE); @@ -1030,7 +871,7 @@ void registerBtcTransactionLockTxNotWhitelisted_before_rskip_146_activation() th tx3.addOutput(Coin.COIN.multiply(3), newFederation.getAddress()); tx3.addOutput(Coin.COIN.multiply(4), retiringFederation.getAddress()); BtcECKey srcKey3 = new BtcECKey(); - tx3.addInput(PegTestUtils.createHash(), 0, ScriptBuilder.createInputScript(null, srcKey3)); + tx3.addInput(BitcoinTestUtils.createHash(1), 0, ScriptBuilder.createInputScript(null, srcKey3)); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); @@ -1041,15 +882,21 @@ void registerBtcTransactionLockTxNotWhitelisted_before_rskip_146_activation() th BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); when(mockFactory.newInstance(repository, bridgeConstantsRegtest, provider, activations)).thenReturn(btcBlockStore); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstantsRegtest, - provider, - repository, - bridgeEventLogger, - executionBlock, - mockFactory, - activations - ); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .withRepository(repository) + .withEventLogger(bridgeEventLogger) + .withExecutionBlock(executionBlock) + .withBtcLockSenderProvider(new BtcLockSenderProvider()) + .withBtcBlockStoreFactory(mockFactory) + .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) + .build(); + byte[] bits = new byte[1]; bits[0] = 0x3f; @@ -1088,17 +935,17 @@ void registerBtcTransactionLockTxNotWhitelisted_before_rskip_146_activation() th RskAddress srcKey2RskAddress = new RskAddress(org.ethereum.crypto.ECKey.fromPrivate(srcKey2.getPrivKey()).getAddress()); RskAddress srcKey3RskAddress = new RskAddress(org.ethereum.crypto.ECKey.fromPrivate(srcKey3.getPrivKey()).getAddress()); - Assertions.assertEquals(0, repository.getBalance(srcKey1RskAddress).asBigInteger().intValue()); - Assertions.assertEquals(0, repository.getBalance(srcKey2RskAddress).asBigInteger().intValue()); - Assertions.assertEquals(0, repository.getBalance(srcKey3RskAddress).asBigInteger().intValue()); - Assertions.assertEquals(LIMIT_MONETARY_BASE, repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); + assertEquals(0, repository.getBalance(srcKey1RskAddress).asBigInteger().intValue()); + assertEquals(0, repository.getBalance(srcKey2RskAddress).asBigInteger().intValue()); + assertEquals(0, repository.getBalance(srcKey3RskAddress).asBigInteger().intValue()); + assertEquals(LIMIT_MONETARY_BASE, repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); - Assertions.assertEquals(0, provider.getNewFederationBtcUTXOs().size()); - Assertions.assertEquals(0, provider.getOldFederationBtcUTXOs().size()); + assertEquals(0, provider.getNewFederationBtcUTXOs().size()); + assertEquals(0, provider.getOldFederationBtcUTXOs().size()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(3, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(3, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); List pegoutBtcTxs = provider.getPegoutsWaitingForConfirmations().getEntries() .stream() @@ -1108,38 +955,38 @@ void registerBtcTransactionLockTxNotWhitelisted_before_rskip_146_activation() th // First release tx should correspond to the 5 BTC lock tx BtcTransaction pegoutBtcTx = pegoutBtcTxs.get(0); - Assertions.assertEquals(1, pegoutBtcTx.getOutputs().size()); - MatcherAssert.assertThat(Coin.COIN.multiply(5).subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); - Assertions.assertEquals(srcKey1.toAddress(btcRegTestParams), pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); - Assertions.assertEquals(1, pegoutBtcTx.getInputs().size()); - Assertions.assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); - Assertions.assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); + assertEquals(1, pegoutBtcTx.getOutputs().size()); + assertThat(Coin.COIN.multiply(5).subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); + assertEquals(srcKey1.toAddress(btcRegTestParams), pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); + assertEquals(1, pegoutBtcTx.getInputs().size()); + assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); + assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx1.getHash()).isPresent()); // Second release tx should correspond to the 7 (3+4) BTC lock tx pegoutBtcTx = pegoutBtcTxs.get(1); - Assertions.assertEquals(1, pegoutBtcTx.getOutputs().size()); - MatcherAssert.assertThat(Coin.COIN.multiply(7).subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); - Assertions.assertEquals(srcKey3.toAddress(btcRegTestParams), pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); - Assertions.assertEquals(2, pegoutBtcTx.getInputs().size()); + assertEquals(1, pegoutBtcTx.getOutputs().size()); + assertThat(Coin.COIN.multiply(7).subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); + assertEquals(srcKey3.toAddress(btcRegTestParams), pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); + assertEquals(2, pegoutBtcTx.getInputs().size()); List releaseOutpoints = pegoutBtcTx.getInputs().stream().map(TransactionInput::getOutpoint).sorted(Comparator.comparing(TransactionOutPoint::getIndex)).collect(Collectors.toList()); - Assertions.assertEquals(tx3.getHash(), releaseOutpoints.get(0).getHash()); - Assertions.assertEquals(tx3.getHash(), releaseOutpoints.get(1).getHash()); - Assertions.assertEquals(0, releaseOutpoints.get(0).getIndex()); - Assertions.assertEquals(1, releaseOutpoints.get(1).getIndex()); + assertEquals(tx3.getHash(), releaseOutpoints.get(0).getHash()); + assertEquals(tx3.getHash(), releaseOutpoints.get(1).getHash()); + assertEquals(0, releaseOutpoints.get(0).getIndex()); + assertEquals(1, releaseOutpoints.get(1).getIndex()); assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx3.getHash()).isPresent()); // Third release tx should correspond to the 10 BTC lock tx pegoutBtcTx = pegoutBtcTxs.get(2); - Assertions.assertEquals(1, pegoutBtcTx.getOutputs().size()); - MatcherAssert.assertThat(Coin.COIN.multiply(10).subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); - Assertions.assertEquals(srcKey2.toAddress(btcRegTestParams), pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); - Assertions.assertEquals(1, pegoutBtcTx.getInputs().size()); - Assertions.assertEquals(tx2.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); - Assertions.assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); + assertEquals(1, pegoutBtcTx.getOutputs().size()); + assertThat(Coin.COIN.multiply(10).subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); + assertEquals(srcKey2.toAddress(btcRegTestParams), pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); + assertEquals(1, pegoutBtcTx.getInputs().size()); + assertEquals(tx2.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); + assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx2.getHash()).isPresent()); - Assertions.assertTrue(provider.getPegoutsWaitingForSignatures().isEmpty()); + assertTrue(provider.getPegoutsWaitingForSignatures().isEmpty()); verify(bridgeEventLogger, never()).logReleaseBtcRequested(any(byte[].class), any(BtcTransaction.class), any(Coin.class)); } @@ -1163,24 +1010,21 @@ void registerBtcTransactionLockTxNotWhitelisted_after_rskip_146_activation() thr 0L, btcParams ); - Federation federation1 = FederationFactory.buildStandardMultiSigFederation( - federation1Args - ); + Federation federation1 = FederationFactory.buildStandardMultiSigFederation(federation1Args); //Creates federation 2 List federation2Keys = Arrays.asList( BtcECKey.fromPrivate(Hex.decode("fb01")), BtcECKey.fromPrivate(Hex.decode("fb02")), - BtcECKey.fromPrivate(Hex.decode("fb03"))); + BtcECKey.fromPrivate(Hex.decode("fb03")) + ); FederationArgs federation2Args = new FederationArgs(FederationTestUtils.getFederationMembersWithBtcKeys(federation2Keys), Instant.ofEpochMilli(2000L), 0L, btcParams ); - Federation federation2 = FederationFactory.buildStandardMultiSigFederation( - federation2Args - ); + Federation federation2 = FederationFactory.buildStandardMultiSigFederation(federation2Args); Repository repository = createRepository(); repository.addBalance(PrecompiledContracts.BRIDGE_ADDR, LIMIT_MONETARY_BASE); @@ -1217,15 +1061,21 @@ void registerBtcTransactionLockTxNotWhitelisted_after_rskip_146_activation() thr BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); when(mockFactory.newInstance(repository, bridgeConstantsRegtest, provider, activations)).thenReturn(btcBlockStore); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstantsRegtest, - provider, - repository, - bridgeEventLogger, - executionBlock, - mockFactory, - activations - ); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .withRepository(repository) + .withEventLogger(bridgeEventLogger) + .withBtcLockSenderProvider(new BtcLockSenderProvider()) + .withExecutionBlock(executionBlock) + .withBtcBlockStoreFactory(mockFactory) + .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) + .build(); + byte[] bits = new byte[1]; bits[0] = 0x3f; @@ -1264,17 +1114,17 @@ void registerBtcTransactionLockTxNotWhitelisted_after_rskip_146_activation() thr RskAddress srcKey2RskAddress = new RskAddress(org.ethereum.crypto.ECKey.fromPrivate(srcKey2.getPrivKey()).getAddress()); RskAddress srcKey3RskAddress = new RskAddress(org.ethereum.crypto.ECKey.fromPrivate(srcKey3.getPrivKey()).getAddress()); - Assertions.assertEquals(0, repository.getBalance(srcKey1RskAddress).asBigInteger().intValue()); - Assertions.assertEquals(0, repository.getBalance(srcKey2RskAddress).asBigInteger().intValue()); - Assertions.assertEquals(0, repository.getBalance(srcKey3RskAddress).asBigInteger().intValue()); - Assertions.assertEquals(LIMIT_MONETARY_BASE, repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); + assertEquals(0, repository.getBalance(srcKey1RskAddress).asBigInteger().intValue()); + assertEquals(0, repository.getBalance(srcKey2RskAddress).asBigInteger().intValue()); + assertEquals(0, repository.getBalance(srcKey3RskAddress).asBigInteger().intValue()); + assertEquals(LIMIT_MONETARY_BASE, repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); - Assertions.assertEquals(0, provider.getNewFederationBtcUTXOs().size()); - Assertions.assertEquals(0, provider.getOldFederationBtcUTXOs().size()); + assertEquals(0, provider.getNewFederationBtcUTXOs().size()); + assertEquals(0, provider.getOldFederationBtcUTXOs().size()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); - Assertions.assertEquals(3, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); + assertEquals(3, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); List pegoutBtcTxs = provider.getPegoutsWaitingForConfirmations().getEntries() .stream() @@ -1284,44 +1134,52 @@ void registerBtcTransactionLockTxNotWhitelisted_after_rskip_146_activation() thr // First release tx should correspond to the 5 BTC lock tx BtcTransaction pegoutBtcTx = pegoutBtcTxs.get(0); - Assertions.assertEquals(1, pegoutBtcTx.getOutputs().size()); - MatcherAssert.assertThat(Coin.COIN.multiply(5).subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); - Assertions.assertEquals(srcKey1.toAddress(btcRegTestParams), pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); - Assertions.assertEquals(1, pegoutBtcTx.getInputs().size()); - Assertions.assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); - Assertions.assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); + assertEquals(1, pegoutBtcTx.getOutputs().size()); + assertThat(Coin.COIN.multiply(5).subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); + assertEquals(srcKey1.toAddress(btcRegTestParams), pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); + assertEquals(1, pegoutBtcTx.getInputs().size()); + assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); + assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx1.getHash()).isPresent()); // First Rsk tx corresponds to this release - verify(bridgeEventLogger, times(1)).logReleaseBtcRequested(rskTx1.getHash().getBytes(), pegoutBtcTx, Coin.COIN.multiply(5)); + verify(bridgeEventLogger, times(1)).logReleaseBtcRequested( + rskTx1.getHash().getBytes(), + pegoutBtcTx, + Coin.COIN.multiply(5) + ); // Second release tx should correspond to the 7 (3+4) BTC lock tx pegoutBtcTx = pegoutBtcTxs.get(1); - Assertions.assertEquals(1, pegoutBtcTx.getOutputs().size()); - MatcherAssert.assertThat(Coin.COIN.multiply(7).subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); - Assertions.assertEquals(srcKey3.toAddress(btcRegTestParams), pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); - Assertions.assertEquals(2, pegoutBtcTx.getInputs().size()); + assertEquals(1, pegoutBtcTx.getOutputs().size()); + assertThat(Coin.COIN.multiply(7).subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); + assertEquals(srcKey3.toAddress(btcRegTestParams), pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); + assertEquals(2, pegoutBtcTx.getInputs().size()); List releaseOutpoints = pegoutBtcTx.getInputs().stream().map(TransactionInput::getOutpoint).sorted(Comparator.comparing(TransactionOutPoint::getIndex)).collect(Collectors.toList()); - Assertions.assertEquals(tx3.getHash(), releaseOutpoints.get(0).getHash()); - Assertions.assertEquals(tx3.getHash(), releaseOutpoints.get(1).getHash()); - Assertions.assertEquals(0, releaseOutpoints.get(0).getIndex()); - Assertions.assertEquals(1, releaseOutpoints.get(1).getIndex()); + assertEquals(tx3.getHash(), releaseOutpoints.get(0).getHash()); + assertEquals(tx3.getHash(), releaseOutpoints.get(1).getHash()); + assertEquals(0, releaseOutpoints.get(0).getIndex()); + assertEquals(1, releaseOutpoints.get(1).getIndex()); assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx3.getHash()).isPresent()); // third Rsk tx corresponds to this release - verify(bridgeEventLogger, times(1)).logReleaseBtcRequested(rskTx3.getHash().getBytes(), pegoutBtcTx, Coin.COIN.multiply(7)); + verify(bridgeEventLogger, times(1)).logReleaseBtcRequested( + rskTx3.getHash().getBytes(), + pegoutBtcTx, + Coin.COIN.multiply(7) + ); // Third release tx should correspond to the 10 BTC lock tx pegoutBtcTx = pegoutBtcTxs.get(2); - Assertions.assertEquals(1, pegoutBtcTx.getOutputs().size()); - MatcherAssert.assertThat(Coin.COIN.multiply(10).subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); - Assertions.assertEquals(srcKey2.toAddress(btcRegTestParams), pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); - Assertions.assertEquals(1, pegoutBtcTx.getInputs().size()); - Assertions.assertEquals(tx2.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); - Assertions.assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); + assertEquals(1, pegoutBtcTx.getOutputs().size()); + assertThat(Coin.COIN.multiply(10).subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); + assertEquals(srcKey2.toAddress(btcRegTestParams), pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); + assertEquals(1, pegoutBtcTx.getInputs().size()); + assertEquals(tx2.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); + assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx2.getHash()).isPresent()); // Second Rsk tx corresponds to this release verify(bridgeEventLogger, times(1)).logReleaseBtcRequested(rskTx2.getHash().getBytes(), pegoutBtcTx, Coin.COIN.multiply(10)); - Assertions.assertTrue(provider.getPegoutsWaitingForSignatures().isEmpty()); + assertTrue(provider.getPegoutsWaitingForSignatures().isEmpty()); } @Test @@ -1445,21 +1303,16 @@ void callProcessFundsMigration_is_migrating_before_rskip_146_activation() throws 5L, btcRegTestParams ); - Federation newFederation = FederationFactory.buildStandardMultiSigFederation( - newFederationArgs - ); + Federation newFederation = FederationFactory.buildStandardMultiSigFederation(newFederationArgs); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - when(provider.getFeePerKb()) - .thenReturn(Coin.MILLICOIN); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(Collections.emptyList())); - when(provider.getPegoutsWaitingForConfirmations()) - .thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); - when(provider.getOldFederation()) - .thenReturn(oldFederation); - when(provider.getNewFederation()) - .thenReturn(newFederation); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Collections.emptyList())); + when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); + when(provider.getOldFederation()).thenReturn(oldFederation); + when(provider.getNewFederation()).thenReturn(newFederation); + + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); BlockGenerator blockGenerator = new BlockGenerator(); // Old federation will be in migration age at block 35 @@ -1481,17 +1334,17 @@ void callProcessFundsMigration_is_migrating_before_rskip_146_activation() throws .withEventLogger(bridgeEventLogger) .withExecutionBlock(rskCurrentBlock) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); List sufficientUTXOsForMigration1 = new ArrayList<>(); sufficientUTXOsForMigration1.add(createUTXO(Coin.COIN, oldFederation.getAddress())); - when(provider.getOldFederationBtcUTXOs()) - .thenReturn(sufficientUTXOsForMigration1); + when(provider.getOldFederationBtcUTXOs()).thenReturn(sufficientUTXOsForMigration1); bridgeSupport.updateCollections(tx); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); verify(bridgeEventLogger, never()).logReleaseBtcRequested(any(byte[].class), any(BtcTransaction.class), any(Coin.class)); } @@ -1505,26 +1358,22 @@ void callProcessFundsMigration_is_migrating_after_rskip_146_activation() throws Federation oldFederation = FederationTestUtils.getGenesisFederation(bridgeConstantsRegtest); - FederationArgs newFederationArgs = new FederationArgs(FederationTestUtils.getFederationMembers(1), + FederationArgs newFederationArgs = new FederationArgs( + FederationTestUtils.getFederationMembers(1), Instant.EPOCH, 5L, btcRegTestParams ); - Federation newFederation = FederationFactory.buildStandardMultiSigFederation( - newFederationArgs - ); + Federation newFederation = FederationFactory.buildStandardMultiSigFederation(newFederationArgs); + + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - when(provider.getFeePerKb()) - .thenReturn(Coin.MILLICOIN); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(Collections.emptyList())); - when(provider.getPegoutsWaitingForConfirmations()) - .thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); - when(provider.getOldFederation()) - .thenReturn(oldFederation); - when(provider.getNewFederation()) - .thenReturn(newFederation); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Collections.emptyList())); + when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); + when(provider.getOldFederation()).thenReturn(oldFederation); + when(provider.getNewFederation()).thenReturn(newFederation); BlockGenerator blockGenerator = new BlockGenerator(); // Old federation will be in migration age at block 35 @@ -1547,20 +1396,24 @@ void callProcessFundsMigration_is_migrating_after_rskip_146_activation() throws .withEventLogger(bridgeEventLogger) .withExecutionBlock(rskCurrentBlock) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); List sufficientUTXOsForMigration1 = new ArrayList<>(); sufficientUTXOsForMigration1.add(createUTXO(Coin.COIN, oldFederation.getAddress())); - when(provider.getOldFederationBtcUTXOs()) - .thenReturn(sufficientUTXOsForMigration1); + when(provider.getOldFederationBtcUTXOs()).thenReturn(sufficientUTXOsForMigration1); bridgeSupport.updateCollections(tx); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); PegoutsWaitingForConfirmations.Entry entry = (PegoutsWaitingForConfirmations.Entry) provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().toArray()[0]; // Should have been logged with the migrated UTXO - verify(bridgeEventLogger, times(1)).logReleaseBtcRequested(tx.getHash().getBytes(), entry.getBtcTransaction(), Coin.COIN); + verify(bridgeEventLogger, times(1)).logReleaseBtcRequested( + tx.getHash().getBytes(), + entry.getBtcTransaction(), + Coin.COIN + ); } @Test @@ -1572,7 +1425,8 @@ void callProcessFundsMigration_is_migrated_before_rskip_146_activation() throws Federation oldFederation = FederationTestUtils.getGenesisFederation(bridgeConstantsRegtest); - FederationArgs newFederationArgs = new FederationArgs(FederationTestUtils.getFederationMembers(1), + FederationArgs newFederationArgs = new FederationArgs( + FederationTestUtils.getFederationMembers(1), Instant.EPOCH, 5L, btcRegTestParams @@ -1581,17 +1435,14 @@ void callProcessFundsMigration_is_migrated_before_rskip_146_activation() throws newFederationArgs ); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - when(provider.getFeePerKb()) - .thenReturn(Coin.MILLICOIN); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(Collections.emptyList())); - when(provider.getPegoutsWaitingForConfirmations()) - .thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); - when(provider.getOldFederation()) - .thenReturn(oldFederation); - when(provider.getNewFederation()) - .thenReturn(newFederation); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Collections.emptyList())); + when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); + when(provider.getOldFederation()).thenReturn(oldFederation); + when(provider.getNewFederation()).thenReturn(newFederation); BlockGenerator blockGenerator = new BlockGenerator(); // Old federation will be in migration age at block 35 @@ -1613,17 +1464,17 @@ void callProcessFundsMigration_is_migrated_before_rskip_146_activation() throws .withEventLogger(bridgeEventLogger) .withExecutionBlock(rskCurrentBlock) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); List sufficientUTXOsForMigration1 = new ArrayList<>(); sufficientUTXOsForMigration1.add(createUTXO(Coin.COIN, oldFederation.getAddress())); - when(provider.getOldFederationBtcUTXOs()) - .thenReturn(sufficientUTXOsForMigration1); + when(provider.getOldFederationBtcUTXOs()).thenReturn(sufficientUTXOsForMigration1); bridgeSupport.updateCollections(tx); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); verify(bridgeEventLogger, never()).logReleaseBtcRequested(any(byte[].class), any(BtcTransaction.class), any(Coin.class)); } @@ -1637,26 +1488,22 @@ void callProcessFundsMigration_is_migrated_after_rskip_146_activation() throws I Federation oldFederation = FederationTestUtils.getGenesisFederation(bridgeConstantsRegtest); - FederationArgs newFederationArgs = new FederationArgs(FederationTestUtils.getFederationMembers(1), + FederationArgs newFederationArgs = new FederationArgs( + FederationTestUtils.getFederationMembers(1), Instant.EPOCH, 5L, btcRegTestParams ); - Federation newFederation = FederationFactory.buildStandardMultiSigFederation( - newFederationArgs - ); + Federation newFederation = FederationFactory.buildStandardMultiSigFederation(newFederationArgs); + + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - when(provider.getFeePerKb()) - .thenReturn(Coin.MILLICOIN); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(Collections.emptyList())); - when(provider.getPegoutsWaitingForConfirmations()) - .thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); - when(provider.getOldFederation()) - .thenReturn(oldFederation); - when(provider.getNewFederation()) - .thenReturn(newFederation); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Collections.emptyList())); + when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); + when(provider.getOldFederation()).thenReturn(oldFederation); + when(provider.getNewFederation()).thenReturn(newFederation); BlockGenerator blockGenerator = new BlockGenerator(); // Old federation will be in migration age at block 35 @@ -1678,20 +1525,24 @@ void callProcessFundsMigration_is_migrated_after_rskip_146_activation() throws I .withEventLogger(bridgeEventLogger) .withExecutionBlock(rskCurrentBlock) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); List sufficientUTXOsForMigration1 = new ArrayList<>(); sufficientUTXOsForMigration1.add(createUTXO(Coin.COIN, oldFederation.getAddress())); - when(provider.getOldFederationBtcUTXOs()) - .thenReturn(sufficientUTXOsForMigration1); + when(provider.getOldFederationBtcUTXOs()).thenReturn(sufficientUTXOsForMigration1); bridgeSupport.updateCollections(tx); - Assertions.assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); + assertEquals(0, provider.getPegoutsWaitingForConfirmations().getEntriesWithoutHash().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().size()); PegoutsWaitingForConfirmations.Entry entry = (PegoutsWaitingForConfirmations.Entry) provider.getPegoutsWaitingForConfirmations().getEntriesWithHash().toArray()[0]; // Should have been logged with the migrated UTXO - verify(bridgeEventLogger, times(1)).logReleaseBtcRequested(tx.getHash().getBytes(), entry.getBtcTransaction(), Coin.COIN); + verify(bridgeEventLogger, times(1)).logReleaseBtcRequested( + tx.getHash().getBytes(), + entry.getBtcTransaction(), + Coin.COIN + ); } @Test @@ -1703,26 +1554,22 @@ void updateFederationCreationBlockHeights_before_rskip_186_activation() throws I Federation oldFederation = FederationTestUtils.getGenesisFederation(bridgeConstantsRegtest); - FederationArgs newFederationArgs = new FederationArgs(FederationTestUtils.getFederationMembers(1), + FederationArgs newFederationArgs = new FederationArgs( + FederationTestUtils.getFederationMembers(1), Instant.EPOCH, 5L, btcRegTestParams ); - Federation newFederation = FederationFactory.buildStandardMultiSigFederation( - newFederationArgs - ); + Federation newFederation = FederationFactory.buildStandardMultiSigFederation(newFederationArgs); + + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - when(provider.getFeePerKb()) - .thenReturn(Coin.MILLICOIN); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(Collections.emptyList())); - when(provider.getPegoutsWaitingForConfirmations()) - .thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); - when(provider.getOldFederation()) - .thenReturn(oldFederation); - when(provider.getNewFederation()) - .thenReturn(newFederation); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Collections.emptyList())); + when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); + when(provider.getOldFederation()).thenReturn(oldFederation); + when(provider.getNewFederation()).thenReturn(newFederation); BlockGenerator blockGenerator = new BlockGenerator(); // Old federation will be in migration age at block 35 @@ -1744,6 +1591,7 @@ void updateFederationCreationBlockHeights_before_rskip_186_activation() throws I .withEventLogger(bridgeEventLogger) .withExecutionBlock(rskCurrentBlock) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); List sufficientUTXOsForMigration1 = new ArrayList<>(); @@ -1773,21 +1621,16 @@ void updateFederationCreationBlockHeights_after_rskip_186_activation() throws IO 5L, btcRegTestParams ); - Federation newFederation = FederationFactory.buildStandardMultiSigFederation( - newFederationArgs - ); + Federation newFederation = FederationFactory.buildStandardMultiSigFederation(newFederationArgs); + + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - when(provider.getFeePerKb()) - .thenReturn(Coin.MILLICOIN); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(Collections.emptyList())); - when(provider.getPegoutsWaitingForConfirmations()) - .thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); - when(provider.getOldFederation()) - .thenReturn(oldFederation); - when(provider.getNewFederation()) - .thenReturn(newFederation); + when(provider.getReleaseRequestQueue()).thenReturn(new ReleaseRequestQueue(Collections.emptyList())); + when(provider.getPegoutsWaitingForConfirmations()).thenReturn(new PegoutsWaitingForConfirmations(Collections.emptySet())); + when(provider.getOldFederation()).thenReturn(oldFederation); + when(provider.getNewFederation()).thenReturn(newFederation); BlockGenerator blockGenerator = new BlockGenerator(); // Old federation will be in migration age at block 35 @@ -1809,12 +1652,12 @@ void updateFederationCreationBlockHeights_after_rskip_186_activation() throws IO .withEventLogger(bridgeEventLogger) .withExecutionBlock(rskCurrentBlock) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); List sufficientUTXOsForMigration1 = new ArrayList<>(); sufficientUTXOsForMigration1.add(createUTXO(Coin.COIN, oldFederation.getAddress())); - when(provider.getOldFederationBtcUTXOs()) - .thenReturn(sufficientUTXOsForMigration1); + when(provider.getOldFederationBtcUTXOs()).thenReturn(sufficientUTXOsForMigration1); when(provider.getNextFederationCreationBlockHeight()).thenReturn(Optional.empty()); @@ -2160,35 +2003,30 @@ void rskTxWaitingForSignature_fail_adding_an_already_existing_key_after_rskip_37 newFederationArgs ); - BridgeStorageProvider provider = mock(BridgeStorageProvider.class); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); - when(provider.getFeePerKb()) - .thenReturn(Coin.MILLICOIN); - when(provider.getReleaseRequestQueue()) - .thenReturn(new ReleaseRequestQueue(PegTestUtils.createReleaseRequestQueueEntries(3))); + BridgeStorageProvider provider = mock(BridgeStorageProvider.class); + when(provider.getReleaseRequestQueue()).thenReturn( + new ReleaseRequestQueue(PegTestUtils.createReleaseRequestQueueEntries(3)) + ); PegoutsWaitingForConfirmations pegoutsWaitingForConfirmations = new PegoutsWaitingForConfirmations(new HashSet<>()); - when(provider.getPegoutsWaitingForConfirmations()) - .thenReturn(pegoutsWaitingForConfirmations); + when(provider.getPegoutsWaitingForConfirmations()).thenReturn(pegoutsWaitingForConfirmations); SortedMap pegoutWaitingForSignatures = new TreeMap<>(); - when(provider.getPegoutsWaitingForSignatures()) - .thenReturn(pegoutWaitingForSignatures); + when(provider.getPegoutsWaitingForSignatures()).thenReturn(pegoutWaitingForSignatures); // Federation change on going - when(provider.getOldFederation()) - .thenReturn(oldFederation); - when(provider.getNewFederation()) - .thenReturn(newFederation); + when(provider.getOldFederation()).thenReturn(oldFederation); + when(provider.getNewFederation()).thenReturn(newFederation); // Utxos to migrate List utxos = PegTestUtils.createUTXOs(10, oldFederation.getAddress()); - when(provider.getOldFederationBtcUTXOs()) - .thenReturn(utxos); + when(provider.getOldFederationBtcUTXOs()).thenReturn(utxos); List utxosNew = PegTestUtils.createUTXOs(10, newFederation.getAddress()); - when(provider.getNewFederationBtcUTXOs()) - .thenReturn(utxosNew); + when(provider.getNewFederationBtcUTXOs()).thenReturn(utxosNew); // Advance blockchain to migration phase BlockGenerator blockGenerator = new BlockGenerator(); @@ -2199,6 +2037,7 @@ void rskTxWaitingForSignature_fail_adding_an_already_existing_key_after_rskip_37 .withProvider(provider) .withExecutionBlock(rskCurrentBlock) .withActivations(fingerrootActivations) + .withFeePerKbSupport(feePerKbSupport) .build(); Transaction tx = Transaction @@ -2250,6 +2089,7 @@ void rskTxWaitingForSignature_fail_adding_an_already_existing_key_after_rskip_37 .withProvider(provider) .withExecutionBlock(rskCurrentBlock) .withActivations(fingerrootActivations) + .withFeePerKbSupport(feePerKbSupport) .build(); tx = Transaction @@ -2284,6 +2124,7 @@ void rskTxWaitingForSignature_fail_adding_an_already_existing_key_after_rskip_37 .withProvider(provider) .withExecutionBlock(rskCurrentBlock) .withActivations(fingerrootActivations) + .withFeePerKbSupport(feePerKbSupport) .build(); Transaction throwsExceptionTx = Transaction @@ -2315,6 +2156,7 @@ void rskTxWaitingForSignature_fail_adding_an_already_existing_key_after_rskip_37 .withProvider(provider) .withExecutionBlock(rskCurrentBlock) .withActivations(fingerrootActivations) + .withFeePerKbSupport(feePerKbSupport) .build(); tx = Transaction @@ -2729,7 +2571,7 @@ void when_registerBtcTransaction_usesLegacyType_beforeFork_lock_and_no_refund() // Assert co.rsk.core.Coin totalAmountExpectedToHaveBeenLocked = co.rsk.core.Coin.fromBitcoin(amountToLock); - MatcherAssert.assertThat(whitelist.isWhitelisted(btcAddress), is(false)); + assertThat(whitelist.isWhitelisted(btcAddress), is(false)); Assertions.assertEquals(totalAmountExpectedToHaveBeenLocked, repository.getBalance(rskAddress)); Assertions.assertEquals(LIMIT_MONETARY_BASE.subtract(totalAmountExpectedToHaveBeenLocked), repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); Assertions.assertEquals(1, provider.getNewFederationBtcUTXOs().size()); @@ -2762,7 +2604,7 @@ void when_registerBtcTransaction_usesLegacyType_afterFork_notWhitelisted_no_lock Coin amountToLock = Coin.COIN.multiply(5); tx1.addOutput(amountToLock, federation1.getAddress()); - tx1.addInput(PegTestUtils.createHash(1), 0, ScriptBuilder.createInputScript(null, srcKey1)); + tx1.addInput(BitcoinTestUtils.createHash(1), 0, ScriptBuilder.createInputScript(null, srcKey1)); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); @@ -2777,17 +2619,22 @@ void when_registerBtcTransaction_usesLegacyType_afterFork_notWhitelisted_no_lock BtcLockSenderProvider btcLockSenderProvider = getBtcLockSenderProvider(TxSenderAddressType.P2PKH, btcAddress, rskAddress); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstantsRegtest, - provider, - repository, - btcLockSenderProvider, - new PeginInstructionsProvider(), - executionBlock, - mockFactory, - activations, - signatureCache - ); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .withRepository(repository) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withExecutionBlock(executionBlock) + .withBtcBlockStoreFactory(mockFactory) + .withActivations(activations) + .withSignatureCache(signatureCache) + .withFeePerKbSupport(feePerKbSupport) + .build(); + byte[] bits = new byte[1]; bits[0] = 0x3f; @@ -2800,7 +2647,7 @@ void when_registerBtcTransaction_usesLegacyType_afterFork_notWhitelisted_no_lock co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( btcRegTestParams, 1, - PegTestUtils.createHash(1), + BitcoinTestUtils.createHash(1), merkleRoot, 1, 1, @@ -2813,11 +2660,11 @@ void when_registerBtcTransaction_usesLegacyType_afterFork_notWhitelisted_no_lock mockChainOfStoredBlocks(btcBlockStore, registerHeader, 35, height); bridgeSupport.registerBtcTransaction(mock(Transaction.class), tx1.bitcoinSerialize(), height, pmt.bitcoinSerialize()); - MatcherAssert.assertThat(whitelist.isWhitelisted(btcAddress), is(false)); - Assertions.assertEquals(co.rsk.core.Coin.ZERO, repository.getBalance(rskAddress)); - Assertions.assertEquals(LIMIT_MONETARY_BASE, repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); - Assertions.assertEquals(0, provider.getNewFederationBtcUTXOs().size()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertThat(whitelist.isWhitelisted(btcAddress), is(false)); + assertEquals(co.rsk.core.Coin.ZERO, repository.getBalance(rskAddress)); + assertEquals(LIMIT_MONETARY_BASE, repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); + assertEquals(0, provider.getNewFederationBtcUTXOs().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); List pegoutBtcTxs = provider.getPegoutsWaitingForConfirmations().getEntries() .stream() @@ -2827,14 +2674,14 @@ void when_registerBtcTransaction_usesLegacyType_afterFork_notWhitelisted_no_lock // First release tx should correspond to the 5 BTC lock tx BtcTransaction pegoutBtcTx = pegoutBtcTxs.get(0); - Assertions.assertEquals(1, pegoutBtcTx.getOutputs().size()); - MatcherAssert.assertThat(amountToLock.subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); - Assertions.assertEquals(btcAddress, pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); - Assertions.assertEquals(1, pegoutBtcTx.getInputs().size()); - Assertions.assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); - Assertions.assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); - Assertions.assertTrue(provider.getPegoutsWaitingForSignatures().isEmpty()); - Assertions.assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx1.getHash()).isPresent()); + assertEquals(1, pegoutBtcTx.getOutputs().size()); + assertThat(amountToLock.subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); + assertEquals(btcAddress, pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); + assertEquals(1, pegoutBtcTx.getInputs().size()); + assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); + assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); + assertTrue(provider.getPegoutsWaitingForSignatures().isEmpty()); + assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx1.getHash()).isPresent()); } @Test @@ -2912,7 +2759,7 @@ void when_registerBtcTransaction_usesLegacyType_afterFork_lock_and_no_refund() t co.rsk.core.Coin totalAmountExpectedToHaveBeenLocked = co.rsk.core.Coin.fromBitcoin(Coin.valueOf(5, 0)); - MatcherAssert.assertThat(whitelist.isWhitelisted(btcAddress), is(false)); + assertThat(whitelist.isWhitelisted(btcAddress), is(false)); Assertions.assertEquals(totalAmountExpectedToHaveBeenLocked, repository.getBalance(rskAddress)); Assertions.assertEquals(LIMIT_MONETARY_BASE.subtract(totalAmountExpectedToHaveBeenLocked), repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); Assertions.assertEquals(1, provider.getNewFederationBtcUTXOs().size()); @@ -3082,7 +2929,7 @@ void when_registerBtcTransaction_usesSegCompatibilityType_afterFork_lock_and_no_ co.rsk.core.Coin totalAmountExpectedToHaveBeenLocked = co.rsk.core.Coin.fromBitcoin(Coin.valueOf(5, 0)); - MatcherAssert.assertThat(whitelist.isWhitelisted(btcAddress), is(false)); + assertThat(whitelist.isWhitelisted(btcAddress), is(false)); Assertions.assertEquals(totalAmountExpectedToHaveBeenLocked, repository.getBalance(rskAddress)); Assertions.assertEquals(LIMIT_MONETARY_BASE.subtract(totalAmountExpectedToHaveBeenLocked), repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); Assertions.assertEquals(1, provider.getNewFederationBtcUTXOs().size()); @@ -3115,7 +2962,7 @@ void when_registerBtcTransaction_usesSegCompatibilityType_afterFork_notWhitelist Coin amountToLock = Coin.COIN.multiply(5); tx1.addOutput(amountToLock, federation1.getAddress()); - tx1.addInput(PegTestUtils.createHash(1), 0, ScriptBuilder.createInputScript(null, srcKey1)); + tx1.addInput(BitcoinTestUtils.createHash(1), 0, ScriptBuilder.createInputScript(null, srcKey1)); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); @@ -3125,17 +2972,28 @@ void when_registerBtcTransaction_usesSegCompatibilityType_afterFork_notWhitelist BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); when(mockFactory.newInstance(repository, bridgeConstantsRegtest, provider, activations)).thenReturn(btcBlockStore); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstantsRegtest, - provider, - repository, - getBtcLockSenderProvider(TxSenderAddressType.P2SHP2WPKH, btcAddress, rskAddress), - new PeginInstructionsProvider(), - executionBlock, - mockFactory, - activations, - signatureCache + BtcLockSenderProvider btcLockSenderProvider =getBtcLockSenderProvider( + TxSenderAddressType.P2SHP2WPKH, + btcAddress, + rskAddress ); + + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .withRepository(repository) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withExecutionBlock(executionBlock) + .withBtcBlockStoreFactory(mockFactory) + .withActivations(activations) + .withSignatureCache(signatureCache) + .withFeePerKbSupport(feePerKbSupport) + .build(); + byte[] bits = new byte[1]; bits[0] = 0x3f; @@ -3148,7 +3006,7 @@ void when_registerBtcTransaction_usesSegCompatibilityType_afterFork_notWhitelist co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( btcRegTestParams, 1, - PegTestUtils.createHash(1), + BitcoinTestUtils.createHash(1), merkleRoot, 1, 1, @@ -3166,10 +3024,10 @@ void when_registerBtcTransaction_usesSegCompatibilityType_afterFork_notWhitelist pmt.bitcoinSerialize() ); - Assertions.assertEquals(co.rsk.core.Coin.ZERO, repository.getBalance(rskAddress)); - Assertions.assertEquals(LIMIT_MONETARY_BASE, repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); - Assertions.assertEquals(0, provider.getNewFederationBtcUTXOs().size()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(co.rsk.core.Coin.ZERO, repository.getBalance(rskAddress)); + assertEquals(LIMIT_MONETARY_BASE, repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); + assertEquals(0, provider.getNewFederationBtcUTXOs().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); List pegoutBtcTxs = provider.getPegoutsWaitingForConfirmations().getEntries() .stream() @@ -3179,14 +3037,14 @@ void when_registerBtcTransaction_usesSegCompatibilityType_afterFork_notWhitelist // First release tx should correspond to the 5 BTC lock tx BtcTransaction pegoutBtcTx = pegoutBtcTxs.get(0); - Assertions.assertEquals(1, pegoutBtcTx.getOutputs().size()); - MatcherAssert.assertThat(amountToLock.subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); - Assertions.assertEquals(btcAddress, pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); - Assertions.assertEquals(1, pegoutBtcTx.getInputs().size()); - Assertions.assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); - Assertions.assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); - Assertions.assertTrue(provider.getPegoutsWaitingForSignatures().isEmpty()); - Assertions.assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx1.getHash()).isPresent()); + assertEquals(1, pegoutBtcTx.getOutputs().size()); + assertThat(amountToLock.subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); + assertEquals(btcAddress, pegoutBtcTx.getOutput(0).getAddressFromP2PKHScript(btcRegTestParams)); + assertEquals(1, pegoutBtcTx.getInputs().size()); + assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); + assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); + assertTrue(provider.getPegoutsWaitingForSignatures().isEmpty()); + assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx1.getHash()).isPresent()); } @Test @@ -3299,17 +3157,22 @@ void when_registerBtcTransaction_usesMultisigType_afterFork_no_lock_and_refund() BtcLockSenderProvider btcLockSenderProvider = getBtcLockSenderProvider(TxSenderAddressType.P2SHMULTISIG, btcAddress, null); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstantsRegtest, - provider, - repository, - btcLockSenderProvider, - new PeginInstructionsProvider(), - executionBlock, - mockFactory, - activations, - signatureCache - ); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .withRepository(repository) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withExecutionBlock(executionBlock) + .withBtcBlockStoreFactory(mockFactory) + .withActivations(activations) + .withSignatureCache(signatureCache) + .withFeePerKbSupport(feePerKbSupport) + .build(); + byte[] bits = new byte[1]; bits[0] = 0x3f; @@ -3348,7 +3211,7 @@ void when_registerBtcTransaction_usesMultisigType_afterFork_no_lock_and_refund() // First release tx should correspond to the 5 BTC lock tx BtcTransaction pegoutBtcTx = pegoutBtcTxs.get(0); Assertions.assertEquals(1, pegoutBtcTx.getOutputs().size()); - MatcherAssert.assertThat(amountToLock.subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); + assertThat(amountToLock.subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); Assertions.assertEquals(btcAddress, pegoutBtcTx.getOutput(0).getScriptPubKey().getToAddress(btcRegTestParams)); Assertions.assertEquals(1, pegoutBtcTx.getInputs().size()); Assertions.assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); @@ -3456,7 +3319,7 @@ void when_registerBtcTransaction_usesMultisigWithWitnessType_afterFork_no_lock_a // First transaction goes only to the first federation BtcTransaction tx1 = new BtcTransaction(btcRegTestParams); tx1.addOutput(amountToLock, federation1.getAddress()); - tx1.addInput(PegTestUtils.createHash(1), 0, ScriptBuilder.createInputScript(null, srcKey1)); + tx1.addInput(BitcoinTestUtils.createHash(1), 0, ScriptBuilder.createInputScript(null, srcKey1)); BtcBlockStoreWithCache btcBlockStore = mock(BtcBlockStoreWithCache.class); @@ -3466,19 +3329,28 @@ void when_registerBtcTransaction_usesMultisigWithWitnessType_afterFork_no_lock_a BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); when(mockFactory.newInstance(repository, bridgeConstantsRegtest, provider, activations)).thenReturn(btcBlockStore); - BtcLockSenderProvider btcLockSenderProvider = getBtcLockSenderProvider(TxSenderAddressType.P2SHP2WSH, btcAddress, null); - - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstantsRegtest, - provider, - repository, - btcLockSenderProvider, - new PeginInstructionsProvider(), - executionBlock, - mockFactory, - activations, - signatureCache + BtcLockSenderProvider btcLockSenderProvider = getBtcLockSenderProvider( + TxSenderAddressType.P2SHP2WSH, + btcAddress, + null ); + + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .withRepository(repository) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withExecutionBlock(executionBlock) + .withBtcBlockStoreFactory(mockFactory) + .withActivations(activations) + .withSignatureCache(signatureCache) + .withFeePerKbSupport(feePerKbSupport) + .build(); + byte[] bits = new byte[1]; bits[0] = 0x3f; @@ -3491,7 +3363,7 @@ void when_registerBtcTransaction_usesMultisigWithWitnessType_afterFork_no_lock_a co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( btcRegTestParams, 1, - PegTestUtils.createHash(1), + BitcoinTestUtils.createHash(1), merkleRoot, 1, 1, @@ -3509,10 +3381,10 @@ void when_registerBtcTransaction_usesMultisigWithWitnessType_afterFork_no_lock_a pmt.bitcoinSerialize() ); - Assertions.assertEquals(LIMIT_MONETARY_BASE, repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); - Assertions.assertEquals(0, provider.getNewFederationBtcUTXOs().size()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(LIMIT_MONETARY_BASE, repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); + assertEquals(0, provider.getNewFederationBtcUTXOs().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); List pegoutBtcTxs = provider.getPegoutsWaitingForConfirmations().getEntries() .stream() @@ -3521,14 +3393,14 @@ void when_registerBtcTransaction_usesMultisigWithWitnessType_afterFork_no_lock_a // First release tx should correspond to the 5 BTC lock tx BtcTransaction pegoutBtcTx = pegoutBtcTxs.get(0); - Assertions.assertEquals(1, pegoutBtcTx.getOutputs().size()); - MatcherAssert.assertThat(amountToLock.subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); - Assertions.assertEquals(btcAddress, pegoutBtcTx.getOutput(0).getScriptPubKey().getToAddress(btcRegTestParams)); - Assertions.assertEquals(1, pegoutBtcTx.getInputs().size()); - Assertions.assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); - Assertions.assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); - Assertions.assertTrue(provider.getPegoutsWaitingForSignatures().isEmpty()); - Assertions.assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx1.getHash()).isPresent()); + assertEquals(1, pegoutBtcTx.getOutputs().size()); + assertThat(amountToLock.subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); + assertEquals(btcAddress, pegoutBtcTx.getOutput(0).getScriptPubKey().getToAddress(btcRegTestParams)); + assertEquals(1, pegoutBtcTx.getInputs().size()); + assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); + assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); + assertTrue(provider.getPegoutsWaitingForSignatures().isEmpty()); + assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx1.getHash()).isPresent()); } @Test @@ -4319,7 +4191,7 @@ void when_registerBtcTransaction_invalidPeginProtocolVersion_afterFork_no_lock_a BtcTransaction tx1 = new BtcTransaction(btcRegTestParams); tx1.addOutput(amountToLock, federation1.getAddress()); - tx1.addInput(PegTestUtils.createHash(1), 0, new Script(new byte[]{})); + tx1.addInput(BitcoinTestUtils.createHash(1), 0, new Script(new byte[]{})); byte[] bits = new byte[1]; bits[0] = 0x3f; @@ -4333,7 +4205,7 @@ void when_registerBtcTransaction_invalidPeginProtocolVersion_afterFork_no_lock_a co.rsk.bitcoinj.core.BtcBlock registerHeader = new co.rsk.bitcoinj.core.BtcBlock( btcRegTestParams, 1, - PegTestUtils.createHash(1), + BitcoinTestUtils.createHash(1), blockMerkleRoot, 1, 1, @@ -4349,7 +4221,7 @@ void when_registerBtcTransaction_invalidPeginProtocolVersion_afterFork_no_lock_a co.rsk.bitcoinj.core.BtcBlock headBlock = new co.rsk.bitcoinj.core.BtcBlock( btcRegTestParams, 1, - PegTestUtils.createHash(2), + BitcoinTestUtils.createHash(2), Sha256Hash.of(new byte[]{1}), 1, 1, @@ -4364,37 +4236,54 @@ void when_registerBtcTransaction_invalidPeginProtocolVersion_afterFork_no_lock_a BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); when(mockFactory.newInstance(any(), any(), any(), any())).thenReturn(btcBlockStore); - BridgeStorageProvider provider = new BridgeStorageProvider(repository, contractAddress, bridgeConstantsRegtest, activations); + BridgeStorageProvider provider = new BridgeStorageProvider( + repository, + contractAddress, + bridgeConstantsRegtest, + activations + ); provider.setNewFederation(federation1); - BtcLockSenderProvider btcLockSenderProvider = getBtcLockSenderProvider(TxSenderAddressType.P2PKH, btcAddressFromBtcLockSender, rskAddress); - - PeginInstructions peginInstructions = mock(PeginInstructions.class); - when(peginInstructions.getProtocolVersion()).thenReturn(99); - when(peginInstructions.getRskDestinationAddress()).thenReturn(rskDestinationAddress); - PeginInstructionsProvider peginInstructionsProvider = mock(PeginInstructionsProvider.class); - when(peginInstructionsProvider.buildPeginInstructions(any())).thenReturn(Optional.of(peginInstructions)); - - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstantsRegtest, - provider, - repository, - btcLockSenderProvider, - peginInstructionsProvider, - mock(Block.class), - mockFactory, - activations, - signatureCache + BtcLockSenderProvider btcLockSenderProvider = getBtcLockSenderProvider( + TxSenderAddressType.P2PKH, + btcAddressFromBtcLockSender, + rskAddress ); + PeginInstructions peginInstructions = mock(PeginInstructions.class); + when(peginInstructions.getProtocolVersion()).thenReturn(99); + when(peginInstructions.getRskDestinationAddress()).thenReturn(rskDestinationAddress); + PeginInstructionsProvider peginInstructionsProvider = mock(PeginInstructionsProvider.class); + when(peginInstructionsProvider.buildPeginInstructions(any())).thenReturn(Optional.of(peginInstructions)); + + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .withRepository(repository) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(peginInstructionsProvider) + .withBtcBlockStoreFactory(mockFactory) + .withActivations(activations) + .withSignatureCache(signatureCache) + .withFeePerKbSupport(feePerKbSupport) + .build(); + // Act - bridgeSupport.registerBtcTransaction(mock(Transaction.class), tx1.bitcoinSerialize(), height, pmtWithoutWitness.bitcoinSerialize()); + bridgeSupport.registerBtcTransaction( + mock(Transaction.class), + tx1.bitcoinSerialize(), + height, + pmtWithoutWitness.bitcoinSerialize() + ); // Assert - Assertions.assertEquals(LIMIT_MONETARY_BASE, repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); - Assertions.assertEquals(0, provider.getNewFederationBtcUTXOs().size()); - Assertions.assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); - Assertions.assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); + assertEquals(LIMIT_MONETARY_BASE, repository.getBalance(PrecompiledContracts.BRIDGE_ADDR)); + assertEquals(0, provider.getNewFederationBtcUTXOs().size()); + assertEquals(0, provider.getReleaseRequestQueue().getEntries().size()); + assertEquals(1, provider.getPegoutsWaitingForConfirmations().getEntries().size()); List pegoutBtcTxs = provider.getPegoutsWaitingForConfirmations().getEntries() .stream() @@ -4403,14 +4292,14 @@ void when_registerBtcTransaction_invalidPeginProtocolVersion_afterFork_no_lock_a // First release tx should correspond to the 5 BTC lock tx BtcTransaction pegoutBtcTx = pegoutBtcTxs.get(0); - Assertions.assertEquals(1, pegoutBtcTx.getOutputs().size()); - MatcherAssert.assertThat(amountToLock.subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); - Assertions.assertEquals(btcAddressFromBtcLockSender, pegoutBtcTx.getOutput(0).getScriptPubKey().getToAddress(btcRegTestParams)); - Assertions.assertEquals(1, pegoutBtcTx.getInputs().size()); - Assertions.assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); - Assertions.assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); - Assertions.assertTrue(provider.getPegoutsWaitingForSignatures().isEmpty()); - Assertions.assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx1.getHash()).isPresent()); + assertEquals(1, pegoutBtcTx.getOutputs().size()); + assertThat(amountToLock.subtract(pegoutBtcTx.getOutput(0).getValue()), is(lessThanOrEqualTo(Coin.MILLICOIN))); + assertEquals(btcAddressFromBtcLockSender, pegoutBtcTx.getOutput(0).getScriptPubKey().getToAddress(btcRegTestParams)); + assertEquals(1, pegoutBtcTx.getInputs().size()); + assertEquals(tx1.getHash(), pegoutBtcTx.getInput(0).getOutpoint().getHash()); + assertEquals(0, pegoutBtcTx.getInput(0).getOutpoint().getIndex()); + assertTrue(provider.getPegoutsWaitingForSignatures().isEmpty()); + assertTrue(provider.getHeightIfBtcTxhashIsAlreadyProcessed(tx1.getHash()).isPresent()); } @Test @@ -4980,7 +4869,7 @@ void getBtcTransactionConfirmations_accepts_tx_without_witness_after_rskip_143() } @Test - void when_RegisterBtcCoinbaseTransaction_wrong_witnessReservedValue_noSent() throws BlockStoreException, AddressFormatException, VMException { + void when_RegisterBtcCoinbaseTransaction_wrong_witnessReservedValue_noSent() throws BlockStoreException, AddressFormatException { ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); when(activations.isActive(ConsensusRule.RSKIP143)).thenReturn(true); @@ -5034,7 +4923,7 @@ void when_RegisterBtcCoinbaseTransaction_wrong_witnessReservedValue_noSent() thr } @Test - void when_RegisterBtcCoinbaseTransaction_MerkleTreeWrongFormat_noSent() throws BlockStoreException, AddressFormatException, VMException { + void when_RegisterBtcCoinbaseTransaction_MerkleTreeWrongFormat_noSent() throws BlockStoreException, AddressFormatException { ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); when(activations.isActive(ConsensusRule.RSKIP143)).thenReturn(true); @@ -5148,7 +5037,7 @@ void when_RegisterBtcCoinbaseTransaction_HashNotInPmt_noSent() throws BlockStore } @Test - void when_RegisterBtcCoinbaseTransaction_notVerify_noSent() throws BlockStoreException, AddressFormatException, VMException { + void when_RegisterBtcCoinbaseTransaction_notVerify_noSent() throws BlockStoreException, AddressFormatException { ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); when(activations.isActive(ConsensusRule.RSKIP143)).thenReturn(true); @@ -5527,17 +5416,20 @@ void isAlreadyBtcTxHashProcessedHeight_true() throws IOException { BridgeStorageProvider provider = new BridgeStorageProvider(repository, PrecompiledContracts.BRIDGE_ADDR, bridgeConstantsRegtest, activationsBeforeForks); provider.setHeightBtcTxhashAlreadyProcessed(btcTransaction.getHash(), 1L); - BridgeSupport bridgeSupport = getBridgeSupport(bridgeConstantsRegtest, provider); + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .build(); - Assertions.assertTrue(bridgeSupport.isAlreadyBtcTxHashProcessed(btcTransaction.getHash())); + assertTrue(bridgeSupport.isAlreadyBtcTxHashProcessed(btcTransaction.getHash())); } @Test void isAlreadyBtcTxHashProcessedHeight_false() throws IOException { BtcTransaction btcTransaction = new BtcTransaction(btcRegTestParams); - BridgeSupport bridgeSupport = getBridgeSupport(bridgeConstantsRegtest, mock(BridgeStorageProvider.class)); + BridgeSupport bridgeSupport = bridgeSupportBuilder.withBridgeConstants(bridgeConstantsRegtest).build(); - Assertions.assertFalse(bridgeSupport.isAlreadyBtcTxHashProcessed(btcTransaction.getHash())); + assertFalse(bridgeSupport.isAlreadyBtcTxHashProcessed(btcTransaction.getHash())); } @Test @@ -5545,11 +5437,14 @@ void validationsForRegisterBtcTransaction_negative_height() throws BlockStoreExc BtcTransaction tx = new BtcTransaction(btcRegTestParams); Repository repository = createRepository(); BridgeStorageProvider provider = new BridgeStorageProvider(repository, PrecompiledContracts.BRIDGE_ADDR, bridgeConstantsRegtest, activationsBeforeForks); - BridgeSupport bridgeSupport = getBridgeSupport(bridgeConstantsRegtest, provider); + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .build(); byte[] data = Hex.decode("ab"); - Assertions.assertFalse(bridgeSupport.validationsForRegisterBtcTransaction(tx.getHash(), -1, data, data)); + assertFalse(bridgeSupport.validationsForRegisterBtcTransaction(tx.getHash(), -1, data, data)); } @Test @@ -5576,7 +5471,7 @@ void validationsForRegisterBtcTransaction_insufficient_confirmations() throws Bl } @Test - void validationsForRegisterBtcTransaction_invalid_pmt() throws BlockStoreException, BridgeIllegalArgumentException { + void validationsForRegisterBtcTransaction_invalid_pmt() throws BlockStoreException { BtcTransaction btcTx = new BtcTransaction(btcRegTestParams); BridgeConstants bridgeConstants = mock(BridgeConstants.class); @@ -5598,14 +5493,10 @@ void validationsForRegisterBtcTransaction_invalid_pmt() throws BlockStoreExcepti BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); when(mockFactory.newInstance(any(), any(), any(), any())).thenReturn(btcBlockStore); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstants, - mock(BridgeStorageProvider.class), - mock(Repository.class), - mock(BridgeEventLogger.class), - null, - mockFactory - ); + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstants) + .withBtcBlockStoreFactory(mockFactory) + .build(); assertThrows(BridgeIllegalArgumentException.class, () -> bridgeSupport.validationsForRegisterBtcTransaction( btcTx.getHash(), @@ -5641,16 +5532,12 @@ void validationsForRegisterBtcTransaction_hash_not_in_pmt() throws BlockStoreExc BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); when(mockFactory.newInstance(any(), any(), any(), any())).thenReturn(btcBlockStore); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstants, - mock(BridgeStorageProvider.class), - mock(Repository.class), - mock(BridgeEventLogger.class), - null, - mockFactory - ); + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstants) + .withBtcBlockStoreFactory(mockFactory) + .build(); - Assertions.assertFalse(bridgeSupport.validationsForRegisterBtcTransaction(btcTx.getHash(), 0, pmt.bitcoinSerialize(), btcTx.bitcoinSerialize())); + assertFalse(bridgeSupport.validationsForRegisterBtcTransaction(btcTx.getHash(), 0, pmt.bitcoinSerialize(), btcTx.bitcoinSerialize())); } @Test @@ -5676,16 +5563,13 @@ void validationsForRegisterBtcTransaction_exception_in_getTxnHashAndMerkleRoot() BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); when(mockFactory.newInstance(any(), any(), any(), any())).thenReturn(btcBlockStore); + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstants) + .withBtcBlockStoreFactory(mockFactory) + .build(); + assertThrows(BridgeIllegalArgumentException.class, () -> { - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstants, - mock(BridgeStorageProvider.class), - mock(Repository.class), - mock(BridgeEventLogger.class), - null, - mockFactory - ); - Assertions.assertFalse(bridgeSupport.validationsForRegisterBtcTransaction(btcTx.getHash(), 0, pmt.bitcoinSerialize(), btcTx.bitcoinSerialize())); + bridgeSupport.validationsForRegisterBtcTransaction(btcTx.getHash(), 0, pmt.bitcoinSerialize(), btcTx.bitcoinSerialize()); }); } @@ -5719,20 +5603,21 @@ void validationsForRegisterBtcTransaction_tx_without_inputs_before_rskip_143() t BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); when(mockFactory.newInstance(any(), any(), any(), any())).thenReturn(btcBlockStore); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstants, - mock(BridgeStorageProvider.class), - mock(Repository.class), - mock(BridgeEventLogger.class), - null, - mockFactory, - activations - ); + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstants) + .withBtcBlockStoreFactory(mockFactory) + .withActivations(activations) + .build(); Sha256Hash hash = btcTx.getHash(); byte[] pmtSerialized = pmt.bitcoinSerialize(); byte[] btcTxSerialized = btcTx.bitcoinSerialize(); - assertThrows(VerificationException.class, () -> bridgeSupport.validationsForRegisterBtcTransaction(hash, btcTxHeight, pmtSerialized, btcTxSerialized)); + assertThrows(VerificationException.class, () -> bridgeSupport.validationsForRegisterBtcTransaction( + hash, + btcTxHeight, + pmtSerialized, + btcTxSerialized + )); } @Test @@ -5764,20 +5649,21 @@ void validationsForRegisterBtcTransaction_tx_without_inputs_after_rskip_143() th BtcBlockStoreWithCache.Factory mockFactory = mock(BtcBlockStoreWithCache.Factory.class); when(mockFactory.newInstance(any(), any(), any(), any())).thenReturn(btcBlockStore); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstants, - mock(BridgeStorageProvider.class), - mock(Repository.class), - mock(BridgeEventLogger.class), - null, - mockFactory, - activations - ); + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstants) + .withBtcBlockStoreFactory(mockFactory) + .withActivations(activations) + .build(); Sha256Hash hash = btcTx.getHash(); byte[] pmtSerialized = pmt.bitcoinSerialize(); byte[] decode = Hex.decode("00000000000100"); - assertThrows(VerificationException.class, () -> bridgeSupport.validationsForRegisterBtcTransaction(hash, 0, pmtSerialized, decode)); + assertThrows(VerificationException.class, () -> bridgeSupport.validationsForRegisterBtcTransaction( + hash, + 0, + pmtSerialized, + decode + )); } @Test @@ -5810,6 +5696,7 @@ void validationsForRegisterBtcTransaction_invalid_block_merkle_root() throws IOE mockChainOfStoredBlocks(btcBlockStore, btcBlock, height + bridgeConstantsRegtest.getBtc2RskMinimumAcceptableConfirmations(), height); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); BridgeSupport bridgeSupport = new BridgeSupport( bridgeConstantsRegtest, mockBridgeStorageProvider, @@ -5820,6 +5707,7 @@ void validationsForRegisterBtcTransaction_invalid_block_merkle_root() throws IOE mock(Block.class), mock(Context.class), mock(FederationSupport.class), + feePerKbSupport, btcBlockStoreFactory, mock(ActivationConfig.ForBlock.class), signatureCache @@ -5863,7 +5751,7 @@ void validationsForRegisterBtcTransaction_successful() throws IOException, Block int height = 1; mockChainOfStoredBlocks(btcBlockStore, btcBlock, height + bridgeConstantsRegtest.getBtc2RskMinimumAcceptableConfirmations(), height); - + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); BridgeSupport bridgeSupport = new BridgeSupport( bridgeConstantsRegtest, mockBridgeStorageProvider, @@ -5874,6 +5762,7 @@ void validationsForRegisterBtcTransaction_successful() throws IOException, Block mock(Block.class), mock(Context.class), mock(FederationSupport.class), + feePerKbSupport, btcBlockStoreFactory, mock(ActivationConfig.ForBlock.class), signatureCache @@ -5952,11 +5841,10 @@ void processPegIn_version1_tx_no_lockable_by_surpassing_locking_cap_unknown_send void processPegIn_noPeginInstructions() { ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstantsRegtest, - mock(BridgeStorageProvider.class), - activations - ); + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withActivations(activations) + .build(); BtcTransaction btcTx = mock(BtcTransaction.class); when(btcTx.getValueSentToMe(any())).thenReturn(Coin.valueOf(1)); @@ -6009,15 +5897,13 @@ void processPegIn_errorParsingPeginInstructions_beforeRskip170_dontRefundSender( Assertions.fail(); // Should have thrown a RegisterBtcTransactionException } catch (Exception e) { // Assert - Assertions.assertTrue(e instanceof RegisterBtcTransactionException); - Assertions.assertEquals(0, pegoutsWaitingForConfirmations.getEntries().size()); + assertInstanceOf(RegisterBtcTransactionException.class, e); + assertEquals(0, pegoutsWaitingForConfirmations.getEntries().size()); } } @Test - void processPegIn_errorParsingPeginInstructions_afterRskip170_refundSender() - throws IOException, PeginInstructionsException { - + void processPegIn_errorParsingPeginInstructions_afterRskip170_refundSender() throws IOException, PeginInstructionsException { // Arrange ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); when(activations.isActive(ConsensusRule.RSKIP170)).thenReturn(true); @@ -6033,7 +5919,7 @@ void processPegIn_errorParsingPeginInstructions_afterRskip170_refundSender() BtcTransaction btcTx = new BtcTransaction(btcRegTestParams); btcTx.addOutput(Coin.COIN.multiply(10), federationAddress); - btcTx.addInput(PegTestUtils.createHash(1), 0, new Script(new byte[]{})); + btcTx.addInput(BitcoinTestUtils.createHash(1), 0, new Script(new byte[]{})); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); @@ -6049,40 +5935,38 @@ void processPegIn_errorParsingPeginInstructions_afterRskip170_refundSender() PeginInstructionsProvider peginInstructionsProvider = mock(PeginInstructionsProvider.class); when(peginInstructionsProvider.buildPeginInstructions(btcTx)).thenThrow(PeginInstructionsException.class); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstantsRegtest, - provider, - repository, - btcLockSenderProvider, - peginInstructionsProvider, - mock(Block.class), - mock(BtcBlockStoreWithCache.Factory.class), - activations, - signatureCache - ); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .withRepository(repository) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(peginInstructionsProvider) + .withActivations(activations) + .withSignatureCache(signatureCache) + .withFeePerKbSupport(feePerKbSupport) + .build(); // Act - try { - bridgeSupport.processPegIn(btcTx, PegTestUtils.createHash3(1), 0); - Assertions.fail(); // Should have thrown a RegisterBtcTransactionException - } catch (Exception ex) { - // Assert - Assertions.assertTrue(ex instanceof RegisterBtcTransactionException); - Assertions.assertEquals(1, pegoutsWaitingForConfirmations.getEntries().size()); + assertThrows(RegisterBtcTransactionException.class, () -> bridgeSupport.processPegIn(btcTx, PegTestUtils.createHash3(1), 0)); - // Check rejection tx input was created from btc tx and sent to the btc refund address indicated by the user - boolean successfulRejection = false; - for (PegoutsWaitingForConfirmations.Entry e : pegoutsWaitingForConfirmations.getEntries()) { - BtcTransaction refundTx = e.getBtcTransaction(); - if (refundTx.getInput(0).getOutpoint().getHash() == btcTx.getHash() && - refundTx.getOutput(0).getScriptPubKey().getToAddress(btcRegTestParams).equals(btcSenderAddress)) { - successfulRejection = true; - break; - } - } + // Assert + assertEquals(1, pegoutsWaitingForConfirmations.getEntries().size()); - Assertions.assertTrue(successfulRejection); + // Check rejection tx input was created from btc tx and sent to the btc refund address indicated by the user + boolean successfulRejection = false; + for (PegoutsWaitingForConfirmations.Entry e : pegoutsWaitingForConfirmations.getEntries()) { + BtcTransaction refundTx = e.getBtcTransaction(); + if (refundTx.getInput(0).getOutpoint().getHash() == btcTx.getHash() && + refundTx.getOutput(0).getScriptPubKey().getToAddress(btcRegTestParams).equals(btcSenderAddress)) { + successfulRejection = true; + break; + } } + + assertTrue(successfulRejection); } @Test @@ -6337,7 +6221,6 @@ void receiveHeader_block_exist_in_storage() throws IOException, BlockStoreExcept activationsAfterForks ); - // when(btcBlockStore.get(any())).thenReturn(nul); int result = bridgeSupport.receiveHeader(btcBlock); // Calls put when is adding the block header. (Saves his storedBlock) @@ -6369,7 +6252,7 @@ private void assertRefundInProcessPegInVersionLegacy( BtcTransaction btcTx = new BtcTransaction(btcRegTestParams); btcTx.addOutput(Coin.COIN.multiply(10), federationAddress); - btcTx.addInput(PegTestUtils.createHash(1), 0, new Script(new byte[]{})); + btcTx.addInput(BitcoinTestUtils.createHash(1), 0, new Script(new byte[]{})); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); @@ -6386,23 +6269,25 @@ private void assertRefundInProcessPegInVersionLegacy( BtcLockSenderProvider btcLockSenderProvider = getBtcLockSenderProvider(lockSenderAddressType, btcAddress, rskAddress); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstantsRegtest, - provider, - repository, - btcLockSenderProvider, - new PeginInstructionsProvider(), - mock(Block.class), - mock(BtcBlockStoreWithCache.Factory.class), - activations, - signatureCache - ); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .withRepository(repository) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withActivations(activations) + .withSignatureCache(signatureCache) + .withFeePerKbSupport(feePerKbSupport) + .build(); // Act bridgeSupport.processPegIn(btcTx, PegTestUtils.createHash3(1), 0); // Assert - Assertions.assertEquals(1, pegoutsWaitingForConfirmations.getEntries().size()); + assertEquals(1, pegoutsWaitingForConfirmations.getEntries().size()); // Check rejection tx input was created from btc tx boolean successfulRejection = false; @@ -6413,10 +6298,10 @@ private void assertRefundInProcessPegInVersionLegacy( } } - Assertions.assertTrue(successfulRejection); + assertTrue(successfulRejection); // Check tx was not marked as processed - Assertions.assertFalse(provider.getHeightIfBtcTxhashIsAlreadyProcessed(btcTx.getHash()).isPresent()); + assertFalse(provider.getHeightIfBtcTxhashIsAlreadyProcessed(btcTx.getHash()).isPresent()); } @Test @@ -6458,9 +6343,7 @@ private void test_migrating_many_utxos(boolean isRskip294Active, int utxosToCrea 0, btcRegTestParams ); - Federation oldFed = FederationFactory.buildStandardMultiSigFederation( - oldFedArgs - ); + Federation oldFed = FederationFactory.buildStandardMultiSigFederation(oldFedArgs); List newFedMembers = Arrays.asList( FederationMember.getFederationMemberFromKey(new BtcECKey()), @@ -6468,9 +6351,7 @@ private void test_migrating_many_utxos(boolean isRskip294Active, int utxosToCrea FederationMember.getFederationMemberFromKey(new BtcECKey()) ); FederationArgs newFedArgs = new FederationArgs(newFedMembers, Instant.now(), 1, btcRegTestParams); - Federation newFed = FederationFactory.buildStandardMultiSigFederation( - newFedArgs - ); + Federation newFed = FederationFactory.buildStandardMultiSigFederation(newFedArgs); Block block = mock(Block.class); // Set block right after the migration should start @@ -6483,7 +6364,7 @@ private void test_migrating_many_utxos(boolean isRskip294Active, int utxosToCrea List utxosToMigrate = new ArrayList<>(); for (int i = 0; i < utxosToCreate; i++) { utxosToMigrate.add(new UTXO( - PegTestUtils.createHash(i), + BitcoinTestUtils.createHash(i), 0, Coin.COIN, 0, @@ -6500,20 +6381,24 @@ private void test_migrating_many_utxos(boolean isRskip294Active, int utxosToCrea when(bridgeStorageProvider.getOldFederation()).thenReturn(oldFed); when(bridgeStorageProvider.getOldFederationBtcUTXOs()).thenReturn(utxosToMigrate); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = bridgeSupportBuilder .withActivations(activations) .withBridgeConstants(bridgeConstantsRegtest) .withProvider(bridgeStorageProvider) .withExecutionBlock(block) + .withFeePerKbSupport(feePerKbSupport) .build(); // Ensure a new transaction is created after each call to updateCollections // until the expected number is reached for (int i = 0; i < expectedTransactions; i++) { bridgeSupport.updateCollections(mock(Transaction.class)); - Assertions.assertEquals(i+1, pegoutsWaitingForConfirmations.getEntries().size()); + assertEquals(i+1, pegoutsWaitingForConfirmations.getEntries().size()); } - Assertions.assertTrue(utxosToMigrate.isEmpty()); // Migrated UTXOs are removed from the list + assertTrue(utxosToMigrate.isEmpty()); // Migrated UTXOs are removed from the list // Assert inputs size of each transaction List expectedInputSizes = new ArrayList<>(); @@ -6538,7 +6423,7 @@ private void test_migrating_many_utxos(boolean isRskip294Active, int utxosToCrea expectedInputSizes.remove(inputsSize); }); - Assertions.assertTrue(expectedInputSizes.isEmpty()); // All expected sizes should have been found and removed + assertTrue(expectedInputSizes.isEmpty()); // All expected sizes should have been found and removed } @Test @@ -6828,15 +6713,16 @@ void getEstimatedFeesForNextPegOutEvent( ) throws IOException { // Arrange BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - when(provider.getReleaseRequestQueueSize()).thenReturn(pegoutRequestsCount); when(provider.getNewFederation()).thenReturn(federation); - Coin feePerKB = Coin.MILLICOIN; - when(provider.getFeePerKb()).thenReturn(feePerKB); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = bridgeSupportBuilder .withProvider(provider) .withActivations(activations) + .withFeePerKbSupport(feePerKbSupport) .build(); // Act @@ -6873,7 +6759,7 @@ private void assertRefundInProcessPegInVersion1( BtcTransaction btcTx = new BtcTransaction(btcRegTestParams); btcTx.addOutput(Coin.COIN.multiply(10), federationAddress); - btcTx.addInput(PegTestUtils.createHash(1), 0, new Script(new byte[]{})); + btcTx.addInput(BitcoinTestUtils.createHash(1), 0, new Script(new byte[]{})); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); @@ -6892,17 +6778,19 @@ private void assertRefundInProcessPegInVersion1( btcRefundAddress ); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstantsRegtest, - provider, - repository, - btcLockSenderProvider, - peginInstructionsProvider, - mock(Block.class), - mock(BtcBlockStoreWithCache.Factory.class), - activations, - signatureCache - ); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .withRepository(repository) + .withBtcLockSenderProvider(btcLockSenderProvider) + .withPeginInstructionsProvider(peginInstructionsProvider) + .withActivations(activations) + .withSignatureCache(signatureCache) + .withFeePerKbSupport(feePerKbSupport) + .build(); // Act bridgeSupport.processPegIn(btcTx, PegTestUtils.createHash3(1), 0); @@ -6910,9 +6798,9 @@ private void assertRefundInProcessPegInVersion1( // Assert if (lockSenderAddressType == TxSenderAddressType.UNKNOWN && !btcRefundAddress.isPresent()) { // Unknown sender and no refund address. Can't refund - Assertions.assertEquals(0, pegoutsWaitingForConfirmations.getEntries().size()); + assertEquals(0, pegoutsWaitingForConfirmations.getEntries().size()); } else { - Assertions.assertEquals(1, pegoutsWaitingForConfirmations.getEntries().size()); + assertEquals(1, pegoutsWaitingForConfirmations.getEntries().size()); // Check rejection tx input was created from btc tx and sent to the btc refund address indicated by the user boolean successfulRejection = false; @@ -6925,7 +6813,7 @@ private void assertRefundInProcessPegInVersion1( } } - Assertions.assertTrue(successfulRejection); + assertTrue(successfulRejection); } } @@ -6944,11 +6832,10 @@ private void assertLockingCap( BridgeConstants bridgeConstants = mock(BridgeConstants.class); when(bridgeConstants.getMinimumPeginTxValue(activations)).thenReturn(Coin.SATOSHI); - when(bridgeConstants.getBtcParams()).thenReturn(BridgeRegTestConstants.getInstance().getBtcParams()); + when(bridgeConstants.getBtcParams()).thenReturn(BridgeMainNetConstants.getInstance().getBtcParams()); when(bridgeConstants.getBtc2RskMinimumAcceptableConfirmations()).thenReturn(1); - when(bridgeConstants.getGenesisFeePerKb()).thenReturn(BridgeRegTestConstants.getInstance().getGenesisFeePerKb()); - when(bridgeConstants.getMaxRbtc()).thenReturn(BridgeRegTestConstants.getInstance().getMaxRbtc()); - when(bridgeConstants.getOldFederationAddress()).thenReturn(BridgeRegTestConstants.getInstance().getOldFederationAddress()); + when(bridgeConstants.getMaxRbtc()).thenReturn(BridgeMainNetConstants.getInstance().getMaxRbtc()); + when(bridgeConstants.getOldFederationAddress()).thenReturn(BridgeMainNetConstants.getInstance().getOldFederationAddress()); // Configure locking cap when(bridgeConstants.getInitialLockingCap()).thenReturn(lockingCap); @@ -7065,19 +6952,23 @@ private void assertLockingCap( Address address = senderBtcKey.toAddress(bridgeConstants.getBtcParams()); whitelist.put(address, new OneOffWhiteListEntry(address, lockValue)); // The address is whitelisted - MatcherAssert.assertThat(whitelist.isWhitelisted(address), is(true)); + assertThat(whitelist.isWhitelisted(address), is(true)); - BridgeSupport bridgeSupport = getBridgeSupport( - bridgeConstants, - provider, - repository, - new BtcLockSenderProvider(), - new PeginInstructionsProvider(), - executionBlock, - mockFactory, - activations, - signatureCache - ); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + + BridgeSupport bridgeSupport = bridgeSupportBuilder + .withBridgeConstants(bridgeConstants) + .withProvider(provider) + .withRepository(repository) + .withBtcLockSenderProvider(new BtcLockSenderProvider()) + .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withExecutionBlock(executionBlock) + .withBtcBlockStoreFactory(mockFactory) + .withActivations(activations) + .withSignatureCache(signatureCache) + .withFeePerKbSupport(feePerKbSupport) + .build(); // Simulate blockchain int height = 1; @@ -7097,7 +6988,7 @@ private void assertLockingCap( bridgeSupport.save(); // If the address is no longer whitelisted, it means it was consumed, whether the lock was rejected by lockingCap or not - MatcherAssert.assertThat(whitelist.isWhitelisted(address), is(false)); + assertThat(whitelist.isWhitelisted(address), is(false)); // The Btc transaction should have been processed assertTrue(bridgeSupport.isBtcTxHashAlreadyProcessed(tx.getHash())); @@ -7127,30 +7018,6 @@ private void assertLockingCap( } } - private BridgeSupport getBridgeSupport(BridgeConstants constants, BridgeStorageProvider provider) { - return getBridgeSupport(constants, provider, null, mock(BridgeEventLogger.class), null, null, null); - } - - private BridgeSupport getBridgeSupport(BridgeConstants constants, BridgeStorageProvider provider, ActivationConfig.ForBlock activations) { - return getBridgeSupport(constants, provider, null, mock(BridgeEventLogger.class), null, null, activations); - } - - private BridgeSupport getBridgeSupport(BridgeConstants constants, BridgeStorageProvider provider, Repository track, - BridgeEventLogger eventLogger, Block executionBlock, - BtcBlockStoreWithCache.Factory blockStoreFactory, - ActivationConfig.ForBlock activations) { - return bridgeSupportBuilder - .withBridgeConstants(constants) - .withProvider(provider) - .withRepository(track) - .withEventLogger(eventLogger) - .withBtcLockSenderProvider(new BtcLockSenderProvider()) - .withExecutionBlock(executionBlock) - .withBtcBlockStoreFactory(blockStoreFactory) - .withActivations(activations) - .build(); - } - private BridgeSupport getBridgeSupport(BridgeConstants constants, BridgeStorageProvider provider, Repository track, BtcLockSenderProvider btcLockSenderProvider, PeginInstructionsProvider peginInstructionsProvider, Block executionBlock, BtcBlockStoreWithCache.Factory blockStoreFactory, @@ -7165,6 +7032,7 @@ private BridgeSupport getBridgeSupport(BridgeConstants constants, BridgeStorageP if (blockStoreFactory == null) { blockStoreFactory = mock(BtcBlockStoreWithCache.Factory.class); } + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); return new BridgeSupport( constants, provider, @@ -7175,26 +7043,13 @@ private BridgeSupport getBridgeSupport(BridgeConstants constants, BridgeStorageP executionBlock, new Context(constants.getBtcParams()), new FederationSupport(constants, provider, executionBlock, activations), + feePerKbSupport, blockStoreFactory, activations, signatureCache ); } - private BridgeSupport getBridgeSupport(BridgeConstants constants, BridgeStorageProvider provider, Repository track, - BridgeEventLogger eventLogger, Block executionBlock, - BtcBlockStoreWithCache.Factory blockStoreFactory) { - return bridgeSupportBuilder - .withBridgeConstants(constants) - .withProvider(provider) - .withRepository(track) - .withEventLogger(eventLogger) - .withBtcLockSenderProvider(new BtcLockSenderProvider()) - .withExecutionBlock(executionBlock) - .withBtcBlockStoreFactory(blockStoreFactory) - .build(); - } - private BridgeSupport getBridgeSupportConfiguredToTestReceiveHeader( BtcBlock btcBlock, BtcBlockStoreWithCache btcBlockStore, @@ -7237,15 +7092,13 @@ private BridgeSupport getBridgeSupportConfiguredToTestReceiveHeader( when(rskBlock.getTimestamp()).thenReturn(1611169584L); - return getBridgeSupport( - bridgeConstantsRegtest, - provider, - mock(Repository.class), - mock(BridgeEventLogger.class), - rskBlock, - mockFactory, - activation - ); + return bridgeSupportBuilder + .withBridgeConstants(bridgeConstantsRegtest) + .withProvider(provider) + .withExecutionBlock(rskBlock) + .withBtcBlockStoreFactory(mockFactory) + .withActivations(activation) + .build(); } private BtcLockSenderProvider getBtcLockSenderProvider(BtcLockSender.TxSenderAddressType txSenderAddressType, Address btcAddress, RskAddress rskAddress) { 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 8987ff2b210..de8c31376b9 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestIntegration.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestIntegration.java @@ -55,6 +55,7 @@ import co.rsk.crypto.Keccak256; import co.rsk.db.MutableTrieCache; import co.rsk.db.MutableTrieImpl; +import co.rsk.peg.feeperkb.FeePerKbSupport; import co.rsk.peg.vote.ABICallElection; import co.rsk.peg.vote.ABICallSpec; import co.rsk.peg.bitcoin.MerkleBranch; @@ -129,6 +130,7 @@ /** * Created by ajlopez on 6/9/2016. */ + @ExtendWith(MockitoExtension.class) // to avoid Junit5 unnecessary stub error due to some setup generalizations @MockitoSettings(strictness = Strictness.LENIENT) @@ -150,6 +152,7 @@ public class BridgeSupportTestIntegration { private ActivationConfig.ForBlock activationsBeforeForks; private SignatureCache signatureCache; + private FeePerKbSupport feePerKbSupport; @BeforeEach void setUpOnEachTest() { @@ -157,6 +160,8 @@ void setUpOnEachTest() { btcParams = bridgeConstants.getBtcParams(); activationsBeforeForks = ActivationConfigsForTest.genesis().forBlock(0); signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); + feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); } @Test @@ -206,8 +211,8 @@ void feePerKbFromStorageProvider() { BridgeStorageProvider provider = new BridgeStorageProvider(track, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants, activationsBeforeForks); Coin expected = Coin.MILLICOIN; - provider.setFeePerKb(expected); - provider.saveFeePerKb(); + + when(feePerKbSupport.getFeePerKb()).thenReturn(expected); BridgeSupport bridgeSupport = getBridgeSupport(provider, track); @@ -255,6 +260,7 @@ void testGetBtcBlockchainBlockLocatorWithBtcCheckpoints() throws Exception { BridgeStorageProvider provider = new BridgeStorageProvider(track, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants, activationsBeforeForks); List checkpoints = createBtcBlocks(btcParams, btcParams.getGenesisBlock(), 10); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); BridgeSupport bridgeSupport = new BridgeSupport( bridgeConstants, provider, @@ -265,6 +271,7 @@ void testGetBtcBlockchainBlockLocatorWithBtcCheckpoints() throws Exception { null, new Context(bridgeConstants.getBtcParams()), new FederationSupport(bridgeConstants, provider, null, activationsBeforeForks), + feePerKbSupport, btcBlockStoreFactory, mock(ActivationConfig.ForBlock.class), signatureCache @@ -396,7 +403,6 @@ void callUpdateCollectionsFundsEnoughForJustTheSmallerTx() throws IOException { provider0.getReleaseRequestQueue().add(new BtcECKey().toAddress(btcParams), Coin.valueOf(30, 0)); provider0.getReleaseRequestQueue().add(new BtcECKey().toAddress(btcParams), Coin.valueOf(20, 0)); provider0.getReleaseRequestQueue().add(new BtcECKey().toAddress(btcParams), Coin.valueOf(10, 0)); - provider0.setFeePerKb(Coin.MILLICOIN); provider0.getNewFederationBtcUTXOs().add(new UTXO( PegTestUtils.createHash(), @@ -466,7 +472,7 @@ void callUpdateCollectionsThrowsCouldNotAdjustDownwards() throws IOException { BridgeStorageProvider provider0 = new BridgeStorageProvider(track, PrecompiledContracts.BRIDGE_ADDR, bridgeConstants, activationsBeforeForks); provider0.getReleaseRequestQueue().add(new BtcECKey().toAddress(btcParams), Coin.valueOf(37500)); - provider0.setFeePerKb(Coin.MILLICOIN); + provider0.getNewFederationBtcUTXOs().add(new UTXO( PegTestUtils.createHash(), 1, @@ -591,6 +597,7 @@ void callUpdateCollectionsThrowsExceededMaxTransactionSize() throws IOException bridgeConstants, activationsBeforeForks ); + BridgeSupport bridgeSupport = getBridgeSupport( bridgeConstants, providerForSupport, @@ -632,8 +639,7 @@ void minimumProcessFundsMigrationValue() throws IOException { ); BridgeStorageProvider provider = mock(BridgeStorageProvider.class); - when(provider.getFeePerKb()) - .thenReturn(Coin.MILLICOIN); + when(provider.getReleaseRequestQueue()) .thenReturn(new ReleaseRequestQueue(Collections.emptyList())); when(provider.getPegoutsWaitingForConfirmations()) @@ -659,6 +665,7 @@ void minimumProcessFundsMigrationValue() throws IOException { Repository repository = createRepository(); Repository track = repository.startTracking(); + BridgeSupport bridgeSupport = getBridgeSupport( bridgeConstants, provider, @@ -702,7 +709,7 @@ void minimumProcessFundsMigrationValue() throws IOException { unsufficientUTXOsForMigration2.add(createUTXO(Coin.MILLICOIN, oldFederation.getAddress())); when(provider.getOldFederationBtcUTXOs()) .thenReturn(unsufficientUTXOsForMigration2); - when(provider.getFeePerKb()) + when(feePerKbSupport.getFeePerKb()) .thenReturn(Coin.COIN); bridgeSupport.updateCollections(tx); @@ -4131,6 +4138,7 @@ private BridgeSupport getBridgeSupport( if (blockStoreFactory == null) { blockStoreFactory = mock(BtcBlockStoreWithCache.Factory.class); } + return new BridgeSupport( constants, provider, @@ -4141,6 +4149,7 @@ private BridgeSupport getBridgeSupport( executionBlock, new Context(constants.getBtcParams()), new FederationSupport(constants, provider, executionBlock, activations), + feePerKbSupport, blockStoreFactory, activations, signatureCache diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java index a3a4156c5e1..e2b5062a7a4 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestUtil.java @@ -35,4 +35,5 @@ public static void mockChainOfStoredBlocks(BtcBlockStoreWithCache btcBlockStore, when(btcBlockStore.getChainHead()).thenReturn(currentStored); when(currentStored.getHeight()).thenReturn(headHeight); } + } diff --git a/rskj-core/src/test/java/co/rsk/peg/InMemoryStorage.java b/rskj-core/src/test/java/co/rsk/peg/InMemoryStorage.java new file mode 100644 index 00000000000..85df7353cdf --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/peg/InMemoryStorage.java @@ -0,0 +1,31 @@ +package co.rsk.peg; + +import co.rsk.peg.storage.StorageAccessor; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.ethereum.vm.DataWord; + +/** + * This is an In-Memory Storage to be used in Unit Tests to reduce the use of mocks, thus + * improving the Unit Tests reliability. + */ +public class InMemoryStorage implements StorageAccessor { + + private final Map storage = new HashMap<>(); + + @Override + public T safeGetFromRepository(DataWord key, RepositoryDeserializer deserializer) { + byte[] data = storage.get(key); + return deserializer.deserialize(data); + } + + @Override + public void safeSaveToRepository(DataWord key, T value, RepositorySerializer serializer) { + byte[] data = null; + if (!Objects.isNull(value)) { + data = serializer.serialize(value); + } + storage.put(key, data); + } +} diff --git a/rskj-core/src/test/java/co/rsk/peg/PegTestUtils.java b/rskj-core/src/test/java/co/rsk/peg/PegTestUtils.java index 57f24bab1d6..f73f1353923 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegTestUtils.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegTestUtils.java @@ -351,15 +351,6 @@ public static ErpFederation createP2shErpFederation(BridgeConstants bridgeConsta return FederationFactory.buildP2shErpFederation(federationArgs, erpPubKeys, activationDelay); } - public static BtcTransaction createBtcTransactionWithOutputToAddress(NetworkParameters networkParameters, Coin amount, Address btcAddress) { - BtcTransaction tx = new BtcTransaction(networkParameters); - tx.addOutput(amount, btcAddress); - BtcECKey srcKey = new BtcECKey(); - tx.addInput(PegTestUtils.createHash(1), - 0, ScriptBuilder.createInputScript(null, srcKey)); - return tx; - } - public static Transaction getMockedRskTxWithHash(String s) { byte[] hash = Keccak256Helper.keccak256(s); return new SimpleRskTransaction(hash); 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 fe89cce85e9..9f5d57d365b 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.feeperkb.FeePerKbSupport; import co.rsk.peg.PegoutsWaitingForConfirmations.Entry; import co.rsk.peg.vote.ABICallSpec; import co.rsk.peg.bitcoin.BitcoinUtils; @@ -117,6 +118,9 @@ private void testChangePowpeg( Block initialBlock = mock(Block.class); when(initialBlock.getNumber()).thenReturn(blockNumber); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + BridgeSupport bridgeSupport = new BridgeSupportBuilder() .withProvider(bridgeStorageProvider) .withRepository(repository) @@ -126,6 +130,7 @@ private void testChangePowpeg( .withBridgeConstants(bridgeConstants) .withBtcBlockStoreFactory(btcBlockStoreFactory) .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withFeePerKbSupport(feePerKbSupport) .build(); List originalPowpegMembers = oldPowPegKeys.stream().map(theseKeys -> @@ -141,8 +146,12 @@ private void testChangePowpeg( Federation originalPowpeg; Instant creationTime = Instant.now(); - FederationArgs federationArgs = - new FederationArgs(originalPowpegMembers, creationTime, 0, btcParams); + FederationArgs federationArgs = new FederationArgs( + originalPowpegMembers, + creationTime, + 0, + btcParams + ); switch (oldPowPegFederationType) { case nonStandardErp: originalPowpeg = FederationFactory.buildNonStandardErpFederation(federationArgs, erpPubKeys, activationDelay, activations); @@ -305,6 +314,7 @@ private void testChangePowpeg( .withBridgeConstants(bridgeConstants) .withBtcBlockStoreFactory(btcBlockStoreFactory) .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withFeePerKbSupport(feePerKbSupport) .build(); assertEquals(oldPowPegAddress, bridgeSupport.getFederationAddress()); @@ -320,6 +330,7 @@ private void testChangePowpeg( .withBridgeConstants(bridgeConstants) .withBtcBlockStoreFactory(btcBlockStoreFactory) .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withFeePerKbSupport(feePerKbSupport) .build(); // New active powpeg and retiring powpeg @@ -381,6 +392,7 @@ private void testChangePowpeg( .withBridgeConstants(bridgeConstants) .withBtcBlockStoreFactory(btcBlockStoreFactory) .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withFeePerKbSupport(feePerKbSupport) .build(); // New active powpeg and retiring powpeg @@ -530,6 +542,7 @@ private void testChangePowpeg( .withBridgeConstants(bridgeConstants) .withBtcBlockStoreFactory(btcBlockStoreFactory) .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withFeePerKbSupport(feePerKbSupport) .build(); // New active powpeg and retiring powpeg is still there @@ -562,6 +575,7 @@ private void testChangePowpeg( .withBridgeConstants(bridgeConstants) .withBtcBlockStoreFactory(btcBlockStoreFactory) .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withFeePerKbSupport(feePerKbSupport) .build(); // New active powpeg and retiring powpeg is still there @@ -714,6 +728,9 @@ private void testPegouts( ) ); + FeePerKbSupport feePerKbSupport = mock(FeePerKbSupport.class); + when(feePerKbSupport.getFeePerKb()).thenReturn(Coin.MILLICOIN); + if (activations.isActive(ConsensusRule.RSKIP271)) { // Peg-out batching is enabled need to move the height to the next pegout event blockNumber = bridgeSupport.getNextPegoutCreationBlockNumber(); @@ -730,6 +747,7 @@ private void testPegouts( .withBridgeConstants(bridgeConstants) .withBtcBlockStoreFactory(btcBlockStoreFactory) .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withFeePerKbSupport(feePerKbSupport) .build(); } @@ -803,6 +821,7 @@ private void testPegouts( .withBridgeConstants(bridgeConstants) .withBtcBlockStoreFactory(btcBlockStoreFactory) .withPeginInstructionsProvider(new PeginInstructionsProvider()) + .withFeePerKbSupport(feePerKbSupport) .build(); int confirmedPegouts = bridgeStorageProvider.getPegoutsWaitingForSignatures().size(); diff --git a/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java b/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java index b76f329969d..35b044993d5 100644 --- a/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java +++ b/rskj-core/src/test/java/co/rsk/peg/bitcoin/BitcoinTestUtils.java @@ -1,18 +1,8 @@ package co.rsk.peg.bitcoin; -import co.rsk.bitcoinj.core.Address; -import co.rsk.bitcoinj.core.BtcECKey; - -import co.rsk.bitcoinj.core.Coin; -import co.rsk.bitcoinj.core.NetworkParameters; -import co.rsk.bitcoinj.core.Sha256Hash; -import co.rsk.bitcoinj.core.TransactionInput; -import co.rsk.bitcoinj.core.UTXO; +import co.rsk.bitcoinj.core.*; import co.rsk.bitcoinj.crypto.TransactionSignature; -import co.rsk.bitcoinj.script.RedeemScriptParser; -import co.rsk.bitcoinj.script.RedeemScriptParserFactory; -import co.rsk.bitcoinj.script.Script; -import co.rsk.bitcoinj.script.ScriptBuilder; +import co.rsk.bitcoinj.script.*; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -20,6 +10,7 @@ import java.util.stream.Collectors; import co.rsk.bitcoinj.script.ScriptChunk; +import org.bouncycastle.util.encoders.Hex; import org.ethereum.crypto.HashUtil; public class BitcoinTestUtils { @@ -101,4 +92,21 @@ public static List createUTXOs(int amount, Address address) { return utxos; } + + public static BtcTransaction createBtcTransactionWithOutputToAddress( + NetworkParameters networkParameters, + Coin amount, + Address btcAddress) { + + BtcTransaction tx = new BtcTransaction(networkParameters); + tx.addOutput(amount, btcAddress); + BtcECKey srcKey = BtcECKey.fromPublicOnly(Hex.decode("02550cc87fa9061162b1dd395a16662529c9d8094c0feca17905a3244713d65fe8")); + tx.addInput( + createHash(100), + 0, + ScriptBuilder.createInputScript(null, srcKey) + ); + + return tx; + } } diff --git a/rskj-core/src/test/java/co/rsk/peg/feeperkb/FeePerKbStorageProviderImplTest.java b/rskj-core/src/test/java/co/rsk/peg/feeperkb/FeePerKbStorageProviderImplTest.java new file mode 100644 index 00000000000..1435140feaf --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/peg/feeperkb/FeePerKbStorageProviderImplTest.java @@ -0,0 +1,89 @@ +package co.rsk.peg.feeperkb; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +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 co.rsk.bitcoinj.core.Coin; +import co.rsk.peg.BridgeSerializationUtils; +import co.rsk.peg.feeperkb.constants.FeePerKbConstants; +import co.rsk.peg.feeperkb.constants.FeePerKbMainNetConstants; +import co.rsk.peg.storage.StorageAccessor; +import co.rsk.peg.vote.ABICallElection; +import co.rsk.peg.vote.AddressBasedAuthorizer; +import java.util.Optional; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) +class FeePerKbStorageProviderImplTest { + + @Mock + StorageAccessor bridgeStorageAccessor; + @InjectMocks + FeePerKbStorageProviderImpl feePerKbStorageProvider; + + @Test + void getFeePerKb() { + Optional feePerKb = Optional.of(Coin.SATOSHI); + when(bridgeStorageAccessor.safeGetFromRepository(any(), any())).thenReturn(feePerKb.get()); + + Optional actualResult = feePerKbStorageProvider.getFeePerKb(); + + assertEquals(feePerKb, actualResult); + } + + @Test + void getFeePerKb_whenFeePerKbIsNotNull() { + Optional feePerKb = Optional.of(Coin.SATOSHI); + feePerKbStorageProvider.setFeePerKb(feePerKb.get()); + + Optional actualResult = feePerKbStorageProvider.getFeePerKb(); + + assertEquals(feePerKb, actualResult); + } + + @Test + void getFeePerKbElection() { + FeePerKbConstants feePerKbConstants = FeePerKbMainNetConstants.getInstance(); + AddressBasedAuthorizer authorizer = feePerKbConstants.getFeePerKbChangeAuthorizer(); + ABICallElection abiCallElection = BridgeSerializationUtils.deserializeElection(new byte[0], + feePerKbConstants.getFeePerKbChangeAuthorizer()); + when(bridgeStorageAccessor.safeGetFromRepository(any(), any())).thenReturn(abiCallElection); + + ABICallElection actualResult = feePerKbStorageProvider.getFeePerKbElection(authorizer); + + assertEquals(abiCallElection, actualResult); + } + + @Test + void save() { + feePerKbStorageProvider.setFeePerKb(Coin.SATOSHI); + doNothing().when(bridgeStorageAccessor).safeSaveToRepository(any(), any(), any()); + doNothing().when(bridgeStorageAccessor).safeSaveToRepository(any(), any(), any()); + + feePerKbStorageProvider.save(); + + verify(bridgeStorageAccessor, times(1)).safeSaveToRepository(any(), any(), any()); + } + + @Test + void save_whenFeePerKbAndFeePerKbElectionAreNull() { + doNothing().when(bridgeStorageAccessor).safeSaveToRepository(any(), any(), any()); + doNothing().when(bridgeStorageAccessor).safeSaveToRepository(any(), any(), any()); + + feePerKbStorageProvider.save(); + + verify(bridgeStorageAccessor, never()).safeSaveToRepository(any(), any(), any()); + } +} diff --git a/rskj-core/src/test/java/co/rsk/peg/feeperkb/FeePerKbSupportImplTest.java b/rskj-core/src/test/java/co/rsk/peg/feeperkb/FeePerKbSupportImplTest.java new file mode 100644 index 00000000000..96312c11f67 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/peg/feeperkb/FeePerKbSupportImplTest.java @@ -0,0 +1,254 @@ +package co.rsk.peg.feeperkb; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import co.rsk.bitcoinj.core.Coin; +import co.rsk.core.RskAddress; +import co.rsk.peg.BridgeSerializationUtils; +import co.rsk.peg.feeperkb.constants.FeePerKbConstants; +import co.rsk.peg.feeperkb.constants.FeePerKbMainNetConstants; +import co.rsk.peg.vote.ABICallElection; +import co.rsk.peg.vote.ABICallSpec; +import co.rsk.peg.vote.AddressBasedAuthorizer; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.ethereum.core.SignatureCache; +import org.ethereum.core.Transaction; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class FeePerKbSupportImplTest { + + private static final String SET_FEE_PER_KB_ABI_FUNCTION = "setFeePerKb"; + + private FeePerKbStorageProvider storageProvider; + private FeePerKbConstants feePerKbConstants; + private FeePerKbSupportImpl feePerKbSupport; + + @BeforeEach + void setUp() { + storageProvider = mock(FeePerKbStorageProvider.class); + feePerKbConstants = FeePerKbMainNetConstants.getInstance(); + feePerKbSupport = new FeePerKbSupportImpl(feePerKbConstants, storageProvider); + } + + @Test + void getFeePerKb() { + Optional currentFeePerKb = Optional.of(Coin.valueOf(50_000L)); + when(storageProvider.getFeePerKb()).thenReturn(currentFeePerKb); + + Coin actualResult = feePerKbSupport.getFeePerKb(); + + Coin expectedResult = currentFeePerKb.get(); + assertEquals(expectedResult, actualResult); + } + + @Test + void getFeePerKb_nullInStorageProvider_shouldReturnGenesisFeePerKb() { + Coin actualResult = feePerKbSupport.getFeePerKb(); + + Coin expectedResult = feePerKbConstants.getGenesisFeePerKb(); + assertEquals(expectedResult, actualResult); + } + + @Test + void voteFeePerKbChange_withUnauthorizedSignature_shouldReturnUnauthorizedCallerResponseCode() { + SignatureCache signatureCache = mock(SignatureCache.class); + Transaction tx = getTransactionFromUnauthorizedCaller(signatureCache); + Coin feePerKbVote = Coin.valueOf(50_000L); + + Integer actualResult = feePerKbSupport.voteFeePerKbChange(tx, feePerKbVote, signatureCache); + + Integer expectedResult = FeePerKbResponseCode.UNAUTHORIZED_CALLER.getCode(); + assertEquals(expectedResult, actualResult); + } + + @Test + void voteFeePerKbChange_negativeFeePerKbValue_shouldReturnNegativeFeeVotedResponseCode() { + SignatureCache signatureCache = mock(SignatureCache.class); + Transaction tx = getTransactionFromAuthorizedCaller(signatureCache); + Coin negativeFeePerKbVote = Coin.NEGATIVE_SATOSHI; + + Integer actualResult = feePerKbSupport.voteFeePerKbChange(tx, negativeFeePerKbVote, signatureCache); + + Integer expectedResult = FeePerKbResponseCode.NEGATIVE_FEE_VOTED.getCode(); + assertEquals(expectedResult, actualResult); + } + + @Test + void voteFeePerKbChange_aboveMaxFeePerKbValue_shouldReturnExcessiveFeeVotedResponseCode() { + SignatureCache signatureCache = mock(SignatureCache.class); + Transaction tx = getTransactionFromAuthorizedCaller(signatureCache); + Coin maxFeePerKb = feePerKbConstants.getMaxFeePerKb(); + Coin excessiveFeePerKbVote = maxFeePerKb.add(Coin.SATOSHI); + + Integer aboveMaxValueVotedResult = feePerKbSupport.voteFeePerKbChange(tx, excessiveFeePerKbVote, signatureCache); + + Integer expectedResult = FeePerKbResponseCode.EXCESSIVE_FEE_VOTED.getCode(); + assertEquals(expectedResult, aboveMaxValueVotedResult); + } + + @Test + void voteFeePerKbChange_zeroFeePerKbValue_shouldReturnNegativeFeeVotedResponseCode() { + SignatureCache signatureCache = mock(SignatureCache.class); + Transaction tx = getTransactionFromAuthorizedCaller(signatureCache); + Coin zeroFeePerKb = Coin.ZERO; + + Integer actualResult = feePerKbSupport.voteFeePerKbChange(tx, zeroFeePerKb, signatureCache); + + Integer expectedResult = FeePerKbResponseCode.NEGATIVE_FEE_VOTED.getCode(); + assertEquals(expectedResult, actualResult); + } + + @Test + void voteFeePerKbChange_veryLowFeePerKbValue_shouldReturnSuccessfulFeeVotedResponseCode() { + SignatureCache signatureCache = mock(SignatureCache.class); + Transaction tx = getTransactionFromAuthorizedCaller(signatureCache); + AddressBasedAuthorizer authorizer = feePerKbConstants.getFeePerKbChangeAuthorizer(); + ABICallElection feePerKbElection = new ABICallElection(authorizer); + when(storageProvider.getFeePerKbElection(authorizer)).thenReturn(feePerKbElection); + Coin veryLowFeePerKb = Coin.SATOSHI; + + Integer actualResult = feePerKbSupport.voteFeePerKbChange(tx, veryLowFeePerKb, signatureCache); + + Integer expectedResult = FeePerKbResponseCode.SUCCESSFUL_VOTE.getCode(); + assertEquals(expectedResult, actualResult); + } + + @Test + void voteFeePerKbChange_equalMaxFeePerKbValue_shouldReturnSuccessfulFeeVotedResponseCode() { + SignatureCache signatureCache = mock(SignatureCache.class); + Transaction tx = getTransactionFromAuthorizedCaller(signatureCache); + AddressBasedAuthorizer authorizer = feePerKbConstants.getFeePerKbChangeAuthorizer(); + ABICallElection feePerKbElection = new ABICallElection(authorizer); + when(storageProvider.getFeePerKbElection(authorizer)).thenReturn(feePerKbElection); + Coin maxFeePerKb = feePerKbConstants.getMaxFeePerKb(); + + Integer actualResult = feePerKbSupport.voteFeePerKbChange(tx, maxFeePerKb, signatureCache); + + Integer expectedResult = FeePerKbResponseCode.SUCCESSFUL_VOTE.getCode(); + assertEquals(expectedResult, actualResult); + } + + @Test + void voteFeePerKbChange_repeatedVote_sameRskAddressSameFeePerKbValue_shouldReturnUnsuccessfulFeeVotedResponseCode() { + SignatureCache signatureCache = mock(SignatureCache.class); + Transaction tx = getTransactionFromAuthorizedCaller(signatureCache); + + AddressBasedAuthorizer authorizer = feePerKbConstants.getFeePerKbChangeAuthorizer(); + Coin feePerKb = Coin.valueOf(50_000L); + RskAddress previousVoter = this.getAuthorizedRskAddresses().get(0); + ABICallElection feePerKbElection = getAbiCallElectionWithExistingVote(authorizer, feePerKb, previousVoter); + when(storageProvider.getFeePerKbElection(authorizer)).thenReturn(feePerKbElection); + + Integer actualResult = feePerKbSupport.voteFeePerKbChange(tx, feePerKb, signatureCache); + + Integer expectedResult = FeePerKbResponseCode.UNSUCCESSFUL_VOTE.getCode(); + assertEquals(expectedResult, actualResult); + } + + @Test + void voteFeePerKbChange_repeatedVote_sameRskAddressDifferentFeePerKbValue_shouldReturnSuccessfulFeeVotedResponseCode() { + SignatureCache signatureCache = mock(SignatureCache.class); + Transaction tx = getTransactionFromAuthorizedCaller(signatureCache); + + AddressBasedAuthorizer authorizer = feePerKbConstants.getFeePerKbChangeAuthorizer(); + Coin firstFeePerKb = Coin.valueOf(50_000L); + RskAddress previousVoter = this.getAuthorizedRskAddresses().get(0); + ABICallElection feePerKbElection = getAbiCallElectionWithExistingVote(authorizer, firstFeePerKb, previousVoter); + when(storageProvider.getFeePerKbElection(authorizer)).thenReturn(feePerKbElection); + + Coin secondFeePerKb = feePerKbConstants.getMaxFeePerKb(); + + Integer actualResult = feePerKbSupport.voteFeePerKbChange(tx, secondFeePerKb, signatureCache); + + Integer expectedResult = FeePerKbResponseCode.SUCCESSFUL_VOTE.getCode(); + assertEquals(expectedResult, actualResult); + } + + @Test + void voteFeePerKbChange_winnerFeePerKbValue_shouldReturnSuccessfulFeeVotedResponseCode() { + SignatureCache signatureCache = mock(SignatureCache.class); + Transaction tx = getTransactionFromAuthorizedCaller(signatureCache); + + AddressBasedAuthorizer authorizer = feePerKbConstants.getFeePerKbChangeAuthorizer(); + Coin feePerKb = Coin.valueOf(50_000L); + + RskAddress previousVoter = this.getAuthorizedRskAddresses().get(1); + ABICallElection feePerKbElection = getAbiCallElectionWithExistingVote(authorizer, feePerKb, previousVoter); + when(storageProvider.getFeePerKbElection(authorizer)).thenReturn(feePerKbElection); + + Integer actualResult = feePerKbSupport.voteFeePerKbChange(tx, feePerKb, signatureCache); + + Integer expectedResult = FeePerKbResponseCode.SUCCESSFUL_VOTE.getCode(); + assertEquals(expectedResult, actualResult); + } + + @Test + void voteFeePerKbChange_nullFeeThrows() { + Transaction tx = mock(Transaction.class); + SignatureCache signatureCache = mock(SignatureCache.class); + + assertThrows(NullPointerException.class, () -> feePerKbSupport.voteFeePerKbChange(tx, null, signatureCache)); + verify(storageProvider, never()).setFeePerKb(any()); + } + + @Test + void save() { + doNothing().when(storageProvider).save(); + + feePerKbSupport.save(); + + verify(storageProvider, times(1)).save(); + } + + private Transaction getTransactionFromUnauthorizedCaller(SignatureCache signatureCache) { + Transaction txFromUnauthorizedCaller = mock(Transaction.class); + when(txFromUnauthorizedCaller.getSender(signatureCache)).thenReturn(this.getUnauthorizedRskAddress()); + + return txFromUnauthorizedCaller; + } + + private Transaction getTransactionFromAuthorizedCaller(SignatureCache signatureCache) { + RskAddress authorizedRskAddress = this.getAuthorizedRskAddresses().get(0); + Transaction txFromAuthorizedCaller = mock(Transaction.class); + when(txFromAuthorizedCaller.getSender(signatureCache)).thenReturn(authorizedRskAddress); + + return txFromAuthorizedCaller; + } + + private RskAddress getUnauthorizedRskAddress(){ + return new RskAddress("e2a5070b4e2cb77fe22dff05d9dcdc4d3eaa6ead"); + } + + private List getAuthorizedRskAddresses(){ + return Stream.of( + "a02db0ed94a5894bc6f9079bb9a2d93ada1917f3", + "180a7edda4e640ea5a3e495e17a1efad260c39e9", + "8418edc8fea47183116b4c8cd6a12e51a7e169c1" + ).map(RskAddress::new).collect(Collectors.toList()); + } + + private ABICallElection getAbiCallElectionWithExistingVote( + AddressBasedAuthorizer authorizer, + Coin feePerKbVote, + RskAddress voter) { + + byte[] feePerKbVoteSerialized = BridgeSerializationUtils.serializeCoin(feePerKbVote); + ABICallSpec feeVote = new ABICallSpec(SET_FEE_PER_KB_ABI_FUNCTION, new byte[][]{feePerKbVoteSerialized}); + + List voters = Collections.singletonList(voter); + Map> existingVotes = new HashMap<>(); + existingVotes.put(feeVote, voters); + + return new ABICallElection(authorizer, existingVotes); + } +} diff --git a/rskj-core/src/test/java/co/rsk/peg/feeperkb/constants/FeePerKbConstantsTest.java b/rskj-core/src/test/java/co/rsk/peg/feeperkb/constants/FeePerKbConstantsTest.java new file mode 100644 index 00000000000..7163870be2f --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/peg/feeperkb/constants/FeePerKbConstantsTest.java @@ -0,0 +1,104 @@ +package co.rsk.peg.feeperkb.constants; + +import co.rsk.bitcoinj.core.Coin; +import co.rsk.peg.vote.AddressBasedAuthorizer; +import org.bouncycastle.util.encoders.Hex; +import org.ethereum.crypto.ECKey; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.samePropertyValuesAs; +import static org.junit.jupiter.api.Assertions.*; + +class FeePerKbConstantsTest { + + @ParameterizedTest + @MethodSource("getGenesisFeePerKbProvider") + void getGenesisFeePerKb(FeePerKbConstants feePerKbConstants, Coin expectedGenesisFeePerKb) { + Coin actualGenesisFeePerKb = feePerKbConstants.getGenesisFeePerKb(); + + assertEquals(expectedGenesisFeePerKb, actualGenesisFeePerKb); + } + + private static Stream getGenesisFeePerKbProvider() { + return Stream.of( + Arguments.of(FeePerKbMainNetConstants.getInstance(), Coin.MILLICOIN.multiply(5)), + Arguments.of(FeePerKbTestNetConstants.getInstance(), Coin.MILLICOIN), + Arguments.of(FeePerKbRegTestConstants.getInstance(), Coin.MILLICOIN) + ); + } + + @ParameterizedTest + @MethodSource("getMaxFeePerKbProvider") + void getMaxFeePerKb(FeePerKbConstants feePerKbConstants, Coin expectedMaxFeePerKb) { + Coin actualMaxFeePerKb = feePerKbConstants.getMaxFeePerKb(); + + assertEquals(expectedMaxFeePerKb, actualMaxFeePerKb); + } + + private static Stream getMaxFeePerKbProvider() { + return Stream.of( + Arguments.of(FeePerKbMainNetConstants.getInstance(), Coin.valueOf(5_000_000L)), + Arguments.of(FeePerKbTestNetConstants.getInstance(), Coin.valueOf(5_000_000L)), + Arguments.of(FeePerKbRegTestConstants.getInstance(), Coin.valueOf(5_000_000L)) + ); + } + + @ParameterizedTest + @MethodSource("getFeePerKbChangeAuthorizerProvider") + void getFeePerKbChangeAuthorizer(FeePerKbConstants feePerKbConstants, + AddressBasedAuthorizer expectedFeePerKbChangeAuthorizer) { + AddressBasedAuthorizer actualFeePerKbChangeAuthorizer = feePerKbConstants.getFeePerKbChangeAuthorizer(); + + assertThat(actualFeePerKbChangeAuthorizer, samePropertyValuesAs(expectedFeePerKbChangeAuthorizer)); + } + + private static Stream getFeePerKbChangeAuthorizerProvider() { + //MainNet + List mainNetFeePerKbAuthorizedKeys = Arrays.stream(new String[]{ + "0448f51638348b034995b1fd934fe14c92afde783e69f120a46ee16eb6bdc2e4f6b5e37772094c68c0dea2b1be3d96ea9651a9eebda7304914c8047f4e3e251378", + "0484c66f75548baf93e322574adac4e4579b6a53f8d11fab640e14c90118e6983ef24b0de349a3e88f72e81e771ae1c897cef446fd7f4da71778c532aee3b6c41b", + "04bb6435dc1ea12da843ebe213893d136c1624acd681fff82551498ae00bf28e9323164b00daf925fa75177463b8254a2aae8a1713e4d851a84ea369c193e9ce51" + }).map(hex -> ECKey.fromPublicOnly(Hex.decode(hex))).collect(Collectors.toList()); + + AddressBasedAuthorizer mainNetFeePerKbChangeAuthorizer = new AddressBasedAuthorizer( + mainNetFeePerKbAuthorizedKeys, + AddressBasedAuthorizer.MinimumRequiredCalculation.MAJORITY + ); + + //TestNet + List testNetFeePerKbAuthorizedKeys = Arrays.stream(new String[]{ + "04701d1d27f8c2ae97912d96fb1f82f10c2395fd320e7a869049268c6b53d2060dfb2e22e3248955332d88cd2ae29a398f8f3858e48dd6d8ffbc37dfd6d1aa4934", + "045ef89e4a5645dc68895dbc33b4c966c3a0a52bb837ecdd2ba448604c4f47266456d1191420e1d32bbe8741f8315fde4d1440908d400e5998dbed6549d499559b", + "0455db9b3867c14e84a6f58bd2165f13bfdba0703cb84ea85788373a6a109f3717e40483aa1f8ef947f435ccdf10e530dd8b3025aa2d4a7014f12180ee3a301d27" + }).map(hex -> ECKey.fromPublicOnly(Hex.decode(hex))).collect(Collectors.toList()); + + AddressBasedAuthorizer testNetFeePerKbChangeAuthorizer = new AddressBasedAuthorizer( + testNetFeePerKbAuthorizedKeys, + AddressBasedAuthorizer.MinimumRequiredCalculation.MAJORITY + ); + + //RegTest + List regTestFeePerKbAuthorizedKeys = Arrays.stream(new String[]{ + "0430c7d0146029db553d60cf11e8d39df1c63979ee2e4cd1e4d4289a5d88cfcbf3a09b06b5cbc88b5bfeb4b87a94cefab81c8d44655e7e813fc3e18f51cfe7e8a0" + }).map(hex -> ECKey.fromPublicOnly(Hex.decode(hex))).collect(Collectors.toList()); + + AddressBasedAuthorizer regTestFeePerKbChangeAuthorizer = new AddressBasedAuthorizer( + regTestFeePerKbAuthorizedKeys, + AddressBasedAuthorizer.MinimumRequiredCalculation.MAJORITY + ); + + return Stream.of( + Arguments.of(FeePerKbMainNetConstants.getInstance(), mainNetFeePerKbChangeAuthorizer), + Arguments.of(FeePerKbTestNetConstants.getInstance(), testNetFeePerKbChangeAuthorizer), + Arguments.of(FeePerKbRegTestConstants.getInstance(), regTestFeePerKbChangeAuthorizer) + ); + } +} diff --git a/rskj-core/src/test/java/co/rsk/peg/performance/GetFeePerKbTest.java b/rskj-core/src/test/java/co/rsk/peg/performance/GetFeePerKbTest.java index 7cbe359f5a5..be73a492a0c 100644 --- a/rskj-core/src/test/java/co/rsk/peg/performance/GetFeePerKbTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/performance/GetFeePerKbTest.java @@ -18,7 +18,6 @@ package co.rsk.peg.performance; -import co.rsk.bitcoinj.core.Coin; import co.rsk.bitcoinj.store.BtcBlockStore; import co.rsk.peg.Bridge; import co.rsk.peg.BridgeStorageProvider; @@ -58,12 +57,11 @@ private void executeTestCaseSection(ABIEncoder abiEncoder, String name, boolean private BridgeStorageProviderInitializer buildInitializer(boolean genesis) { return (BridgeStorageProvider provider, Repository repository, int executionIndex, BtcBlockStore blockStore) -> { if (!genesis) { - provider.setFeePerKb(Helper.randomCoin(Coin.MILLICOIN, 1, 100)); + // TODO: This logic needs to be adjusted to use the new FeePerKbStorageProvider class +// provider.setFeePerKb(Helper.randomCoin(Coin.MILLICOIN, 1, 100)); } else { genesisFederation = FederationTestUtils.getGenesisFederation(bridgeConstants); } }; } - - } diff --git a/rskj-core/src/test/java/co/rsk/peg/performance/VoteFeePerKbChangeTest.java b/rskj-core/src/test/java/co/rsk/peg/performance/VoteFeePerKbChangeTest.java index 7d8e18649fa..af8dcea2748 100644 --- a/rskj-core/src/test/java/co/rsk/peg/performance/VoteFeePerKbChangeTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/performance/VoteFeePerKbChangeTest.java @@ -19,8 +19,9 @@ package co.rsk.peg.performance; import co.rsk.bitcoinj.core.Coin; -import co.rsk.peg.constants.BridgeRegTestConstants; import co.rsk.peg.Bridge; +import co.rsk.peg.feeperkb.constants.FeePerKbConstants; +import co.rsk.peg.feeperkb.constants.FeePerKbMainNetConstants; import org.ethereum.crypto.ECKey; import org.ethereum.crypto.HashUtil; import org.ethereum.vm.exception.VMException; @@ -72,7 +73,8 @@ void voteFeePerKbChange() throws VMException { void voteFeePerKbChange_unauthorized() throws VMException { BridgeStorageProviderInitializer storageInitializer = Helper.buildNoopInitializer(); - Coin genesisFeePerKB = BridgeRegTestConstants.getInstance().getGenesisFeePerKb(); + FeePerKbConstants feePerKbMainNetConstants= FeePerKbMainNetConstants.getInstance(); + Coin genesisFeePerKB = feePerKbMainNetConstants.getGenesisFeePerKb(); ABIEncoder abiEncoder = (int executionIndex) -> Bridge.VOTE_FEE_PER_KB.encode(BigInteger.valueOf(Helper.randomCoin(Coin.MILLICOIN, 1, 100).getValue())); TxBuilder txBuilder = (int executionIndex) -> { diff --git a/rskj-core/src/test/java/co/rsk/peg/vote/ABICallSpecTest.java b/rskj-core/src/test/java/co/rsk/peg/vote/ABICallSpecTest.java index 3527197f153..37d186729cb 100644 --- a/rskj-core/src/test/java/co/rsk/peg/vote/ABICallSpecTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/vote/ABICallSpecTest.java @@ -31,8 +31,8 @@ class ABICallSpecTest { @Test void argumentsIsCopy() { ABICallSpec spec = new ABICallSpec("a-function", new byte[][]{ - Hex.decode("aabb"), - Hex.decode("ccddee") + Hex.decode("aabb"), + Hex.decode("ccddee") }); byte[][] arguments = spec.getArguments(); @@ -50,8 +50,8 @@ void getFunction() { @Test void getEncoded() { ABICallSpec spec = new ABICallSpec("a-function", new byte[][]{ - Hex.decode("1122"), - Hex.decode("334455"), + Hex.decode("1122"), + Hex.decode("334455"), }); StringBuilder expectedBuilder = new StringBuilder(); @@ -63,27 +63,27 @@ void getEncoded() { @Test void testEquals() { ABICallSpec specA = new ABICallSpec("function-a", new byte[][]{ - Hex.decode("aabb"), - Hex.decode("ccddee") + Hex.decode("aabb"), + Hex.decode("ccddee") }); ABICallSpec specB = new ABICallSpec("function-b", new byte[][]{ - Hex.decode("aabb"), - Hex.decode("ccddee") + Hex.decode("aabb"), + Hex.decode("ccddee") }); ABICallSpec specC = new ABICallSpec("function-a", new byte[][]{ - Hex.decode("ccddee"), - Hex.decode("aabb") + Hex.decode("ccddee"), + Hex.decode("aabb") }); ABICallSpec specD = new ABICallSpec("function-a", new byte[][]{ - Hex.decode("aabb"), - Hex.decode("ccdd") + Hex.decode("aabb"), + Hex.decode("ccdd") }); ABICallSpec specE = new ABICallSpec("function-a", new byte[][]{ - Hex.decode("aabb") + Hex.decode("aabb") }); ABICallSpec specF = new ABICallSpec("function-a", new byte[][]{ - Hex.decode("aabb"), - Hex.decode("ccddee") + Hex.decode("aabb"), + Hex.decode("ccddee") }); Assertions.assertEquals(specA, specF); diff --git a/rskj-core/src/test/java/co/rsk/peg/vote/AddressBasedAuthorizerTest.java b/rskj-core/src/test/java/co/rsk/peg/vote/AddressBasedAuthorizerTest.java index 761a506f024..0aa5ea1adbc 100644 --- a/rskj-core/src/test/java/co/rsk/peg/vote/AddressBasedAuthorizerTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/vote/AddressBasedAuthorizerTest.java @@ -38,10 +38,10 @@ class AddressBasedAuthorizerTest { @Test void numberOfKeys_one() { AddressBasedAuthorizer auth = new AddressBasedAuthorizer(Arrays.asList( - mock(ECKey.class), - mock(ECKey.class), - mock(ECKey.class), - mock(ECKey.class) + mock(ECKey.class), + mock(ECKey.class), + mock(ECKey.class), + mock(ECKey.class) ), AddressBasedAuthorizer.MinimumRequiredCalculation.ONE); Assertions.assertEquals(4, auth.getNumberOfAuthorizedKeys()); @@ -51,10 +51,10 @@ void numberOfKeys_one() { @Test void numberOfKeys_majority() { AddressBasedAuthorizer auth = new AddressBasedAuthorizer(Arrays.asList( - mock(ECKey.class), - mock(ECKey.class), - mock(ECKey.class), - mock(ECKey.class) + mock(ECKey.class), + mock(ECKey.class), + mock(ECKey.class), + mock(ECKey.class) ), AddressBasedAuthorizer.MinimumRequiredCalculation.MAJORITY); Assertions.assertEquals(4, auth.getNumberOfAuthorizedKeys()); @@ -64,10 +64,10 @@ void numberOfKeys_majority() { @Test void numberOfKeys_all() { AddressBasedAuthorizer auth = new AddressBasedAuthorizer(Arrays.asList( - mock(ECKey.class), - mock(ECKey.class), - mock(ECKey.class), - mock(ECKey.class) + mock(ECKey.class), + mock(ECKey.class), + mock(ECKey.class), + mock(ECKey.class) ), AddressBasedAuthorizer.MinimumRequiredCalculation.ALL); Assertions.assertEquals(4, auth.getNumberOfAuthorizedKeys()); @@ -77,9 +77,9 @@ void numberOfKeys_all() { @Test void isAuthorized() { AddressBasedAuthorizer auth = new AddressBasedAuthorizer(Arrays.asList( - ECKey.fromPrivate(BigInteger.valueOf(100L)), - ECKey.fromPrivate(BigInteger.valueOf(101L)), - ECKey.fromPrivate(BigInteger.valueOf(102L)) + ECKey.fromPrivate(BigInteger.valueOf(100L)), + ECKey.fromPrivate(BigInteger.valueOf(101L)), + ECKey.fromPrivate(BigInteger.valueOf(102L)) ), AddressBasedAuthorizer.MinimumRequiredCalculation.MAJORITY); for (long n = 100L; n <= 102L; n++) { diff --git a/rskj-core/src/test/java/co/rsk/test/builders/BridgeSupportBuilder.java b/rskj-core/src/test/java/co/rsk/test/builders/BridgeSupportBuilder.java index ae7d38e3062..dc0f9ed0ff0 100644 --- a/rskj-core/src/test/java/co/rsk/test/builders/BridgeSupportBuilder.java +++ b/rskj-core/src/test/java/co/rsk/test/builders/BridgeSupportBuilder.java @@ -9,6 +9,7 @@ import co.rsk.peg.BtcBlockStoreWithCache.Factory; import co.rsk.peg.FederationSupport; import co.rsk.peg.btcLockSender.BtcLockSenderProvider; +import co.rsk.peg.feeperkb.FeePerKbSupport; import co.rsk.peg.pegininstructions.PeginInstructionsProvider; import co.rsk.peg.utils.BridgeEventLogger; import org.ethereum.config.blockchain.upgrades.ActivationConfig; @@ -25,6 +26,7 @@ public class BridgeSupportBuilder { private Factory btcBlockStoreFactory; private ActivationConfig.ForBlock activations; private SignatureCache signatureCache; + private FeePerKbSupport feePerKbSupport; public BridgeSupportBuilder() { this.bridgeConstants = mock(BridgeConstants.class); @@ -37,6 +39,7 @@ public BridgeSupportBuilder() { this.btcBlockStoreFactory = mock(Factory.class); this.activations = mock(ActivationConfig.ForBlock.class); this.signatureCache = mock(BlockTxSignatureCache.class); + this.feePerKbSupport = mock(FeePerKbSupport.class); } public BridgeSupportBuilder withBridgeConstants(BridgeConstants bridgeConstants) { @@ -89,8 +92,13 @@ public BridgeSupportBuilder withSignatureCache(SignatureCache signatureCache) { return this; } + public BridgeSupportBuilder withFeePerKbSupport(FeePerKbSupport feePerKbSupport) { + this.feePerKbSupport = feePerKbSupport; + return this; + } + public BridgeSupport build() { - return new BridgeSupport( + return new BridgeSupport( bridgeConstants, provider, eventLogger, @@ -100,6 +108,7 @@ public BridgeSupport build() { executionBlock, new Context(bridgeConstants.getBtcParams()), new FederationSupport(bridgeConstants, provider, executionBlock, activations), + feePerKbSupport, btcBlockStoreFactory, activations, signatureCache