diff --git a/rskj-core/src/main/java/co/rsk/config/BridgeConstants.java b/rskj-core/src/main/java/co/rsk/config/BridgeConstants.java index 11329b1accf..cda9026acd5 100644 --- a/rskj-core/src/main/java/co/rsk/config/BridgeConstants.java +++ b/rskj-core/src/main/java/co/rsk/config/BridgeConstants.java @@ -24,6 +24,7 @@ import co.rsk.peg.AddressBasedAuthorizer; import co.rsk.peg.Federation; import java.util.List; + import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; diff --git a/rskj-core/src/main/java/co/rsk/config/BridgeDevNetConstants.java b/rskj-core/src/main/java/co/rsk/config/BridgeDevNetConstants.java index c625c6bed4e..4b363336571 100644 --- a/rskj-core/src/main/java/co/rsk/config/BridgeDevNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/config/BridgeDevNetConstants.java @@ -22,8 +22,8 @@ import co.rsk.bitcoinj.core.Coin; import co.rsk.bitcoinj.core.NetworkParameters; import co.rsk.peg.AddressBasedAuthorizer; -import co.rsk.peg.Federation; import co.rsk.peg.FederationMember; +import co.rsk.peg.StandardMultisigFederation; import org.bouncycastle.util.encoders.Hex; import org.ethereum.crypto.ECKey; @@ -58,7 +58,7 @@ public BridgeDevNetConstants(List federationPublicKeys) { // Expected federation address is: // 2NCEo1RdmGDj6MqiipD6DUSerSxKv79FNWX - genesisFederation = new Federation( + genesisFederation = new StandardMultisigFederation( federationMembers, genesisFederationAddressCreatedAt, 1L, diff --git a/rskj-core/src/main/java/co/rsk/config/BridgeMainNetConstants.java b/rskj-core/src/main/java/co/rsk/config/BridgeMainNetConstants.java index 0c55020e5e7..b07ccb57250 100644 --- a/rskj-core/src/main/java/co/rsk/config/BridgeMainNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/config/BridgeMainNetConstants.java @@ -4,8 +4,8 @@ import co.rsk.bitcoinj.core.Coin; import co.rsk.bitcoinj.core.NetworkParameters; import co.rsk.peg.AddressBasedAuthorizer; -import co.rsk.peg.Federation; import co.rsk.peg.FederationMember; +import co.rsk.peg.StandardMultisigFederation; import com.google.common.collect.Lists; import org.bouncycastle.util.encoders.Hex; import org.ethereum.crypto.ECKey; @@ -53,7 +53,7 @@ public class BridgeMainNetConstants extends BridgeConstants { // Wednesday, January 3, 2018 12:00:00 AM GMT-03:00 Instant genesisFederationAddressCreatedAt = Instant.ofEpochMilli(1514948400l); - genesisFederation = new Federation( + genesisFederation = new StandardMultisigFederation( federationMembers, genesisFederationAddressCreatedAt, 1L, diff --git a/rskj-core/src/main/java/co/rsk/config/BridgeRegTestConstants.java b/rskj-core/src/main/java/co/rsk/config/BridgeRegTestConstants.java index feba5514fac..db7c4f3520f 100644 --- a/rskj-core/src/main/java/co/rsk/config/BridgeRegTestConstants.java +++ b/rskj-core/src/main/java/co/rsk/config/BridgeRegTestConstants.java @@ -22,8 +22,8 @@ import co.rsk.bitcoinj.core.Coin; import co.rsk.bitcoinj.core.NetworkParameters; import co.rsk.peg.AddressBasedAuthorizer; -import co.rsk.peg.Federation; import co.rsk.peg.FederationMember; +import co.rsk.peg.StandardMultisigFederation; import org.bouncycastle.util.encoders.Hex; import org.ethereum.crypto.ECKey; import org.ethereum.crypto.HashUtil; @@ -56,7 +56,7 @@ public BridgeRegTestConstants(List federationPublicKeys) { Instant genesisFederationCreatedAt = ZonedDateTime.parse("2016-01-01T00:00:00Z").toInstant(); - genesisFederation = new Federation( + genesisFederation = new StandardMultisigFederation( federationMembers, genesisFederationCreatedAt, 1L, diff --git a/rskj-core/src/main/java/co/rsk/config/BridgeTestNetConstants.java b/rskj-core/src/main/java/co/rsk/config/BridgeTestNetConstants.java index dcb96de245d..540fec54195 100644 --- a/rskj-core/src/main/java/co/rsk/config/BridgeTestNetConstants.java +++ b/rskj-core/src/main/java/co/rsk/config/BridgeTestNetConstants.java @@ -22,8 +22,8 @@ import co.rsk.bitcoinj.core.Coin; import co.rsk.bitcoinj.core.NetworkParameters; import co.rsk.peg.AddressBasedAuthorizer; -import co.rsk.peg.Federation; import co.rsk.peg.FederationMember; +import co.rsk.peg.StandardMultisigFederation; import org.bouncycastle.util.encoders.Hex; import org.ethereum.crypto.ECKey; @@ -61,7 +61,7 @@ public class BridgeTestNetConstants extends BridgeConstants { // Currently set to: Monday, October 8, 2018 12:00:00 AM GMT-03:00 Instant genesisFederationAddressCreatedAt = Instant.ofEpochMilli(1538967600l); - genesisFederation = new Federation( + genesisFederation = new StandardMultisigFederation( federationMembers, genesisFederationAddressCreatedAt, 1L, diff --git a/rskj-core/src/main/java/co/rsk/peg/BridgeSerializationUtils.java b/rskj-core/src/main/java/co/rsk/peg/BridgeSerializationUtils.java index 852d04602b4..b9cdac52c4c 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSerializationUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSerializationUtils.java @@ -246,7 +246,7 @@ private static byte[] serializeFederationWithSerializer(Federation federation, F } // For the serialization format, see BridgeSerializationUtils::serializeFederationWithSerializer - private static Federation deserializeFederationWithDeserializer( + private static StandardMultisigFederation deserializeStandardMultisigFederationWithDeserializer( byte[] data, NetworkParameters networkParameters, FederationMemberDesserializer federationMemberDesserializer) { @@ -273,7 +273,7 @@ private static Federation deserializeFederationWithDeserializer( federationMembers.add(member); } - return new Federation(federationMembers, creationTime, creationBlockNumber, networkParameters); + return new StandardMultisigFederation(federationMembers, creationTime, creationBlockNumber, networkParameters); } /** @@ -287,8 +287,8 @@ public static byte[] serializeFederationOnlyBtcKeys(Federation federation) { } // For the serialization format, see BridgeSerializationUtils::serializeFederationOnlyBtcKeys - public static Federation deserializeFederationOnlyBtcKeys(byte[] data, NetworkParameters networkParameters) { - return deserializeFederationWithDeserializer(data, networkParameters, + public static StandardMultisigFederation deserializeStandardMultisigFederationOnlyBtcKeys(byte[] data, NetworkParameters networkParameters) { + return deserializeStandardMultisigFederationWithDeserializer(data, networkParameters, (pubKeyBytes -> FederationMember.getFederationMemberFromKey(BtcECKey.fromPublicOnly(pubKeyBytes)))); } @@ -304,29 +304,29 @@ public static byte[] serializeFederation(Federation federation) { } // For the serialization format, see BridgeSerializationUtils::serializeFederation - public static Federation deserializeFederation( + public static StandardMultisigFederation deserializeStandardMultisigFederation( byte[] data, NetworkParameters networkParameters ) { - return deserializeFederationWithDeserializer( + return deserializeStandardMultisigFederationWithDeserializer( data, networkParameters, BridgeSerializationUtils::deserializeFederationMember ); } - public static ErpFederation deserializeErpFederation( + public static LegacyErpFederation deserializeLegacyErpFederation( byte[] data, BridgeConstants bridgeConstants, ActivationConfig.ForBlock activations ) { - Federation federation = deserializeFederationWithDeserializer( + Federation federation = deserializeStandardMultisigFederationWithDeserializer( data, bridgeConstants.getBtcParams(), BridgeSerializationUtils::deserializeFederationMember ); - return new ErpFederation( + return new LegacyErpFederation( federation.getMembers(), federation.creationTime, federation.getCreationBlockNumber(), @@ -342,7 +342,7 @@ public static P2shErpFederation deserializeP2shErpFederation( BridgeConstants bridgeConstants, ActivationConfig.ForBlock activations ) { - Federation federation = deserializeFederationWithDeserializer( + Federation federation = deserializeStandardMultisigFederationWithDeserializer( data, bridgeConstants.getBtcParams(), BridgeSerializationUtils::deserializeFederationMember 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 9ea7e840400..75d2e211d36 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeStorageProvider.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeStorageProvider.java @@ -48,9 +48,9 @@ * @author Oscar Guindzberg */ public class BridgeStorageProvider { - private static final int FEDERATION_FORMAT_VERSION_MULTIKEY = 1000; - private static final int ERP_FEDERATION_FORMAT_VERSION = 2000; - private static final int P2SH_ERP_FEDERATION_FORMAT_VERSION = 3000; + protected static final int STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION = 1000; + protected static final int LEGACY_ERP_FEDERATION_FORMAT_VERSION = 2000; + protected static final int P2SH_ERP_FEDERATION_FORMAT_VERSION = 3000; // Dummy value to use when saved Fast Bridge Derivation Argument Hash private static final byte FLYOVER_FEDERATION_DERIVATION_HASH_TRUE_VALUE = (byte) 1; @@ -336,7 +336,7 @@ public Federation getNewFederation() { return deserializeFederationAccordingToVersion(data, storageVersion.get(), bridgeConstants); } - return BridgeSerializationUtils.deserializeFederationOnlyBtcKeys(data, networkParameters); + return BridgeSerializationUtils.deserializeStandardMultisigFederationOnlyBtcKeys(data, networkParameters); } ); @@ -364,15 +364,15 @@ public void saveNewFederation() { NEW_FEDERATION_FORMAT_VERSION.getKey(), P2SH_ERP_FEDERATION_FORMAT_VERSION ); - } else if (activations.isActive(RSKIP201) && newFederation instanceof ErpFederation) { + } else if (activations.isActive(RSKIP201) && newFederation instanceof LegacyErpFederation) { saveStorageVersion( NEW_FEDERATION_FORMAT_VERSION.getKey(), - ERP_FEDERATION_FORMAT_VERSION + LEGACY_ERP_FEDERATION_FORMAT_VERSION ); } else { saveStorageVersion( NEW_FEDERATION_FORMAT_VERSION.getKey(), - FEDERATION_FORMAT_VERSION_MULTIKEY + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION ); } serializer = BridgeSerializationUtils::serializeFederation; @@ -398,7 +398,7 @@ public Federation getOldFederation() { return deserializeFederationAccordingToVersion(data, storageVersion.get(), bridgeConstants); } - return BridgeSerializationUtils.deserializeFederationOnlyBtcKeys(data, networkParameters); + return BridgeSerializationUtils.deserializeStandardMultisigFederationOnlyBtcKeys(data, networkParameters); } ); @@ -428,12 +428,12 @@ protected void saveOldFederation() { } else if (activations.isActive(RSKIP201) && oldFederation instanceof ErpFederation) { saveStorageVersion( OLD_FEDERATION_FORMAT_VERSION.getKey(), - ERP_FEDERATION_FORMAT_VERSION + LEGACY_ERP_FEDERATION_FORMAT_VERSION ); } else { saveStorageVersion( OLD_FEDERATION_FORMAT_VERSION.getKey(), - FEDERATION_FORMAT_VERSION_MULTIKEY + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION ); } @@ -480,7 +480,7 @@ public void savePendingFederation() { RepositorySerializer serializer = BridgeSerializationUtils::serializePendingFederationOnlyBtcKeys; if (activations.isActive(RSKIP123)) { - saveStorageVersion(PENDING_FEDERATION_FORMAT_VERSION.getKey(), FEDERATION_FORMAT_VERSION_MULTIKEY); + saveStorageVersion(PENDING_FEDERATION_FORMAT_VERSION.getKey(), STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION); serializer = BridgeSerializationUtils::serializePendingFederation; } @@ -1028,8 +1028,8 @@ private Federation deserializeFederationAccordingToVersion( BridgeConstants bridgeConstants ) { switch (version) { - case ERP_FEDERATION_FORMAT_VERSION: - return BridgeSerializationUtils.deserializeErpFederation( + case LEGACY_ERP_FEDERATION_FORMAT_VERSION: + return BridgeSerializationUtils.deserializeLegacyErpFederation( data, bridgeConstants, activations @@ -1040,9 +1040,17 @@ private Federation deserializeFederationAccordingToVersion( bridgeConstants, activations ); + case STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION: + return BridgeSerializationUtils.deserializeStandardMultisigFederation( + data, + networkParameters + ); default: - // Assume this is the multi-key version - return BridgeSerializationUtils.deserializeFederation(data, networkParameters); + // To keep backwards compatibility + return BridgeSerializationUtils.deserializeStandardMultisigFederation( + data, + networkParameters + ); } } 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 ec6d8515c15..fe8c001d04a 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeSupport.java @@ -17,6 +17,15 @@ */ package co.rsk.peg; +import static co.rsk.peg.BridgeUtils.getRegularPegoutTxSize; +import static co.rsk.peg.ReleaseTransactionBuilder.BTC_TX_VERSION_2; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP186; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP219; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP271; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP293; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP294; +import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP377; + import co.rsk.bitcoinj.core.Address; import co.rsk.bitcoinj.core.AddressFormatException; import co.rsk.bitcoinj.core.BtcBlock; @@ -57,7 +66,12 @@ import co.rsk.peg.flyover.FlyoverTxResponseCodes; import co.rsk.peg.pegininstructions.PeginInstructionsException; import co.rsk.peg.pegininstructions.PeginInstructionsProvider; -import co.rsk.peg.utils.*; +import co.rsk.peg.utils.BridgeEventLogger; +import co.rsk.peg.utils.BtcTransactionFormatUtils; +import co.rsk.peg.utils.PartialMerkleTreeFormatUtils; +import co.rsk.peg.utils.RejectedPeginReason; +import co.rsk.peg.utils.RejectedPegoutReason; +import co.rsk.peg.utils.UnrefundablePeginReason; import co.rsk.peg.whitelist.LockWhitelist; import co.rsk.peg.whitelist.LockWhitelistEntry; import co.rsk.peg.whitelist.OneOffWhiteListEntry; @@ -78,7 +92,6 @@ import java.util.Optional; import java.util.stream.Collectors; import javax.annotation.Nullable; - import org.apache.commons.lang3.tuple.Pair; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.blockchain.upgrades.ActivationConfig; @@ -100,15 +113,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static co.rsk.peg.BridgeUtils.getRegularPegoutTxSize; -import static co.rsk.peg.ReleaseTransactionBuilder.BTC_TX_VERSION_2; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP186; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP219; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP293; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP271; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP294; -import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP377; - /** * Helper class to move funds from btc to rsk and rsk to btc * @author Oscar Guindzberg @@ -1337,27 +1341,30 @@ private void adjustBalancesIfChangeOutputWasDust(BtcTransaction btcTx, Coin sent public void addSignature(BtcECKey federatorPublicKey, List signatures, byte[] rskTxHash) throws Exception { Context.propagate(btcContext); - Federation retiringFederation = getRetiringFederation(); - Federation activeFederation = getActiveFederation(); - Federation federation = - activeFederation.hasBtcPublicKey(federatorPublicKey) ? - activeFederation : - (retiringFederation != null && retiringFederation.hasBtcPublicKey(federatorPublicKey) ? - retiringFederation: - null); - - if (federation == null) { - logger.warn("Supplied federator public key {} does not belong to any of the federators.", federatorPublicKey); + Optional optionalFederation = getFederationFromPublicKey(federatorPublicKey); + if (!optionalFederation.isPresent()) { + logger.warn( + "Supplied federator public key {} does not belong to any of the federators.", + federatorPublicKey + ); return; } + Federation federation = optionalFederation.get(); BtcTransaction btcTx = provider.getPegoutsWaitingForSignatures().get(new Keccak256(rskTxHash)); if (btcTx == null) { - logger.warn("No tx waiting for signature for hash {}. Probably fully signed already.", new Keccak256(rskTxHash)); + logger.warn( + "No tx waiting for signature for hash {}. Probably fully signed already.", + new Keccak256(rskTxHash) + ); return; } if (btcTx.getInputs().size() != signatures.size()) { - logger.warn("Expected {} signatures but received {}.", btcTx.getInputs().size(), signatures.size()); + logger.warn( + "Expected {} signatures but received {}.", + btcTx.getInputs().size(), + signatures.size() + ); return; } @@ -1368,7 +1375,26 @@ public void addSignature(BtcECKey federatorPublicKey, List signatures, b processSigning(federatorPublicKey, signatures, rskTxHash, btcTx, federation); } - private void processSigning(BtcECKey federatorPublicKey, List signatures, byte[] rskTxHash, BtcTransaction btcTx, Federation federation) throws IOException { + private Optional getFederationFromPublicKey(BtcECKey federatorPublicKey) { + Federation retiringFederation = getRetiringFederation(); + Federation activeFederation = getActiveFederation(); + + if (activeFederation.hasBtcPublicKey(federatorPublicKey)) { + return Optional.of(activeFederation); + } + if (retiringFederation != null && retiringFederation.hasBtcPublicKey(federatorPublicKey)) { + return Optional.of(retiringFederation); + } + + return Optional.empty(); + } + + private void processSigning( + BtcECKey federatorPublicKey, + List signatures, + byte[] rskTxHash, + BtcTransaction btcTx, + Federation federation) throws IOException { // Build input hashes for signatures int numInputs = btcTx.getInputs().size(); @@ -1389,7 +1415,12 @@ private void processSigning(BtcECKey federatorPublicKey, List signatures try { sig = BtcECKey.ECDSASignature.decodeFromDER(signatures.get(i)); } catch (RuntimeException e) { - logger.warn("Malformed signature for input {} of tx {}: {}", i, new Keccak256(rskTxHash), ByteUtil.toHexString(signatures.get(i))); + logger.warn( + "Malformed signature for input {} of tx {}: {}", + i, + new Keccak256(rskTxHash), + ByteUtil.toHexString(signatures.get(i)) + ); return; } @@ -2079,7 +2110,8 @@ protected Integer commitFederation(boolean dryRun, Keccak256 hash) throws IOExce // Preserve federation change info long nextFederationCreationBlockHeight = rskExecutionBlock.getNumber(); provider.setNextFederationCreationBlockHeight(nextFederationCreationBlockHeight); - Script oldFederationP2SHScript = activations.isActive(RSKIP377)? oldFederation.getStandardP2SHScript(): oldFederation.getP2SHScript(); + Script oldFederationP2SHScript = activations.isActive(RSKIP377) && oldFederation instanceof ErpFederation ? + ((ErpFederation) oldFederation).getStandardP2SHScript() : oldFederation.getP2SHScript(); provider.setLastRetiredFederationP2SHScript(oldFederationP2SHScript); } 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 0a1035365f0..f4dbcdae97e 100644 --- a/rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java +++ b/rskj-core/src/main/java/co/rsk/peg/BridgeUtils.java @@ -402,7 +402,10 @@ public static boolean isValidPegInTx( throw new ScriptException(message); } Script inputStandardRedeemScript = redeemScriptParser.extractStandardRedeemScript(); - if (activeFederations.stream().anyMatch(federation -> federation.getStandardRedeemScript().equals(inputStandardRedeemScript))) { + if (activeFederations.stream().anyMatch(federation -> + (federation instanceof ErpFederation ? ((ErpFederation) federation).getStandardRedeemScript() + : federation.getRedeemScript() + ).equals(inputStandardRedeemScript))) { return false; } @@ -490,7 +493,10 @@ private static boolean isPegOutTx(BtcTransaction tx, Federation federation, Acti } public static boolean isPegOutTx(BtcTransaction tx, List federations, ActivationConfig.ForBlock activations) { - return isPegOutTx(tx, activations, federations.stream().filter(Objects::nonNull).map(Federation::getStandardP2SHScript).toArray(Script[]::new)); + return isPegOutTx(tx, activations, federations.stream().filter(Objects::nonNull).map(fed -> + fed instanceof ErpFederation ? ((ErpFederation) fed).getStandardP2SHScript() + : fed.getP2SHScript() + ).toArray(Script[]::new)); } public static boolean isPegOutTx(BtcTransaction tx, ActivationConfig.ForBlock activations, Script... p2shScript) { @@ -515,7 +521,8 @@ public static boolean isPegOutTx(BtcTransaction tx, ActivationConfig.ForBlock ac } Script outputScript = ScriptBuilder.createP2SHOutputScript(redeemScript); - if (Stream.of(p2shScript).anyMatch(federationPayScript -> federationPayScript.equals(outputScript))) { + if (Stream.of(p2shScript).anyMatch(federationPayScript -> + federationPayScript.equals(outputScript))) { return true; } } diff --git a/rskj-core/src/main/java/co/rsk/peg/ErpFederation.java b/rskj-core/src/main/java/co/rsk/peg/ErpFederation.java index b8d303f94a5..28228bbc22a 100644 --- a/rskj-core/src/main/java/co/rsk/peg/ErpFederation.java +++ b/rskj-core/src/main/java/co/rsk/peg/ErpFederation.java @@ -1,34 +1,26 @@ package co.rsk.peg; -import co.rsk.bitcoinj.core.Address; import co.rsk.bitcoinj.core.BtcECKey; import co.rsk.bitcoinj.core.NetworkParameters; -import co.rsk.bitcoinj.script.ErpFederationRedeemScriptParser; import co.rsk.bitcoinj.script.Script; import co.rsk.bitcoinj.script.ScriptBuilder; import co.rsk.peg.utils.EcKeyUtils; import java.time.Instant; import java.util.Collections; import java.util.List; -import java.util.Objects; -import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.blockchain.upgrades.ActivationConfig; -import org.ethereum.config.blockchain.upgrades.ConsensusRule; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ErpFederation extends Federation { - private static final byte[] ERP_TESTNET_REDEEM_SCRIPT_BYTES = Hex.decode("6453210208f40073a9e43b3e9103acec79767a6de9b0409749884e989960fee578012fce210225e892391625854128c5c4ea4340de0c2a70570f33db53426fc9c746597a03f42102afc230c2d355b1a577682b07bc2646041b5d0177af0f98395a46018da699b6da210344a3c38cd59afcba3edcebe143e025574594b001700dec41e59409bdbd0f2a0921039a060badbeb24bee49eb2063f616c0f0f0765d4ca646b20a88ce828f259fcdb955670300cd50b27552210216c23b2ea8e4f11c3f9e22711addb1d16a93964796913830856b568cc3ea21d3210275562901dd8faae20de0a4166362a4f82188db77dbed4ca887422ea1ec185f1421034db69f2112f4fb1bb6141bf6e2bd6631f0484d0bd95b16767902c9fe219d4a6f5368ae"); - private static final Logger logger = LoggerFactory.getLogger(ErpFederation.class); +import static co.rsk.peg.FederationCreationException.Reason.INVALID_CSV_VALUE; +import static co.rsk.peg.FederationCreationException.Reason.NULL_OR_EMPTY_EMERGENCY_KEYS; +public abstract class ErpFederation extends Federation { + protected static final long MAX_CSV_VALUE = 65_535L; // 2^16 - 1, since bitcoin will interpret up to 16 bits as the CSV value protected final List erpPubKeys; protected final long activationDelay; protected final ActivationConfig.ForBlock activations; - protected Script standardRedeemScript; protected Script standardP2SHScript; - public ErpFederation( + protected ErpFederation( List members, Instant creationTime, long creationBlockNumber, @@ -38,15 +30,11 @@ public ErpFederation( ActivationConfig.ForBlock activations) { super(members, creationTime, creationBlockNumber, btcParams); + validateErpFederationValues(erpPubKeys, activationDelay); + this.erpPubKeys = EcKeyUtils.getCompressedPubKeysList(erpPubKeys); this.activationDelay = activationDelay; this.activations = activations; - - // Try getting the redeem script in order to validate it can be built - // using the given public keys and csv value - getRedeemScript(); // NOSONAR - validateRedeemScript(); - getStandardRedeemScript(); // NOSONAR } public List getErpPubKeys() { @@ -57,52 +45,8 @@ public long getActivationDelay() { return activationDelay; } - @Override - public Script getRedeemScript() { - if (!activations.isActive(ConsensusRule.RSKIP284) && - btcParams.getId().equals(NetworkParameters.ID_TESTNET)) { - logger.debug("[getRedeemScript] Returning hardcoded redeem script"); - return new Script(ERP_TESTNET_REDEEM_SCRIPT_BYTES); - } - - if (redeemScript == null) { - logger.debug("[getRedeemScript] Creating the redeem script from the keys"); - redeemScript = activations.isActive(ConsensusRule.RSKIP293) ? - ErpFederationRedeemScriptParser.createErpRedeemScript( - ScriptBuilder.createRedeemScript(getNumberOfSignaturesRequired(), getBtcPublicKeys()), - ScriptBuilder.createRedeemScript(erpPubKeys.size() / 2 + 1, erpPubKeys), - activationDelay - ) : - ErpFederationRedeemScriptParser.createErpRedeemScriptDeprecated( - ScriptBuilder.createRedeemScript(getNumberOfSignaturesRequired(), getBtcPublicKeys()), - ScriptBuilder.createRedeemScript(erpPubKeys.size() / 2 + 1, erpPubKeys), - activationDelay - ); - } - - return redeemScript; - } - - @Override - public Script getStandardRedeemScript() { - if (standardRedeemScript == null) { - standardRedeemScript = ErpFederationRedeemScriptParser.extractStandardRedeemScript( - getRedeemScript().getChunks() - ); - } - return standardRedeemScript; - } - - @Override - public Script getP2SHScript() { - if (p2shScript == null) { - p2shScript = ScriptBuilder.createP2SHOutputScript(getRedeemScript()); - } + public abstract Script getStandardRedeemScript(); - return p2shScript; - } - - @Override public Script getStandardP2SHScript() { if (standardP2SHScript == null) { standardP2SHScript = ScriptBuilder.createP2SHOutputScript(getStandardRedeemScript()); @@ -111,60 +55,20 @@ public Script getStandardP2SHScript() { return standardP2SHScript; } - @Override - public Address getAddress() { - if (address == null) { - address = Address.fromP2SHScript(btcParams, getP2SHScript()); + private void validateErpFederationValues(List erpPubKeys, long activationDelay) { + if (erpPubKeys == null || erpPubKeys.isEmpty()) { + String message = "Emergency keys are not provided"; + throw new FederationCreationException(message, NULL_OR_EMPTY_EMERGENCY_KEYS); } - return address; - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - - if (other == null || this.getClass() != other.getClass()) { - return false; + if (activationDelay <= 0 || activationDelay > MAX_CSV_VALUE) { + String message = String.format( + "Provided csv value %d must be larger than 0 and lower than %d", + activationDelay, + MAX_CSV_VALUE + ); + throw new FederationCreationException(message, INVALID_CSV_VALUE); } - - ErpFederation otherErpFederation = (ErpFederation) other; - - return this.getNumberOfSignaturesRequired() == otherErpFederation.getNumberOfSignaturesRequired() && - this.getSize() == otherErpFederation.getSize() && - this.getCreationTime().equals(otherErpFederation.getCreationTime()) && - this.creationBlockNumber == otherErpFederation.creationBlockNumber && - this.btcParams.equals(otherErpFederation.btcParams) && - this.members.equals(otherErpFederation.members) && - this.getRedeemScript().equals(otherErpFederation.getRedeemScript()) && - this.erpPubKeys.equals(otherErpFederation.erpPubKeys) && - this.activationDelay == otherErpFederation.activationDelay; - } - - @Override - public int hashCode() { - // Can use java.util.Objects.hash since all of Instant, int and List have - // well-defined hashCode()s - return Objects.hash( - getCreationTime(), - this.creationBlockNumber, - getNumberOfSignaturesRequired(), - getBtcPublicKeys(), - getErpPubKeys(), - getActivationDelay() - ); } - private void validateRedeemScript() { - if (activations.isActive(ConsensusRule.RSKIP293) && - this.redeemScript.equals(new Script(ERP_TESTNET_REDEEM_SCRIPT_BYTES))) { - - String message = "Unable to create ERP Federation. The obtained redeem script matches the one hardcoded for testnet. " - + "This would cause bitcoinj-thin to identify it as invalid"; - logger.debug("[validateRedeemScript] {}", message); - throw new FederationCreationException(message); - } - } } diff --git a/rskj-core/src/main/java/co/rsk/peg/Federation.java b/rskj-core/src/main/java/co/rsk/peg/Federation.java index 0008949397c..247554623c1 100644 --- a/rskj-core/src/main/java/co/rsk/peg/Federation.java +++ b/rskj-core/src/main/java/co/rsk/peg/Federation.java @@ -29,17 +29,16 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; /** * Immutable representation of an RSK Federation in the context of * a specific BTC network. * - * @author Ariel Mendelzon */ -public class Federation { +public abstract class Federation { protected final List members; protected final Instant creationTime; protected final long creationBlockNumber; @@ -49,12 +48,11 @@ public class Federation { protected Script p2shScript; protected Address address; - public Federation(List members, Instant creationTime, long creationBlockNumber, NetworkParameters btcParams) { + protected Federation(List members, Instant creationTime, long creationBlockNumber, NetworkParameters btcParams) { // Sorting members ensures same order of federation members for same members // Immutability provides protection against unwanted modification, thus making the Federation instance // effectively immutable this.members = Collections.unmodifiableList(members.stream().sorted(FederationMember.BTC_RSK_MST_PUBKEYS_COMPARATOR).collect(Collectors.toList())); - this.creationTime = creationTime.truncatedTo(ChronoUnit.MILLIS); this.creationBlockNumber = creationBlockNumber; this.btcParams = btcParams; @@ -91,30 +89,16 @@ public long getCreationBlockNumber() { return creationBlockNumber; } - public Script getRedeemScript() { - if (redeemScript == null) { - redeemScript = ScriptBuilder.createRedeemScript(getNumberOfSignaturesRequired(), getBtcPublicKeys()); - } - - return redeemScript; - } - - public Script getStandardRedeemScript() { - return getRedeemScript(); - } + public abstract Script getRedeemScript(); public Script getP2SHScript() { if (p2shScript == null) { - p2shScript = ScriptBuilder.createP2SHOutputScript(getNumberOfSignaturesRequired(), getBtcPublicKeys()); + p2shScript = ScriptBuilder.createP2SHOutputScript(getRedeemScript()); } return p2shScript; } - public Script getStandardP2SHScript() { - return getP2SHScript(); - } - public Address getAddress() { if (address == null) { address = Address.fromP2SHScript(btcParams, getP2SHScript()); @@ -127,20 +111,20 @@ public int getSize() { return members.size(); } - public Integer getBtcPublicKeyIndex(BtcECKey key) { + public Optional getBtcPublicKeyIndex(BtcECKey key) { for (int i = 0; i < members.size(); i++) { // note that this comparison doesn't take into account // key compression if (Arrays.equals(key.getPubKey(), members.get(i).getBtcPublicKey().getPubKey())) { - return i; + return Optional.of(i); } } - return null; + return Optional.empty(); } public boolean hasBtcPublicKey(BtcECKey key) { - return getBtcPublicKeyIndex(key) != null; + return getBtcPublicKeyIndex(key).isPresent(); } public boolean hasMemberWithRskAddress(byte[] address) { @@ -154,7 +138,12 @@ public boolean isMember(FederationMember federationMember){ @Override public String toString() { - return String.format("%d of %d signatures federation", getNumberOfSignaturesRequired(), members.size()); + return String.format( + "Got %d of %d signatures federation with address %s", + getNumberOfSignaturesRequired(), + members.size(), + getAddress() + ); } @Override @@ -168,25 +157,11 @@ public boolean equals(Object other) { } Federation otherFederation = (Federation) other; - - return this.getNumberOfSignaturesRequired() == otherFederation.getNumberOfSignaturesRequired() && - this.getSize() == otherFederation.getSize() && - this.getCreationTime().equals(otherFederation.getCreationTime()) && - this.creationBlockNumber == otherFederation.creationBlockNumber && - this.btcParams.equals(otherFederation.btcParams) && - this.members.equals(otherFederation.members) && - this.getRedeemScript().equals(otherFederation.getRedeemScript()); + return this.getAddress().equals(otherFederation.getAddress()); } @Override public int hashCode() { - // Can use java.util.Objects.hash since all of Instant, int and List have - // well-defined hashCode()s - return Objects.hash( - getCreationTime(), - this.creationBlockNumber, - getNumberOfSignaturesRequired(), - getBtcPublicKeys() - ); + return getAddress().hashCode(); } } diff --git a/rskj-core/src/main/java/co/rsk/peg/FederationCreationException.java b/rskj-core/src/main/java/co/rsk/peg/FederationCreationException.java index 54856fc4a7c..4c440272063 100644 --- a/rskj-core/src/main/java/co/rsk/peg/FederationCreationException.java +++ b/rskj-core/src/main/java/co/rsk/peg/FederationCreationException.java @@ -5,16 +5,24 @@ * that could result in the 2wp to stop working as expected */ public class FederationCreationException extends RuntimeException { + private final Reason reason; - public FederationCreationException() { - super(); + public enum Reason { + ABOVE_MAX_SCRIPT_ELEMENT_SIZE, + NULL_OR_EMPTY_EMERGENCY_KEYS, + INVALID_CSV_VALUE, + HARDCODED_LEGACY_ERP_TESTNET_REDEEM_SCRIPT } - public FederationCreationException(String s) { + public FederationCreationException(String s, Reason reason) { super(s); + this.reason = reason; } - public FederationCreationException(String message, Throwable cause) { + public FederationCreationException(String message, Throwable cause, Reason reason) { super(message, cause); + this.reason = reason; } + + public Reason getReason() { return reason; } } diff --git a/rskj-core/src/main/java/co/rsk/peg/FederationUtils.java b/rskj-core/src/main/java/co/rsk/peg/FederationUtils.java new file mode 100644 index 00000000000..bf8b3509555 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/FederationUtils.java @@ -0,0 +1,22 @@ +package co.rsk.peg; + +import co.rsk.bitcoinj.script.Script; +import co.rsk.peg.bitcoin.Standardness; + +import static co.rsk.peg.FederationCreationException.Reason.ABOVE_MAX_SCRIPT_ELEMENT_SIZE; + +public class FederationUtils { + private FederationUtils() { + } + + public static void validateScriptSize(Script script) throws FederationCreationException { + // Check if the size of the script does not exceed the maximum size allowed + int bytesFromScript = script.getProgram().length; + if (bytesFromScript > Standardness.MAX_SCRIPT_ELEMENT_SIZE) { + String message = String.format("The script size is %d, that is above the maximum allowed.", + bytesFromScript + ); + throw new FederationCreationException(message, ABOVE_MAX_SCRIPT_ELEMENT_SIZE); + } + } +} diff --git a/rskj-core/src/main/java/co/rsk/peg/LegacyErpFederation.java b/rskj-core/src/main/java/co/rsk/peg/LegacyErpFederation.java new file mode 100644 index 00000000000..828c0809eb1 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/LegacyErpFederation.java @@ -0,0 +1,93 @@ +package co.rsk.peg; + +import co.rsk.bitcoinj.core.BtcECKey; +import co.rsk.bitcoinj.core.NetworkParameters; +import co.rsk.bitcoinj.script.ErpFederationRedeemScriptParser; +import co.rsk.bitcoinj.script.Script; +import co.rsk.bitcoinj.script.ScriptBuilder; +import java.time.Instant; +import java.util.List; + +import org.bouncycastle.util.encoders.Hex; +import org.ethereum.config.blockchain.upgrades.ActivationConfig; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import static co.rsk.peg.FederationCreationException.Reason.*; + +/** + * @deprecated This class represents a Legacy ERP Federation that is non-standard. + * It has been deprecated but it must be kept because of backwards compatibility. + */ + +@Deprecated +public class LegacyErpFederation extends ErpFederation { + private static final Logger logger = LoggerFactory.getLogger(LegacyErpFederation.class); + private static final byte[] LEGACY_ERP_TESTNET_REDEEM_SCRIPT_BYTES = Hex.decode("6453210208f40073a9e43b3e9103acec79767a6de9b0409749884e989960fee578012fce210225e892391625854128c5c4ea4340de0c2a70570f33db53426fc9c746597a03f42102afc230c2d355b1a577682b07bc2646041b5d0177af0f98395a46018da699b6da210344a3c38cd59afcba3edcebe143e025574594b001700dec41e59409bdbd0f2a0921039a060badbeb24bee49eb2063f616c0f0f0765d4ca646b20a88ce828f259fcdb955670300cd50b27552210216c23b2ea8e4f11c3f9e22711addb1d16a93964796913830856b568cc3ea21d3210275562901dd8faae20de0a4166362a4f82188db77dbed4ca887422ea1ec185f1421034db69f2112f4fb1bb6141bf6e2bd6631f0484d0bd95b16767902c9fe219d4a6f5368ae"); + + public LegacyErpFederation( + List members, + Instant creationTime, + long creationBlockNumber, + NetworkParameters btcParams, + List erpPubKeys, + long activationDelay, + ActivationConfig.ForBlock activations) { + + super(members, creationTime, creationBlockNumber, btcParams, erpPubKeys, activationDelay, activations); + + validateRedeemScript(); + } + + @Override + public Script getRedeemScript() { + if (!activations.isActive(ConsensusRule.RSKIP284) && + btcParams.getId().equals(NetworkParameters.ID_TESTNET)) { + logger.debug("[getRedeemScript] Returning hardcoded redeem script"); + return new Script(LEGACY_ERP_TESTNET_REDEEM_SCRIPT_BYTES); + } + + if (redeemScript == null) { + logger.debug("[getRedeemScript] Creating the redeem script from the keys"); + redeemScript = activations.isActive(ConsensusRule.RSKIP293) ? + ErpFederationRedeemScriptParser.createErpRedeemScript( + ScriptBuilder.createRedeemScript(getNumberOfSignaturesRequired(), getBtcPublicKeys()), + ScriptBuilder.createRedeemScript(erpPubKeys.size() / 2 + 1, erpPubKeys), + activationDelay + ) : + ErpFederationRedeemScriptParser.createErpRedeemScriptDeprecated( + ScriptBuilder.createRedeemScript(getNumberOfSignaturesRequired(), getBtcPublicKeys()), + ScriptBuilder.createRedeemScript(erpPubKeys.size() / 2 + 1, erpPubKeys), + activationDelay + ); + } + + return redeemScript; + } + + @Override + public Script getStandardRedeemScript() { + if (standardRedeemScript == null) { + standardRedeemScript = ErpFederationRedeemScriptParser.extractStandardRedeemScript( + getRedeemScript().getChunks() + ); + } + return standardRedeemScript; + } + + private void validateRedeemScript() { + Script redeemScript = this.getRedeemScript(); + + if (activations.isActive(ConsensusRule.RSKIP293) && + redeemScript.equals(new Script(LEGACY_ERP_TESTNET_REDEEM_SCRIPT_BYTES))) { + + String message = "Unable to create ERP Federation. The obtained redeem script matches the one hardcoded for testnet. " + + "This would cause bitcoinj-thin to identify it as invalid"; + logger.debug("[validateRedeemScript] {}", message); + throw new FederationCreationException(message, HARDCODED_LEGACY_ERP_TESTNET_REDEEM_SCRIPT); + } + + FederationUtils.validateScriptSize(redeemScript); + } +} + diff --git a/rskj-core/src/main/java/co/rsk/peg/P2shErpFederation.java b/rskj-core/src/main/java/co/rsk/peg/P2shErpFederation.java index 573fe02f903..b578ee4ee5f 100644 --- a/rskj-core/src/main/java/co/rsk/peg/P2shErpFederation.java +++ b/rskj-core/src/main/java/co/rsk/peg/P2shErpFederation.java @@ -7,6 +7,7 @@ import co.rsk.bitcoinj.script.ScriptBuilder; import java.time.Instant; import java.util.List; + import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,6 +25,8 @@ public P2shErpFederation( ActivationConfig.ForBlock activations ) { super(members, creationTime, creationBlockNumber, btcParams, erpPubKeys, activationDelay, activations); + + validateRedeemScriptSize(); } @Override @@ -49,4 +52,9 @@ public final Script getStandardRedeemScript() { } return standardRedeemScript; } + + private void validateRedeemScriptSize() { + Script redeemScript = this.getRedeemScript(); + FederationUtils.validateScriptSize(redeemScript); + } } diff --git a/rskj-core/src/main/java/co/rsk/peg/PendingFederation.java b/rskj-core/src/main/java/co/rsk/peg/PendingFederation.java index 33e388bed43..c0ddd49878e 100644 --- a/rskj-core/src/main/java/co/rsk/peg/PendingFederation.java +++ b/rskj-core/src/main/java/co/rsk/peg/PendingFederation.java @@ -119,7 +119,7 @@ public Federation buildFederation( if (activations.isActive(ConsensusRule.RSKIP201)) { logger.info("[buildFederation] Going to create an ERP Federation"); - return new ErpFederation( + return new LegacyErpFederation( members, creationTime, blockNumber, @@ -130,7 +130,7 @@ public Federation buildFederation( ); } - return new Federation( + return new StandardMultisigFederation( members, creationTime, blockNumber, diff --git a/rskj-core/src/main/java/co/rsk/peg/StandardMultisigFederation.java b/rskj-core/src/main/java/co/rsk/peg/StandardMultisigFederation.java new file mode 100644 index 00000000000..50965e8e9e2 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/StandardMultisigFederation.java @@ -0,0 +1,60 @@ +/* + * This file is part of RskJ + * Copyright (C) 2017 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.peg; + +import co.rsk.bitcoinj.core.NetworkParameters; +import co.rsk.bitcoinj.script.Script; +import co.rsk.bitcoinj.script.ScriptBuilder; + +import java.time.Instant; +import java.util.List; + +/** + * Immutable representation of an RSK Federation in the context of + * a specific BTC network. + * + */ + +public class StandardMultisigFederation extends Federation { + + public StandardMultisigFederation( + List members, + Instant creationTime, + long creationBlockNumber, + NetworkParameters btcParams) { + + super(members, creationTime, creationBlockNumber, btcParams); + + validateRedeemScriptSize(); + } + + @Override + public Script getRedeemScript() { + if (redeemScript == null) { + redeemScript = ScriptBuilder.createRedeemScript(getNumberOfSignaturesRequired(), getBtcPublicKeys()); + } + + return redeemScript; + } + + private void validateRedeemScriptSize() { + Script redeemScript = this.getRedeemScript(); + FederationUtils.validateScriptSize(redeemScript); + } +} diff --git a/rskj-core/src/main/java/co/rsk/peg/bitcoin/Standardness.java b/rskj-core/src/main/java/co/rsk/peg/bitcoin/Standardness.java new file mode 100644 index 00000000000..b4edf404b28 --- /dev/null +++ b/rskj-core/src/main/java/co/rsk/peg/bitcoin/Standardness.java @@ -0,0 +1,7 @@ +package co.rsk.peg.bitcoin; + +public class Standardness { + public static final int MAX_SCRIPT_ELEMENT_SIZE = 520; + private Standardness() { + } +} diff --git a/rskj-core/src/main/java/co/rsk/rpc/ExecutionBlockRetriever.java b/rskj-core/src/main/java/co/rsk/rpc/ExecutionBlockRetriever.java index e9cfce28517..8cf8cd8a715 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/ExecutionBlockRetriever.java +++ b/rskj-core/src/main/java/co/rsk/rpc/ExecutionBlockRetriever.java @@ -62,8 +62,7 @@ public ExecutionBlockRetriever(Blockchain blockchain, BlockToMineBuilder builder } public Result retrieveExecutionBlock(String bnOrId) { - - if(BlockTag.EARLIEST.tagEquals(bnOrId)) { + if (BlockTag.EARLIEST.tagEquals(bnOrId)) { return Result.ofBlock(blockchain.getBlockByNumber(0)); } diff --git a/rskj-core/src/main/java/co/rsk/rpc/Web3EthModule.java b/rskj-core/src/main/java/co/rsk/rpc/Web3EthModule.java index bc320508e1e..f4e7df6e256 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/Web3EthModule.java +++ b/rskj-core/src/main/java/co/rsk/rpc/Web3EthModule.java @@ -19,26 +19,35 @@ package co.rsk.rpc; import co.rsk.rpc.modules.eth.EthModule; -import org.ethereum.rpc.CallArguments; -import org.ethereum.rpc.FilterRequest; import org.ethereum.rpc.dto.BlockResultDTO; import org.ethereum.rpc.dto.CompilationResultDTO; import org.ethereum.rpc.dto.TransactionReceiptDTO; import org.ethereum.rpc.dto.TransactionResultDTO; +import org.ethereum.rpc.parameters.BlockHashParam; +import org.ethereum.rpc.parameters.FilterRequestParam; +import org.ethereum.rpc.parameters.BlockIdentifierParam; +import org.ethereum.rpc.parameters.BlockRefParam; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.rpc.parameters.HexAddressParam; +import org.ethereum.rpc.parameters.HexDataParam; +import org.ethereum.rpc.parameters.HexIndexParam; +import org.ethereum.rpc.parameters.HexNumberParam; +import org.ethereum.rpc.parameters.TxHashParam; import java.math.BigInteger; import java.util.Map; +@SuppressWarnings({"java:S100", "java:S112"}) public interface Web3EthModule { default String[] eth_accounts() { return getEthModule().accounts(); } - default String eth_sign(String addr, String data) { - return getEthModule().sign(addr, data); + default String eth_sign(HexAddressParam addr, HexDataParam data) { + return getEthModule().sign(addr.getAddress().toHexString(), data.getAsHexString()); } - default String eth_call(CallArguments args, String bnOrId) { + default String eth_call(CallArgumentsParam args, BlockIdentifierParam bnOrId) { return getEthModule().call(args, bnOrId); } @@ -50,8 +59,8 @@ default String eth_chainId() { return getEthModule().chainId(); } - String eth_estimateGas(CallArguments args, String bnOrId); - String eth_estimateGas(CallArguments args); + String eth_estimateGas(CallArgumentsParam args); + String eth_estimateGas(CallArgumentsParam args, BlockIdentifierParam bnOrId); EthModule getEthModule(); @@ -69,59 +78,53 @@ default String eth_chainId() { String eth_blockNumber(); - String eth_call(CallArguments args, Map blockRef) throws Exception; // NOSONAR + String eth_call(CallArgumentsParam args, Map blockRef) throws Exception; // NOSONAR - String eth_getBalance(String address, String block) throws Exception; + String eth_getBalance(HexAddressParam address, BlockRefParam blockRefParam) throws Exception; - String eth_getBalance(String address) throws Exception; + String eth_getBalance(HexAddressParam address) throws Exception; - String eth_getBalance(String address, Map blockRef) throws Exception; // NOSONAR + String eth_getStorageAt(HexAddressParam address, HexNumberParam storageIdx, BlockRefParam blockRefParam) throws Exception; - String eth_getStorageAt(String address, String storageIdx, Map blockRef) throws Exception; // NOSONAR + String eth_getTransactionCount(HexAddressParam address, BlockRefParam blockRefParam) throws Exception; - String eth_getStorageAt(String address, String storageIdx, String blockId) throws Exception; + String eth_getBlockTransactionCountByHash(BlockHashParam blockHash)throws Exception; - String eth_getTransactionCount(String address, Map blockRef) throws Exception; // NOSONAR + String eth_getBlockTransactionCountByNumber(BlockIdentifierParam bnOrId)throws Exception; - String eth_getTransactionCount(String address, String blockId) throws Exception ; + String eth_getUncleCountByBlockHash(BlockHashParam blockHash)throws Exception; - String eth_getBlockTransactionCountByHash(String blockHash)throws Exception; + String eth_getUncleCountByBlockNumber(BlockIdentifierParam bnOrId)throws Exception; - String eth_getBlockTransactionCountByNumber(String bnOrId)throws Exception; + String eth_getCode(HexAddressParam address, BlockRefParam blockRefParam) throws Exception; - String eth_getUncleCountByBlockHash(String blockHash)throws Exception; - - String eth_getUncleCountByBlockNumber(String bnOrId)throws Exception; - - default String eth_getCode(String address, String blockId) { + default String getCode(HexAddressParam address, String blockId) { return getEthModule().getCode(address, blockId); } - String eth_getCode(String address, Map blockRef) throws Exception; // NOSONAR - - default String eth_sendRawTransaction(String rawData) { + default String eth_sendRawTransaction(HexDataParam rawData) { return getEthModule().sendRawTransaction(rawData); } - default String eth_sendTransaction(CallArguments args) { + default String eth_sendTransaction(CallArgumentsParam args) { return getEthModule().sendTransaction(args); } - BlockResultDTO eth_getBlockByHash(String blockHash, Boolean fullTransactionObjects) throws Exception; + BlockResultDTO eth_getBlockByHash(BlockHashParam blockHash, Boolean fullTransactionObjects) throws Exception; - BlockResultDTO eth_getBlockByNumber(String bnOrId, Boolean fullTransactionObjects) throws Exception; + BlockResultDTO eth_getBlockByNumber(BlockIdentifierParam bnOrId, Boolean fullTransactionObjects) throws Exception; - TransactionResultDTO eth_getTransactionByHash(String transactionHash) throws Exception; + TransactionResultDTO eth_getTransactionByHash(TxHashParam transactionHash) throws Exception; - TransactionResultDTO eth_getTransactionByBlockHashAndIndex(String blockHash, String index) throws Exception; + TransactionResultDTO eth_getTransactionByBlockHashAndIndex(BlockHashParam blockHash, HexIndexParam index) throws Exception; - TransactionResultDTO eth_getTransactionByBlockNumberAndIndex(String bnOrId, String index) throws Exception; + TransactionResultDTO eth_getTransactionByBlockNumberAndIndex(BlockIdentifierParam bnOrId, HexIndexParam index) throws Exception; - TransactionReceiptDTO eth_getTransactionReceipt(String transactionHash) throws Exception; + TransactionReceiptDTO eth_getTransactionReceipt(TxHashParam transactionHash) throws Exception; - BlockResultDTO eth_getUncleByBlockHashAndIndex(String blockHash, String uncleIdx) throws Exception; + BlockResultDTO eth_getUncleByBlockHashAndIndex(BlockHashParam blockHash, HexIndexParam uncleIdx) throws Exception; - BlockResultDTO eth_getUncleByBlockNumberAndIndex(String blockId, String uncleIdx) throws Exception; + BlockResultDTO eth_getUncleByBlockNumberAndIndex(BlockIdentifierParam blockId, HexIndexParam uncleIdx) throws Exception; String[] eth_getCompilers(); @@ -131,19 +134,19 @@ default String eth_sendTransaction(CallArguments args) { Map eth_compileSolidity(String contract); - String eth_newFilter(FilterRequest fr) throws Exception; + String eth_newFilter(FilterRequestParam fr) throws Exception; String eth_newBlockFilter(); String eth_newPendingTransactionFilter(); - boolean eth_uninstallFilter(String id); + boolean eth_uninstallFilter(HexIndexParam id); - Object[] eth_getFilterChanges(String id); + Object[] eth_getFilterChanges(HexIndexParam id); - Object[] eth_getFilterLogs(String id); + Object[] eth_getFilterLogs(HexIndexParam id); - Object[] eth_getLogs(FilterRequest fr) throws Exception; + Object[] eth_getLogs(FilterRequestParam fr) throws Exception; BigInteger eth_netHashrate(); diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModule.java b/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModule.java index 3f26ebb2a62..4c6c02f1c2f 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModule.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModule.java @@ -39,6 +39,10 @@ import org.ethereum.rpc.CallArguments; import org.ethereum.rpc.converters.CallArgumentsToByteArray; import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.BlockIdentifierParam; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.rpc.parameters.HexAddressParam; +import org.ethereum.rpc.parameters.HexDataParam; import org.ethereum.vm.GasCost; import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.program.ProgramResult; @@ -122,10 +126,11 @@ public Map bridgeState() throws IOException, BlockStoreException return state.stateToMap(); } - public String call(CallArguments args, String bnOrId) { + public String call(CallArgumentsParam argsParam, BlockIdentifierParam bnOrId) { String hReturn = null; + CallArguments args = argsParam.toCallArguments(); try { - ExecutionBlockRetriever.Result result = executionBlockRetriever.retrieveExecutionBlock(bnOrId); + ExecutionBlockRetriever.Result result = executionBlockRetriever.retrieveExecutionBlock(bnOrId.getIdentifier()); Block block = result.getBlock(); Trie finalState = result.getFinalState(); ProgramResult res; @@ -152,8 +157,8 @@ public String call(CallArguments args, String bnOrId) { } } - public String estimateGas(CallArguments args, @Nonnull String bnOrId) { - ExecutionBlockRetriever.Result result = executionBlockRetriever.retrieveExecutionBlock(bnOrId); + public String estimateGas(CallArgumentsParam args, @Nonnull BlockIdentifierParam bnOrId) { + ExecutionBlockRetriever.Result result = executionBlockRetriever.retrieveExecutionBlock(bnOrId.getIdentifier()); Block block = result.getBlock(); Trie finalState = result.getFinalState(); RepositorySnapshot snapshot = finalState == null @@ -162,7 +167,7 @@ public String estimateGas(CallArguments args, @Nonnull String bnOrId) { String estimation = null; try { - CallArgumentsToByteArray hexArgs = new CallArgumentsToByteArray(args); + CallArgumentsToByteArray hexArgs = new CallArgumentsToByteArray(args.toCallArguments()); TransactionExecutor executor = reversibleTransactionExecutor.estimateGas( block, @@ -203,12 +208,12 @@ protected String internalEstimateGas(ProgramResult reversibleExecutionResult) { } @Override - public String sendTransaction(CallArguments args) { + public String sendTransaction(CallArgumentsParam args) { return ethModuleTransaction.sendTransaction(args); } @Override - public String sendRawTransaction(String rawData) { + public String sendRawTransaction(HexDataParam rawData) { return ethModuleTransaction.sendRawTransaction(rawData); } @@ -221,14 +226,14 @@ public String chainId() { return HexUtils.toJsonHex(new byte[]{chainId}); } - public String getCode(String address, String blockId) { + public String getCode(HexAddressParam address, String blockId) { if (blockId == null) { throw new NullPointerException(); } String s = null; + RskAddress addr = address.getAddress(); try { - RskAddress addr = new RskAddress(address); AccountInformationProvider accountInformationProvider = getAccountInformationProvider(blockId); @@ -246,7 +251,7 @@ public String getCode(String address, String blockId) { return s; } finally { if (LOGGER.isDebugEnabled()) { - LOGGER.debug("eth_getCode({}, {}): {}", address, blockId, s); + LOGGER.debug("eth_getCode({}, {}): {}", addr.toHexString(), blockId, s); } } } diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransaction.java b/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransaction.java index f3c1ea1300b..d9357b05c19 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransaction.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransaction.java @@ -18,10 +18,11 @@ package co.rsk.rpc.modules.eth; -import org.ethereum.rpc.CallArguments; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.rpc.parameters.HexDataParam; public interface EthModuleTransaction { - String sendTransaction(CallArguments args); + String sendTransaction(CallArgumentsParam args); - String sendRawTransaction(String rawData); + String sendRawTransaction(HexDataParam rawData); } diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransactionBase.java b/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransactionBase.java index 6cc64af4c22..f2b7a125a86 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransactionBase.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransactionBase.java @@ -30,6 +30,8 @@ import org.ethereum.core.TransactionPoolAddResult; import org.ethereum.rpc.CallArguments; import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.rpc.parameters.HexDataParam; import org.ethereum.util.TransactionArgumentsUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,7 +39,6 @@ import co.rsk.core.RskAddress; import co.rsk.core.Wallet; import co.rsk.net.TransactionGateway; -import co.rsk.util.HexUtils; public class EthModuleTransactionBase implements EthModuleTransaction { @@ -56,7 +57,12 @@ public EthModuleTransactionBase(Constants constants, Wallet wallet, TransactionP } @Override - public synchronized String sendTransaction(CallArguments args) { + public synchronized String sendTransaction(CallArgumentsParam argsParam) { + CallArguments args = argsParam.toCallArguments(); + + if(args.getFrom() == null) { + throw invalidParamError("from is null"); + } Account senderAccount = this.wallet.getAccount(new RskAddress(args.getFrom())); @@ -97,10 +103,10 @@ public synchronized String sendTransaction(CallArguments args) { } @Override - public String sendRawTransaction(String rawData) { + public String sendRawTransaction(HexDataParam rawData) { String s = null; try { - Transaction tx = new ImmutableTransaction(HexUtils.stringHexToByteArray(rawData)); + Transaction tx = new ImmutableTransaction(rawData.getRawDataBytes()); if (null == tx.getGasLimit() || null == tx.getGasPrice() || null == tx.getValue()) { throw invalidParamError("Missing parameter, gasPrice, gas or value"); diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransactionDisabled.java b/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransactionDisabled.java index 0f1bee0cad6..6b0313f6033 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransactionDisabled.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransactionDisabled.java @@ -21,7 +21,7 @@ import co.rsk.net.TransactionGateway; import org.ethereum.config.Constants; import org.ethereum.core.TransactionPool; -import org.ethereum.rpc.CallArguments; +import org.ethereum.rpc.parameters.CallArgumentsParam; import static org.ethereum.rpc.exception.RskJsonRpcRequestException.invalidParamError; @@ -36,7 +36,7 @@ public EthModuleTransactionDisabled(Constants constants, TransactionPool transac } @Override - public String sendTransaction(CallArguments args) { // lgtm [java/non-sync-override] + public synchronized String sendTransaction(CallArgumentsParam args) { // lgtm [java/non-sync-override] LOGGER.debug("eth_sendTransaction({}): {}", args, null); throw invalidParamError("Local wallet is disabled in this node"); } diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransactionInstant.java b/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransactionInstant.java index ee879308874..f5b08ae5dfa 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransactionInstant.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleTransactionInstant.java @@ -27,8 +27,9 @@ import org.ethereum.core.Blockchain; import org.ethereum.core.TransactionPool; import org.ethereum.db.TransactionInfo; -import org.ethereum.rpc.CallArguments; import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.rpc.parameters.HexDataParam; import org.ethereum.vm.program.ProgramResult; import co.rsk.core.Wallet; @@ -64,7 +65,7 @@ public EthModuleTransactionInstant( } @Override - public synchronized String sendTransaction(CallArguments args) { + public synchronized String sendTransaction(CallArgumentsParam args) { try { this.blockExecutor.setRegisterProgramResults(true); @@ -80,7 +81,7 @@ public synchronized String sendTransaction(CallArguments args) { } @Override - public String sendRawTransaction(String rawData) { + public String sendRawTransaction(HexDataParam rawData) { try { this.blockExecutor.setRegisterProgramResults(true); diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleWalletEnabled.java b/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleWalletEnabled.java index 2341857377c..7ac52b5e3a1 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleWalletEnabled.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/eth/EthModuleWalletEnabled.java @@ -23,6 +23,7 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; +import co.rsk.core.RskAddress; import org.bouncycastle.util.BigIntegers; import org.ethereum.core.Account; import org.ethereum.crypto.ECKey; @@ -32,7 +33,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import co.rsk.core.RskAddress; import co.rsk.core.Wallet; import co.rsk.util.HexUtils; @@ -55,7 +55,9 @@ public String sign(String addr, String data) { throw invalidParamError("Account not found"); } - return s = this.sign(data, account.getEcKey()); + s = this.sign(data, account.getEcKey()); + + return s; } finally { LOGGER.debug("eth_sign({}, {}): {}", addr, data, s); } diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModule.java b/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModule.java index 62b5cbd8f4d..af1102c80f7 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModule.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModule.java @@ -18,24 +18,27 @@ package co.rsk.rpc.modules.personal; -import org.ethereum.rpc.CallArguments; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.rpc.parameters.HexAddressParam; +import org.ethereum.rpc.parameters.HexDurationParam; +import org.ethereum.rpc.parameters.HexKeyParam; public interface PersonalModule { - String dumpRawKey(String address) throws Exception; + String dumpRawKey(HexAddressParam address) throws Exception; - String importRawKey(String key, String passphrase); + String importRawKey(HexKeyParam key, String passphrase); void init(); String[] listAccounts(); - boolean lockAccount(String address); + boolean lockAccount(HexAddressParam address); String newAccountWithSeed(String seed); String newAccount(String passphrase); - String sendTransaction(CallArguments args, String passphrase) throws Exception; + String sendTransaction(CallArgumentsParam args, String passphrase) throws Exception; - boolean unlockAccount(String address, String passphrase, String duration); + boolean unlockAccount(HexAddressParam address, String passphrase, HexDurationParam duration); } diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModuleWalletDisabled.java b/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModuleWalletDisabled.java index 0379c0fe5c1..616b912b2d4 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModuleWalletDisabled.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModuleWalletDisabled.java @@ -18,8 +18,11 @@ package co.rsk.rpc.modules.personal; -import org.ethereum.rpc.CallArguments; import org.ethereum.rpc.exception.DisabledWalletException; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.rpc.parameters.HexAddressParam; +import org.ethereum.rpc.parameters.HexDurationParam; +import org.ethereum.rpc.parameters.HexKeyParam; public class PersonalModuleWalletDisabled implements PersonalModule { @Override @@ -45,27 +48,27 @@ public String[] listAccounts() { } @Override - public String importRawKey(String key, String passphrase) { + public String importRawKey(HexKeyParam key, String passphrase) { throw new DisabledWalletException(); } @Override - public String sendTransaction(CallArguments args, String passphrase) { + public String sendTransaction(CallArgumentsParam args, String passphrase) { throw new DisabledWalletException(); } @Override - public boolean unlockAccount(String address, String passphrase, String duration) { + public boolean unlockAccount(HexAddressParam address, String passphrase, HexDurationParam duration) { throw new DisabledWalletException(); } @Override - public boolean lockAccount(String address) { + public boolean lockAccount(HexAddressParam address) { throw new DisabledWalletException(); } @Override - public String dumpRawKey(String address) { + public String dumpRawKey(HexAddressParam address) { throw new DisabledWalletException(); } } \ No newline at end of file diff --git a/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModuleWalletEnabled.java b/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModuleWalletEnabled.java index 141319d7c6c..eb294b1f43e 100644 --- a/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModuleWalletEnabled.java +++ b/rskj-core/src/main/java/co/rsk/rpc/modules/personal/PersonalModuleWalletEnabled.java @@ -29,12 +29,17 @@ import org.ethereum.facade.Ethereum; import org.ethereum.rpc.CallArguments; import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.rpc.parameters.HexAddressParam; +import org.ethereum.rpc.parameters.HexDurationParam; +import org.ethereum.rpc.parameters.HexKeyParam; import org.ethereum.util.ByteUtil; import org.ethereum.util.TransactionArgumentsUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; +import java.util.Optional; import static org.ethereum.rpc.exception.RskJsonRpcRequestException.invalidParamError; @@ -121,8 +126,13 @@ public String[] listAccounts() { } @Override - public String importRawKey(String key, String passphrase) { + public String importRawKey(HexKeyParam keyParam, String passphrase) { String s = null; + String key = Optional.ofNullable(keyParam).map(HexKeyParam::getHexKey) + .orElseThrow( + () -> RskJsonRpcRequestException.invalidParamError("Key cannot be null.") + ); + try { if (key != null && key.startsWith("0x")) { key = key.substring(2); @@ -136,8 +146,9 @@ public String importRawKey(String key, String passphrase) { } @Override - public String sendTransaction(CallArguments args, String passphrase) throws Exception { + public String sendTransaction(CallArgumentsParam argsParam, String passphrase) throws Exception { String s = null; + CallArguments args = argsParam.toCallArguments(); try { return s = sendTransaction(args, getAccount(args.getFrom(), passphrase)); } finally { @@ -146,15 +157,15 @@ public String sendTransaction(CallArguments args, String passphrase) throws Exce } @Override - public boolean unlockAccount(String address, String passphrase, String duration) { - return unlockAccount(new RskAddress(address), passphrase, duration); + public boolean unlockAccount(HexAddressParam address, String passphrase, HexDurationParam duration) { + return unlockAccount(address.getAddress(), passphrase, duration); } - private boolean unlockAccount(RskAddress addr, String passphrase, String duration) { + private boolean unlockAccount(RskAddress addr, String passphrase, HexDurationParam duration) { long dur = (long) 1000 * 60 * 30; - if (duration != null && duration.length() > 0) { + if (duration != null && duration.getDuration() != null) { try { - dur = convertFromJsonHexToLong(duration); + dur = duration.getDuration(); } catch (Exception e) { throw invalidParamError("Can't parse duration param", e); } @@ -164,15 +175,15 @@ private boolean unlockAccount(RskAddress addr, String passphrase, String duratio } @Override - public boolean lockAccount(String address) { - return this.wallet.lockAccount(new RskAddress(address)); + public boolean lockAccount(HexAddressParam address) { + return this.wallet.lockAccount(address.getAddress()); } @Override - public String dumpRawKey(String address) throws Exception { + public String dumpRawKey(HexAddressParam address) throws Exception { String s = null; try { - Account account = wallet.getAccount(new RskAddress(convertFromJsonHexToHex(address))); + Account account = wallet.getAccount(address.getAddress()); if (account == null) { throw new Exception("Address private key is locked or could not be found in this node"); } @@ -209,19 +220,4 @@ private String sendTransaction(CallArguments args, Account senderAccount) throws } return tx.getHash().toJsonString(); } - - private String convertFromJsonHexToHex(String x) throws Exception { - if (!x.startsWith("0x")) { - throw new Exception("Incorrect hex syntax"); - } - - return x.substring(2); - } - - private long convertFromJsonHexToLong(String x) throws Exception { - if (!x.startsWith("0x")) { - throw new Exception("Incorrect hex syntax"); - } - return Long.parseLong(x.substring(2), 16); - } } diff --git a/rskj-core/src/main/java/co/rsk/util/HexUtils.java b/rskj-core/src/main/java/co/rsk/util/HexUtils.java index 3007001e23d..f04aae64aef 100644 --- a/rskj-core/src/main/java/co/rsk/util/HexUtils.java +++ b/rskj-core/src/main/java/co/rsk/util/HexUtils.java @@ -22,12 +22,12 @@ import org.bouncycastle.util.encoders.Hex; import org.ethereum.util.ByteUtil; -import static org.ethereum.rpc.exception.RskJsonRpcRequestException.invalidParamError; - import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.util.regex.Pattern; +import static org.ethereum.rpc.exception.RskJsonRpcRequestException.invalidParamError; + /** * Hex utils */ @@ -362,4 +362,14 @@ public static int jsonHexToInt(final String param) { return Integer.parseInt(preResult, 16); } + public static int jsonHexToIntOptionalPrefix(final String param) { + if (!hasHexPrefix(param) && !HexUtils.isHex(param)) { + throw invalidParamError(INCORRECT_HEX_SYNTAX); + } + + String preResult = removeHexPrefix(param); + + return Integer.parseInt(preResult, 16); + } + } diff --git a/rskj-core/src/main/java/org/ethereum/crypto/HashUtil.java b/rskj-core/src/main/java/org/ethereum/crypto/HashUtil.java index 59bed4e8cb6..aad79a2df3c 100644 --- a/rskj-core/src/main/java/org/ethereum/crypto/HashUtil.java +++ b/rskj-core/src/main/java/org/ethereum/crypto/HashUtil.java @@ -53,7 +53,9 @@ public static MessageDigest makeMessageDigest() { * @return - sha256 hash of the data */ public static byte[] sha256(byte[] input) { - return sha256digest.digest(input); + synchronized (sha256digest) { + return sha256digest.digest(input); + } } public static byte[] keccak256(byte[] input) { diff --git a/rskj-core/src/main/java/org/ethereum/rpc/Web3.java b/rskj-core/src/main/java/org/ethereum/rpc/Web3.java index a27803107e9..8b16c98019b 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/Web3.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/Web3.java @@ -30,6 +30,10 @@ import co.rsk.rpc.Web3TxPoolModule; import co.rsk.scoring.PeerScoringInformation; import co.rsk.scoring.PeerScoringReputationSummary; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.rpc.parameters.HexAddressParam; +import org.ethereum.rpc.parameters.HexDurationParam; +import org.ethereum.rpc.parameters.HexKeyParam; @java.lang.SuppressWarnings("squid:S100") public interface Web3 extends InternalService, Web3TxPoolModule, Web3EthModule, Web3EvmModule, Web3MnrModule, Web3DebugModule, Web3TraceModule, Web3RskModule { @@ -54,11 +58,11 @@ public interface Web3 extends InternalService, Web3TxPoolModule, Web3EthModule, String personal_newAccountWithSeed(String seed); String personal_newAccount(String passphrase); String[] personal_listAccounts(); - String personal_importRawKey(String key, String passphrase); - String personal_sendTransaction(CallArguments transactionArgs, String passphrase) throws Exception; - boolean personal_unlockAccount(String key, String passphrase, String duration); - boolean personal_lockAccount(String key); - String personal_dumpRawKey(String address) throws Exception; + String personal_importRawKey(HexKeyParam key, String passphrase); + String personal_sendTransaction(CallArgumentsParam transactionArgs, String passphrase) throws Exception; + boolean personal_unlockAccount(HexAddressParam key, String passphrase, HexDurationParam duration); + boolean personal_lockAccount(HexAddressParam key); + String personal_dumpRawKey(HexAddressParam address) throws Exception; void sco_banAddress(String address); void sco_unbanAddress(String address); diff --git a/rskj-core/src/main/java/org/ethereum/rpc/Web3Impl.java b/rskj-core/src/main/java/org/ethereum/rpc/Web3Impl.java index e91578400b4..1c224f659d3 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/Web3Impl.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/Web3Impl.java @@ -43,7 +43,6 @@ import co.rsk.scoring.*; import co.rsk.util.HexUtils; import com.google.common.annotations.VisibleForTesting; -import org.apache.commons.lang3.StringUtils; import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.*; import org.ethereum.core.genesis.BlockTag; @@ -61,11 +60,14 @@ import org.ethereum.rpc.dto.CompilationResultDTO; import org.ethereum.rpc.dto.TransactionReceiptDTO; import org.ethereum.rpc.dto.TransactionResultDTO; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.*; import org.ethereum.util.BuildInfo; import org.ethereum.vm.DataWord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nullable; import java.math.BigInteger; import java.net.InetAddress; import java.net.UnknownHostException; @@ -79,6 +81,7 @@ import static java.lang.Math.max; import static org.ethereum.rpc.exception.RskJsonRpcRequestException.*; +@SuppressWarnings("java:S100") public class Web3Impl implements Web3 { private static final Logger logger = LoggerFactory.getLogger("web3"); @@ -398,17 +401,33 @@ public String eth_blockNumber() { } @Override - public String eth_call(CallArguments args, Map inputs) { - return invokeByBlockRef(inputs, blockNumber -> this.eth_call(args, blockNumber)); + public String eth_call(CallArgumentsParam args, Map inputs) { + return invokeByBlockRef(inputs, blockNumber -> this.eth_call(args, new BlockIdentifierParam(blockNumber))); } @Override - public String eth_getCode(String address, Map inputs) { - return invokeByBlockRef(inputs, blockNumber -> this.eth_getCode(address, blockNumber)); + public String eth_getCode(HexAddressParam address, BlockRefParam blockRefParam) { + if (blockRefParam.getIdentifier() != null) { + return this.getCode(address, blockRefParam.getIdentifier()); + } else { + return this.eth_getCode(address, blockRefParam.getInputs()); + } + } + + private String eth_getCode(HexAddressParam address, Map inputs) { + return invokeByBlockRef(inputs, blockNumber -> this.getCode(address, blockNumber)); } @Override - public String eth_getBalance(String address, String block) { + public String eth_getBalance(HexAddressParam address, BlockRefParam blockRefParam) { + if (blockRefParam.getIdentifier() != null) { + return this.eth_getBalance(address, blockRefParam.getIdentifier()); + } else { + return this.eth_getBalance(address, blockRefParam.getInputs()); + } + } + + private String eth_getBalance(HexAddressParam address, String block) { /* HEX String - an integer block number * String "earliest" for the earliest/genesis block * String "latest" - for the latest mined block @@ -417,14 +436,14 @@ public String eth_getBalance(String address, String block) { AccountInformationProvider accountInformationProvider = web3InformationRetriever.getInformationProvider(block); - RskAddress addr = new RskAddress(address); + RskAddress addr = address.getAddress(); Coin balance = accountInformationProvider.getBalance(addr); return toQuantityJsonHex(balance.asBigInteger()); } - @Override - public String eth_getBalance(String address, Map inputs) { + + private String eth_getBalance(HexAddressParam address, Map inputs) { return invokeByBlockRef(inputs, blockNumber -> this.eth_getBalance(address, blockNumber)); } @@ -438,27 +457,34 @@ private boolean isInMainChain(Block block) { } @Override - public String eth_getBalance(String address) { + public String eth_getBalance(HexAddressParam address) { return eth_getBalance(address, "latest"); } @Override - public String eth_getStorageAt(String address, String storageIdx, Map blockRef) { + public String eth_getStorageAt(HexAddressParam address, HexNumberParam storageIdx, BlockRefParam blockRefParam) { + if (blockRefParam.getIdentifier() != null) { + return this.eth_getStorageAt(address, storageIdx, blockRefParam.getIdentifier()); + } else { + return this.eth_getStorageAt(address, storageIdx, blockRefParam.getInputs()); + } + } + + private String eth_getStorageAt(HexAddressParam address, HexNumberParam storageIdx, Map blockRef) { return invokeByBlockRef(blockRef, blockNumber -> this.eth_getStorageAt(address, storageIdx, blockNumber)); } - @Override - public String eth_getStorageAt(String address, String storageIdx, String blockId) { + private String eth_getStorageAt(HexAddressParam address, HexNumberParam storageIdx, String blockId) { String s = null; try { - RskAddress addr = new RskAddress(address); + RskAddress addr = address.getAddress(); AccountInformationProvider accountInformationProvider = web3InformationRetriever.getInformationProvider(blockId); DataWord sv = accountInformationProvider - .getStorageValue(addr, DataWord.valueOf(HexUtils.strHexOrStrNumberToByteArray(storageIdx))); + .getStorageValue(addr, DataWord.valueOf(HexUtils.strHexOrStrNumberToByteArray(storageIdx.getHexNumber()))); if (sv == null) { s = "0x0"; @@ -475,7 +501,15 @@ public String eth_getStorageAt(String address, String storageIdx, String blockId } @Override - public String eth_getTransactionCount(String address, Map inputs) { + public String eth_getTransactionCount(HexAddressParam address, BlockRefParam blockRefParam) { + if (blockRefParam.getIdentifier() != null) { + return this.eth_getTransactionCount(address, blockRefParam.getIdentifier()); + } else { + return this.eth_getTransactionCount(address, blockRefParam.getInputs()); + } + } + + private String eth_getTransactionCount(HexAddressParam address, Map inputs) { return invokeByBlockRef(inputs, blockNumber -> this.eth_getTransactionCount(address, blockNumber)); } @@ -509,11 +543,10 @@ private String toInvokeByBlockHash(String blockHash, boolean requireCanonical, F return toInvokeByBlockNumber.apply(toQuantityJsonHex(block.getNumber())); } - @Override - public String eth_getTransactionCount(String address, String blockId) { + private String eth_getTransactionCount(HexAddressParam address, String blockId) { String s = null; try { - RskAddress addr = new RskAddress(address); + RskAddress addr = address.getAddress(); AccountInformationProvider accountInformationProvider = web3InformationRetriever .getInformationProvider(blockId); BigInteger nonce = accountInformationProvider.getNonce(addr); @@ -537,10 +570,10 @@ public Block getBlockByJSonHash(String blockHash) { } @Override - public String eth_getBlockTransactionCountByHash(String blockHash) { + public String eth_getBlockTransactionCountByHash(BlockHashParam blockHash) { String s = null; try { - Block b = getBlockByJSonHash(blockHash); + Block b = blockchain.getBlockByHash(blockHash.getHash().getBytes()); if (b == null) { return null; @@ -575,11 +608,11 @@ public static Block getBlockByNumberOrStr(String bnOrId, Blockchain blockchain) } @Override - public String eth_getBlockTransactionCountByNumber(String bnOrId) { + public String eth_getBlockTransactionCountByNumber(BlockIdentifierParam bnOrId) { String s = null; try { - List txs = web3InformationRetriever.getTransactions(bnOrId); + List txs = web3InformationRetriever.getTransactions(bnOrId.getIdentifier()); s = toQuantityJsonHex(txs.size()); return s; @@ -591,7 +624,8 @@ public String eth_getBlockTransactionCountByNumber(String bnOrId) { } @Override - public String eth_getUncleCountByBlockHash(String blockHash) { + public String eth_getUncleCountByBlockHash(BlockHashParam blockHashParam) { + String blockHash = blockHashParam.getHash().toString(); Block b = getBlockByJSonHash(blockHash); if (b == null) { throw blockNotFound(String.format("Block with hash %s not found", blockHash)); @@ -602,12 +636,13 @@ public String eth_getUncleCountByBlockHash(String blockHash) { } @Override - public String eth_getUncleCountByBlockNumber(String bnOrId) { - return web3InformationRetriever.getBlock(bnOrId) + public String eth_getUncleCountByBlockNumber(BlockIdentifierParam identifierParam) { + String bnorId = identifierParam.getIdentifier(); + return web3InformationRetriever.getBlock(bnorId) .map(Block::getUncleList) .map(List::size) .map(HexUtils::toQuantityJsonHex) - .orElseThrow(() -> blockNotFound(String.format("Block %s not found", bnOrId))); + .orElseThrow(() -> blockNotFound(String.format("Block %s not found", bnorId))); } public BlockInformationResult getBlockInformationResult(BlockInformation blockInformation) { @@ -644,10 +679,14 @@ public BlockInformationResult[] eth_getBlocksByNumber(String number) { } @Override - public BlockResultDTO eth_getBlockByHash(String blockHash, Boolean fullTransactionObjects) { + public BlockResultDTO eth_getBlockByHash(BlockHashParam blockHash, Boolean fullTransactionObjects) { + if (blockHash == null) { + throw invalidParamError("blockHash is null"); + } + BlockResultDTO s = null; try { - Block b = getBlockByJSonHash(blockHash); + Block b = this.blockchain.getBlockByHash(blockHash.getHash().getBytes()); s = (b == null ? null : getBlockResult(b, fullTransactionObjects)); return s; } finally { @@ -658,8 +697,10 @@ public BlockResultDTO eth_getBlockByHash(String blockHash, Boolean fullTransacti } @Override - public BlockResultDTO eth_getBlockByNumber(String bnOrId, Boolean fullTransactionObjects) { + public BlockResultDTO eth_getBlockByNumber(BlockIdentifierParam identifierParam, Boolean fullTransactionObjects) { BlockResultDTO s = null; + String bnOrId = identifierParam.getIdentifier(); + try { s = web3InformationRetriever.getBlock(bnOrId) @@ -675,10 +716,10 @@ public BlockResultDTO eth_getBlockByNumber(String bnOrId, Boolean fullTransactio } @Override - public TransactionResultDTO eth_getTransactionByHash(String transactionHash) { + public TransactionResultDTO eth_getTransactionByHash(TxHashParam transactionHash) { TransactionResultDTO s = null; try { - Keccak256 txHash = new Keccak256(stringHexToByteArray(transactionHash)); + Keccak256 txHash = transactionHash.getHash(); Block block = null; TransactionInfo txInfo = this.receiptStore.getInMainChain(txHash.getBytes(), blockStore).orElse(null); @@ -713,16 +754,24 @@ public TransactionResultDTO eth_getTransactionByHash(String transactionHash) { } @Override - public TransactionResultDTO eth_getTransactionByBlockHashAndIndex(String blockHash, String index) { + public TransactionResultDTO eth_getTransactionByBlockHashAndIndex(BlockHashParam blockHash, HexIndexParam index) { + if (blockHash == null) { + throw invalidParamError("blockHash is null"); + } + + if (index == null) { + throw invalidParamError("index is null"); + } + TransactionResultDTO s = null; try { - Block b = getBlockByJSonHash(blockHash); + Block b = blockchain.getBlockByHash(blockHash.getHash().getBytes()); if (b == null) { return null; } - int idx = jsonHexToInt(index); + int idx = index.getIndex(); if (idx >= b.getTransactionsList().size()) { return null; @@ -739,15 +788,16 @@ public TransactionResultDTO eth_getTransactionByBlockHashAndIndex(String blockHa } @Override - public TransactionResultDTO eth_getTransactionByBlockNumberAndIndex(String bnOrId, String index) { + public TransactionResultDTO eth_getTransactionByBlockNumberAndIndex(BlockIdentifierParam identifierParam, HexIndexParam index) { TransactionResultDTO s = null; + String bnOrId = identifierParam.getIdentifier(); try { Optional block = web3InformationRetriever.getBlock(bnOrId); if (!block.isPresent()) { return null; } - int idx = jsonHexToInt(index); + int idx = index.getIndex(); List txs = web3InformationRetriever.getTransactions(bnOrId); if (idx >= txs.size()) { return null; @@ -763,10 +813,10 @@ public TransactionResultDTO eth_getTransactionByBlockNumberAndIndex(String bnOrI } @Override - public TransactionReceiptDTO eth_getTransactionReceipt(String transactionHash) { + public TransactionReceiptDTO eth_getTransactionReceipt(TxHashParam transactionHash) { logger.trace("eth_getTransactionReceipt({})", transactionHash); - byte[] hash = stringHexToByteArray(transactionHash); + byte[] hash = stringHexToByteArray(transactionHash.getHash().toHexString()); TransactionInfo txInfo = receiptStore.getInMainChain(hash, blockStore).orElse(null); if (txInfo == null) { @@ -782,17 +832,17 @@ public TransactionReceiptDTO eth_getTransactionReceipt(String transactionHash) { } @Override - public BlockResultDTO eth_getUncleByBlockHashAndIndex(String blockHash, String uncleIdx) { + public BlockResultDTO eth_getUncleByBlockHashAndIndex(BlockHashParam blockHash, HexIndexParam uncleIdx) { BlockResultDTO s = null; try { - Block block = blockchain.getBlockByHash(stringHexToByteArray(blockHash)); + Block block = blockchain.getBlockByHash(blockHash.getHash().getBytes()); if (block == null) { return null; } - s = getUncleResultDTO(uncleIdx, block); + s = getUncleResultDTO(uncleIdx.getIndex(), block); return s; } finally { @@ -802,14 +852,13 @@ public BlockResultDTO eth_getUncleByBlockHashAndIndex(String blockHash, String u } } - private BlockResultDTO getUncleResultDTO(String uncleIdx, Block block) { - int idx = jsonHexToInt(uncleIdx); + private BlockResultDTO getUncleResultDTO(Integer uncleIdx, Block block) { - if (idx >= block.getUncleList().size()) { + if (uncleIdx >= block.getUncleList().size()) { return null; } - BlockHeader uncleHeader = block.getUncleList().get(idx); + BlockHeader uncleHeader = block.getUncleList().get(uncleIdx); Block uncle = blockchain.getBlockByHash(uncleHeader.getHash().getBytes()); if (uncle == null) { @@ -821,16 +870,18 @@ private BlockResultDTO getUncleResultDTO(String uncleIdx, Block block) { } @Override - public BlockResultDTO eth_getUncleByBlockNumberAndIndex(String blockId, String uncleIdx) { + public BlockResultDTO eth_getUncleByBlockNumberAndIndex(BlockIdentifierParam identifierParam, HexIndexParam uncleIdx) { BlockResultDTO s = null; + String blockId = identifierParam.getIdentifier(); + try { Optional block = web3InformationRetriever.getBlock(blockId); if (!block.isPresent()) { return null; } - - s = getUncleResultDTO(uncleIdx, block.get()); + int idx = uncleIdx.getIndex(); + s = getUncleResultDTO(idx, block.get()); return s; } finally { @@ -868,7 +919,11 @@ public Map eth_compileSolidity(String contract) { } @Override - public String eth_newFilter(FilterRequest fr) throws Exception { + public String eth_newFilter(FilterRequestParam filterRequestParam) throws Exception { + return newFilter(filterRequestParam.toFilterRequest()); + } + + private String newFilter(FilterRequest fr) { String str = null; try { Filter filter = LogFilter.fromFilterRequest(fr, blockchain, blocksBloomStore, config.getRpcEthGetLogsMaxBlockToQuery(), config.getRpcEthGetLogsMaxLogsToReturn()); @@ -914,7 +969,7 @@ public String eth_newPendingTransactionFilter() { } @Override - public boolean eth_uninstallFilter(String id) { + public boolean eth_uninstallFilter(HexIndexParam id) { Boolean s = null; try { @@ -922,7 +977,7 @@ public boolean eth_uninstallFilter(String id) { return false; } - return filterManager.removeFilter(stringHexToBigInteger(id).intValue()); + return filterManager.removeFilter(id.getIndex()); } finally { if (logger.isDebugEnabled()) { logger.debug("eth_uninstallFilter({}): {}", id, s); @@ -931,7 +986,7 @@ public boolean eth_uninstallFilter(String id) { } @Override - public Object[] eth_getFilterChanges(String id) { + public Object[] eth_getFilterChanges(HexIndexParam id) { logger.debug("eth_getFilterChanges ..."); // TODO(mc): this is a quick solution that seems to work with OpenZeppelin tests, but needs to be reviewed @@ -944,7 +999,7 @@ public Object[] eth_getFilterChanges(String id) { Object[] s = null; try { - s = getFilterEvents(id, true); + s = this.filterManager.getFilterEvents(id.getIndex(), true); } finally { if (logger.isDebugEnabled()) { logger.debug("eth_getFilterChanges({}): {}", id, Arrays.toString(s)); @@ -955,13 +1010,14 @@ public Object[] eth_getFilterChanges(String id) { } @Override - public Object[] eth_getFilterLogs(String id) { + public Object[] eth_getFilterLogs(HexIndexParam id) { logger.debug("eth_getFilterLogs ..."); Object[] s = null; try { - s = getFilterEvents(id, false); + s = this.filterManager.getFilterEvents(id.getIndex(), false); + } finally { if (logger.isDebugEnabled()) { logger.debug("eth_getFilterLogs({}): {}", id, Arrays.toString(s)); @@ -971,16 +1027,13 @@ public Object[] eth_getFilterLogs(String id) { return s; } - private Object[] getFilterEvents(String id, boolean newevents) { - return this.filterManager.getFilterEvents(stringHexToBigInteger(id).intValue(), newevents); - } - @Override - public Object[] eth_getLogs(FilterRequest fr) throws Exception { + public Object[] eth_getLogs(FilterRequestParam fr) throws Exception { logger.debug("eth_getLogs ..."); - String id = eth_newFilter(fr); - Object[] ret = eth_getFilterLogs(id); - eth_uninstallFilter(id); + String id = newFilter(fr.toFilterRequest()); + HexIndexParam idParam = new HexIndexParam(id); + Object[] ret = eth_getFilterLogs(idParam); + eth_uninstallFilter(idParam); return ret; } @@ -1027,21 +1080,27 @@ public void db_getHex() { @Override public String personal_newAccountWithSeed(String seed) { + if (seed == null) { + throw RskJsonRpcRequestException.invalidParamError("Seed is null"); + } return personalModule.newAccountWithSeed(seed); } @Override public String personal_newAccount(String passphrase) { + if (passphrase == null) { + throw RskJsonRpcRequestException.invalidParamError("Passphrase is null"); + } return personalModule.newAccount(passphrase); } @Override - public String personal_importRawKey(String key, String passphrase) { + public String personal_importRawKey(HexKeyParam key, String passphrase) { return personalModule.importRawKey(key, passphrase); } @Override - public String personal_dumpRawKey(String address) throws Exception { + public String personal_dumpRawKey(HexAddressParam address) throws Exception { return personalModule.dumpRawKey(address); } @@ -1051,29 +1110,29 @@ public String[] personal_listAccounts() { } @Override - public String personal_sendTransaction(CallArguments args, String passphrase) throws Exception { + public String personal_sendTransaction(CallArgumentsParam args, String passphrase) throws Exception { return personalModule.sendTransaction(args, passphrase); } @Override - public boolean personal_unlockAccount(String address, String passphrase, String duration) { + public boolean personal_unlockAccount(HexAddressParam address, String passphrase, HexDurationParam duration) { return personalModule.unlockAccount(address, passphrase, duration); } @Override - public boolean personal_lockAccount(String address) { + public boolean personal_lockAccount(HexAddressParam address) { return personalModule.lockAccount(address); } @Override - public String eth_estimateGas(CallArguments args) { + public String eth_estimateGas(CallArgumentsParam args) { return eth_estimateGas(args, null); } @Override - public String eth_estimateGas(CallArguments args, String bnOrId) { - if (StringUtils.isEmpty(bnOrId)) { - bnOrId = BlockTag.LATEST.getTag(); + public String eth_estimateGas(CallArgumentsParam args, @Nullable BlockIdentifierParam bnOrId) { + if (bnOrId == null) { + bnOrId = new BlockIdentifierParam(BlockTag.LATEST.getTag()); } return getEthModule().estimateGas(args, bnOrId); } diff --git a/rskj-core/src/main/java/org/ethereum/rpc/exception/RskJsonRpcRequestException.java b/rskj-core/src/main/java/org/ethereum/rpc/exception/RskJsonRpcRequestException.java index 44c8c63df82..0a4cc78e30f 100644 --- a/rskj-core/src/main/java/org/ethereum/rpc/exception/RskJsonRpcRequestException.java +++ b/rskj-core/src/main/java/org/ethereum/rpc/exception/RskJsonRpcRequestException.java @@ -61,5 +61,4 @@ public static RskJsonRpcRequestException stateNotFound(String message) { public static RskJsonRpcRequestException filterNotFound(String message) { return new RskJsonRpcRequestException(-32000, message); } - } diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/BlockHashParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/BlockHashParam.java new file mode 100644 index 00000000000..a2cfbf97967 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/BlockHashParam.java @@ -0,0 +1,54 @@ +/* + * This file is part of RskJ + * Copyright (C) 2023 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import java.io.IOException; + +@JsonDeserialize(using = BlockHashParam.Deserializer.class) +public class BlockHashParam extends HashParam32 { + + private static final String HASH_TYPE = "block hash"; + + public BlockHashParam(String hash) { + super(HASH_TYPE, hash); + } + + public static class Deserializer extends StdDeserializer { + + private static final long serialVersionUID = 8071595037666226210L; + + public Deserializer() { + this(null); + } + + public Deserializer(Class vc) { + super(vc); + } + + @Override + public BlockHashParam deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + String hash = jp.getText(); + return new BlockHashParam(hash); + } + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/BlockIdentifierParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/BlockIdentifierParam.java new file mode 100644 index 00000000000..53d7bb3c1a4 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/BlockIdentifierParam.java @@ -0,0 +1,68 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.ethereum.core.genesis.BlockTag; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.util.Utils; + +import java.io.IOException; +import java.io.Serializable; + +@JsonDeserialize(using = BlockIdentifierParam.Deserializer.class) +public class BlockIdentifierParam implements Serializable { + private static final long serialVersionUID = 1L; + + private final String identifier; + + public BlockIdentifierParam(String identifier) { + if (identifier == null || identifier.isEmpty()) { + throw RskJsonRpcRequestException.invalidParamError("Invalid block identifier: empty or null."); + } + + if(BlockTag.fromString(identifier) == null + && !Utils.isDecimalString(identifier) + && !Utils.isHexadecimalString(identifier)) { + throw RskJsonRpcRequestException.invalidParamError("Invalid block identifier '" + identifier + "'"); + } + + this.identifier = identifier; + } + + public String getIdentifier() { + return identifier; + } + + public static class Deserializer extends StdDeserializer { + private static final long serialVersionUID = 1L; + + public Deserializer() { this(null); } + + public Deserializer(Class vc) { super(vc); } + + @Override + public BlockIdentifierParam deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + String identifier = jp.getText(); + return new BlockIdentifierParam(identifier); + } + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/BlockRefParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/BlockRefParam.java new file mode 100644 index 00000000000..b47b89af84d --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/BlockRefParam.java @@ -0,0 +1,119 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import com.fasterxml.jackson.databind.node.JsonNodeType; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.util.Utils; + +import java.io.IOException; +import java.io.Serializable; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +@JsonDeserialize(using = BlockRefParam.Deserializer.class) +public class BlockRefParam implements Serializable { + private static final long serialVersionUID = 1L; + + private static final String REQUIRED_CANONICAL_KEY = "requireCanonical"; + private static final String BLOCK_HASH_KEY = "blockHash"; + private static final String BLOCK_NUMBER_KEY = "blockNumber"; + private static final List BLOCK_INPUT_KEYS_TO_VALIDATE = Arrays.asList(BLOCK_HASH_KEY, BLOCK_NUMBER_KEY); + private static final List IDENTIFIERS_TO_VALIDATE = Arrays.asList("earliest", "latest", "pending"); + + private String identifier; + private Map inputs; + + public BlockRefParam(String identifier) { + if(!IDENTIFIERS_TO_VALIDATE.contains(identifier) + && !Utils.isDecimalString(identifier) + && !Utils.isHexadecimalString(identifier)) { + throw RskJsonRpcRequestException.invalidParamError("Invalid block identifier '" + identifier + "'"); + } + + this.identifier = identifier; + } + + public BlockRefParam(Map inputs) { + if(inputs.keySet().stream().noneMatch(BLOCK_INPUT_KEYS_TO_VALIDATE::contains)) { + throw RskJsonRpcRequestException.invalidParamError("Invalid block input"); + } + + validateMapItems(inputs); + + this.inputs = inputs; + } + + private void validateMapItems(Map inputs) { + inputs.forEach((key, value) -> { + switch (key) { + case REQUIRED_CANONICAL_KEY: + if(!value.equalsIgnoreCase("true") && !value.equalsIgnoreCase("false")) { + throw RskJsonRpcRequestException.invalidParamError(String + .format("Invalid input: %s must be a String \"true\" or \"false\"", REQUIRED_CANONICAL_KEY)); + } + break; + case BLOCK_HASH_KEY: + new BlockHashParam(value); + break; + case BLOCK_NUMBER_KEY: + new HexNumberParam(value); + break; + } + }); + } + + public String getIdentifier() { + return identifier; + } + + public Map getInputs() { + return inputs; + } + + public static class Deserializer extends StdDeserializer { + private static final long serialVersionUID = 1L; + private final ObjectMapper mapper = new ObjectMapper(); + + public Deserializer() { this(null); } + + public Deserializer(Class vc) { super(vc); } + + @Override + public BlockRefParam deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + JsonNode node = jp.getCodec().readTree(jp); + JsonNodeType nodeType = node.getNodeType(); + + if(nodeType == JsonNodeType.STRING) { + return new BlockRefParam(node.asText()); + } else if(nodeType == JsonNodeType.OBJECT) { + Map inputs = mapper.convertValue(node, Map.class); + return new BlockRefParam(inputs); + } else { + throw RskJsonRpcRequestException.invalidParamError("Invalid input"); + } + } + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/CallArgumentsParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/CallArgumentsParam.java new file mode 100644 index 00000000000..c7b40fee4a6 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/CallArgumentsParam.java @@ -0,0 +1,144 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.ethereum.rpc.CallArguments; + +import java.io.IOException; + +@JsonDeserialize(using = CallArgumentsParam.Deserializer.class) +public class CallArgumentsParam { + + private final HexAddressParam from; + private final HexAddressParam to; + private final HexNumberParam gas; + private final HexNumberParam gasPrice; + private final HexNumberParam gasLimit; + private final HexNumberParam nonce; + private final HexNumberParam chainId; + private final HexNumberParam value; + private final HexDataParam data; + + public CallArgumentsParam(HexAddressParam from, HexAddressParam to, HexNumberParam gas, + HexNumberParam gasPrice, HexNumberParam gasLimit, HexNumberParam nonce, + HexNumberParam chainId, HexNumberParam value, HexDataParam data) { + this.from = from; + this.to = to; + this.gas = gas; + this.gasPrice = gasPrice; + this.gasLimit = gasLimit; + this.nonce = nonce; + this.chainId = chainId; + this.value = value; + this.data = data; + } + + public HexAddressParam getFrom() { + return from; + } + + public HexAddressParam getTo() { + return to; + } + + public HexNumberParam getGas() { + return gas; + } + + public HexNumberParam getGasPrice() { + return gasPrice; + } + + public HexNumberParam getGasLimit() { + return gasLimit; + } + + public HexNumberParam getNonce() { + return nonce; + } + + public HexNumberParam getChainId() { + return chainId; + } + + public HexNumberParam getValue() { + return value; + } + + public HexDataParam getData() { + return data; + } + + public CallArguments toCallArguments() { + + String caFrom = this.from == null ? null : this.from.getAddress().toJsonString(); + String caTo = this.to == null ? null : this.to.getAddress().toJsonString(); + String caGas = this.gas == null ? null : this.gas.getHexNumber(); + String caGasPrice = this.gasPrice == null ? null : this.gasPrice.getHexNumber(); + String caGasLimit = this.gasLimit == null ? null : this.gasLimit.getHexNumber(); + String caNonce = this.nonce == null ? null : this.nonce.getHexNumber(); + String caChainId = this.chainId == null ? null : this.chainId.getHexNumber(); + String caValue = this.value == null ? null : this.value.getHexNumber(); + String caData = this.data == null ? null : this.data.getAsHexString(); + + CallArguments callArguments = new CallArguments(); + callArguments.setFrom(caFrom); + callArguments.setTo(caTo); + callArguments.setGas(caGas); + callArguments.setGasPrice(caGasPrice); + callArguments.setGasLimit(caGasLimit); + callArguments.setNonce(caNonce); + callArguments.setChainId(caChainId); + callArguments.setValue(caValue); + callArguments.setData(caData); + + return callArguments; + } + + public static class Deserializer extends StdDeserializer { + private static final long serialVersionUID = 1L; + + public Deserializer() { this(null); } + + public Deserializer(Class vc) { super(vc); } + + @Override + public CallArgumentsParam deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + JsonNode node = jp.getCodec().readTree(jp); + + BlockIdentifierParam fromBlock = node.has("fromBlock") ? new BlockIdentifierParam(node.get("fromBlock").asText()) : null; + + HexAddressParam from = node.has("from") ? new HexAddressParam(node.get("from").asText()) : null; + HexAddressParam to = node.has("to") ? new HexAddressParam(node.get("to").asText()) : null; + HexNumberParam gas = node.has("gas") ? new HexNumberParam(node.get("gas").asText()) : null; + HexNumberParam gasPrice = node.has("gasPrice") ? new HexNumberParam(node.get("gasPrice").asText()) : null; + HexNumberParam gasLimit = node.has("gasLimit") ? new HexNumberParam(node.get("gasLimit").asText()) : null; + HexNumberParam nonce = node.has("nonce") ? new HexNumberParam(node.get("nonce").asText()) : null; + HexNumberParam chainId = node.has("chainId") ? new HexNumberParam(node.get("chainId").asText()) : null; + HexNumberParam value = node.has("value") ? new HexNumberParam(node.get("value").asText()) : null; + HexDataParam data = node.has("data") ? new HexDataParam(node.get("data").asText()) : null; + + return new CallArgumentsParam(from, to, gas, gasPrice, gasLimit, nonce, chainId, value, data); + } + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/FilterRequestParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/FilterRequestParam.java new file mode 100644 index 00000000000..2042cc82d70 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/FilterRequestParam.java @@ -0,0 +1,192 @@ +/* + * This file is part of RskJ + * Copyright (C) 2023 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.ethereum.rpc.FilterRequest; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +@JsonDeserialize(using = FilterRequestParam.Deserializer.class) +public class FilterRequestParam { + + private final BlockIdentifierParam fromBlock; + private final BlockIdentifierParam toBlock; + private final HexAddressParam[] address; + private final TopicParam[][] topics; + private final BlockHashParam blockHash; + + public FilterRequestParam(BlockIdentifierParam fromBlock, BlockIdentifierParam toBlock, HexAddressParam[] address, TopicParam[][] topics, BlockHashParam blockHash) { + this.fromBlock = fromBlock; + this.toBlock = toBlock; + this.address = address; + this.topics = topics; + this.blockHash = blockHash; + } + + public BlockIdentifierParam getFromBlock() { + return fromBlock; + } + + public BlockIdentifierParam getToBlock() { + return toBlock; + } + + public HexAddressParam[] getAddress() { + return address; + } + + public TopicParam[][] getTopics() { + return topics; + } + + public BlockHashParam getBlockHash() { + return blockHash; + } + + public FilterRequest toFilterRequest() { + String fb = this.fromBlock == null ? null : this.fromBlock.getIdentifier(); + String tb = this.toBlock == null ? null : this.toBlock.getIdentifier(); + Object ad = this.address == null ? null : this.parseAddressArray(); + String bh = this.blockHash == null ? null : this.blockHash.getHash().toJsonString(); + Object[] tp = this.topics == null ? null : this.parseTopicArrayToObjectArray(); + + FilterRequest filterRequest = new FilterRequest(); + filterRequest.setAddress(ad); + filterRequest.setBlockHash(bh); + filterRequest.setFromBlock(fb); + filterRequest.setToBlock(tb); + filterRequest.setTopics(tp); + + return filterRequest; + } + + private Object parseAddressArray() { + if (this.address == null) { + return null; + } + if (this.address.length == 1) { + return this.address[0].getAddress().toJsonString(); + } else { + List arrayList = new ArrayList<>(); + for (int i = 0; i < this.address.length; i++) { + arrayList.add(this.address[i].getAddress().toJsonString()); + } + return arrayList; + } + } + + private Object[] parseTopicArrayToObjectArray() { + if (this.topics == null) { + return new Object[0]; + } + Object[] result = new Object[this.topics.length]; + for (int i = 0; i < this.topics.length; i++) { + TopicParam[] topicArray = this.topics[i]; + if (topicArray.length == 1) { + result[i] = topicArray[0] != null ? topicArray[0].getHash().toJsonString() : null; + } else { + List arrayList = new ArrayList<>(); + for (TopicParam topicParam : topicArray) { + arrayList.add(topicParam != null ? topicParam.getHash().toJsonString() : null); + } + result[i] = arrayList; + } + } + return result; + } + + public static class Deserializer extends StdDeserializer { + private static final long serialVersionUID = -72304400913233552L; + + public Deserializer() { + this(null); + } + + public Deserializer(Class vc) { + super(vc); + } + + @Override + public FilterRequestParam deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + JsonNode node = jp.getCodec().readTree(jp); + BlockIdentifierParam fromBlock = node.has("fromBlock") ? new BlockIdentifierParam(node.get("fromBlock").asText()) : null; + BlockIdentifierParam toBlock = node.has("toBlock") ? new BlockIdentifierParam(node.get("toBlock").asText()) : null; + HexAddressParam[] address = node.has("address") ? getAddressParam(node.get("address")) : null; + BlockHashParam blockHash = node.has("blockHash") ? new BlockHashParam(node.get("blockHash").asText()) : null; + TopicParam[][] topics = node.has("topics") ? getTopicArray(node.get("topics")) : null; + + return new FilterRequestParam(fromBlock, toBlock, address, topics, blockHash); + } + + private HexAddressParam[] getAddressParam(JsonNode node) { + if (node == null || node.isNull()) { + return null; + } + + if (node.isArray()) { + HexAddressParam[] addresses = new HexAddressParam[node.size()]; + for (int i = 0; i < node.size(); i++) { + JsonNode subNode = node.get(i); + addresses[i] = new HexAddressParam(subNode.asText()); + } + return addresses; + } + return new HexAddressParam[]{new HexAddressParam(node.asText())}; + } + + private TopicParam[][] getTopicArray(JsonNode node) { + if (node == null || node.isNull()) { + return new TopicParam[0][0]; + } + if (node.isArray()) { + TopicParam[][] topics = new TopicParam[node.size()][]; + for (int i = 0; i < node.size(); i++) { + JsonNode subNode = node.get(i); + if (subNode.isArray()) { + TopicParam[] topicParams = getTopics(subNode); + topics[i] = topicParams; + } else { + TopicParam subNodeTopic = subNode.isNull() ? null : new TopicParam(subNode.asText()); + topics[i] = new TopicParam[]{subNodeTopic}; + } + } + return topics; + } + TopicParam topicParam = new TopicParam(node.asText()); + return new TopicParam[][]{new TopicParam[]{topicParam}}; + } + + private TopicParam[] getTopics(JsonNode jsonNode) { + TopicParam[] topicParams = new TopicParam[jsonNode.size()]; + for (int j = 0; j < jsonNode.size(); j++) { + JsonNode subNode = jsonNode.get(j); + topicParams[j] = subNode.isNull() ? null : new TopicParam(subNode.asText()); + } + return topicParams; + } + + } + +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HashParam32.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HashParam32.java new file mode 100644 index 00000000000..4ff85034314 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HashParam32.java @@ -0,0 +1,53 @@ +/* + * This file is part of RskJ + * Copyright (C) 2023 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import co.rsk.crypto.Keccak256; +import co.rsk.util.HexUtils; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; + +import static co.rsk.util.HexUtils.stringHexToByteArray; + +public abstract class HashParam32 { + private static final int HASH_BYTE_LENGTH = 32; + private final Keccak256 hash; + + HashParam32(String hashType, String hash) { + if (hash == null || hash.isEmpty()) { + throw RskJsonRpcRequestException.invalidParamError("Invalid " + hashType + ": empty or null."); + } + + byte[] hashBytes; + + try { + hashBytes = HexUtils.stringHexToByteArray(hash); + } catch (Exception e) { + throw RskJsonRpcRequestException.invalidParamError("Invalid " + hashType + " format: invalid hex value", e); + } + + if (HASH_BYTE_LENGTH != hashBytes.length) { + throw RskJsonRpcRequestException.invalidParamError("Invalid " + hashType + ": incorrect length."); + } + + this.hash = new Keccak256(stringHexToByteArray(hash)); + } + + public Keccak256 getHash() { + return hash; + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexAddressParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexAddressParam.java new file mode 100644 index 00000000000..a8c939cc7e5 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexAddressParam.java @@ -0,0 +1,65 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import co.rsk.core.RskAddress; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; + +import java.io.IOException; +import java.io.Serializable; + +@JsonDeserialize(using = HexAddressParam.Deserializer.class) +public class HexAddressParam implements Serializable { + private static final long serialVersionUID = 1L; + + private transient final RskAddress address; + + public HexAddressParam(String hexAddress) { + if (hexAddress == null || hexAddress.isEmpty()) { + throw RskJsonRpcRequestException.invalidParamError("Invalid address: empty or null."); + } + + try { + this.address = new RskAddress(hexAddress); + } catch (Exception e) { + throw RskJsonRpcRequestException.invalidParamError("Invalid address format: invalid hex value.", e); + } + } + + public RskAddress getAddress() { + return address; + } + + public static class Deserializer extends StdDeserializer { + private static final long serialVersionUID = 1L; + + public Deserializer() { this(null); } + + public Deserializer(Class vc) { super(vc); } + + @Override + public HexAddressParam deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + String hexAddress = jp.getText(); + return new HexAddressParam(hexAddress); + } + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexDataParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexDataParam.java new file mode 100644 index 00000000000..940a5f2f0d1 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexDataParam.java @@ -0,0 +1,66 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import co.rsk.util.HexUtils; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.util.ByteUtil; + +import java.io.IOException; +import java.io.Serializable; + +@JsonDeserialize(using = HexDataParam.Deserializer.class) +public class HexDataParam implements Serializable { + private static final long serialVersionUID = 1L; + + private final byte[] rawDataBytes; + + public HexDataParam(String rawData){ + try { + this.rawDataBytes = HexUtils.stringHexToByteArray(rawData); + } catch (Exception e) { + throw RskJsonRpcRequestException.invalidParamError("Invalid data format: invalid hex value.", e); + } + } + + public byte[] getRawDataBytes() { + return rawDataBytes; + } + + public String getAsHexString() { + return "0x" + ByteUtil.toHexString(rawDataBytes); + } + + public static class Deserializer extends StdDeserializer { + private static final long serialVersionUID = 1L; + + public Deserializer() { this(null); } + + public Deserializer(Class vc) { super(vc); } + + @Override + public HexDataParam deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + String hexRawData = jp.getText(); + return new HexDataParam(hexRawData); + } + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexDurationParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexDurationParam.java new file mode 100644 index 00000000000..aae2edb8395 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexDurationParam.java @@ -0,0 +1,63 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; + +import java.io.IOException; + +@JsonDeserialize(using = HexDurationParam.Deserializer.class) +public class HexDurationParam extends HexStringParam { + private final Long duration; + + public HexDurationParam(String hexDurationStr) { + super(hexDurationStr); + + if (hexDurationStr.isEmpty()) { + this.duration = null; + } else { + try { + this.duration = Long.parseLong(hexDurationStr.substring(2), 16); + } catch (NumberFormatException e) { + throw RskJsonRpcRequestException.invalidParamError("Invalid duration param: value must be a valid hex number.", e); + } + } + } + + public Long getDuration() { + return duration; + } + + public static class Deserializer extends StdDeserializer { + private static final long serialVersionUID = 1L; + + public Deserializer() { this(null); } + + public Deserializer(Class vc) { super(vc); } + + @Override + public HexDurationParam deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + String hexDurationStr = jp.getText(); + return new HexDurationParam(hexDurationStr); + } + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexIndexParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexIndexParam.java new file mode 100644 index 00000000000..51376c1b59e --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexIndexParam.java @@ -0,0 +1,67 @@ +/* + * This file is part of RskJ + * Copyright (C) 2023 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import co.rsk.util.HexUtils; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; + +import java.io.IOException; + +@JsonDeserialize(using = HexIndexParam.Deserializer.class) +public class HexIndexParam extends HexStringParam { + private final Integer index; + + public HexIndexParam(String indexString) { + super(indexString); + + String preResult = HexUtils.removeHexPrefix(indexString); + try { + this.index = Integer.parseInt(preResult, 16); + } catch (NumberFormatException e) { + throw RskJsonRpcRequestException.invalidParamError("Invalid index param: value must be a valid hex number.", e); + } + } + + public Integer getIndex() { + return index; + } + + public static class Deserializer extends StdDeserializer { + + private static final long serialVersionUID = 1L; + + public Deserializer() { + this(null); + } + + public Deserializer(Class vc) { + super(vc); + } + + @Override + public HexIndexParam deserialize(JsonParser jp, DeserializationContext ctxt) + throws IOException { + String indexString = jp.getText(); + return new HexIndexParam(indexString); + } + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexKeyParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexKeyParam.java new file mode 100644 index 00000000000..48d86c83ad4 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexKeyParam.java @@ -0,0 +1,62 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import co.rsk.util.HexUtils; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; + +import java.io.IOException; +import java.io.Serializable; + +@JsonDeserialize(using = HexKeyParam.Deserializer.class) +public class HexKeyParam implements Serializable { + private static final long serialVersionUID = 1L; + + private final String hexKey; + + public HexKeyParam(String hexKey) { + boolean hasPrefix = HexUtils.hasHexPrefix(hexKey); + if (!HexUtils.isHex(hexKey.toLowerCase(), hasPrefix ? 2 : 0)) { + throw RskJsonRpcRequestException.invalidParamError("Invalid param " + hexKey + ": value must be a valid hex."); + } + + this.hexKey = hexKey; + } + + public String getHexKey() { + return hexKey; + } + + public static class Deserializer extends StdDeserializer { + private static final long serialVersionUID = 1L; + + public Deserializer() { this(null); } + + public Deserializer(Class vc) { super(vc); } + + @Override + public HexKeyParam deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + String hexKey = jp.getText(); + return new HexKeyParam(hexKey); + } + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexNumberParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexNumberParam.java new file mode 100644 index 00000000000..aca8eeb28ef --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexNumberParam.java @@ -0,0 +1,67 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import co.rsk.util.HexUtils; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; + +import java.io.IOException; +import java.io.Serializable; +import java.math.BigInteger; + +@JsonDeserialize(using = HexNumberParam.Deserializer.class) +public class HexNumberParam implements Serializable { + private static final long serialVersionUID = 1L; + + private final String hexNumber; + + public HexNumberParam(String hexNumber) { + boolean hasPrefix = HexUtils.hasHexPrefix(hexNumber); + if (!HexUtils.isHex(hexNumber.toLowerCase(), hasPrefix ? 2 : 0)) { + try { + new BigInteger(hexNumber); + } catch(Exception e) { + throw RskJsonRpcRequestException.invalidParamError("Invalid param " + hexNumber + ": value must be a valid hex or string number.", e); + } + } + + this.hexNumber = hexNumber; + } + + public String getHexNumber() { + return this.hexNumber; + } + + public static class Deserializer extends StdDeserializer { + private static final long serialVersionUID = 1L; + + public Deserializer() { this(null); } + + public Deserializer(Class vc) { super(vc); } + + @Override + public HexNumberParam deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + String hexNumber = jp.getText(); + return new HexNumberParam(hexNumber); + } + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexStringParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexStringParam.java new file mode 100644 index 00000000000..c36d838ed86 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/HexStringParam.java @@ -0,0 +1,33 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import co.rsk.util.HexUtils; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; + +public abstract class HexStringParam { + HexStringParam(String hexString) { + if(hexString.isEmpty()) { + return; + } + + if (!HexUtils.hasHexPrefix(hexString) || !HexUtils.isHex(hexString,2)) { + throw RskJsonRpcRequestException.invalidParamError(String.format("Invalid argument \"%s\": param should be a hex value string.", hexString)); + } + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/TopicParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/TopicParam.java new file mode 100644 index 00000000000..1c643c97a78 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/TopicParam.java @@ -0,0 +1,26 @@ +/* + * This file is part of RskJ + * Copyright (C) 2023 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +public class TopicParam extends HashParam32 { + private static final String HASH_TYPE = "topic"; + + public TopicParam(String hash) { + super(HASH_TYPE, hash); + } +} diff --git a/rskj-core/src/main/java/org/ethereum/rpc/parameters/TxHashParam.java b/rskj-core/src/main/java/org/ethereum/rpc/parameters/TxHashParam.java new file mode 100644 index 00000000000..b1c9b3674b7 --- /dev/null +++ b/rskj-core/src/main/java/org/ethereum/rpc/parameters/TxHashParam.java @@ -0,0 +1,53 @@ +/* + * This file is part of RskJ + * Copyright (C) 2023 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import java.io.IOException; + +@JsonDeserialize(using = TxHashParam.Deserializer.class) +public class TxHashParam extends HashParam32 { + private static final String HASH_TYPE = "transaction hash"; + public TxHashParam(String hash) { + super(HASH_TYPE, hash); + } + + public static class Deserializer extends StdDeserializer { + + private static final long serialVersionUID = 2669501504172497269L; + + public Deserializer() { + this(null); + } + + public Deserializer(Class vc) { + super(vc); + } + + @Override + public TxHashParam deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + String hash = jp.getText(); + return new TxHashParam(hash); + } + } +} + diff --git a/rskj-core/src/main/resources/config/testnet.conf b/rskj-core/src/main/resources/config/testnet.conf index 37085c7eef9..3e0d1952a8b 100644 --- a/rskj-core/src/main/resources/config/testnet.conf +++ b/rskj-core/src/main/resources/config/testnet.conf @@ -41,7 +41,9 @@ peer { "bootstrap03.testnet.rsk.co:50505", "bootstrap04.testnet.rsk.co:50505", "bootstrap05.testnet.rsk.co:50505", - "bootstrap06.testnet.rsk.co:50505" + "bootstrap06.testnet.rsk.co:50505", + "bootstrap07.testnet.rsk.co:50505", + "bootstrap08.testnet.rsk.co:50505" ] } diff --git a/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java b/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java index 1dda751c7ce..9359b0c3d42 100644 --- a/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java +++ b/rskj-core/src/test/java/co/rsk/mine/TransactionModuleTest.java @@ -67,9 +67,11 @@ import org.ethereum.rpc.Simples.SimpleConfigCapabilities; import org.ethereum.rpc.Web3Impl; import org.ethereum.rpc.Web3Mocks; +import org.ethereum.rpc.parameters.HexDataParam; import org.ethereum.sync.SyncPool; import org.ethereum.util.BuildInfo; import org.ethereum.util.ByteUtil; +import org.ethereum.util.TransactionFactoryHelper; import org.ethereum.vm.GasCost; import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.program.invoke.ProgramInvokeFactoryImpl; @@ -306,7 +308,7 @@ public int checkEstimateGas(int method, long expectedValue, long gasLimit, Assertions.assertNotEquals(expectedValue, gasLimit); CallArguments args = getContractCallTransactionParameters(method, gasLimit, srcAddr, contractAddress, repository); - String gas = web3.eth_estimateGas(args, null); + String gas = web3.eth_estimateGas(TransactionFactoryHelper.toCallArgumentsParam(args), null); byte[] gasReturnedBytes = Hex.decode(gas.substring("0x".length())); BigInteger gasReturned = BigIntegers.fromUnsignedByteArray(gasReturnedBytes); int gasReturnedInt = gasReturned.intValueExact(); @@ -332,7 +334,7 @@ private String sendRawTransaction(Web3Impl web3) { String rawData = ByteUtil.toHexString(tx.getEncoded()); - return web3.eth_sendRawTransaction(rawData); + return web3.eth_sendRawTransaction(new HexDataParam(rawData)); } private Transaction getTransactionFromBlockWhichWasSend(BlockChainImpl blockchain, String tx) { @@ -350,13 +352,13 @@ private Transaction getTransactionFromBlockWhichWasSend(BlockChainImpl blockchai private String sendContractCreationTransaction(RskAddress srcaddr, Web3Impl web3, RepositorySnapshot repository) { CallArguments args = getContractCreationTransactionParameters(srcaddr, web3, repository); - return web3.eth_sendTransaction(args); + return web3.eth_sendTransaction(TransactionFactoryHelper.toCallArgumentsParam(args)); } private String sendTransaction(Web3Impl web3, RepositorySnapshot repository) { CallArguments args = getTransactionParameters(web3, repository); - return web3.eth_sendTransaction(args); + return web3.eth_sendTransaction(TransactionFactoryHelper.toCallArgumentsParam(args)); } //////////////////////////////////////////////// diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSerializationUtilsTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSerializationUtilsTest.java index efaea5539e4..35190f974fc 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSerializationUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSerializationUtilsTest.java @@ -151,7 +151,7 @@ void serializeFederationOnlyBtcKeys() throws Exception { }; // Only actual keys serialized are BTC keys, so we don't really care about RSK or MST keys - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(Arrays.asList(new BtcECKey[]{ BtcECKey.fromPublicOnly(publicKeyBytes[0]), BtcECKey.fromPublicOnly(publicKeyBytes[1]), @@ -202,7 +202,7 @@ void deserializeFederationOnlyBtcKeys_ok() throws Exception { byte[] data = RLP.encodeList(rlpFirstElement, rlpSecondElement, rlpKeyList); - Federation deserializedFederation = BridgeSerializationUtils.deserializeFederationOnlyBtcKeys(data, NetworkParameters.fromID(NetworkParameters.ID_REGTEST)); + Federation deserializedFederation = BridgeSerializationUtils.deserializeStandardMultisigFederationOnlyBtcKeys(data, NetworkParameters.fromID(NetworkParameters.ID_REGTEST)); Assertions.assertEquals(5000, deserializedFederation.getCreationTime().toEpochMilli()); Assertions.assertEquals(4, deserializedFederation.getNumberOfSignaturesRequired()); @@ -228,7 +228,7 @@ void deserializeFederationOnlyBtcKeys_wrongListSize() throws Exception { boolean thrown = false; try { - BridgeSerializationUtils.deserializeFederationOnlyBtcKeys(data, NetworkParameters.fromID(NetworkParameters.ID_REGTEST)); + BridgeSerializationUtils.deserializeStandardMultisigFederationOnlyBtcKeys(data, NetworkParameters.fromID(NetworkParameters.ID_REGTEST)); } catch (Exception e) { Assertions.assertTrue(e.getMessage().contains("Expected 3 elements")); thrown = true; @@ -302,7 +302,7 @@ void serializeFederation_serializedKeysAreCompressedAndThree() { members.add(new FederationMember(new BtcECKey(), new ECKey(), new ECKey())); } - Federation testFederation = new Federation( + Federation testFederation = new StandardMultisigFederation( members, Instant.now(), 123, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); @@ -330,7 +330,7 @@ void serializeFederation_serializedKeysAreCompressedAndThree() { void deserializeFederation_wrongListSize() { byte[] serialized = RLP.encodeList(RLP.encodeElement(new byte[0]), RLP.encodeElement(new byte[0])); NetworkParameters networkParameters = NetworkParameters.fromID(NetworkParameters.ID_REGTEST); - Exception ex = Assertions.assertThrows(RuntimeException.class, () -> BridgeSerializationUtils.deserializeFederation(serialized, networkParameters)); + Exception ex = Assertions.assertThrows(RuntimeException.class, () -> BridgeSerializationUtils.deserializeStandardMultisigFederation(serialized, networkParameters)); Assertions.assertTrue(ex.getMessage().contains("Invalid serialized Federation")); } @@ -344,7 +344,7 @@ void deserializeFederation_invalidFederationMember() { NetworkParameters networkParameters = NetworkParameters.fromID(NetworkParameters.ID_REGTEST); - Exception ex = Assertions.assertThrows(RuntimeException.class, () -> BridgeSerializationUtils.deserializeFederation(serialized, networkParameters)); + Exception ex = Assertions.assertThrows(RuntimeException.class, () -> BridgeSerializationUtils.deserializeStandardMultisigFederation(serialized, networkParameters)); Assertions.assertTrue(ex.getMessage().contains("Invalid serialized FederationMember")); } @@ -787,7 +787,7 @@ void serializeAndDeserializeFederationOnlyBtcKeysWithRealRLP() { }; // Only actual keys serialized are BTC keys, so deserialization will fill RSK and MST keys with those - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithKeys(Arrays.asList( BtcECKey.fromPublicOnly(publicKeyBytes[0]), BtcECKey.fromPublicOnly(publicKeyBytes[1]), @@ -802,7 +802,7 @@ void serializeAndDeserializeFederationOnlyBtcKeysWithRealRLP() { ); byte[] result = BridgeSerializationUtils.serializeFederationOnlyBtcKeys(federation); - Federation deserializedFederation = BridgeSerializationUtils.deserializeFederationOnlyBtcKeys(result, networkParms); + Federation deserializedFederation = BridgeSerializationUtils.deserializeStandardMultisigFederationOnlyBtcKeys(result, networkParms); MatcherAssert.assertThat(federation, is(deserializedFederation)); } @@ -1246,7 +1246,7 @@ private void testSerializeAndDeserializeFederation( members.add(new FederationMember(new BtcECKey(), new ECKey(), new ECKey())); } - Federation testFederation = new Federation( + Federation testFederation = new StandardMultisigFederation( members, Instant.now(), 123, @@ -1254,12 +1254,12 @@ private void testSerializeAndDeserializeFederation( ); byte[] serializedTestFederation = BridgeSerializationUtils.serializeFederation(testFederation); - Federation deserializedTestFederation = BridgeSerializationUtils.deserializeFederation( + Federation deserializedTestFederation = BridgeSerializationUtils.deserializeStandardMultisigFederation( serializedTestFederation, bridgeConstants.getBtcParams() ); - Federation testErpFederation = new ErpFederation( + Federation testErpFederation = new LegacyErpFederation( members, Instant.now(), 123, @@ -1270,7 +1270,7 @@ private void testSerializeAndDeserializeFederation( ); byte[] serializedTestErpFederation = BridgeSerializationUtils.serializeFederation(testErpFederation); - Federation deserializedTestErpFederation = BridgeSerializationUtils.deserializeErpFederation( + Federation deserializedTestErpFederation = BridgeSerializationUtils.deserializeLegacyErpFederation( serializedTestErpFederation, bridgeConstants, activations diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeStorageProviderFederationTests.java b/rskj-core/src/test/java/co/rsk/peg/BridgeStorageProviderFederationTests.java index 5f3e0cbdbd5..23bf87e0b64 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeStorageProviderFederationTests.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeStorageProviderFederationTests.java @@ -24,8 +24,8 @@ class BridgeStorageProviderFederationTests { - private static final int FEDERATION_FORMAT_VERSION_MULTIKEY = 1000; - private static final int ERP_FEDERATION_FORMAT_VERSION = 2000; + private static final int STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION = 1000; + private static final int LEGACY_ERP_FEDERATION_FORMAT_VERSION = 2000; private static final int P2SH_ERP_FEDERATION_FORMAT_VERSION = 3000; private final BridgeConstants bridgeConstantsRegtest = BridgeRegTestConstants.getInstance(); @@ -43,18 +43,18 @@ void getNewFederation_should_return_P2shErpFederation() { @Test void getNewFederation_should_return_erp_federation() { - Federation federation = createFederation(ERP_FEDERATION_FORMAT_VERSION); + Federation federation = createFederation(LEGACY_ERP_FEDERATION_FORMAT_VERSION); testGetNewFederation( - ERP_FEDERATION_FORMAT_VERSION, + LEGACY_ERP_FEDERATION_FORMAT_VERSION, federation ); } @Test void getNewFederation_should_return_legacy_federation() { - Federation federation = createFederation(FEDERATION_FORMAT_VERSION_MULTIKEY); + Federation federation = createFederation(STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION); testGetNewFederation( - FEDERATION_FORMAT_VERSION_MULTIKEY, + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION, federation ); } @@ -62,12 +62,12 @@ void getNewFederation_should_return_legacy_federation() { @Test void getNewFederation_should_return_null() { testGetNewFederation( - FEDERATION_FORMAT_VERSION_MULTIKEY, + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION, null ); testGetNewFederation( - ERP_FEDERATION_FORMAT_VERSION, + LEGACY_ERP_FEDERATION_FORMAT_VERSION, null ); @@ -148,18 +148,18 @@ void getOldFederation_should_return_P2shErpFederation() { @Test void getOldFederation_should_return_erp_federation() { - Federation federation = createFederation(ERP_FEDERATION_FORMAT_VERSION); + Federation federation = createFederation(LEGACY_ERP_FEDERATION_FORMAT_VERSION); testGetOldFederation( - ERP_FEDERATION_FORMAT_VERSION, + LEGACY_ERP_FEDERATION_FORMAT_VERSION, federation ); } @Test void getOldFederation_should_return_legacy_fed() { - Federation federation = createFederation(FEDERATION_FORMAT_VERSION_MULTIKEY); + Federation federation = createFederation(STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION); testGetOldFederation( - FEDERATION_FORMAT_VERSION_MULTIKEY, + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION, federation ); } @@ -167,12 +167,12 @@ void getOldFederation_should_return_legacy_fed() { @Test void getOldFederation_should_return_null() { testGetOldFederation( - FEDERATION_FORMAT_VERSION_MULTIKEY, + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION, null ); testGetOldFederation( - ERP_FEDERATION_FORMAT_VERSION, + LEGACY_ERP_FEDERATION_FORMAT_VERSION, null ); @@ -244,13 +244,13 @@ private void testGetOldFederation( @Test void saveNewFederation_before_RSKIP123_should_allow_to_save_any_fed_type() throws IOException { testSaveNewFederation( - FEDERATION_FORMAT_VERSION_MULTIKEY, - createFederation(FEDERATION_FORMAT_VERSION_MULTIKEY) + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION, + createFederation(STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION) ); testSaveNewFederation( - ERP_FEDERATION_FORMAT_VERSION, - createFederation(ERP_FEDERATION_FORMAT_VERSION) + LEGACY_ERP_FEDERATION_FORMAT_VERSION, + createFederation(LEGACY_ERP_FEDERATION_FORMAT_VERSION) ); testSaveNewFederation( @@ -263,8 +263,8 @@ void saveNewFederation_before_RSKIP123_should_allow_to_save_any_fed_type() throw void saveNewFederation_after_RSKIP123_should_save_legacy_fed_format() throws IOException { activations = ActivationConfigsForTest.only(ConsensusRule.RSKIP123).forBlock(0); testSaveNewFederation( - FEDERATION_FORMAT_VERSION_MULTIKEY, - createFederation(FEDERATION_FORMAT_VERSION_MULTIKEY) + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION, + createFederation(STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION) ); } @@ -275,8 +275,8 @@ void saveNewFederation_after_RSKIP201_should_save_legacy_fed_format() throws IOE ConsensusRule.RSKIP201 ).forBlock(0); testSaveNewFederation( - FEDERATION_FORMAT_VERSION_MULTIKEY, - createFederation(FEDERATION_FORMAT_VERSION_MULTIKEY) + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION, + createFederation(STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION) ); } @@ -288,8 +288,8 @@ void saveNewFederation_after_RSKIP353_should_save_legacy_fed_format() throws IOE ConsensusRule.RSKIP353 ).forBlock(0); testSaveNewFederation( - FEDERATION_FORMAT_VERSION_MULTIKEY, - createFederation(FEDERATION_FORMAT_VERSION_MULTIKEY) + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION, + createFederation(STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION) ); } @@ -300,8 +300,8 @@ void saveNewFederation_after_RSKIP201_should_save_erp_fed_format() throws IOExce ConsensusRule.RSKIP201 ).forBlock(0); testSaveNewFederation( - ERP_FEDERATION_FORMAT_VERSION, - createFederation(ERP_FEDERATION_FORMAT_VERSION) + LEGACY_ERP_FEDERATION_FORMAT_VERSION, + createFederation(LEGACY_ERP_FEDERATION_FORMAT_VERSION) ); } @@ -313,8 +313,8 @@ void saveNewFederation_after_RSKIP353_should_save_erp_fed_format() throws IOExce ConsensusRule.RSKIP353 ).forBlock(0); testSaveNewFederation( - ERP_FEDERATION_FORMAT_VERSION, - createFederation(ERP_FEDERATION_FORMAT_VERSION) + LEGACY_ERP_FEDERATION_FORMAT_VERSION, + createFederation(LEGACY_ERP_FEDERATION_FORMAT_VERSION) ); } @@ -417,13 +417,13 @@ private void testSaveNewFederation( void saveOldFederation_before_RSKIP123_should_allow_to_save_any_fed_type() throws IOException { activations = ActivationConfigsForTest.only().forBlock(0); testSaveOldFederation( - FEDERATION_FORMAT_VERSION_MULTIKEY, - createFederation(FEDERATION_FORMAT_VERSION_MULTIKEY) + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION, + createFederation(STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION) ); testSaveOldFederation( - ERP_FEDERATION_FORMAT_VERSION, - createFederation(ERP_FEDERATION_FORMAT_VERSION) + LEGACY_ERP_FEDERATION_FORMAT_VERSION, + createFederation(LEGACY_ERP_FEDERATION_FORMAT_VERSION) ); testSaveOldFederation( @@ -436,8 +436,8 @@ void saveOldFederation_before_RSKIP123_should_allow_to_save_any_fed_type() throw void saveOldFederation_after_RSKIP123_should_save_legacy_fed_format() throws IOException { activations = ActivationConfigsForTest.only(ConsensusRule.RSKIP123).forBlock(0); testSaveOldFederation( - FEDERATION_FORMAT_VERSION_MULTIKEY, - createFederation(FEDERATION_FORMAT_VERSION_MULTIKEY) + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION, + createFederation(STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION) ); } @@ -448,8 +448,8 @@ void saveOldFederation_after_RSKIP201_should_save_legacy_fed_format() throws IOE ConsensusRule.RSKIP201 ).forBlock(0); testSaveOldFederation( - FEDERATION_FORMAT_VERSION_MULTIKEY, - createFederation(FEDERATION_FORMAT_VERSION_MULTIKEY) + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION, + createFederation(STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION) ); } @@ -461,8 +461,8 @@ void saveOldFederation_after_RSKIP353_should_save_legacy_fed_format() throws IOE ConsensusRule.RSKIP353 ).forBlock(0); testSaveOldFederation( - FEDERATION_FORMAT_VERSION_MULTIKEY, - createFederation(FEDERATION_FORMAT_VERSION_MULTIKEY) + STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION, + createFederation(STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION) ); } @@ -473,8 +473,8 @@ void saveOldFederation_after_RSKIP201_should_save_erp_fed_format() throws IOExce ConsensusRule.RSKIP201 ).forBlock(0); testSaveOldFederation( - ERP_FEDERATION_FORMAT_VERSION, - createFederation(ERP_FEDERATION_FORMAT_VERSION) + LEGACY_ERP_FEDERATION_FORMAT_VERSION, + createFederation(LEGACY_ERP_FEDERATION_FORMAT_VERSION) ); } @@ -486,8 +486,8 @@ void saveOldFederation_after_RSKIP353_should_save_erp_fed_format() throws IOExce ConsensusRule.RSKIP353 ).forBlock(0); testSaveOldFederation( - ERP_FEDERATION_FORMAT_VERSION, - createFederation(ERP_FEDERATION_FORMAT_VERSION) + LEGACY_ERP_FEDERATION_FORMAT_VERSION, + createFederation(LEGACY_ERP_FEDERATION_FORMAT_VERSION) ); } @@ -551,7 +551,7 @@ void saveOldFederation_after_RSKIP123_should_save_null() throws IOException { verify(repository, times(1)).addStorageBytes( PrecompiledContracts.BRIDGE_ADDR, BridgeStorageIndexKey.OLD_FEDERATION_FORMAT_VERSION.getKey(), - BridgeSerializationUtils.serializeInteger(FEDERATION_FORMAT_VERSION_MULTIKEY) + BridgeSerializationUtils.serializeInteger(STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION) ); verify(repository, times(1)).addStorageBytes( PrecompiledContracts.BRIDGE_ADDR, @@ -613,8 +613,8 @@ private Federation createFederation(int version) { bridgeConstantsRegtest.getErpFedActivationDelay(), activations ); - case ERP_FEDERATION_FORMAT_VERSION: - return new ErpFederation( + case LEGACY_ERP_FEDERATION_FORMAT_VERSION: + return new LegacyErpFederation( members, Instant.now(), 1L, @@ -624,7 +624,7 @@ private Federation createFederation(int version) { activations ); default: - return new Federation( + return new StandardMultisigFederation( members, Instant.now(), 1L, 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 66e84c07618..8e8fd5a9301 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeStorageProviderTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeStorageProviderTest.java @@ -335,7 +335,7 @@ void getNewFederation_initialVersion() { }); try (MockedStatic bridgeSerializationUtilsMocked = mockStatic(BridgeSerializationUtils.class)) { - bridgeSerializationUtilsMocked.when(() -> BridgeSerializationUtils.deserializeFederationOnlyBtcKeys(any(byte[].class), any(NetworkParameters.class))).then((InvocationOnMock invocation) -> { + bridgeSerializationUtilsMocked.when(() -> BridgeSerializationUtils.deserializeStandardMultisigFederationOnlyBtcKeys(any(byte[].class), any(NetworkParameters.class))).then((InvocationOnMock invocation) -> { deserializeCalls.add(0); byte[] data = invocation.getArgument(0); NetworkParameters networkParameters = invocation.getArgument(1); @@ -388,8 +388,8 @@ void getNewFederation_initialVersion_nullBytes() { assertNull(storageProvider.getNewFederation()); Assertions.assertEquals(3, storageCalls.size()); - bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeFederationOnlyBtcKeys(any(byte[].class), any(NetworkParameters.class)), never()); - bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeFederation(any(byte[].class), any(NetworkParameters.class)), never()); + bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeStandardMultisigFederationOnlyBtcKeys(any(byte[].class), any(NetworkParameters.class)), never()); + bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeStandardMultisigFederation(any(byte[].class), any(NetworkParameters.class)), never()); } } @@ -402,7 +402,7 @@ void getNewFederation_multiKeyVersion() { @Test void getNewFederation_erp_fed() { Federation newFederation = buildMockFederation(100, 200, 300); - ErpFederation erpFederation = new ErpFederation( + ErpFederation erpFederation = new LegacyErpFederation( newFederation.getMembers(), newFederation.getCreationTime(), newFederation.getCreationBlockNumber(), @@ -469,12 +469,12 @@ void getNewFederation_multiKeyVersion_nullBytes() { assertNull(storageProvider.getNewFederation()); assertEquals(3, storageCalls.size()); - bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeFederationOnlyBtcKeys( + bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeStandardMultisigFederationOnlyBtcKeys( any(byte[].class), any(NetworkParameters.class)), never() ); - bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeFederation( + bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeStandardMultisigFederation( any(byte[].class), any(NetworkParameters.class)), never() @@ -546,7 +546,7 @@ void saveNewFederation_postMultiKey_RSKIP_201_active_erp_fed() { BridgeConstants bridgeConstants = config.getNetworkConstants().getBridgeConstants(); Federation newFederation = buildMockFederation(100, 200, 300); - ErpFederation erpFederation = new ErpFederation( + ErpFederation erpFederation = new LegacyErpFederation( newFederation.getMembers(), newFederation.getCreationTime(), newFederation.getCreationBlockNumber(), @@ -614,7 +614,7 @@ void getOldFederation_initialVersion() { }); try (MockedStatic bridgeSerializationUtilsMocked = mockStatic(BridgeSerializationUtils.class)) { - bridgeSerializationUtilsMocked.when(() -> BridgeSerializationUtils.deserializeFederationOnlyBtcKeys(any(byte[].class), any(NetworkParameters.class))).then((InvocationOnMock invocation) -> { + bridgeSerializationUtilsMocked.when(() -> BridgeSerializationUtils.deserializeStandardMultisigFederationOnlyBtcKeys(any(byte[].class), any(NetworkParameters.class))).then((InvocationOnMock invocation) -> { deserializeCalls.add(0); byte[] data = invocation.getArgument(0); NetworkParameters networkParameters = invocation.getArgument(1); @@ -665,8 +665,8 @@ void getOldFederation_initialVersion_nullBytes() { assertNull(storageProvider.getOldFederation()); Assertions.assertEquals(3, storageCalls.size()); - bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeFederationOnlyBtcKeys(any(byte[].class), any(NetworkParameters.class)), never()); - bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeFederation(any(byte[].class), any(NetworkParameters.class)), never()); + bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeStandardMultisigFederationOnlyBtcKeys(any(byte[].class), any(NetworkParameters.class)), never()); + bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeStandardMultisigFederation(any(byte[].class), any(NetworkParameters.class)), never()); } } @@ -680,7 +680,7 @@ void getOldFederation_multiKeyVersion() { void getOldFederation_erp_fed() { BridgeConstants bridgeConstants = config.getNetworkConstants().getBridgeConstants(); Federation oldFederation = buildMockFederation(100, 200, 300); - ErpFederation erpFederation = new ErpFederation( + ErpFederation erpFederation = new LegacyErpFederation( oldFederation.getMembers(), oldFederation.getCreationTime(), oldFederation.getCreationBlockNumber(), @@ -745,12 +745,12 @@ void getOldFederation_multiKeyVersion_nullBytes() { assertNull(storageProvider.getOldFederation()); assertEquals(3, storageCalls.size()); - bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeFederationOnlyBtcKeys( + bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeStandardMultisigFederationOnlyBtcKeys( any(byte[].class), any(NetworkParameters.class)), never() ); - bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeFederation( + bridgeSerializationUtilsMocked.verify(() -> BridgeSerializationUtils.deserializeStandardMultisigFederation( any(byte[].class), any(NetworkParameters.class)), never() @@ -820,7 +820,7 @@ void saveOldFederation_postMultikey_RSKIP_201_active_erp_fed() { BridgeConstants bridgeConstants = config.getNetworkConstants().getBridgeConstants(); Federation oldFederation = buildMockFederation(100, 200, 300); - ErpFederation erpFederation = new ErpFederation( + ErpFederation erpFederation = new LegacyErpFederation( oldFederation.getMembers(), oldFederation.getCreationTime(), oldFederation.getCreationBlockNumber(), @@ -3564,7 +3564,6 @@ void getReleaseRequestQueueSize_when_releaseRequestQueue_is_not_null() throws IO private void testGetOldFederation(Federation oldFederation) { BridgeConstants bridgeConstants = config.getNetworkConstants().getBridgeConstants(); List storageCalls = new ArrayList<>(); - List deserializeCalls = new ArrayList<>(); Repository repositoryMock = mock(Repository.class); BridgeStorageProvider storageProvider = new BridgeStorageProvider( repositoryMock, @@ -3583,34 +3582,18 @@ private void testGetOldFederation(Federation oldFederation) { if (storageCalls.size() == 1) { // First call is storage version getter Assertions.assertEquals(OLD_FEDERATION_FORMAT_VERSION.getKey(), address); - return RLP.encodeBigInteger(BigInteger.valueOf(1234)); + int federationVersion = getFederationVersion(oldFederation); + return RLP.encodeBigInteger(BigInteger.valueOf(federationVersion)); } else { // Second call is the actual storage getter Assertions.assertEquals(2, storageCalls.size()); Assertions.assertEquals(OLD_FEDERATION_KEY.getKey(), address); - return new byte[]{(byte) 0xaa}; + return BridgeSerializationUtils.serializeFederation(oldFederation); } }); - try (MockedStatic bridgeSerializationUtilsMocked = mockStatic(BridgeSerializationUtils.class)) { - bridgeSerializationUtilsMocked.when(() -> BridgeSerializationUtils.deserializeFederation( - any(byte[].class), - any(NetworkParameters.class) - )).then((InvocationOnMock invocation) -> { - deserializeCalls.add(0); - byte[] data = invocation.getArgument(0); - NetworkParameters networkParameters = invocation.getArgument(1); - // Make sure we're deserializing what just came from the repo with the correct BTC context - assertArrayEquals(new byte[]{(byte) 0xaa}, data); - assertEquals(networkParameters, bridgeConstants.getBtcParams()); - Assertions.assertEquals(networkParameters, bridgeConstants.getBtcParams()); - return oldFederation; - }); - assertEquals(oldFederation, storageProvider.getOldFederation()); assertEquals(2, storageCalls.size()); - assertEquals(1, deserializeCalls.size()); - } } private void testSaveOldFederation(Federation oldFederation, int version, ActivationConfig.ForBlock activations) { @@ -3668,7 +3651,6 @@ private void testSaveOldFederation(Federation oldFederation, int version, Activa private void testGetNewFederationPostMultiKey(Federation federation) { List storageCalls = new ArrayList<>(); - List deserializeCalls = new ArrayList<>(); Repository repositoryMock = mock(Repository.class); BridgeConstants bridgeConstants = config.getNetworkConstants().getBridgeConstants(); BridgeStorageProvider storageProvider = new BridgeStorageProvider( @@ -3691,33 +3673,18 @@ private void testGetNewFederationPostMultiKey(Federation federation) { if (storageCalls.size() == 1) { // First call is storage version getter Assertions.assertEquals(NEW_FEDERATION_FORMAT_VERSION.getKey(), address); - return RLP.encodeBigInteger(BigInteger.valueOf(1234)); + int federationVersion = getFederationVersion(federation); + return RLP.encodeBigInteger(BigInteger.valueOf(federationVersion)); } else { // Second call is the actual storage getter Assertions.assertEquals(2, storageCalls.size()); Assertions.assertEquals(NEW_FEDERATION_KEY.getKey(), address); - return new byte[]{(byte) 0xaa}; + return BridgeSerializationUtils.serializeFederation(federation); } }); - try (MockedStatic bridgeSerializationUtilsMocked = mockStatic(BridgeSerializationUtils.class)) { - bridgeSerializationUtilsMocked.when(() -> BridgeSerializationUtils.deserializeFederation( - any(byte[].class), - any(NetworkParameters.class)) - ).then((InvocationOnMock invocation) -> { - deserializeCalls.add(0); - byte[] data = invocation.getArgument(0); - NetworkParameters networkParameters = invocation.getArgument(1); - // Make sure we're deserializing what just came from the repo with the correct BTC context - assertArrayEquals(new byte[]{(byte) 0xaa}, data); - assertEquals(networkParameters, bridgeConstants.getBtcParams()); - return federation; - }); - assertEquals(federation, storageProvider.getNewFederation()); assertEquals(2, storageCalls.size()); - assertEquals(1, deserializeCalls.size()); - } } private void testSaveNewFederationPostMultiKey(Federation newFederation, int version, ActivationConfig.ForBlock activations) { @@ -3912,10 +3879,11 @@ private Address getBtcAddress(String addr) { } private Federation buildMockFederation(Integer... pks) { - return new Federation( + return new StandardMultisigFederation( FederationTestUtils.getFederationMembersFromPks(pks), Instant.ofEpochMilli(1000), - 0L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) + 1, + NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); } @@ -3932,4 +3900,17 @@ private static Repository createRepository() { TrieStore trieStore = new TrieStoreImpl(new HashMapDB()); return new MutableRepository(new MutableTrieCache(new MutableTrieImpl(trieStore, new Trie(trieStore)))); } + + private int getFederationVersion(Federation federation) { + if (federation instanceof StandardMultisigFederation) { + return BridgeStorageProvider.STANDARD_MULTISIG_FEDERATION_FORMAT_VERSION; + } + if (federation instanceof LegacyErpFederation) { + return BridgeStorageProvider.LEGACY_ERP_FEDERATION_FORMAT_VERSION; + } + if (federation instanceof P2shErpFederation) { + return BridgeStorageProvider.P2SH_ERP_FEDERATION_FORMAT_VERSION; + } + throw new IllegalArgumentException("Unknown Federation type: " + federation.getClass()); + } } 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 76e1a98cba5..5f4744eef9e 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportAddSignatureTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportAddSignatureTest.java @@ -75,7 +75,7 @@ void addSignature_fedPubKey_belongs_to_active_federation() throws Exception { ); federation1Keys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(federation1Keys), Instant.ofEpochMilli(1000L), 0L, @@ -133,7 +133,7 @@ void addSignature_fedPubKey_belongs_to_retiring_federation() throws Exception { BtcECKey.fromPrivate(Hex.decode("fa02"))); federation1Keys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation retiringFederation = new Federation( + Federation retiringFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(federation1Keys), Instant.ofEpochMilli(1000L), 0L, @@ -147,7 +147,7 @@ void addSignature_fedPubKey_belongs_to_retiring_federation() throws Exception { ); activeFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(activeFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -191,7 +191,7 @@ void addSignature_fedPubKey_no_belong_to_retiring_or_active_federation() throws ); federation1Keys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation retiringFederation = new Federation( + Federation retiringFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(federation1Keys), Instant.ofEpochMilli(1000L), 0L, @@ -205,7 +205,7 @@ void addSignature_fedPubKey_no_belong_to_retiring_or_active_federation() throws ); activeFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(activeFederationKeys), Instant.ofEpochMilli(1000L), 0L, diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportGetTransactionTypeTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportGetTransactionTypeTest.java index 8b86aaa01dd..2d8e8e8ae81 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportGetTransactionTypeTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportGetTransactionTypeTest.java @@ -49,9 +49,24 @@ class BridgeSupportGetTransactionTypeTest { void getTransactionType_sentFromP2SHErpFed() { ActivationConfig.ForBlock activations = ActivationConfigsForTest.hop400().forBlock(0); + BtcECKey federator0PublicKey = BtcECKey.fromPublicOnly(Hex.decode("03b53899c390573471ba30e5054f78376c5f797fda26dde7a760789f02908cbad2")); + BtcECKey federator1PublicKey = BtcECKey.fromPublicOnly(Hex.decode("027319afb15481dbeb3c426bcc37f9a30e7f51ceff586936d85548d9395bcc2344")); + BtcECKey federator2PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0355a2e9bf100c00fc0a214afd1bf272647c7824eb9cb055480962f0c382596a70")); + BtcECKey federator3PublicKey = BtcECKey.fromPublicOnly(Hex.decode("02566d5ded7c7db1aa7ee4ef6f76989fb42527fcfdcddcd447d6793b7d869e46f7")); + BtcECKey federator4PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0294c817150f78607566e961b3c71df53a22022a80acbb982f83c0c8baac040adc")); + BtcECKey federator5PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0372cd46831f3b6afd4c044d160b7667e8ebf659d6cb51a825a3104df6ee0638c6")); + BtcECKey federator6PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0340df69f28d69eef60845da7d81ff60a9060d4da35c767f017b0dd4e20448fb44")); + BtcECKey federator7PublicKey = BtcECKey.fromPublicOnly(Hex.decode("02ac1901b6fba2c1dbd47d894d2bd76c8ba1d296d65f6ab47f1c6b22afb53e73eb")); + BtcECKey federator8PublicKey = BtcECKey.fromPublicOnly(Hex.decode("031aabbeb9b27258f98c2bf21f36677ae7bae09eb2d8c958ef41a20a6e88626d26")); + List standardKeys = Arrays.asList( + federator0PublicKey, federator1PublicKey, federator2PublicKey, + federator3PublicKey, federator4PublicKey, federator5PublicKey, + federator6PublicKey, federator7PublicKey, federator8PublicKey + ); + // Arrange Federation activeFederation = new P2shErpFederation( - bridgeMainnetConstants.getGenesisFederation().getMembers(), + FederationTestUtils.getFederationMembersWithBtcKeys(standardKeys), bridgeMainnetConstants.getGenesisFederation().getCreationTime(), 5L, bridgeMainnetConstants.getGenesisFederation().getBtcParams(), @@ -128,7 +143,7 @@ void getTransactionType_sentFromOldFed(ActivationConfig.ForBlock activations, Pe .withProvider(provider) .build(); - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( bridgeRegTestConstants.getGenesisFederation().getMembers(), bridgeRegTestConstants.getGenesisFederation().getCreationTime(), 5L, @@ -258,7 +273,7 @@ void getTransactionType_pegout_tx() { new String[]{"fa01", "fa02", "fa03"}, true ); - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(fedKeys), Instant.ofEpochMilli(1000L), 0L, @@ -304,7 +319,7 @@ void getTransactionType_migration_tx() { new String[]{"fa01", "fa02", "fa03"}, true );; - Federation retiringFederation = new Federation( + Federation retiringFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiringFedKeys), Instant.ofEpochMilli(1000L), 0L, 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 10133a00253..6f1a565d7d3 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportProcessFundsMigrationTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportProcessFundsMigrationTest.java @@ -127,7 +127,7 @@ void test_processFundsMigration( federationActivationAge + bridgeConstants.getFundsMigrationAgeSinceActivationEnd(activations) + 1; - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(1), Instant.EPOCH, federationCreationBlockNumber, 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 11a4cbaaa28..35cfde10491 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportReleaseBtcTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportReleaseBtcTest.java @@ -1250,7 +1250,7 @@ private static Repository createRepository() { } private static Federation getFederation() { - return new Federation( + return new StandardMultisigFederation( FederationTestUtils.getFederationMembers(3), Instant.ofEpochMilli(1000), 0L, 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 3a4457a91b6..7576c1c34b7 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTest.java @@ -970,7 +970,7 @@ void registerBtcTransactionLockTxNotWhitelisted_before_rskip_146_activation() th BtcECKey.fromPrivate(Hex.decode("fa02")) ); - Federation federation1 = new Federation( + Federation federation1 = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(federation1Keys), Instant.ofEpochMilli(1000L), 0L, @@ -983,7 +983,7 @@ void registerBtcTransactionLockTxNotWhitelisted_before_rskip_146_activation() th BtcECKey.fromPrivate(Hex.decode("fb02")), BtcECKey.fromPrivate(Hex.decode("fb03"))); - Federation federation2 = new Federation( + Federation federation2 = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(federation2Keys), Instant.ofEpochMilli(2000L), 0L, @@ -1140,7 +1140,7 @@ void registerBtcTransactionLockTxNotWhitelisted_after_rskip_146_activation() thr BtcECKey.fromPrivate(Hex.decode("fa02")) ); - Federation federation1 = new Federation( + Federation federation1 = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(federation1Keys), Instant.ofEpochMilli(1000L), 0L, @@ -1153,7 +1153,7 @@ void registerBtcTransactionLockTxNotWhitelisted_after_rskip_146_activation() thr BtcECKey.fromPrivate(Hex.decode("fb02")), BtcECKey.fromPrivate(Hex.decode("fb03"))); - Federation federation2 = new Federation( + Federation federation2 = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(federation2Keys), Instant.ofEpochMilli(2000L), 0L, @@ -1324,7 +1324,7 @@ void registerBtcTransaction_sending_segwit_tx_twice_locks_just_once() throws Blo BtcECKey.fromPrivate(Hex.decode("fa02")) ); - Federation fed = new Federation( + Federation fed = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(fedKeys), Instant.ofEpochMilli(1000L), 0L, @@ -1416,7 +1416,7 @@ void callProcessFundsMigration_is_migrating_before_rskip_146_activation() throws Federation oldFederation = bridgeConstantsRegtest.getGenesisFederation(); - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(1), Instant.EPOCH, 5L, @@ -1479,7 +1479,7 @@ void callProcessFundsMigration_is_migrating_after_rskip_146_activation() throws Federation oldFederation = bridgeConstantsRegtest.getGenesisFederation(); - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(1), Instant.EPOCH, 5L, @@ -1544,7 +1544,7 @@ void callProcessFundsMigration_is_migrated_before_rskip_146_activation() throws Federation oldFederation = bridgeConstantsRegtest.getGenesisFederation(); - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(1), Instant.EPOCH, 5L, @@ -1607,7 +1607,7 @@ void callProcessFundsMigration_is_migrated_after_rskip_146_activation() throws I Federation oldFederation = bridgeConstantsRegtest.getGenesisFederation(); - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(1), Instant.EPOCH, 5L, @@ -1671,7 +1671,7 @@ void updateFederationCreationBlockHeights_before_rskip_186_activation() throws I Federation oldFederation = bridgeConstantsRegtest.getGenesisFederation(); - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(1), Instant.EPOCH, 5L, @@ -1734,7 +1734,7 @@ void updateFederationCreationBlockHeights_after_rskip_186_activation() throws IO Federation oldFederation = bridgeConstantsRegtest.getGenesisFederation(); - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(1), Instant.EPOCH, 5L, @@ -2115,7 +2115,7 @@ void rskTxWaitingForSignature_fail_adding_an_already_existing_key_after_rskip_37 // Set state to make concur a pegout migration tx and pegout batch creation on the same updateCollection Federation oldFederation = bridgeConstants.getGenesisFederation(); - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(1), Instant.EPOCH, 5L, @@ -6410,13 +6410,13 @@ private void test_migrating_many_utxos(boolean isRskip294Active, int utxosToCrea oldFedMembers.add(FederationMember.getFederationMemberFromKey(new BtcECKey())); } - Federation oldFed = new Federation( + Federation oldFed = new StandardMultisigFederation( oldFedMembers, Instant.now(), 0, btcRegTestParams ); - Federation newFed = new Federation( + Federation newFed = new StandardMultisigFederation( Arrays.asList( FederationMember.getFederationMemberFromKey(new BtcECKey()), FederationMember.getFederationMemberFromKey(new BtcECKey()), 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 a7e4d2663a2..c49937c0e45 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestIntegration.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeSupportTestIntegration.java @@ -584,7 +584,7 @@ void minimumProcessFundsMigrationValue() throws IOException { Federation oldFederation = bridgeConstants.getGenesisFederation(); BtcECKey key = new BtcECKey(new SecureRandom()); FederationMember member = new FederationMember(key, new ECKey(), new ECKey()); - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( Collections.singletonList(member), Instant.EPOCH, 5L, @@ -1346,14 +1346,14 @@ void registerBtcTransactionMigrationTx() throws BlockStoreException, AddressForm BtcECKey.fromPrivate(Hex.decode("fa02")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation activeFederation = new Federation(FederationTestUtils.getFederationMembersWithBtcKeys(activeFederationKeys), Instant.ofEpochMilli(2000L), 2L, parameters); + Federation activeFederation = new StandardMultisigFederation(FederationTestUtils.getFederationMembersWithBtcKeys(activeFederationKeys), Instant.ofEpochMilli(2000L), 2L, parameters); List retiringFederationKeys = Stream.of( BtcECKey.fromPrivate(Hex.decode("fb01")), BtcECKey.fromPrivate(Hex.decode("fb02")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation retiringFederation = new Federation(FederationTestUtils.getFederationMembersWithBtcKeys(retiringFederationKeys), Instant.ofEpochMilli(1000L), 1L, parameters); + Federation retiringFederation = new StandardMultisigFederation(FederationTestUtils.getFederationMembersWithBtcKeys(retiringFederationKeys), Instant.ofEpochMilli(1000L), 1L, parameters); Repository repository = createRepository(); repository.addBalance(PrecompiledContracts.BRIDGE_ADDR, LIMIT_MONETARY_BASE); @@ -1459,7 +1459,7 @@ void registerBtcTransactionWithCrossFederationsChange() throws Exception { .map(BtcECKey::fromPrivate) .sorted(BtcECKey.PUBKEY_COMPARATOR) .collect(Collectors.toList()); - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(activeFederationKeys), Instant.ofEpochMilli(1000L), 0L, params ); @@ -1469,7 +1469,7 @@ void registerBtcTransactionWithCrossFederationsChange() throws Exception { .map(BtcECKey::fromPrivate) .sorted(BtcECKey.PUBKEY_COMPARATOR) .collect(Collectors.toList()); - Federation retiringFederation = new Federation( + Federation retiringFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiringFederationKeys), Instant.ofEpochMilli(2000L), 0L, params ); @@ -1566,7 +1566,7 @@ void registerBtcTransactionLockTxWhitelisted() throws Exception { }); federation1Keys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation federation1 = new Federation(FederationTestUtils.getFederationMembersWithBtcKeys(federation1Keys), Instant.ofEpochMilli(1000L), 0L, btcParams); + Federation federation1 = new StandardMultisigFederation(FederationTestUtils.getFederationMembersWithBtcKeys(federation1Keys), Instant.ofEpochMilli(1000L), 0L, btcParams); List federation2Keys = Arrays.asList(new BtcECKey[]{ BtcECKey.fromPrivate(Hex.decode("fb01")), @@ -1575,7 +1575,7 @@ void registerBtcTransactionLockTxWhitelisted() throws Exception { }); federation2Keys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation federation2 = new Federation(FederationTestUtils.getFederationMembersWithBtcKeys(federation2Keys), Instant.ofEpochMilli(2000L), 0L, btcParams); + Federation federation2 = new StandardMultisigFederation(FederationTestUtils.getFederationMembersWithBtcKeys(federation2Keys), Instant.ofEpochMilli(2000L), 0L, btcParams); Repository repository = createRepository(); repository.addBalance(PrecompiledContracts.BRIDGE_ADDR, LIMIT_MONETARY_BASE); @@ -1726,13 +1726,13 @@ void getBtcTxHashProcessedHeight() throws IOException, BlockStoreException { @Test void getFederationMethods_genesis() throws IOException { - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(3), Instant.ofEpochMilli(1000), 0L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); - Federation genesisFederation = new Federation( + Federation genesisFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(6), Instant.ofEpochMilli(1000), 0L, @@ -1754,13 +1754,13 @@ void getFederationMethods_genesis() throws IOException { @Test void getFederationMethods_active() throws IOException { - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(3), Instant.ofEpochMilli(1000), 0L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); - Federation genesisFederation = new Federation( + Federation genesisFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(6), Instant.ofEpochMilli(1000), 0L, @@ -1790,13 +1790,13 @@ void getFederationMethods_active() throws IOException { @Test void getFederationMethods_newActivated() throws IOException { - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(3), Instant.ofEpochMilli(1000), 15L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); - Federation oldFederation = new Federation( + Federation oldFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(6), Instant.ofEpochMilli(1000), 0L, @@ -1830,13 +1830,13 @@ void getFederationMethods_newActivated() throws IOException { @Test void getFederationMethods_newNotActivated() throws IOException { - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(3), Instant.ofEpochMilli(1000), 15L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); - Federation oldFederation = new Federation( + Federation oldFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(6), Instant.ofEpochMilli(1000), 0L, @@ -1883,14 +1883,14 @@ void getRetiringFederationMethods_none() throws IOException { @Test void getRetiringFederationMethods_presentNewInactive() throws IOException { - Federation mockedNewFederation = new Federation( + Federation mockedNewFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(2), Instant.ofEpochMilli(2000), 10L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); - Federation mockedOldFederation = new Federation( + Federation mockedOldFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(4), Instant.ofEpochMilli(1000), 0L, @@ -1920,14 +1920,14 @@ void getRetiringFederationMethods_presentNewInactive() throws IOException { @Test void getRetiringFederationMethods_presentNewActive() throws IOException { - Federation mockedNewFederation = new Federation( + Federation mockedNewFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(2), Instant.ofEpochMilli(2000), 10L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); - Federation mockedOldFederation = new Federation( + Federation mockedOldFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(4), Instant.ofEpochMilli(1000), 0L, @@ -2137,14 +2137,14 @@ void createFederation_pendingExists() throws IOException, BridgeIllegalArgumentE void createFederation_withPendingActivation() throws IOException, BridgeIllegalArgumentException { VotingMocksProvider mocksProvider = new VotingMocksProvider("create", new byte[][]{}, false); - Federation mockedNewFederation = new Federation( + Federation mockedNewFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(2), Instant.ofEpochMilli(2000), 10L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); - Federation mockedOldFederation = new Federation( + Federation mockedOldFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(4), Instant.ofEpochMilli(1000), 0L, @@ -2178,14 +2178,14 @@ void createFederation_withPendingActivation() throws IOException, BridgeIllegalA void createFederation_withExistingRetiringFederation() throws IOException, BridgeIllegalArgumentException { VotingMocksProvider mocksProvider = new VotingMocksProvider("create", new byte[][]{}, false); - Federation mockedNewFederation = new Federation( + Federation mockedNewFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(2), Instant.ofEpochMilli(2000), 10L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); - Federation mockedOldFederation = new Federation( + Federation mockedOldFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(4), Instant.ofEpochMilli(1000), 0L, @@ -2722,14 +2722,14 @@ void commitFederation_ok() throws IOException, BridgeIllegalArgumentException { when(executionBlock.getTimestamp()).thenReturn(15005L); when(executionBlock.getNumber()).thenReturn(15L); - Federation expectedFederation = new Federation(FederationTestUtils.getFederationMembersWithKeys(Arrays.asList( + Federation expectedFederation = new StandardMultisigFederation(FederationTestUtils.getFederationMembersWithKeys(Arrays.asList( BtcECKey.fromPublicOnly(Hex.decode("036bb9eab797eadc8b697f0e82a01d01cabbfaaca37e5bafc06fdc6fdd38af894a")), BtcECKey.fromPublicOnly(Hex.decode("031da807c71c2f303b7f409dd2605b297ac494a563be3b9ca5f52d95a43d183cc5")), BtcECKey.fromPublicOnly(Hex.decode("025eefeeeed5cdc40822880c7db1d0a88b7b986945ed3fc05a0b45fe166fe85e12")), BtcECKey.fromPublicOnly(Hex.decode("03c67ad63527012fd4776ae892b5dc8c56f80f1be002dc65cd520a2efb64e37b49")))), Instant.ofEpochMilli(15005L), 15L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST)); - Federation newFederation = new Federation(FederationTestUtils.getFederationMembersWithKeys(Arrays.asList( + Federation newFederation = new StandardMultisigFederation(FederationTestUtils.getFederationMembersWithKeys(Arrays.asList( BtcECKey.fromPublicOnly(Hex.decode("0346cb6b905e4dee49a862eeb2288217d06afcd4ace4b5ca77ebedfbc6afc1c19d")), BtcECKey.fromPublicOnly(Hex.decode("0269a0dbe7b8f84d1b399103c466fb20531a56b1ad3a7b44fe419e74aad8c46db7")), BtcECKey.fromPublicOnly(Hex.decode("026192d8ab41bd402eb0431457f6756a3f3ce15c955c534d2b87f1e0372d8ba338")))), @@ -2876,7 +2876,7 @@ void commitFederation_hashMismatch() throws IOException, BridgeIllegalArgumentEx @Test void getActiveFederationWallet() throws IOException { - Federation expectedFederation = new Federation(FederationTestUtils.getFederationMembersWithBtcKeys(Arrays.asList(new BtcECKey[]{ + Federation expectedFederation = new StandardMultisigFederation(FederationTestUtils.getFederationMembersWithBtcKeys(Arrays.asList(new BtcECKey[]{ BtcECKey.fromPublicOnly(Hex.decode("036bb9eab797eadc8b697f0e82a01d01cabbfaaca37e5bafc06fdc6fdd38af894a")), BtcECKey.fromPublicOnly(Hex.decode("031da807c71c2f303b7f409dd2605b297ac494a563be3b9ca5f52d95a43d183cc5")) })), Instant.ofEpochMilli(5005L), 0L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST)); @@ -2909,14 +2909,14 @@ void getActiveFederationWallet() throws IOException { @Test void getRetiringFederationWallet_nonEmpty() throws IOException { - Federation mockedNewFederation = new Federation( + Federation mockedNewFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(2), Instant.ofEpochMilli(2000), 10L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); - Federation expectedFederation = new Federation(FederationTestUtils.getFederationMembersWithBtcKeys(Arrays.asList(new BtcECKey[]{ + Federation expectedFederation = new StandardMultisigFederation(FederationTestUtils.getFederationMembersWithBtcKeys(Arrays.asList(new BtcECKey[]{ BtcECKey.fromPublicOnly(Hex.decode("036bb9eab797eadc8b697f0e82a01d01cabbfaaca37e5bafc06fdc6fdd38af894a")), BtcECKey.fromPublicOnly(Hex.decode("031da807c71c2f303b7f409dd2605b297ac494a563be3b9ca5f52d95a43d183cc5")) })), Instant.ofEpochMilli(5005L), 0L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST)); @@ -3745,7 +3745,7 @@ private BridgeSupport getBridgeSupportWithMocksForFederationTests( BridgeEventLogger eventLogger) throws IOException { BridgeConstants constantsMock = mock(BridgeConstants.class); - when(constantsMock.getGenesisFederation()).thenReturn(mockedGenesisFederation); + when(constantsMock.getGenesisFederation()).thenReturn((StandardMultisigFederation) mockedGenesisFederation); when(constantsMock.getBtcParams()).thenReturn(NetworkParameters.fromID(NetworkParameters.ID_REGTEST)); when(constantsMock.getFederationChangeAuthorizer()).thenReturn(bridgeConstants.getFederationChangeAuthorizer()); diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeTest.java index e073d92caee..2bfee1299fc 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeTest.java @@ -238,7 +238,7 @@ void registerBtcTransaction_beforeRskip199_rejectsExternalCalls() ActivationConfig activations = spy(ActivationConfigsForTest.genesis()); doReturn(false).when(activations).isActive(eq(RSKIP199), anyLong()); - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(3), Instant.ofEpochMilli(1000), 0L, @@ -284,7 +284,7 @@ void registerBtcTransaction_beforeRskip199_acceptsCallFromFederationMember() List federationKeys = Arrays.asList(fed1Key, new BtcECKey(), new BtcECKey()); federationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithKeys(federationKeys), Instant.ofEpochMilli(1000), 0L, diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeUtilsLegacyTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeUtilsLegacyTest.java index 61c25b21ae1..5f59ad6f9f3 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeUtilsLegacyTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeUtilsLegacyTest.java @@ -456,7 +456,7 @@ void calculatePegoutTxSize_before_rskip_271() { when(activations.isActive(ConsensusRule.RSKIP271)).thenReturn(false); List keys = PegTestUtils.createRandomBtcECKeys(13); - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(keys), Instant.now(), 0, @@ -478,7 +478,7 @@ void calculatePegoutTxSize_after_rskip_271() { when(activations.isActive(ConsensusRule.RSKIP271)).thenReturn(true); List keys = PegTestUtils.createRandomBtcECKeys(13); - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(keys), Instant.now(), 0, @@ -493,7 +493,7 @@ void calculatePegoutTxSize_ZeroInput_ZeroOutput() { when(activations.isActive(ConsensusRule.RSKIP271)).thenReturn(false); List keys = PegTestUtils.createRandomBtcECKeys(13); - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(keys), Instant.now(), 0, diff --git a/rskj-core/src/test/java/co/rsk/peg/BridgeUtilsTest.java b/rskj-core/src/test/java/co/rsk/peg/BridgeUtilsTest.java index faed33c78a1..c7ae74957fc 100644 --- a/rskj-core/src/test/java/co/rsk/peg/BridgeUtilsTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/BridgeUtilsTest.java @@ -249,7 +249,7 @@ void testIsValidPegInTxForTwoFederations() { BtcECKey.fromPrivate(Hex.decode("fa02")) ); federation1Keys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation federation1 = new Federation( + Federation federation1 = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(federation1Keys), Instant.ofEpochMilli(1000L), 0L, @@ -262,7 +262,7 @@ void testIsValidPegInTxForTwoFederations() { BtcECKey.fromPrivate(Hex.decode("fb03")) ); federation2Keys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation federation2 = new Federation( + Federation federation2 = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(federation2Keys), Instant.ofEpochMilli(2000L), 0L, @@ -574,7 +574,7 @@ void testIsValidPegInTx_hasChangeUtxoFromFlyoverErpFederation_beforeRskip201_isP BtcECKey.fromPrivate(Hex.decode("fa02")) ); erpFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation erpFederation = new Federation( + Federation erpFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(erpFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -616,7 +616,7 @@ void testIsValidPegInTx_hasChangeUtxoFromFlyoverErpFederation_afterRskip201_notP BtcECKey.fromPrivate(Hex.decode("fa02")) ); erpFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation erpFederation = new Federation( + Federation erpFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(erpFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -658,7 +658,7 @@ void testIsValidPegInTx_hasChangeUtxoFromErpFederation_beforeRskip201_isPegin() BtcECKey.fromPrivate(Hex.decode("fa02")) ); erpFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation erpFederation = new Federation( + Federation erpFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(erpFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -691,7 +691,7 @@ void testIsValidPegInTx_hasChangeUtxoFromErpFederation_afterRskip201_notPegin() BtcECKey.fromPrivate(Hex.decode("fa02")) ); erpFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation erpFederation = new Federation( + Federation erpFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(erpFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -724,7 +724,7 @@ void testIsValidPegInTx_hasChangeUtxoFromFlyoverRetiredFederation_beforeRskip201 BtcECKey.fromPrivate(Hex.decode("fa02")) ); retiredFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation retiredFederation = new Federation( + Federation retiredFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -769,7 +769,7 @@ void testIsValidPegInTx_hasChangeUtxoFromFlyoverRetiredFederation_afterRskip201_ BtcECKey.fromPrivate(Hex.decode("fa02")) ); retiredFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation retiredFederation = new Federation( + Federation retiredFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -814,7 +814,7 @@ void testIsValidPegInTx_hasChangeUtxoFromFlyoverErpRetiredFederation_beforeRskip BtcECKey.fromPrivate(Hex.decode("fa02")) ); retiredFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation retiredFederation = new Federation( + Federation retiredFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -827,7 +827,7 @@ void testIsValidPegInTx_hasChangeUtxoFromFlyoverErpRetiredFederation_beforeRskip ); erpFederationPublicKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation erpFederation = new ErpFederation( + Federation erpFederation = new LegacyErpFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -875,7 +875,7 @@ void testIsValidPegInTx_hasChangeUtxoFromFlyoverErpRetiredFederation_afterRskip2 BtcECKey.fromPrivate(Hex.decode("fa02")) ); retiredFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation retiredFederation = new Federation( + Federation retiredFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -888,7 +888,7 @@ void testIsValidPegInTx_hasChangeUtxoFromFlyoverErpRetiredFederation_afterRskip2 ); erpFederationPublicKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation erpFederation = new ErpFederation( + Federation erpFederation = new LegacyErpFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -935,7 +935,7 @@ void testIsValidPegInTx_hasChangeUtxoFromErpRetiredFederation_beforeRskip201_isP BtcECKey.fromPrivate(Hex.decode("fa02")) ); retiredFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation retiredFederation = new Federation( + Federation retiredFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -948,7 +948,7 @@ void testIsValidPegInTx_hasChangeUtxoFromErpRetiredFederation_beforeRskip201_isP ); erpFederationPublicKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation erpFederation = new ErpFederation( + Federation erpFederation = new LegacyErpFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -991,7 +991,7 @@ void testIsValidPegInTx_hasChangeUtxoFromErpRetiredFederation_afterRskip201_notP BtcECKey.fromPrivate(Hex.decode("fa02")) ); retiredFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation retiredFederation = new Federation( + Federation retiredFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -1004,7 +1004,7 @@ void testIsValidPegInTx_hasChangeUtxoFromErpRetiredFederation_afterRskip201_notP ); erpFederationPublicKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation erpFederation = new ErpFederation( + Federation erpFederation = new LegacyErpFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -1308,7 +1308,7 @@ void testIsMigrationTx_sending_funds_from_retired_p2sh_fed_to_active_p2sh_fed() BtcECKey.fromPrivate(Hex.decode("fc02")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation retiredFederation = new P2shErpFederation( + ErpFederation retiredFederation = new P2shErpFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 1L, @@ -1438,7 +1438,7 @@ void testIsMigrationTx_sending_funds_from_retired_standard_fed_to_active_p2sh_fe BtcECKey.fromPrivate(Hex.decode("fc02")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation retiredFederation = new Federation( + Federation retiredFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 1L, @@ -1487,7 +1487,7 @@ void testIsMigrationTx_sending_funds_from_retired_standard_fed_to_active_p2sh_fe migrationTx, activeFederation, null, - retiredFederation.getStandardP2SHScript(), + retiredFederation.getP2SHScript(), btcContext, bridgeConstantsMainnet, activations @@ -1505,7 +1505,7 @@ void testIsMigrationTx_sending_funds_from_retiring_standard_fed_to_active_p2sh_f BtcECKey.fromPrivate(Hex.decode("fc02")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation retiringFederation = new Federation( + Federation retiringFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiringFederationKeys), Instant.ofEpochMilli(1000L), 1L, @@ -1562,7 +1562,7 @@ void testIsMigrationTx_sending_funds_from_retired_standard_fed_to_active_standar BtcECKey.fromPrivate(Hex.decode("fc02")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation retiredFederation = new Federation( + Federation retiredFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 1L, @@ -1574,7 +1574,7 @@ void testIsMigrationTx_sending_funds_from_retired_standard_fed_to_active_standar BtcECKey.fromPrivate(Hex.decode("fa02")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(activeFederationKeys), Instant.ofEpochMilli(1000L), 1L, @@ -1598,7 +1598,7 @@ void testIsMigrationTx_sending_funds_from_retired_standard_fed_to_active_standar migrationTx, activeFederation, null, - retiredFederation.getStandardP2SHScript(), + retiredFederation.getP2SHScript(), btcContext, bridgeConstantsMainnet, activations @@ -1626,7 +1626,7 @@ void testIsMigrationTx_sending_funds_from_retiring_standard_fed_to_active_standa BtcECKey.fromPrivate(Hex.decode("fc02")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation retiringFederation = new Federation( + Federation retiringFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiringFederationKeys), Instant.ofEpochMilli(1000L), 1L, @@ -1638,7 +1638,7 @@ void testIsMigrationTx_sending_funds_from_retiring_standard_fed_to_active_standa BtcECKey.fromPrivate(Hex.decode("fa02")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(activeFederationKeys), Instant.ofEpochMilli(1000L), 1L, @@ -1677,7 +1677,7 @@ void testIsMigrationTx() { BtcECKey.fromPrivate(Hex.decode("fa01")), BtcECKey.fromPrivate(Hex.decode("fa02")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation activeFederation = new Federation( + Federation activeFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(activeFederationKeys), Instant.ofEpochMilli(2000L), 2L, @@ -1689,7 +1689,7 @@ void testIsMigrationTx() { BtcECKey.fromPrivate(Hex.decode("fb02")), BtcECKey.fromPrivate(Hex.decode("fb03")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation retiringFederation = new Federation( + Federation retiringFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiringFederationKeys), Instant.ofEpochMilli(1000L), 1L, @@ -1700,7 +1700,7 @@ void testIsMigrationTx() { BtcECKey.fromPrivate(Hex.decode("fc01")), BtcECKey.fromPrivate(Hex.decode("fc02")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation retiredFederation = new Federation( + Federation retiredFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(retiredFederationKeys), Instant.ofEpochMilli(1000L), 1L, @@ -1831,7 +1831,7 @@ void testIsPegOutTx() { BtcECKey.fromPrivate(Hex.decode("fa02")), BtcECKey.fromPrivate(Hex.decode("fa03")) ).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - Federation federation2 = new Federation( + Federation federation2 = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(activeFederationKeys), Instant.ofEpochMilli(2000L), 2L, @@ -1868,7 +1868,7 @@ void testIsPegOutTx_fromFlyoverFederation() { BtcECKey.fromPrivate(Hex.decode("fa03")) ); flyoverFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation flyoverFederation = new Federation( + Federation flyoverFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(flyoverFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -1926,7 +1926,7 @@ void testIsPegOutTx_fromErpFederation() { BtcECKey.fromPrivate(Hex.decode("fa03")) ); defaultFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation defaultFederation = new Federation( + Federation defaultFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(defaultFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -1940,7 +1940,7 @@ void testIsPegOutTx_fromErpFederation() { ); erpFederationPublicKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation erpFederation = new ErpFederation( + ErpFederation erpFederation = new LegacyErpFederation( FederationTestUtils.getFederationMembersWithBtcKeys(defaultFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -2002,7 +2002,7 @@ void testIsPegOutTx_fromFlyoverErpFederation() { BtcECKey.fromPrivate(Hex.decode("fa03")) ); defaultFederationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation defaultFederation = new Federation( + Federation defaultFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(defaultFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -2016,7 +2016,7 @@ void testIsPegOutTx_fromFlyoverErpFederation() { ); erpFederationPublicKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation erpFederation = new ErpFederation( + Federation erpFederation = new LegacyErpFederation( FederationTestUtils.getFederationMembersWithBtcKeys(defaultFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -2116,7 +2116,7 @@ void testChangeBetweenFederations() { .map(BtcECKey::fromPrivate) .sorted(BtcECKey.PUBKEY_COMPARATOR) .collect(Collectors.toList()); - Federation federation1 = new Federation( + Federation federation1 = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(federation1Keys), Instant.ofEpochMilli(1000L), 0L, networkParameters ); @@ -2126,7 +2126,7 @@ void testChangeBetweenFederations() { .map(BtcECKey::fromPrivate) .sorted(BtcECKey.PUBKEY_COMPARATOR) .collect(Collectors.toList()); - Federation federation2 = new Federation( + Federation federation2 = new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(federation2Keys), Instant.ofEpochMilli(2000L), 0L, networkParameters ); @@ -2536,7 +2536,7 @@ void isInputSignedByThisFederator_isSigned() { // Arrange BtcECKey federator1Key = new BtcECKey(); BtcECKey federator2Key = new BtcECKey(); - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(Arrays.asList(federator1Key, federator2Key)), Instant.now(), 0, @@ -2584,7 +2584,7 @@ void isInputSignedByThisFederator_isSignedByAnotherFederator() { // Arrange BtcECKey federator1Key = new BtcECKey(); BtcECKey federator2Key = new BtcECKey(); - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(Arrays.asList(federator1Key, federator2Key)), Instant.now(), 0, @@ -2632,7 +2632,7 @@ void isInputSignedByThisFederator_notSigned() { // Arrange BtcECKey federator1Key = new BtcECKey(); BtcECKey federator2Key = new BtcECKey(); - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(Arrays.asList(federator1Key, federator2Key)), Instant.now(), 0, @@ -2978,7 +2978,7 @@ void testCalculatePegoutTxSize_ZeroInput_ZeroOutput() { when(activations.isActive(ConsensusRule.RSKIP271)).thenReturn(true); List keys = PegTestUtils.createRandomBtcECKeys(13); - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(keys), Instant.now(), 0, @@ -2994,7 +2994,7 @@ void testCalculatePegoutTxSize_2Inputs_2Outputs() { when(activations.isActive(ConsensusRule.RSKIP271)).thenReturn(true); List keys = PegTestUtils.createRandomBtcECKeys(13); - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(keys), Instant.now(), 0, @@ -3019,7 +3019,7 @@ void testCalculatePegoutTxSize_9Inputs_2Outputs() { when(activations.isActive(ConsensusRule.RSKIP271)).thenReturn(true); List keys = PegTestUtils.createRandomBtcECKeys(13); - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(keys), Instant.now(), 0, @@ -3044,7 +3044,7 @@ void testCalculatePegoutTxSize_10Inputs_20Outputs() { when(activations.isActive(ConsensusRule.RSKIP271)).thenReturn(true); List keys = PegTestUtils.createRandomBtcECKeys(13); - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(keys), Instant.now(), 0, @@ -3072,7 +3072,7 @@ void testCalculatePegoutTxSize_50Inputs_200Outputs() { when(activations.isActive(ConsensusRule.RSKIP271)).thenReturn(true); List keys = PegTestUtils.createRandomBtcECKeys(13); - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(keys), Instant.now(), 0, @@ -3113,7 +3113,7 @@ void testCalculatePegoutTxSize_50Inputs_200Outputs_erpFederation() { ); erpFederationPublicKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation erpFederation = new ErpFederation( + Federation erpFederation = new LegacyErpFederation( FederationTestUtils.getFederationMembersWithBtcKeys(defaultFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -3157,7 +3157,7 @@ void testCalculatePegoutTxSize_100Inputs_50Outputs_erpFederation() { ); erpFederationPublicKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - Federation erpFederation = new ErpFederation( + Federation erpFederation = new LegacyErpFederation( FederationTestUtils.getFederationMembersWithBtcKeys(defaultFederationKeys), Instant.ofEpochMilli(1000L), 0L, @@ -3191,7 +3191,7 @@ void getRegularPegoutTxSize_has_proper_calculations() { BtcECKey key2 = new BtcECKey(); BtcECKey key3 = new BtcECKey(); List keys = Arrays.asList(key1, key2, key3); - Federation fed = new Federation( + Federation fed = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(keys), Instant.now(), 0, @@ -3274,7 +3274,7 @@ void scriptCorrectlySpends_invalidScript() { } private void test_getSpendWallet(boolean isFlyoverCompatible) throws UTXOProviderException { - Federation federation = new Federation(FederationTestUtils.getFederationMembersWithBtcKeys(Arrays.asList( + Federation federation = new StandardMultisigFederation(FederationTestUtils.getFederationMembersWithBtcKeys(Arrays.asList( BtcECKey.fromPublicOnly(Hex.decode("036bb9eab797eadc8b697f0e82a01d01cabbfaaca37e5bafc06fdc6fdd38af894a")), BtcECKey.fromPublicOnly(Hex.decode("031da807c71c2f303b7f409dd2605b297ac494a563be3b9ca5f52d95a43d183cc5")))), Instant.ofEpochMilli(5005L), @@ -3305,7 +3305,7 @@ private void test_getSpendWallet(boolean isFlyoverCompatible) throws UTXOProvide } private void test_getNoSpendWallet(boolean isFlyoverCompatible) { - Federation federation = new Federation(FederationTestUtils.getFederationMembersWithBtcKeys(Arrays.asList( + Federation federation = new StandardMultisigFederation(FederationTestUtils.getFederationMembersWithBtcKeys(Arrays.asList( BtcECKey.fromPublicOnly(Hex.decode("036bb9eab797eadc8b697f0e82a01d01cabbfaaca37e5bafc06fdc6fdd38af894a")), BtcECKey.fromPublicOnly(Hex.decode("031da807c71c2f303b7f409dd2605b297ac494a563be3b9ca5f52d95a43d183cc5")))), Instant.ofEpochMilli(5005L), @@ -3534,7 +3534,7 @@ private Genesis getGenesisInstance(TrieStore trieStore) { private ErpFederation createErpFederation() { Federation genesisFederation = bridgeConstantsRegtest.getGenesisFederation(); - return new ErpFederation( + return new LegacyErpFederation( genesisFederation.getMembers(), genesisFederation.getCreationTime(), genesisFederation.getCreationBlockNumber(), diff --git a/rskj-core/src/test/java/co/rsk/peg/FederationSupportTest.java b/rskj-core/src/test/java/co/rsk/peg/FederationSupportTest.java index 42d49ae32b4..e6ae63a464f 100644 --- a/rskj-core/src/test/java/co/rsk/peg/FederationSupportTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/FederationSupportTest.java @@ -22,6 +22,7 @@ import co.rsk.config.BridgeConstants; import co.rsk.config.BridgeMainNetConstants; import co.rsk.config.BridgeTestNetConstants; +import co.rsk.peg.bitcoin.BitcoinTestUtils; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; @@ -87,6 +88,7 @@ void whenOldFederationIsNullThenActiveFederationIsNewFederation() { when(provider.getOldFederation()) .thenReturn(null); + assertThat(federationSupport.getActiveFederation(), is(newFederation)); } @@ -165,7 +167,7 @@ void getFederatorPublicKeys() { ECKey rskKey1 = new ECKey(); ECKey mstKey1 = new ECKey(); - Federation theFederation = new Federation( + Federation theFederation = new StandardMultisigFederation( Arrays.asList( new FederationMember(btcKey0, rskKey0, mstKey0), new FederationMember(btcKey1, rskKey1, mstKey1) @@ -235,8 +237,14 @@ void getMemberPublicKeyOfType_OutOfBounds() { } private Federation getNewFakeFederation(long creationBlockNumber) { - return new Federation( - Collections.emptyList(), Instant.ofEpochMilli(123), + List keys = BitcoinTestUtils.getBtcEcKeysFromSeeds( + new String[]{"fed1", "fed2"}, + true + ); + List members = FederationTestUtils.getFederationMembersWithBtcKeys(keys); + + return new StandardMultisigFederation( + members, Instant.ofEpochMilli(123), creationBlockNumber, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); } diff --git a/rskj-core/src/test/java/co/rsk/peg/FederationTest.java b/rskj-core/src/test/java/co/rsk/peg/FederationTest.java deleted file mode 100644 index 5344712c00b..00000000000 --- a/rskj-core/src/test/java/co/rsk/peg/FederationTest.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * This file is part of RskJ - * Copyright (C) 2017 RSK Labs Ltd. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package co.rsk.peg; - -import co.rsk.bitcoinj.core.BtcECKey; -import co.rsk.bitcoinj.core.NetworkParameters; -import co.rsk.bitcoinj.script.Script; -import co.rsk.bitcoinj.script.ScriptBuilder; -import org.bouncycastle.util.encoders.Hex; -import org.ethereum.TestUtils; -import org.ethereum.crypto.ECKey; -import org.hamcrest.MatcherAssert; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockedStatic; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.math.BigInteger; -import java.time.ZonedDateTime; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mockStatic; - -@ExtendWith(MockitoExtension.class) -class FederationTest { - private Federation federation; - private List sortedPublicKeys; - private List rskPubKeys; - private List rskAddresses; - - @BeforeEach - void createFederation() { - federation = new Federation( - FederationTestUtils.getFederationMembersFromPks(100, 200, 300, 400, 500, 600), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_REGTEST) - ); - - sortedPublicKeys = Arrays.stream(new BtcECKey[]{ - BtcECKey.fromPrivate(BigInteger.valueOf(100)), - BtcECKey.fromPrivate(BigInteger.valueOf(200)), - BtcECKey.fromPrivate(BigInteger.valueOf(300)), - BtcECKey.fromPrivate(BigInteger.valueOf(400)), - BtcECKey.fromPrivate(BigInteger.valueOf(500)), - BtcECKey.fromPrivate(BigInteger.valueOf(600)), - }).sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); - - rskPubKeys = Stream.of(101, 201, 301, 401, 501, 601) - .map(i -> ECKey.fromPrivate(BigInteger.valueOf(i))) - .collect(Collectors.toList()); - - rskAddresses = rskPubKeys - .stream() - .map(ECKey::getAddress) - .collect(Collectors.toList()); - } - - @Test - void membersImmutable() { - boolean exception = false; - try { - federation.getMembers().add(new FederationMember(new BtcECKey(), new ECKey(), new ECKey())); - } catch (Exception e) { - exception = true; - } - Assertions.assertTrue(exception); - - exception = false; - try { - federation.getMembers().remove(0); - } catch (Exception e) { - exception = true; - } - Assertions.assertTrue(exception); - } - - @Test - void redeemScript() { - final List calls = new ArrayList<>(); - try (MockedStatic scriptBuilderMocked = mockStatic(ScriptBuilder.class)) { - scriptBuilderMocked.when(() -> ScriptBuilder.createRedeemScript(any(int.class), any(List.class))).thenAnswer((invocationOnMock) -> { - calls.add(1); - int numberOfSignaturesRequired = invocationOnMock.getArgument(0); - List publicKeys = invocationOnMock.getArgument(1); - Assertions.assertEquals(4, numberOfSignaturesRequired); - Assertions.assertEquals(6, publicKeys.size()); - for (int i = 0; i < sortedPublicKeys.size(); i++) { - Assertions.assertArrayEquals(sortedPublicKeys.get(i).getPubKey(), - publicKeys.get(i).getPubKey()); - } - return new Script(new byte[]{(byte) 0xaa}); - }); - Assertions.assertArrayEquals(federation.getRedeemScript().getProgram(), new byte[]{(byte) 0xaa}); - // Make sure the script creation happens only once - Assertions.assertEquals(1, calls.size()); - } - } - - @Test - void P2SHScript() { - final List calls = new ArrayList<>(); - try (MockedStatic scriptBuilderMocked = mockStatic(ScriptBuilder.class)) { - scriptBuilderMocked.when(() -> ScriptBuilder.createP2SHOutputScript(any(int.class), any(List.class))).thenAnswer((invocationOnMock) -> { - calls.add(0); - int numberOfSignaturesRequired = invocationOnMock.getArgument(0); - List publicKeys = invocationOnMock.getArgument(1); - Assertions.assertEquals(4, numberOfSignaturesRequired); - Assertions.assertEquals(6, publicKeys.size()); - for (int i = 0; i < sortedPublicKeys.size(); i++) { - Assertions.assertArrayEquals(sortedPublicKeys.get(i).getPubKey(), - publicKeys.get(i).getPubKey()); - } - return new Script(new byte[]{(byte) 0xaa}); - }); - Assertions.assertArrayEquals(federation.getP2SHScript().getProgram(), new byte[]{(byte) 0xaa}); - // Make sure the script creation happens only once - Assertions.assertEquals(1, calls.size()); - } - } - - @Test - void Address() { - // Since we can't mock both Address and ScriptBuilder at the same time (due to PowerMockito limitations) - // we use a well known P2SH and its corresponding address - // and just mock the ScriptBuilder - // a914896ed9f3446d51b5510f7f0b6ef81b2bde55140e87 => 2N5muMepJizJE1gR7FbHJU6CD18V3BpNF9p - final List calls = new ArrayList<>(); - try (MockedStatic scriptBuilderMocked = mockStatic(ScriptBuilder.class)) { - scriptBuilderMocked.when(() -> ScriptBuilder.createP2SHOutputScript(any(int.class), any(List.class))).thenAnswer((invocationOnMock) -> { - calls.add(0); - int numberOfSignaturesRequired = invocationOnMock.getArgument(0); - List publicKeys = invocationOnMock.getArgument(1); - Assertions.assertEquals(4, numberOfSignaturesRequired); - Assertions.assertEquals(6, publicKeys.size()); - for (int i = 0; i < sortedPublicKeys.size(); i++) { - Assertions.assertArrayEquals(sortedPublicKeys.get(i).getPubKey(), - publicKeys.get(i).getPubKey()); - } - return new Script(Hex.decode("a914896ed9f3446d51b5510f7f0b6ef81b2bde55140e87")); - }); - - Assertions.assertEquals("2N5muMepJizJE1gR7FbHJU6CD18V3BpNF9p", federation.getAddress().toBase58()); - // Make sure the address creation happens only once - Assertions.assertEquals(1, calls.size()); - } - } - - @Test - void testEquals_basic() { - Assertions.assertNotEquals(null, federation); - Assertions.assertNotEquals(federation, new Object()); - Assertions.assertNotEquals("something else", federation); - } - - @Test - void testEquals_differentNumberOfMembers() { - Federation otherFederation = new Federation( - FederationTestUtils.getFederationMembersFromPks(100, 200, 300, 400, 500, 600, 700), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_REGTEST) - ); - Assertions.assertNotEquals(federation, otherFederation); - } - - @Test - void testEquals_differentCreationTime() { - Federation otherFederation = new Federation( - FederationTestUtils.getFederationMembersFromPks(100, 200, 300, 400, 500, 600), - ZonedDateTime.parse("2017-06-10T02:30:01Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_REGTEST) - ); - Assertions.assertNotEquals(federation, otherFederation); - } - - @Test - void testEquals_differentCreationBlockNumber() { - Federation otherFederation = new Federation( - FederationTestUtils.getFederationMembersFromPks(100, 200, 300, 400, 500, 600), - ZonedDateTime.parse("2017-06-10T02:30:01Z").toInstant(), - 1L, - NetworkParameters.fromID(NetworkParameters.ID_REGTEST) - ); - MatcherAssert.assertThat(federation, is(not(otherFederation))); - } - - @Test - void testEquals_differentNetworkParameters() { - Federation otherFederation = new Federation( - FederationTestUtils.getFederationMembersFromPks(100, 200, 300, 400, 500, 600), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_TESTNET) - ); - Assertions.assertNotEquals(federation, otherFederation); - } - - @Test - void testEquals_differentMembers() { - List members = FederationTestUtils.getFederationMembersFromPks(100, 200, 300, 400, 500); - - members.add(new FederationMember(BtcECKey.fromPrivate(BigInteger.valueOf(610)), ECKey.fromPrivate(BigInteger.valueOf(600)), ECKey.fromPrivate(BigInteger.valueOf(620)))); - Federation otherFederation = new Federation( - members, - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_REGTEST) - ); - - members.remove(members.size()-1); - members.add(new FederationMember(BtcECKey.fromPrivate(BigInteger.valueOf(600)), ECKey.fromPrivate(BigInteger.valueOf(610)), ECKey.fromPrivate(BigInteger.valueOf(620)))); - Federation yetOtherFederation = new Federation( - members, - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_REGTEST) - ); - - Assertions.assertNotEquals(otherFederation, yetOtherFederation); - Assertions.assertNotEquals(federation, otherFederation); - Assertions.assertNotEquals(federation, yetOtherFederation); - } - - @Test - void testEquals_same() { - Federation otherFederation = new Federation( - FederationTestUtils.getFederationMembersFromPks(100, 200, 300, 400, 500, 600), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_REGTEST) - ); - Assertions.assertEquals(federation, otherFederation); - } - - @Test - void getBtcPublicKeyIndex() { - for (int i = 0; i < federation.getBtcPublicKeys().size(); i++) { - Assertions.assertEquals(i, federation.getBtcPublicKeyIndex(sortedPublicKeys.get(i)).intValue()); - } - Assertions.assertNull(federation.getBtcPublicKeyIndex(BtcECKey.fromPrivate(BigInteger.valueOf(1234)))); - } - - @Test - void hasBtcPublicKey() { - for (int i = 0; i < federation.getBtcPublicKeys().size(); i++) { - Assertions.assertTrue(federation.hasBtcPublicKey(sortedPublicKeys.get(i))); - } - Assertions.assertFalse(federation.hasBtcPublicKey(BtcECKey.fromPrivate(BigInteger.valueOf(1234)))); - } - - @Test - void hasMemberWithRskAddress() { - for (int i = 0; i < federation.getBtcPublicKeys().size(); i++) { - Assertions.assertTrue(federation.hasMemberWithRskAddress(rskAddresses.get(i))); - } - - byte[] nonFederateRskAddress = ECKey.fromPrivate(BigInteger.valueOf(1234)).getAddress(); - Assertions.assertFalse(federation.hasMemberWithRskAddress(nonFederateRskAddress)); - } - - @Test - void testToString() { - Assertions.assertEquals("4 of 6 signatures federation", federation.toString()); - } - - @Test - void isMember(){ - //Both valid params - FederationMember federationMember = federation.getMembers().get(0); - Assertions.assertTrue(federation.isMember(federationMember)); - - byte[] b = TestUtils.generateBytes("b",20); - - ECKey invalidRskKey = ECKey.fromPrivate(b); - BtcECKey invalidBtcKey = BtcECKey.fromPrivate(b); - - // Valid PubKey, invalid rskAddress - FederationMember invalidRskPubKey = new FederationMember(federationMember.getBtcPublicKey(), invalidRskKey, federationMember.getMstPublicKey()); - Assertions.assertFalse(federation.isMember(invalidRskPubKey)); - - //Invalid PubKey, valid rskAddress - FederationMember invalidBtcPubKey = new FederationMember(invalidBtcKey, federationMember.getRskPublicKey(), federationMember.getMstPublicKey()); - Assertions.assertFalse(federation.isMember(invalidBtcPubKey)); - - //Valid btcKey & valid rskAddress, invalid mstKey - FederationMember invalidMstPubKey = new FederationMember(federationMember.getBtcPublicKey(), federationMember.getRskPublicKey(), invalidRskKey); - Assertions.assertFalse(federation.isMember(invalidMstPubKey)); - - //All invalid params - FederationMember invalidPubKeys = new FederationMember(invalidBtcKey, invalidRskKey, invalidRskKey); - Assertions.assertFalse(federation.isMember(invalidPubKeys)); - } -} diff --git a/rskj-core/src/test/java/co/rsk/peg/FederationTestUtils.java b/rskj-core/src/test/java/co/rsk/peg/FederationTestUtils.java index a860b294a8b..bd83f63d2d5 100644 --- a/rskj-core/src/test/java/co/rsk/peg/FederationTestUtils.java +++ b/rskj-core/src/test/java/co/rsk/peg/FederationTestUtils.java @@ -41,7 +41,7 @@ public class FederationTestUtils { public static Federation getFederation(Integer... federationMemberPks) { - return new Federation( + return new StandardMultisigFederation( getFederationMembersFromPks(federationMemberPks), ZonedDateTime.parse("2017-06-10T02:30:01Z").toInstant(), 0L, diff --git a/rskj-core/src/test/java/co/rsk/peg/FlyoverCompatibleBtcWalletWithStorageTest.java b/rskj-core/src/test/java/co/rsk/peg/FlyoverCompatibleBtcWalletWithStorageTest.java index 3fd1d7cbf11..8c2c5567e20 100644 --- a/rskj-core/src/test/java/co/rsk/peg/FlyoverCompatibleBtcWalletWithStorageTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/FlyoverCompatibleBtcWalletWithStorageTest.java @@ -45,14 +45,14 @@ void setup() { ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); when(activations.isActive(ConsensusRule.RSKIP284)).thenReturn(true); - federation = new Federation( + federation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(3), Instant.ofEpochMilli(1000), 0L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); - erpFederation = new ErpFederation( + erpFederation = new LegacyErpFederation( FederationTestUtils.getFederationMembers(3), Instant.ofEpochMilli(1000), 0L, diff --git a/rskj-core/src/test/java/co/rsk/peg/FlyoverCompatibleBtcWallextWithSingleScriptTest.java b/rskj-core/src/test/java/co/rsk/peg/FlyoverCompatibleBtcWallextWithSingleScriptTest.java index 0335d6c70e1..afb20abf11d 100644 --- a/rskj-core/src/test/java/co/rsk/peg/FlyoverCompatibleBtcWallextWithSingleScriptTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/FlyoverCompatibleBtcWallextWithSingleScriptTest.java @@ -41,14 +41,14 @@ void setup() { ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); when(activations.isActive(ConsensusRule.RSKIP284)).thenReturn(true); - federation = new Federation( + federation = new StandardMultisigFederation( FederationTestUtils.getFederationMembers(3), Instant.ofEpochMilli(1000), 0L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST) ); - erpFederation = new ErpFederation( + erpFederation = new LegacyErpFederation( FederationTestUtils.getFederationMembers(3), Instant.ofEpochMilli(1000), 0L, diff --git a/rskj-core/src/test/java/co/rsk/peg/ErpFederationTest.java b/rskj-core/src/test/java/co/rsk/peg/LegacyErpFederationTest.java similarity index 67% rename from rskj-core/src/test/java/co/rsk/peg/ErpFederationTest.java rename to rskj-core/src/test/java/co/rsk/peg/LegacyErpFederationTest.java index b097cd091bc..e62b900e596 100644 --- a/rskj-core/src/test/java/co/rsk/peg/ErpFederationTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/LegacyErpFederationTest.java @@ -1,7 +1,9 @@ package co.rsk.peg; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static co.rsk.peg.ErpFederation.MAX_CSV_VALUE; +import static co.rsk.peg.FederationCreationException.Reason.*; +import static co.rsk.peg.bitcoin.Standardness.MAX_SCRIPT_ELEMENT_SIZE; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -12,7 +14,6 @@ import co.rsk.bitcoinj.core.NetworkParameters; import co.rsk.bitcoinj.core.ScriptException; import co.rsk.bitcoinj.core.Utils; -import co.rsk.bitcoinj.core.VerificationException; import co.rsk.bitcoinj.script.ErpFederationRedeemScriptParser; import co.rsk.bitcoinj.script.Script; import co.rsk.bitcoinj.script.ScriptOpCodes; @@ -30,6 +31,8 @@ import java.nio.file.Paths; import java.time.Instant; import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -43,9 +46,10 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -class ErpFederationTest { - private ErpFederation federation; - private List defaultKeys; +class LegacyErpFederationTest { + private LegacyErpFederation federation; + private NetworkParameters networkParameters; + private List standardKeys; private List emergencyKeys; private long activationDelayValue; private ActivationConfig.ForBlock activations; @@ -54,14 +58,116 @@ class ErpFederationTest { void setup() { BridgeConstants bridgeConstants = BridgeMainNetConstants.getInstance(); - defaultKeys = bridgeConstants.getGenesisFederation().getBtcPublicKeys(); + BtcECKey federator0PublicKey = BtcECKey.fromPublicOnly(Hex.decode("03b53899c390573471ba30e5054f78376c5f797fda26dde7a760789f02908cbad2")); + BtcECKey federator1PublicKey = BtcECKey.fromPublicOnly(Hex.decode("027319afb15481dbeb3c426bcc37f9a30e7f51ceff586936d85548d9395bcc2344")); + BtcECKey federator2PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0355a2e9bf100c00fc0a214afd1bf272647c7824eb9cb055480962f0c382596a70")); + BtcECKey federator3PublicKey = BtcECKey.fromPublicOnly(Hex.decode("02566d5ded7c7db1aa7ee4ef6f76989fb42527fcfdcddcd447d6793b7d869e46f7")); + BtcECKey federator4PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0294c817150f78607566e961b3c71df53a22022a80acbb982f83c0c8baac040adc")); + BtcECKey federator5PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0372cd46831f3b6afd4c044d160b7667e8ebf659d6cb51a825a3104df6ee0638c6")); + BtcECKey federator6PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0340df69f28d69eef60845da7d81ff60a9060d4da35c767f017b0dd4e20448fb44")); + BtcECKey federator7PublicKey = BtcECKey.fromPublicOnly(Hex.decode("02ac1901b6fba2c1dbd47d894d2bd76c8ba1d296d65f6ab47f1c6b22afb53e73eb")); + BtcECKey federator8PublicKey = BtcECKey.fromPublicOnly(Hex.decode("031aabbeb9b27258f98c2bf21f36677ae7bae09eb2d8c958ef41a20a6e88626d26")); + BtcECKey federator9PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0245ef34f5ee218005c9c21227133e8568a4f3f11aeab919c66ff7b816ae1ffeea")); + standardKeys = Arrays.asList( + federator0PublicKey, federator1PublicKey, federator2PublicKey, + federator3PublicKey, federator4PublicKey, federator5PublicKey, + federator6PublicKey, federator7PublicKey, federator8PublicKey, federator9PublicKey + ); + + networkParameters = bridgeConstants.getBtcParams(); emergencyKeys = bridgeConstants.getErpFedPubKeysList(); activationDelayValue = bridgeConstants.getErpFedActivationDelay(); - activations = mock(ActivationConfig.ForBlock.class); when(activations.isActive(ConsensusRule.RSKIP284)).thenReturn(true); - federation = createDefaultErpFederation(); + federation = createDefaultLegacyErpFederation(); + } + + private LegacyErpFederation createDefaultLegacyErpFederation() { + List standardMembers = FederationTestUtils.getFederationMembersWithBtcKeys(standardKeys); + Instant creationTime = ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(); + long creationBlockNumber = 0L; + + return new LegacyErpFederation( + standardMembers, + creationTime, + creationBlockNumber, + networkParameters, + emergencyKeys, + activationDelayValue, + activations + ); + } + + @Test + void createInvalidLegacyErpFederation_nullErpKeys() { + emergencyKeys = null; + FederationCreationException exception = assertThrows( + FederationCreationException.class, this::createDefaultLegacyErpFederation + ); + assertEquals(NULL_OR_EMPTY_EMERGENCY_KEYS, exception.getReason()); + } + + @Test + void createInvalidLegacyErpFederation_emptyErpKeys() { + emergencyKeys = new ArrayList<>(); + FederationCreationException exception = assertThrows( + FederationCreationException.class, this::createDefaultLegacyErpFederation + ); + assertEquals(NULL_OR_EMPTY_EMERGENCY_KEYS, exception.getReason()); + } + + @Test + void createValidLegacyErpFederation_oneErpKey() { + emergencyKeys = Collections.singletonList(emergencyKeys.get(0)); + assertDoesNotThrow(this::createDefaultLegacyErpFederation); + } + @Test + void createInvalidLegacyErpFederation_negativeCsvValue() { + activationDelayValue = -100L; + FederationCreationException exception = assertThrows( + FederationCreationException.class, this::createDefaultLegacyErpFederation + ); + assertEquals(INVALID_CSV_VALUE, exception.getReason()); + } + + @Test + void createInvalidLegacyErpFederation_zeroCsvValue() { + activationDelayValue = 0L; + FederationCreationException exception = assertThrows( + FederationCreationException.class, this::createDefaultLegacyErpFederation + ); + assertEquals(INVALID_CSV_VALUE, exception.getReason()); + } + + @Test + void createInvalidLegacyErpFederation_aboveMaxCsvValue() { + activationDelayValue = MAX_CSV_VALUE + 1; + FederationCreationException exception = assertThrows( + FederationCreationException.class, this::createDefaultLegacyErpFederation + ); + assertEquals(INVALID_CSV_VALUE, exception.getReason()); + } + + @Test + void createValidLegacyErpFederation_exactMaxCsvValue() { + activationDelayValue = MAX_CSV_VALUE; + assertDoesNotThrow(this::createDefaultLegacyErpFederation); + } + + @Test + void createInvalidLegacyErpFederation_aboveMaxScriptSigSize() { + // add one member to exceed redeem script size limit + List newStandardKeys = federation.getBtcPublicKeys(); + BtcECKey federator10PublicKey = BtcECKey.fromPublicOnly( + Hex.decode("02550cc87fa9061162b1dd395a16662529c9d8094c0feca17905a3244713d65fe8") + ); + newStandardKeys.add(federator10PublicKey); + standardKeys = newStandardKeys; + FederationCreationException exception = assertThrows( + FederationCreationException.class, this::createDefaultLegacyErpFederation + ); + assertEquals(ABOVE_MAX_SCRIPT_ELEMENT_SIZE, exception.getReason()); } @Test @@ -75,89 +181,151 @@ void getActivationDelay() { } @Test - void getRedeemScript_before_RSKIP293() { - Script redeemScript = federation.getRedeemScript(); - validateErpRedeemScript( - redeemScript, - activationDelayValue, - false - ); + void testEquals_basic() { + assertEquals(federation, federation); + + assertNotEquals(null, federation); + assertNotEquals(federation, new Object()); + assertNotEquals("something else", federation); } @Test - void getRedeemScript_after_RSKIP293() { - when(activations.isActive(ConsensusRule.RSKIP293)).thenReturn(true); - federation = createDefaultErpFederation(); - Script redeemScript = federation.getRedeemScript(); + void testEquals_same() { + ErpFederation otherFederation = new LegacyErpFederation( + federation.getMembers(), + federation.getCreationTime(), + federation.getCreationBlockNumber(), + federation.getBtcParams(), + federation.getErpPubKeys(), + federation.getActivationDelay(), + activations + ); - validateErpRedeemScript( - redeemScript, - activationDelayValue, - true + assertEquals(federation, otherFederation); + } + + @Test + void testEquals_differentCreationTime() { + ErpFederation otherFederation = new LegacyErpFederation( + federation.getMembers(), + federation.getCreationTime().plus(1, ChronoUnit.MILLIS), + federation.getCreationBlockNumber(), + federation.getBtcParams(), + federation.getErpPubKeys(), + federation.getActivationDelay(), + activations ); + assertEquals(federation, otherFederation); } @Test - void getRedeemScript_changes_after_RSKIP293() { - Script preRskip293RedeemScript = federation.getRedeemScript(); + void testEquals_differentCreationBlockNumber() { + ErpFederation otherFederation = new LegacyErpFederation( + federation.getMembers(), + federation.getCreationTime(), + federation.getCreationBlockNumber() + 1, + federation.getBtcParams(), + federation.getErpPubKeys(), + federation.getActivationDelay(), + activations + ); + assertEquals(federation, otherFederation); + } - when(activations.isActive(ConsensusRule.RSKIP293)).thenReturn(true); - federation = createDefaultErpFederation(); - Script postRskip293RedeemScript = federation.getRedeemScript(); + @Test + void testEquals_differentNetworkParameters() { + networkParameters = NetworkParameters.fromID(NetworkParameters.ID_REGTEST); - Assertions.assertNotEquals(preRskip293RedeemScript, postRskip293RedeemScript); + ErpFederation otherFederation = createDefaultLegacyErpFederation(); + Assertions.assertNotEquals(federation, otherFederation); } @Test - void getP2SHScript() { - Script p2shs = federation.getP2SHScript(); - String expectedProgram = "a914e16874869871d2fbc116ed503699b42b886e4eeb87"; + void testEquals_differentNumberOfMembers() { + // remove federator9 + List newStandardKeys = federation.getBtcPublicKeys(); + newStandardKeys.remove(9); + standardKeys = newStandardKeys; - assertEquals(expectedProgram, Hex.toHexString(p2shs.getProgram())); - assertEquals(3, p2shs.getChunks().size()); - assertEquals( - federation.getAddress(), - p2shs.getToAddress(NetworkParameters.fromID(NetworkParameters.ID_REGTEST)) - ); + ErpFederation otherFederation = createDefaultLegacyErpFederation(); + Assertions.assertNotEquals(federation, otherFederation); } @Test - void getAddress() { - String fedAddress = federation.getAddress().toBase58(); - String expectedAddress = "2NDo5A7r5GbgMt9hH4iQ3fvuxspixP67xgU"; + void testEquals_differentMembers() { + // replace federator8 with federator9 + BtcECKey federator9PublicKey = BtcECKey.fromPublicOnly( + Hex.decode("0245ef34f5ee218005c9c21227133e8568a4f3f11aeab919c66ff7b816ae1ffeea") + ); + List newStandardKeys = federation.getBtcPublicKeys(); + newStandardKeys.remove(8); + newStandardKeys.add(federator9PublicKey); + standardKeys = newStandardKeys; - assertEquals(expectedAddress, fedAddress); + ErpFederation otherFederation = createDefaultLegacyErpFederation(); + Assertions.assertNotEquals(federation, otherFederation); } @Test - void getErpPubKeys_compressed_public_keys() { - assertEquals(emergencyKeys, federation.getErpPubKeys()); + void getP2SHScriptAndAddress() { + // standard and emergency keys from real legacy erp fed in testnet + BridgeConstants bridgeTestNetConstants = BridgeTestNetConstants.getInstance(); + networkParameters = bridgeTestNetConstants.getBtcParams(); + emergencyKeys = bridgeTestNetConstants.getErpFedPubKeysList(); + activationDelayValue = bridgeTestNetConstants.getErpFedActivationDelay(); + + standardKeys = Arrays.asList( + BtcECKey.fromPublicOnly( + Hex.decode("0208f40073a9e43b3e9103acec79767a6de9b0409749884e989960fee578012fce") + ), + BtcECKey.fromPublicOnly( + Hex.decode("0225e892391625854128c5c4ea4340de0c2a70570f33db53426fc9c746597a03f4") + ), + BtcECKey.fromPublicOnly( + Hex.decode("025a2f522aea776fab5241ad72f7f05918e8606676461cb6ce38265a52d4ca9ed6") + ), + BtcECKey.fromPublicOnly( + Hex.decode("02afc230c2d355b1a577682b07bc2646041b5d0177af0f98395a46018da699b6da") + ), + BtcECKey.fromPublicOnly( + Hex.decode("0344a3c38cd59afcba3edcebe143e025574594b001700dec41e59409bdbd0f2a09") + ) + ); + + ErpFederation realLegacyErpFederation = createDefaultLegacyErpFederation(); + Script p2shScript = realLegacyErpFederation.getP2SHScript(); + Address address = realLegacyErpFederation.getAddress(); + + String expectedProgram = "a9148f38b3d8ec8816f7f58a390f306bb90bb178d6ac87"; + Address expectedAddress = Address.fromBase58( + networkParameters, + "2N6JWYUb6Li4Kux6UB2eihT7n3rm3YX97uv" + ); + + assertEquals(expectedProgram, Hex.toHexString(p2shScript.getProgram())); + assertEquals(3, p2shScript.getChunks().size()); + assertEquals( + address, + p2shScript.getToAddress(networkParameters) + ); + assertEquals(expectedAddress, address); } @Test void getErpPubKeys_uncompressed_public_keys() { // Public keys used for creating federation, but uncompressed format now - List uncompressedErpKeys = emergencyKeys + emergencyKeys = emergencyKeys .stream() .map(BtcECKey::decompress) .collect(Collectors.toList()); // Recreate federation - ErpFederation federationWithUncompressedKeys = new ErpFederation( - FederationTestUtils.getFederationMembersWithBtcKeys(defaultKeys), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_REGTEST), - uncompressedErpKeys, - activationDelayValue, - mock(ActivationConfig.ForBlock.class) - ); - + ErpFederation federationWithUncompressedKeys = createDefaultLegacyErpFederation(); assertEquals(emergencyKeys, federationWithUncompressedKeys.getErpPubKeys()); } @Test - void getErpRedeemScript_compareOtherImplementation() throws IOException { + void getLegacyErpRedeemScript_compareOtherImplementation() throws IOException { when(activations.isActive(ConsensusRule.RSKIP293)).thenReturn(true); byte[] rawRedeemScripts; @@ -170,52 +338,58 @@ void getErpRedeemScript_compareOtherImplementation() throws IOException { RawGeneratedRedeemScript[] generatedScripts = new ObjectMapper().readValue(rawRedeemScripts, RawGeneratedRedeemScript[].class); for (RawGeneratedRedeemScript generatedScript : generatedScripts) { - Federation erpFederation = new ErpFederation( - FederationTestUtils.getFederationMembersWithBtcKeys(generatedScript.mainFed), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_TESTNET), - generatedScript.emergencyFed, - generatedScript.timelock, - activations - ); - - Script rskjScript = erpFederation.getRedeemScript(); - Script alternativeScript = generatedScript.script; - - assertEquals(alternativeScript, rskjScript); + // Skip test cases with invalid redeem script that exceed the maximum size + if (generatedScript.script.getProgram().length <= MAX_SCRIPT_ELEMENT_SIZE) { + Federation erpFederation = new LegacyErpFederation( + FederationTestUtils.getFederationMembersWithBtcKeys(generatedScript.mainFed), + ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), + 1, + NetworkParameters.fromID(NetworkParameters.ID_TESTNET), + generatedScript.emergencyFed, + generatedScript.timelock, + activations + ); + + Script rskjScript = erpFederation.getRedeemScript(); + Script alternativeScript = generatedScript.script; + + assertEquals(alternativeScript, rskjScript); + } } } @Test - void getErpRedeemScript_compareOtherImplementation_P2SHERPFederation() throws IOException { + void getRedeemScript_before_RSKIP293() { + Script redeemScript = federation.getRedeemScript(); + validateErpRedeemScript( + redeemScript, + activationDelayValue, + false + ); + } + + @Test + void getRedeemScript_after_RSKIP293() { when(activations.isActive(ConsensusRule.RSKIP293)).thenReturn(true); + federation = createDefaultLegacyErpFederation(); + Script redeemScript = federation.getRedeemScript(); - byte[] rawRedeemScripts; - try { - rawRedeemScripts = Files.readAllBytes(Paths.get("src/test/resources/redeemScripts_p2shERP.json")); - } catch (IOException e) { - System.out.println("redeemScripts_p2shERP.json file not found"); - throw(e); - } + validateErpRedeemScript( + redeemScript, + activationDelayValue, + true + ); + } - RawGeneratedRedeemScript[] generatedScripts = new ObjectMapper().readValue(rawRedeemScripts, RawGeneratedRedeemScript[].class); - for (RawGeneratedRedeemScript generatedScript : generatedScripts) { - // NOTE: difference with other tests is here, this one tests a P2shErpFederation - Federation erpFederation = new P2shErpFederation( - FederationTestUtils.getFederationMembersWithBtcKeys(generatedScript.mainFed), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_TESTNET), - generatedScript.emergencyFed, - generatedScript.timelock, - activations - ); - - Script rskjScript = erpFederation.getRedeemScript(); - Script alternativeScript = generatedScript.script; - assertEquals(alternativeScript, rskjScript); - } + @Test + void getRedeemScript_changes_after_RSKIP293() { + Script preRskip293RedeemScript = federation.getRedeemScript(); + + when(activations.isActive(ConsensusRule.RSKIP293)).thenReturn(true); + federation = createDefaultLegacyErpFederation(); + Script postRskip293RedeemScript = federation.getRedeemScript(); + + Assertions.assertNotEquals(preRskip293RedeemScript, postRskip293RedeemScript); } @Test @@ -238,63 +412,15 @@ void createErpFederation_mainnet_constants_after_RSKIP293() { createErpFederation(BridgeMainNetConstants.getInstance(), true); } - @Test - void createInvalidErpFederation_negativeCsvValue() { - List federationMembersFromPks = FederationTestUtils.getFederationMembersFromPks(100, 200, 300); - Instant creationTime = ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(); - NetworkParameters btcParams = NetworkParameters.fromID(NetworkParameters.ID_REGTEST); - assertThrows(VerificationException.class, () -> new ErpFederation( - federationMembersFromPks, - creationTime, - 0L, - btcParams, - emergencyKeys, - -100L, - activations - )); - } - - @Test - void createInvalidErpFederation_csvValueZero() { - List federationMembersFromPks = FederationTestUtils.getFederationMembersFromPks(100, 200, 300); - Instant creationTime = ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(); - NetworkParameters btcParams = NetworkParameters.fromID(NetworkParameters.ID_REGTEST); - assertThrows(VerificationException.class, () -> new ErpFederation( - federationMembersFromPks, - creationTime, - 0L, - btcParams, - emergencyKeys, - 0, - activations - )); - } - - @Test - void createInvalidErpFederation_csvValueAboveMax() { - List federationMembersFromPks = FederationTestUtils.getFederationMembersFromPks(100, 200, 300); - Instant creationTime = ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(); - NetworkParameters btcParams = NetworkParameters.fromID(NetworkParameters.ID_REGTEST); - assertThrows(VerificationException.class, () -> new ErpFederation( - federationMembersFromPks, - creationTime, - 0L, - btcParams, - emergencyKeys, - ErpFederationRedeemScriptParser.MAX_CSV_VALUE + 1, - activations - )); - } - @Test void getRedeemScript_before_RSKIP_284_testnet() { ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); when(activations.isActive(ConsensusRule.RSKIP284)).thenReturn(false); - Federation erpFederation = new ErpFederation( + Federation erpFederation = new LegacyErpFederation( FederationTestUtils.getFederationMembersFromPks(100, 200, 300), ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, + 1, NetworkParameters.fromID(NetworkParameters.ID_TESTNET), emergencyKeys, activationDelayValue, @@ -309,10 +435,10 @@ void getRedeemScript_before_RSKIP_284_mainnet() { ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); when(activations.isActive(ConsensusRule.RSKIP284)).thenReturn(false); - Federation erpFederation = new ErpFederation( - FederationTestUtils.getFederationMembersWithBtcKeys(defaultKeys), + Federation erpFederation = new LegacyErpFederation( + FederationTestUtils.getFederationMembersWithBtcKeys(standardKeys), ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, + 1, NetworkParameters.fromID(NetworkParameters.ID_MAINNET), emergencyKeys, activationDelayValue, @@ -329,10 +455,10 @@ void getRedeemScript_before_RSKIP_284_mainnet() { @Test void getRedeemScript_after_RSKIP_284_testnet() { - Federation erpFederation = new ErpFederation( - FederationTestUtils.getFederationMembersWithBtcKeys(defaultKeys), + Federation erpFederation = new LegacyErpFederation( + FederationTestUtils.getFederationMembersWithBtcKeys(standardKeys), ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, + 1, NetworkParameters.fromID(NetworkParameters.ID_TESTNET), emergencyKeys, activationDelayValue, @@ -349,10 +475,10 @@ void getRedeemScript_after_RSKIP_284_testnet() { @Test void getRedeemScript_after_RSKIP_284_mainnet() { - Federation erpFederation = new ErpFederation( - FederationTestUtils.getFederationMembersWithBtcKeys(defaultKeys), + Federation erpFederation = new LegacyErpFederation( + FederationTestUtils.getFederationMembersWithBtcKeys(standardKeys), ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, + 1, NetworkParameters.fromID(NetworkParameters.ID_MAINNET), emergencyKeys, activationDelayValue, @@ -367,105 +493,6 @@ void getRedeemScript_after_RSKIP_284_mainnet() { ); } - @Test - void testEquals_basic() { - assertEquals(federation, federation); - - Assertions.assertNotEquals(null, federation); - Assertions.assertNotEquals(federation, new Object()); - Assertions.assertNotEquals("something else", federation); - } - - @Test - void testEquals_same() { - Federation otherFederation = new ErpFederation( - federation.getMembers(), - federation.getCreationTime(), - federation.getCreationBlockNumber(), - federation.getBtcParams(), - federation.getErpPubKeys(), - federation.getActivationDelay(), - activations - ); - - assertEquals(federation, otherFederation); - } - - @Test - void testEquals_differentNumberOfMembers() { - Federation otherFederation = new ErpFederation( - FederationTestUtils.getFederationMembersFromPks(100, 200, 300, 400, 500, 600, 700), - federation.getCreationTime(), - federation.getCreationBlockNumber(), - federation.getBtcParams(), - federation.getErpPubKeys(), - federation.getActivationDelay(), - activations - ); - - Assertions.assertNotEquals(federation, otherFederation); - } - - @Test - void testEquals_differentCreationTime() { - Federation otherFederation = new ErpFederation( - federation.getMembers(), - Instant.now(), - federation.getCreationBlockNumber(), - federation.getBtcParams(), - federation.getErpPubKeys(), - federation.getActivationDelay(), - activations - ); - - Assertions.assertNotEquals(federation, otherFederation); - } - - @Test - void testEquals_differentCreationBlockNumber() { - Federation otherFederation = new ErpFederation( - federation.getMembers(), - federation.getCreationTime(), - federation.getCreationBlockNumber() + 1, - federation.getBtcParams(), - federation.getErpPubKeys(), - federation.getActivationDelay(), - activations - ); - - Assertions.assertNotEquals(federation, otherFederation); - } - - @Test - void testEquals_differentNetworkParameters() { - Federation otherFederation = new ErpFederation( - federation.getMembers(), - federation.getCreationTime(), - federation.getCreationBlockNumber(), - NetworkParameters.fromID(NetworkParameters.ID_MAINNET), - federation.getErpPubKeys(), - federation.getActivationDelay(), - activations - ); - - Assertions.assertNotEquals(federation, otherFederation); - } - - @Test - void testEquals_differentMembers() { - Federation otherFederation = new ErpFederation( - FederationTestUtils.getFederationMembersFromPks(101, 201, 301), - federation.getCreationTime(), - federation.getCreationBlockNumber(), - federation.getBtcParams(), - federation.getErpPubKeys(), - federation.getActivationDelay(), - activations - ); - - Assertions.assertNotEquals(federation, otherFederation); - } - @Test void testEquals_differentRedeemScript() { ActivationConfig.ForBlock activationsPre = mock(ActivationConfig.ForBlock.class); @@ -474,53 +501,22 @@ void testEquals_differentRedeemScript() { ActivationConfig.ForBlock activationsPost = mock(ActivationConfig.ForBlock.class); when(activationsPost.isActive(ConsensusRule.RSKIP284)).thenReturn(true); - // Both federations created before RSKIP284 with the same data, should have the same redeem script - Federation erpFederation = new ErpFederation( - FederationTestUtils.getFederationMembersFromPks(100, 200, 300), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_TESTNET), - emergencyKeys, - activationDelayValue, - activationsPre - ); + networkParameters = NetworkParameters.fromID(NetworkParameters.ID_TESTNET); - Federation otherErpFederation = new ErpFederation( - FederationTestUtils.getFederationMembersFromPks(100, 200, 300), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_TESTNET), - emergencyKeys, - activationDelayValue, - activationsPre - ); + // Both federations created before RSKIP284 with the same data, should have the same redeem script + activations = activationsPre; + Federation erpFederation = createDefaultLegacyErpFederation(); + Federation otherErpFederation = createDefaultLegacyErpFederation(); assertEquals(erpFederation, otherErpFederation); + activations = activationsPost; // One federation created after RSKIP284 with the same data, should have different redeem script - otherErpFederation = new ErpFederation( - FederationTestUtils.getFederationMembersFromPks(100, 200, 300), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_TESTNET), - emergencyKeys, - activationDelayValue, - activationsPost - ); - - Assertions.assertNotEquals(erpFederation, otherErpFederation); + otherErpFederation = createDefaultLegacyErpFederation(); + assertNotEquals(erpFederation, otherErpFederation); // The other federation created after RSKIP284 with the same data, should have same redeem script - erpFederation = new ErpFederation( - FederationTestUtils.getFederationMembersFromPks(100, 200, 300), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_TESTNET), - emergencyKeys, - activationDelayValue, - activationsPost - ); - + erpFederation = createDefaultLegacyErpFederation(); assertEquals(erpFederation, otherErpFederation); } @@ -551,10 +547,10 @@ void createErpFedWithSameRedeemScriptAsHardcodedOne_after_RSKIP293_fails() { List federationMembersWithBtcKeys = FederationTestUtils.getFederationMembersWithBtcKeys(standardMultisigKeys); Instant creationTime = ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(); NetworkParameters btcParams = NetworkParameters.fromID(NetworkParameters.ID_TESTNET); - assertThrows(FederationCreationException.class, () -> new ErpFederation( + assertThrows(FederationCreationException.class, () -> new LegacyErpFederation( federationMembersWithBtcKeys, creationTime, - 0L, + 1, btcParams, emergencyMultisigKeys, activationDelay, @@ -569,7 +565,7 @@ void spendFromErpFed_before_RSKIP293_testnet_using_erp_multisig_can_spend() { // The CSV value defined in BridgeTestnetConstants, // actually allows the emergency multisig to spend before the expected amount of blocks // Since it's encoded as BE and decoded as LE, the result is a number lower than the one defined in the constant - Assertions.assertDoesNotThrow(() -> + assertDoesNotThrow(() -> spendFromErpFed( constants.getBtcParams(), constants.getErpFedActivationDelay(), @@ -599,7 +595,7 @@ void spendFromErpFed_before_RSKIP293_testnet_using_standard_multisig() { BridgeConstants constants = BridgeTestNetConstants.getInstance(); // Should validate since it's not executing the path of the script with the CSV value - Assertions.assertDoesNotThrow(() -> spendFromErpFed( + assertDoesNotThrow(() -> spendFromErpFed( constants.getBtcParams(), constants.getErpFedActivationDelay(), false, @@ -614,7 +610,7 @@ void spendFromErpFed_before_RSKIP293_mainnet_using_erp_multisig_can_spend() { // The CSV value defined in BridgeMainnetConstants, // actually allows the emergency multisig to spend before the expected amount of blocks // Since it's encoded as BE and decoded as LE, the result is a number lower than the one defined in the constant - Assertions.assertDoesNotThrow(() -> spendFromErpFed( + assertDoesNotThrow(() -> spendFromErpFed( constants.getBtcParams(), constants.getErpFedActivationDelay(), false, @@ -643,7 +639,7 @@ void spendFromErpFed_before_RSKIP293_mainnet_using_standard_multisig() { BridgeConstants constants = BridgeMainNetConstants.getInstance(); // Should validate since it's not executing the path of the script with the CSV value - Assertions.assertDoesNotThrow(() -> spendFromErpFed( + assertDoesNotThrow(() -> spendFromErpFed( constants.getBtcParams(), constants.getErpFedActivationDelay(), false, @@ -656,7 +652,7 @@ void spendFromErpFed_after_RSKIP293_testnet_using_erp_multisig() { BridgeConstants constants = BridgeTestNetConstants.getInstance(); // Post RSKIP293 activation it should encode the CSV value correctly - Assertions.assertDoesNotThrow(() -> spendFromErpFed( + assertDoesNotThrow(() -> spendFromErpFed( constants.getBtcParams(), constants.getErpFedActivationDelay(), true, @@ -668,7 +664,7 @@ void spendFromErpFed_after_RSKIP293_testnet_using_erp_multisig() { void spendFromErpFed_after_RSKIP293_testnet_using_standard_multisig() { BridgeConstants constants = BridgeTestNetConstants.getInstance(); - Assertions.assertDoesNotThrow(() -> spendFromErpFed( + assertDoesNotThrow(() -> spendFromErpFed( constants.getBtcParams(), constants.getErpFedActivationDelay(), true, @@ -681,7 +677,7 @@ void spendFromErpFed_after_RSKIP293_mainnet_using_erp_multisig() { BridgeConstants constants = BridgeMainNetConstants.getInstance(); // Post RSKIP293 activation it should encode the CSV value correctly - Assertions.assertDoesNotThrow(() -> spendFromErpFed( + assertDoesNotThrow(() -> spendFromErpFed( constants.getBtcParams(), constants.getErpFedActivationDelay(), true, @@ -693,7 +689,7 @@ void spendFromErpFed_after_RSKIP293_mainnet_using_erp_multisig() { void spendFromErpFed_after_RSKIP293_mainnet_using_standard_multisig() { BridgeConstants constants = BridgeMainNetConstants.getInstance(); - Assertions.assertDoesNotThrow(() -> spendFromErpFed( + assertDoesNotThrow(() -> spendFromErpFed( constants.getBtcParams(), constants.getErpFedActivationDelay(), true, @@ -704,10 +700,10 @@ void spendFromErpFed_after_RSKIP293_mainnet_using_standard_multisig() { private void createErpFederation(BridgeConstants constants, boolean isRskip293Active) { when(activations.isActive(ConsensusRule.RSKIP293)).thenReturn(isRskip293Active); - Federation erpFederation = new ErpFederation( - FederationTestUtils.getFederationMembersWithBtcKeys(defaultKeys), + Federation erpFederation = new LegacyErpFederation( + FederationTestUtils.getFederationMembersWithBtcKeys(standardKeys), ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, + 1, constants.getBtcParams(), constants.getErpFedPubKeysList(), constants.getErpFedActivationDelay(), @@ -716,7 +712,7 @@ private void createErpFederation(BridgeConstants constants, boolean isRskip293Ac validateErpRedeemScript( erpFederation.getRedeemScript(), - defaultKeys, + standardKeys, constants.getErpFedPubKeysList(), constants.getErpFedActivationDelay(), isRskip293Active @@ -744,10 +740,10 @@ private void spendFromErpFed( Collections.singletonList(ConsensusRule.RSKIP293); ActivationConfig activations = ActivationConfigsForTest.hop400(except); - ErpFederation erpFed = new ErpFederation( + ErpFederation erpFed = new LegacyErpFederation( FederationMember.getFederationMembersFromKeys(standardKeys), ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, + 1, networkParameters, emergencyKeys, activationDelay, @@ -776,18 +772,6 @@ private void spendFromErpFed( ); } - private ErpFederation createDefaultErpFederation() { - return new ErpFederation( - FederationTestUtils.getFederationMembersWithBtcKeys(defaultKeys), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - NetworkParameters.fromID(NetworkParameters.ID_REGTEST), - emergencyKeys, - activationDelayValue, - activations - ); - } - private void validateErpRedeemScript( Script erpRedeemScript, Long csvValue, @@ -795,7 +779,7 @@ private void validateErpRedeemScript( validateErpRedeemScript( erpRedeemScript, - defaultKeys, + standardKeys, emergencyKeys, csvValue, isRskip293Active diff --git a/rskj-core/src/test/java/co/rsk/peg/P2shErpFederationTest.java b/rskj-core/src/test/java/co/rsk/peg/P2shErpFederationTest.java index 6d718db995d..46908b100cd 100644 --- a/rskj-core/src/test/java/co/rsk/peg/P2shErpFederationTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/P2shErpFederationTest.java @@ -1,68 +1,260 @@ package co.rsk.peg; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static co.rsk.peg.ErpFederation.MAX_CSV_VALUE; +import static co.rsk.peg.FederationCreationException.Reason.*; +import static co.rsk.peg.bitcoin.Standardness.MAX_SCRIPT_ELEMENT_SIZE; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mock; -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.NetworkParameters; -import co.rsk.bitcoinj.core.Utils; -import co.rsk.bitcoinj.script.Script; -import co.rsk.bitcoinj.script.ScriptOpCodes; +import co.rsk.bitcoinj.core.*; +import co.rsk.bitcoinj.script.*; import co.rsk.config.BridgeConstants; import co.rsk.config.BridgeMainNetConstants; import co.rsk.config.BridgeRegTestConstants; import co.rsk.config.BridgeTestNetConstants; import co.rsk.peg.bitcoin.BitcoinTestUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.time.Instant; import java.time.ZonedDateTime; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; import org.bouncycastle.util.encoders.Hex; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; class P2shErpFederationTest { + private P2shErpFederation federation; + private NetworkParameters networkParameters; + private List standardKeys; + private List emergencyKeys; + private long activationDelayValue; + private ActivationConfig.ForBlock activations; + + @BeforeEach + void setup() { + BridgeConstants bridgeConstants = BridgeMainNetConstants.getInstance(); + + BtcECKey federator0PublicKey = BtcECKey.fromPublicOnly(Hex.decode("03b53899c390573471ba30e5054f78376c5f797fda26dde7a760789f02908cbad2")); + BtcECKey federator1PublicKey = BtcECKey.fromPublicOnly(Hex.decode("027319afb15481dbeb3c426bcc37f9a30e7f51ceff586936d85548d9395bcc2344")); + BtcECKey federator2PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0355a2e9bf100c00fc0a214afd1bf272647c7824eb9cb055480962f0c382596a70")); + BtcECKey federator3PublicKey = BtcECKey.fromPublicOnly(Hex.decode("02566d5ded7c7db1aa7ee4ef6f76989fb42527fcfdcddcd447d6793b7d869e46f7")); + BtcECKey federator4PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0294c817150f78607566e961b3c71df53a22022a80acbb982f83c0c8baac040adc")); + BtcECKey federator5PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0372cd46831f3b6afd4c044d160b7667e8ebf659d6cb51a825a3104df6ee0638c6")); + BtcECKey federator6PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0340df69f28d69eef60845da7d81ff60a9060d4da35c767f017b0dd4e20448fb44")); + BtcECKey federator7PublicKey = BtcECKey.fromPublicOnly(Hex.decode("02ac1901b6fba2c1dbd47d894d2bd76c8ba1d296d65f6ab47f1c6b22afb53e73eb")); + BtcECKey federator8PublicKey = BtcECKey.fromPublicOnly(Hex.decode("031aabbeb9b27258f98c2bf21f36677ae7bae09eb2d8c958ef41a20a6e88626d26")); + BtcECKey federator9PublicKey = BtcECKey.fromPublicOnly(Hex.decode("0245ef34f5ee218005c9c21227133e8568a4f3f11aeab919c66ff7b816ae1ffeea")); + standardKeys = Arrays.asList( + federator0PublicKey, federator1PublicKey, federator2PublicKey, + federator3PublicKey, federator4PublicKey, federator5PublicKey, + federator6PublicKey, federator7PublicKey, federator8PublicKey, federator9PublicKey + ); - @ParameterizedTest - @MethodSource("getRedeemScriptArgsProvider") - void getRedeemScript(BridgeConstants bridgeConstants) { - List standardKeys = bridgeConstants.getGenesisFederation().getBtcPublicKeys(); - List emergencyKeys = bridgeConstants.getErpFedPubKeysList(); - long activationDelay = bridgeConstants.getErpFedActivationDelay(); + networkParameters = bridgeConstants.getBtcParams(); + emergencyKeys = bridgeConstants.getErpFedPubKeysList(); + activationDelayValue = bridgeConstants.getErpFedActivationDelay(); + activations = mock(ActivationConfig.ForBlock.class); + + federation = createDefaultP2shErpFederation(); + } - ActivationConfig.ForBlock activations = mock(ActivationConfig.ForBlock.class); + private P2shErpFederation createDefaultP2shErpFederation() { + List standardMembers = FederationTestUtils.getFederationMembersWithBtcKeys(standardKeys); + Instant creationTime = ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(); + long creationBlockNumber = 0L; - Federation p2shErpFederation = new P2shErpFederation( - FederationTestUtils.getFederationMembersWithBtcKeys(standardKeys), - ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), - 0L, - bridgeConstants.getBtcParams(), + return new P2shErpFederation( + standardMembers, + creationTime, + creationBlockNumber, + networkParameters, emergencyKeys, - activationDelay, + activationDelayValue, + activations + ); + } + + @Test + void createInvalidP2shErpFederation_nullErpKeys() { + emergencyKeys = null; + FederationCreationException exception = assertThrows( + FederationCreationException.class, this::createDefaultP2shErpFederation + ); + assertEquals(NULL_OR_EMPTY_EMERGENCY_KEYS, exception.getReason()); + } + + @Test + void createInvalidP2shErpFederation_emptyErpKeys() { + emergencyKeys = new ArrayList<>(); + FederationCreationException exception = assertThrows( + FederationCreationException.class, this::createDefaultP2shErpFederation + ); + assertEquals(NULL_OR_EMPTY_EMERGENCY_KEYS, exception.getReason()); + } + + @Test + void createValidP2shErpFederation_oneErpKey() { + emergencyKeys = Collections.singletonList(emergencyKeys.get(0)); + assertDoesNotThrow(this::createDefaultP2shErpFederation); + } + + @Test + void createInvalidP2shErpFederation_negativeCsvValue() { + activationDelayValue = -100L; + FederationCreationException exception = assertThrows( + FederationCreationException.class, this::createDefaultP2shErpFederation + ); + assertEquals(INVALID_CSV_VALUE, exception.getReason()); + } + + @Test + void createInvalidP2shErpFederation_zeroCsvValue() { + activationDelayValue = 0L; + FederationCreationException exception = assertThrows( + FederationCreationException.class, this::createDefaultP2shErpFederation + ); + assertEquals(INVALID_CSV_VALUE, exception.getReason()); + } + + @Test + void createInvalidP2shErpFederation_aboveMaxCsvValue() { + activationDelayValue = MAX_CSV_VALUE + 1; + FederationCreationException exception = assertThrows( + FederationCreationException.class, this::createDefaultP2shErpFederation + ); + assertEquals(INVALID_CSV_VALUE, exception.getReason()); + } + + @Test + void createValidP2shErpFederation_exactMaxCsvValue() { + activationDelayValue = MAX_CSV_VALUE; + assertDoesNotThrow(this::createDefaultP2shErpFederation); + } + + @Test + void createInvalidFederation_aboveMaxScriptSigSize() { + // add one member to exceed redeem script size limit + List newStandardKeys = federation.getBtcPublicKeys(); + BtcECKey federator10PublicKey = BtcECKey.fromPublicOnly( + Hex.decode("02550cc87fa9061162b1dd395a16662529c9d8094c0feca17905a3244713d65fe8") + ); + newStandardKeys.add(federator10PublicKey); + standardKeys = newStandardKeys; + FederationCreationException exception = assertThrows( + FederationCreationException.class, this::createDefaultP2shErpFederation + ); + assertEquals(ABOVE_MAX_SCRIPT_ELEMENT_SIZE, exception.getReason()); + } + + @Test + void getErpPubKeys() { + assertEquals(emergencyKeys, federation.getErpPubKeys()); + } + + @Test + void getActivationDelay() { + assertEquals(activationDelayValue, federation.getActivationDelay()); + } + + @Test + void testEquals_basic() { + assertEquals(federation, federation); + + Assertions.assertNotEquals(null, federation); + Assertions.assertNotEquals(federation, new Object()); + Assertions.assertNotEquals("something else", federation); + } + + @Test + void testEquals_same() { + ErpFederation otherFederation = new P2shErpFederation( + federation.getMembers(), + federation.getCreationTime(), + federation.getCreationBlockNumber(), + federation.getBtcParams(), + federation.getErpPubKeys(), + federation.getActivationDelay(), activations ); + assertEquals(federation, otherFederation); + } + + @Test + void testEquals_differentNumberOfMembers() { + // remove federator9 + List newStandardKeys = federation.getBtcPublicKeys(); + newStandardKeys.remove(9); + standardKeys = newStandardKeys; + + ErpFederation otherFederation = createDefaultP2shErpFederation(); + Assertions.assertNotEquals(federation, otherFederation); + } + + @Test + void testEquals_differentNetworkParameters() { + networkParameters = NetworkParameters.fromID(NetworkParameters.ID_REGTEST); + + ErpFederation otherFederation = createDefaultP2shErpFederation(); + Assertions.assertNotEquals(federation, otherFederation); + } + + @Test + void testEquals_differentMembers() { + BtcECKey federator9PublicKey = BtcECKey.fromPublicOnly( + Hex.decode("0245ef34f5ee218005c9c21227133e8568a4f3f11aeab919c66ff7b816ae1ffeea") + ); + // replace federator8 with federator9 + List newStandardKeys = federation.getBtcPublicKeys(); + newStandardKeys.remove(8); + newStandardKeys.add(federator9PublicKey); + standardKeys = newStandardKeys; + + ErpFederation otherFederation = createDefaultP2shErpFederation(); + Assertions.assertNotEquals(federation, otherFederation); + } + + @ParameterizedTest + @MethodSource("getRedeemScriptArgsProvider") + void getRedeemScript(BridgeConstants bridgeConstants) { + if (!(bridgeConstants instanceof BridgeMainNetConstants)) { + // should add this case because adding erp to mainnet genesis federation + // throws a validation error, so in that case we use the one set up before each test. + // if using testnet constants, we can add them with no errors + standardKeys = bridgeConstants.getGenesisFederation().getBtcPublicKeys(); + } + + emergencyKeys = bridgeConstants.getErpFedPubKeysList(); + activationDelayValue = bridgeConstants.getErpFedActivationDelay(); + + ErpFederation p2shErpFederation = createDefaultP2shErpFederation(); validateP2shErpRedeemScript( p2shErpFederation.getRedeemScript(), standardKeys, emergencyKeys, - activationDelay + activationDelayValue ); } @Test - void getStandardRedeemscript() { + void getStandardRedeemScript() { List members = FederationMember.getFederationMembersFromKeys( Arrays.asList(new BtcECKey(), new BtcECKey(), new BtcECKey()) ); @@ -73,7 +265,7 @@ void getStandardRedeemscript() { ActivationConfig.ForBlock activations = ActivationConfigsForTest.all().forBlock(0); // Create a legacy powpeg and then a p2sh valid one. Both of them should produce the same standard redeem script - Federation legacyFed = new Federation( + StandardMultisigFederation legacyFed = new StandardMultisigFederation( members, creationTime, creationBlock, @@ -95,43 +287,49 @@ void getStandardRedeemscript() { } @Test - void getPowPegAddress_testnet() { + void getPowPegAddressAndP2shScript_testnet() { BridgeConstants bridgeTestNetConstants = BridgeTestNetConstants.getInstance(); - - List powpegKeys = Arrays.stream(new String[]{ - "020ace50bab1230f8002a0bfe619482af74b338cc9e4c956add228df47e6adae1c", - "0275d473555de2733c47125f9702b0f870df1d817379f5587f09b6c40ed2c6c949", - "025093f439fb8006fd29ab56605ffec9cdc840d16d2361004e1337a2f86d8bd2db", - "026b472f7d59d201ff1f540f111b6eb329e071c30a9d23e3d2bcd128fe73dc254c", - "03250c11be0561b1d7ae168b1f59e39cbc1fd1ba3cf4d2140c1a365b2723a2bf93", - "0357f7ed4c118e581f49cd3b4d9dd1edb4295f4def49d6dcf2faaaaac87a1a0a42", - "03ae72827d25030818c4947a800187b1fbcc33ae751e248ae60094cc989fb880f6", - "03e05bf6002b62651378b1954820539c36ca405cbb778c225395dd9ebff6780299", - "03b58a5da144f5abab2e03e414ad044b732300de52fa25c672a7f7b35888771906" + networkParameters = bridgeTestNetConstants.getBtcParams(); + emergencyKeys = bridgeTestNetConstants.getErpFedPubKeysList(); + activationDelayValue = bridgeTestNetConstants.getErpFedActivationDelay(); + + standardKeys = Arrays.stream(new String[]{ + "02099fd69cf6a350679a05593c3ff814bfaa281eb6dde505c953cf2875979b1209", + "022a159227df514c7b7808ee182ae07d71770b67eda1e5ee668272761eefb2c24c", + "0233bc8c1a994a921d7818f93e57a559373133ba531928843bf84c59c15e47eab0", + "02937df9948c6f18359e473beeee0a19c27dd4f6d4114e5809aa862671bb765b5b", + "02afc230c2d355b1a577682b07bc2646041b5d0177af0f98395a46018da699b6da", + "03db2ebad883823cefe8b2336c03b8d9c6afee4cbac77c7e935bc8c51ec20b2663", + "03fb8e1d5d0392d35ca8c3656acb6193dbf392b3e89b9b7b86693f5c80f7ce8581", }).map(hex -> BtcECKey.fromPublicOnly(Hex.decode(hex))).collect(Collectors.toList()); + + ErpFederation realP2shErpFederation = createDefaultP2shErpFederation(); + Script p2shScript = realP2shErpFederation.getP2SHScript(); + Address address = realP2shErpFederation.getAddress(); + + String expectedProgram = "a914007c29a1d854639220aefca2587cdde07f381f4787"; Address expectedAddress = Address.fromBase58( - bridgeTestNetConstants.getBtcParams(), - "2N7Y1BW8pMLMTQ1fg4kSAftSrwMwpb4S9B7" + networkParameters, + "2MsHnjFiAt5srgHJtwnwZTtZQPrKN8yiDqh" ); - Federation p2shErpFederation = new P2shErpFederation( - FederationTestUtils.getFederationMembersWithBtcKeys(powpegKeys), - Instant.now(), - 0L, - bridgeTestNetConstants.getBtcParams(), - bridgeTestNetConstants.getErpFedPubKeysList(), - bridgeTestNetConstants.getErpFedActivationDelay(), - mock(ActivationConfig.ForBlock.class) + assertEquals(expectedProgram, Hex.toHexString(p2shScript.getProgram())); + assertEquals(3, p2shScript.getChunks().size()); + assertEquals( + address, + p2shScript.getToAddress(networkParameters) ); - - assertEquals(expectedAddress, p2shErpFederation.getAddress()); + assertEquals(expectedAddress, address); } @Test - void getPowPegAddress_mainnet() { + void getPowPegAddressAndP2shScript_mainnet() { BridgeConstants bridgeMainNetConstants = BridgeMainNetConstants.getInstance(); + networkParameters = bridgeMainNetConstants.getBtcParams(); + emergencyKeys = bridgeMainNetConstants.getErpFedPubKeysList(); + activationDelayValue = bridgeMainNetConstants.getErpFedActivationDelay(); - List powpegKeys = Arrays.stream(new String[]{ + standardKeys = Arrays.stream(new String[]{ "020ace50bab1230f8002a0bfe619482af74b338cc9e4c956add228df47e6adae1c", "0275d473555de2733c47125f9702b0f870df1d817379f5587f09b6c40ed2c6c949", "025093f439fb8006fd29ab56605ffec9cdc840d16d2361004e1337a2f86d8bd2db", @@ -142,22 +340,69 @@ void getPowPegAddress_mainnet() { "03e05bf6002b62651378b1954820539c36ca405cbb778c225395dd9ebff6780299", "03b58a5da144f5abab2e03e414ad044b732300de52fa25c672a7f7b35888771906" }).map(hex -> BtcECKey.fromPublicOnly(Hex.decode(hex))).collect(Collectors.toList()); + + ErpFederation realP2shErpFederation = createDefaultP2shErpFederation(); + Script p2shScript = realP2shErpFederation.getP2SHScript(); + Address address = realP2shErpFederation.getAddress(); + + String expectedProgram = "a9142c1bab6ea51fdaf85c8366bd2b1502eaa69b6ae687"; Address expectedAddress = Address.fromBase58( - bridgeMainNetConstants.getBtcParams(), + networkParameters, "35iEoWHfDfEXRQ5ZWM5F6eMsY2Uxrc64YK" ); - Federation p2shErpFederation = new P2shErpFederation( - FederationTestUtils.getFederationMembersWithBtcKeys(powpegKeys), - Instant.now(), - 0L, - bridgeMainNetConstants.getBtcParams(), - bridgeMainNetConstants.getErpFedPubKeysList(), - bridgeMainNetConstants.getErpFedActivationDelay(), - mock(ActivationConfig.ForBlock.class) + assertEquals(expectedProgram, Hex.toHexString(p2shScript.getProgram())); + assertEquals(3, p2shScript.getChunks().size()); + assertEquals( + address, + p2shScript.getToAddress(networkParameters) ); + assertEquals(expectedAddress, address); + } + + @Test + void getErpPubKeys_uncompressed_public_keys() { + // Public keys used for creating federation, but uncompressed format now + emergencyKeys = emergencyKeys + .stream() + .map(BtcECKey::decompress) + .collect(Collectors.toList()); + + // Recreate federation + ErpFederation federationWithUncompressedKeys = createDefaultP2shErpFederation(); + assertEquals(emergencyKeys, federationWithUncompressedKeys.getErpPubKeys()); + } + + @Test + void getErpRedeemScript_compareOtherImplementation_P2SHERPFederation() throws IOException { + + byte[] rawRedeemScripts; + try { + rawRedeemScripts = Files.readAllBytes(Paths.get("src/test/resources/redeemScripts_p2shERP.json")); + } catch (IOException e) { + System.out.println("redeemScripts_p2shERP.json file not found"); + throw(e); + } - assertEquals(expectedAddress, p2shErpFederation.getAddress()); + RawGeneratedRedeemScript[] generatedScripts = new ObjectMapper().readValue(rawRedeemScripts, RawGeneratedRedeemScript[].class); + for (RawGeneratedRedeemScript generatedScript : generatedScripts) { + // Skip test cases with invalid redeem script that exceed the maximum size + if (generatedScript.script.getProgram().length <= MAX_SCRIPT_ELEMENT_SIZE) { + Federation erpFederation = new P2shErpFederation( + FederationTestUtils.getFederationMembersWithBtcKeys(generatedScript.mainFed), + ZonedDateTime.parse("2017-06-10T02:30:00Z").toInstant(), + 1, + NetworkParameters.fromID(NetworkParameters.ID_TESTNET), + generatedScript.emergencyFed, + generatedScript.timelock, + activations + ); + + Script rskjScript = erpFederation.getRedeemScript(); + Script alternativeScript = generatedScript.script; + assertEquals(alternativeScript, rskjScript); + } + } } @ParameterizedTest() @@ -319,4 +564,26 @@ private static Stream getRedeemScriptArgsProvider() { Arguments.of(BridgeTestNetConstants.getInstance()) ); } + + private static class RawGeneratedRedeemScript { + List mainFed; + List emergencyFed; + Long timelock; + Script script; + + @JsonCreator + public RawGeneratedRedeemScript(@JsonProperty("mainFed") List mainFed, + @JsonProperty("emergencyFed") List emergencyFed, + @JsonProperty("timelock") Long timelock, + @JsonProperty("script") String script) { + this.mainFed = parseFed(mainFed); + this.emergencyFed = parseFed(emergencyFed); + this.timelock = timelock; + this.script = new Script(Hex.decode(script)); + } + + private List parseFed(List fed) { + return fed.stream().map(Hex::decode).map(BtcECKey::fromPublicOnly).collect(Collectors.toList()); + } + } } 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 a5181a228df..76e19263bd4 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PegTestUtils.java +++ b/rskj-core/src/test/java/co/rsk/peg/PegTestUtils.java @@ -263,7 +263,7 @@ public static Federation createFederation(BridgeConstants bridgeConstants, Strin public static Federation createFederation(BridgeConstants bridgeConstants, List federationKeys) { federationKeys.sort(BtcECKey.PUBKEY_COMPARATOR); - return new Federation( + return new StandardMultisigFederation( FederationTestUtils.getFederationMembersWithBtcKeys(federationKeys), Instant.ofEpochMilli(1000L), 0L, diff --git a/rskj-core/src/test/java/co/rsk/peg/PendingFederationTest.java b/rskj-core/src/test/java/co/rsk/peg/PendingFederationTest.java index 26c80f27b0d..e0b2d77d73c 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PendingFederationTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PendingFederationTest.java @@ -298,7 +298,7 @@ private void testBuildFederation( activations ); } else if (isRskip201Active) { - expectedFederation = new ErpFederation( + expectedFederation = new LegacyErpFederation( FederationTestUtils.getFederationMembersFromPks(privateKeys), creationTime, 0L, @@ -308,7 +308,7 @@ private void testBuildFederation( activations ); } else { - expectedFederation = new Federation( + expectedFederation = new StandardMultisigFederation( FederationTestUtils.getFederationMembersFromPks(privateKeys), creationTime, 0L, 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 4e8f0c19797..4909cc5219e 100644 --- a/rskj-core/src/test/java/co/rsk/peg/PowpegMigrationTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/PowpegMigrationTest.java @@ -134,8 +134,8 @@ private void testChangePowpeg( Federation originalPowpeg; switch (oldPowPegFederationType) { - case erp: - originalPowpeg = new ErpFederation( + case legacyErp: + originalPowpeg = new LegacyErpFederation( originalPowpegMembers, Instant.now(), 0, @@ -145,7 +145,7 @@ private void testChangePowpeg( activations ); break; - case p2sh: + case p2shErp: originalPowpeg = new P2shErpFederation( originalPowpegMembers, Instant.now(), @@ -204,10 +204,10 @@ private void testChangePowpeg( Federation newPowPeg = argumentCaptor.getValue(); assertEquals(newPowPegAddress, newPowPeg.getAddress()); switch (newPowPegFederationType) { - case erp: - assertSame(ErpFederation.class, newPowPeg.getClass()); + case legacyErp: + assertSame(LegacyErpFederation.class, newPowPeg.getClass()); break; - case p2sh: + case p2shErp: assertSame(P2shErpFederation.class, newPowPeg.getClass()); // TODO: CHECK REDEEMSCRIPT break; @@ -588,17 +588,17 @@ private void testChangePowpeg( Script lastRetiredFederationP2SHScript = lastRetiredFederationP2SHScriptOptional.get(); if (activations.isActive(ConsensusRule.RSKIP377)){ - if (oldPowPegFederationType == FederationType.erp || oldPowPegFederationType == FederationType.p2sh){ + if (oldPowPegFederationType == FederationType.legacyErp || oldPowPegFederationType == FederationType.p2shErp){ assertNotEquals(lastRetiredFederationP2SHScript, originalPowpeg.getP2SHScript()); } - assertEquals(lastRetiredFederationP2SHScript, originalPowpeg.getStandardP2SHScript()); + assertEquals(lastRetiredFederationP2SHScript, originalPowpeg instanceof ErpFederation ? ((ErpFederation) originalPowpeg).getStandardP2SHScript() : originalPowpeg.getP2SHScript()); } else { - if (oldPowPegFederationType == FederationType.erp || oldPowPegFederationType == FederationType.p2sh){ + if (oldPowPegFederationType == FederationType.legacyErp || oldPowPegFederationType == FederationType.p2shErp){ assertEquals(lastRetiredFederationP2SHScript, originalPowpeg.getP2SHScript()); - assertNotEquals(lastRetiredFederationP2SHScript, originalPowpeg.getStandardP2SHScript()); + assertNotEquals(lastRetiredFederationP2SHScript, originalPowpeg instanceof ErpFederation ? ((ErpFederation) originalPowpeg).getStandardP2SHScript() : originalPowpeg.getP2SHScript()); } else { assertEquals(lastRetiredFederationP2SHScript, originalPowpeg.getP2SHScript()); - assertEquals(lastRetiredFederationP2SHScript, originalPowpeg.getStandardP2SHScript()); + assertEquals(lastRetiredFederationP2SHScript, originalPowpeg instanceof ErpFederation ? ((ErpFederation) originalPowpeg).getStandardP2SHScript() : originalPowpeg.getP2SHScript()); } } } @@ -620,10 +620,10 @@ private void verifyPegouts(BridgeStorageProvider bridgeStorageProvider) throws I Script inputStandardRedeemScript = RedeemScriptParserFactory.get(result.getChunks()).extractStandardRedeemScript(); Optional spendingFederationOptional = Optional.empty(); - if (inputStandardRedeemScript.equals(activeFederation.getStandardRedeemScript())) { + if (inputStandardRedeemScript.equals(activeFederation instanceof ErpFederation ? ((ErpFederation) activeFederation).getStandardRedeemScript() : activeFederation.getRedeemScript())) { spendingFederationOptional = Optional.of(activeFederation); } else if (retiringFederation != null && - inputStandardRedeemScript.equals(retiringFederation.getStandardRedeemScript())) { + inputStandardRedeemScript.equals(retiringFederation instanceof ErpFederation ? ((ErpFederation) retiringFederation).getStandardRedeemScript() : retiringFederation.getRedeemScript()) ) { spendingFederationOptional = Optional.of(retiringFederation); } else { fail("pegout scriptsig does not match any Federation"); @@ -1321,11 +1321,11 @@ void test_change_powpeg_from_erpFederation_with_mainnet_powpeg_pre_RSKIP_353_cre ); testChangePowpeg( - FederationType.erp, + FederationType.legacyErp, getMainnetPowpegKeys(), originalPowpegAddress, utxos, - FederationType.erp, + FederationType.legacyErp, newPowpegKeys, newPowpegAddress, bridgeConstants, @@ -1347,11 +1347,11 @@ void test_change_powpeg_from_erpFederation_with_mainnet_powpeg_post_RSKIP_353_cr ); testChangePowpeg( - FederationType.erp, + FederationType.legacyErp, getMainnetPowpegKeys(), originalPowpegAddress, utxos, - FederationType.p2sh, + FederationType.p2shErp, getMainnetPowpegKeys(), // Using same keys as the original powpeg, should result in a different address since it will create a p2sh erp federation newPowpegAddress, bridgeConstants, @@ -1393,11 +1393,11 @@ void test_change_powpeg_from_p2shErpFederation_with_mainnet_powpeg_post_RSKIP_35 ); testChangePowpeg( - FederationType.p2sh, + FederationType.p2shErp, getMainnetPowpegKeys(), originalPowpegAddress, utxos, - FederationType.p2sh, + FederationType.p2shErp, newPowPegKeys, newPowPegAddress, bridgeConstants, @@ -1458,11 +1458,11 @@ void test_change_powpeg_from_p2shErpFederation_with_mainnet_powpeg(ActivationCon ); testChangePowpeg( - FederationType.p2sh, + FederationType.p2shErp, getMainnetPowpegKeys(), originalPowpegAddress, utxos, - FederationType.p2sh, + FederationType.p2shErp, newPowPegKeys, newPowPegAddress, bridgeConstants, @@ -1506,11 +1506,11 @@ void test_change_powpeg_from_p2shErpFederation_with_mainnet_powpeg_post_RSKIP_37 ); testChangePowpeg( - FederationType.p2sh, + FederationType.p2shErp, getMainnetPowpegKeys(), originalPowpegAddress, utxos, - FederationType.p2sh, + FederationType.p2shErp, newPowPegKeys, newPowPegAddress, bridgeConstants, @@ -1520,8 +1520,8 @@ void test_change_powpeg_from_p2shErpFederation_with_mainnet_powpeg_post_RSKIP_37 } private enum FederationType { - erp, - p2sh, - standard + legacyErp, + p2shErp, + standardMultisig } } diff --git a/rskj-core/src/test/java/co/rsk/peg/ReleaseTransactionBuilderTest.java b/rskj-core/src/test/java/co/rsk/peg/ReleaseTransactionBuilderTest.java index 481f50c57aa..8d2ef553fe8 100644 --- a/rskj-core/src/test/java/co/rsk/peg/ReleaseTransactionBuilderTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/ReleaseTransactionBuilderTest.java @@ -90,7 +90,7 @@ void setup() { @Test void first_output_pay_fees() { - Federation federation = new Federation( + Federation federation = new StandardMultisigFederation( FederationMember.getFederationMembersFromKeys(Arrays.asList( new BtcECKey(), new BtcECKey(), @@ -164,7 +164,7 @@ void build_pegout_tx_from_erp_federation() { // Use mainnet constants to test a real situation BridgeConstants bridgeConstants = BridgeMainNetConstants.getInstance(); - Federation erpFederation = new ErpFederation( + Federation erpFederation = new LegacyErpFederation( FederationMember.getFederationMembersFromKeys(Arrays.asList( new BtcECKey(), new BtcECKey(), diff --git a/rskj-core/src/test/java/co/rsk/peg/StandardMultisigFederationTest.java b/rskj-core/src/test/java/co/rsk/peg/StandardMultisigFederationTest.java new file mode 100644 index 00000000000..fee7f0045e7 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/peg/StandardMultisigFederationTest.java @@ -0,0 +1,323 @@ +/* + * This file is part of RskJ + * Copyright (C) 2017 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package co.rsk.peg; + +import static co.rsk.peg.FederationCreationException.Reason.ABOVE_MAX_SCRIPT_ELEMENT_SIZE; +import static org.junit.jupiter.api.Assertions.*; + +import co.rsk.bitcoinj.core.Address; +import co.rsk.bitcoinj.core.BtcECKey; +import co.rsk.bitcoinj.core.NetworkParameters; +import co.rsk.bitcoinj.script.Script; +import co.rsk.bitcoinj.script.ScriptOpCodes; +import java.math.BigInteger; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import co.rsk.config.BridgeConstants; +import co.rsk.config.BridgeMainNetConstants; +import org.bouncycastle.util.encoders.Hex; +import org.ethereum.TestUtils; +import org.ethereum.crypto.ECKey; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + + +class StandardMultisigFederationTest { + private Federation federation; + private NetworkParameters networkParameters; + + private List keys; + private List sortedPublicKeys; + private List rskAddresses; + + @BeforeEach + void setUp() { + BridgeConstants bridgeConstants = BridgeMainNetConstants.getInstance(); + + networkParameters = bridgeConstants.getBtcParams(); + federation = bridgeConstants.getGenesisFederation(); + + keys = federation.getBtcPublicKeys(); + sortedPublicKeys = keys.stream() + .sorted(BtcECKey.PUBKEY_COMPARATOR).collect(Collectors.toList()); + + List rskPubKeys = sortedPublicKeys.stream() + .map(btcECKey -> ECKey.fromPublicOnly(btcECKey.getPubKey())) + .collect(Collectors.toList()); + rskAddresses = rskPubKeys + .stream() + .map(ECKey::getAddress) + .collect(Collectors.toList()); + } + + @Test + void createInvalidFederation_aboveMaxScriptSigSize() { + List newKeys = federation.getBtcPublicKeys(); + BtcECKey federator15PublicKey = BtcECKey.fromPublicOnly( + Hex.decode("03b65684ccccda83cbb1e56b31308acd08e993114c33f66a456b627c2c1c68bed6") + ); + + // add one member to exceed redeem script size limit + newKeys.add(federator15PublicKey); + List newMembers = FederationTestUtils.getFederationMembersWithBtcKeys(newKeys); + Instant creationTime = federation.getCreationTime(); + FederationCreationException exception = + assertThrows(FederationCreationException.class, () -> new StandardMultisigFederation( + newMembers, + creationTime, + federation.creationBlockNumber, + federation.btcParams + )); + assertEquals(ABOVE_MAX_SCRIPT_ELEMENT_SIZE, exception.getReason()); + } + + @Test + void membersImmutable() { + boolean exception = false; + try { + federation.getMembers().add(new FederationMember(new BtcECKey(), new ECKey(), new ECKey())); + } catch (Exception e) { + exception = true; + } + Assertions.assertTrue(exception); + + exception = false; + try { + federation.getMembers().remove(0); + } catch (Exception e) { + exception = true; + } + Assertions.assertTrue(exception); + } + + @Test + void testEquals_basic() { + assertEquals(federation, federation); + + assertNotEquals(null, federation); + assertNotEquals(federation, new Object()); + assertNotEquals("something else", federation); + } + + @Test + void testEquals_same() { + Federation otherFederation = new StandardMultisigFederation( + federation.getMembers(), + federation.getCreationTime(), + federation.getCreationBlockNumber(), + federation.getBtcParams() + ); + + assertEquals(federation, otherFederation); + } + + @Test + void testEquals_differentCreationTime() { + Federation otherFederation = new StandardMultisigFederation( + federation.getMembers(), + federation.getCreationTime().plus(1, ChronoUnit.MILLIS), + federation.getCreationBlockNumber(), + networkParameters + ); + assertEquals(federation, otherFederation); + } + + @Test + void testEquals_differentCreationBlockNumber() { + Federation otherFederation = new StandardMultisigFederation( + federation.getMembers(), + federation.getCreationTime(), + federation.getCreationBlockNumber() + 1, + networkParameters + ); + assertEquals(federation, otherFederation); + } + + @Test + void testEquals_differentNetworkParameters() { + Federation otherFederation = new StandardMultisigFederation( + federation.getMembers(), + federation.getCreationTime(), + federation.getCreationBlockNumber(), + NetworkParameters.fromID(NetworkParameters.ID_REGTEST) + ); + // Different network parameters will result in a different address + assertNotEquals(federation, otherFederation); + } + + @Test + void testEquals_differentNumberOfMembers() { + // remove federator14 + List newKeys = federation.getBtcPublicKeys(); + newKeys.remove(14); + List newMembers = FederationTestUtils.getFederationMembersWithKeys(newKeys); + + Federation otherFederation = new StandardMultisigFederation( + newMembers, + federation.getCreationTime(), + federation.getCreationBlockNumber(), + federation.getBtcParams() + ); + + Assertions.assertNotEquals(federation, otherFederation); + } + + @Test + void testEquals_differentMembers() { + // replace federator15 with another pkey + BtcECKey anotherPublicKey = BtcECKey.fromPublicOnly( + Hex.decode("03b65694ccccda83cbb1e56b31308acd08e993114c33f66a456b627c2c1c68bed7") + ); + List newKeys = federation.getBtcPublicKeys(); + newKeys.remove(14); + newKeys.add(anotherPublicKey); + List differentMembers = FederationTestUtils.getFederationMembersWithKeys(newKeys); + + Federation otherFederation = new StandardMultisigFederation( + differentMembers, + federation.getCreationTime(), + federation.getCreationBlockNumber(), + networkParameters + ); + + assertNotEquals(federation, otherFederation); + } + + @Test + void getP2SHScriptAndAddress() { + Script p2shScript = federation.getP2SHScript(); + Address address = federation.getAddress(); + + String expectedProgram = "a91451f103320b435b5fe417b3f3e0f18972ccc710a087"; + Address expectedAddress = Address.fromBase58( + networkParameters, + "39AHNvUmzaYgewA8yCtBtNsfRz7QD7ZJYi" + ); + + assertEquals(expectedProgram, Hex.toHexString(p2shScript.getProgram())); + assertEquals(3, p2shScript.getChunks().size()); + assertEquals( + address, + p2shScript.getToAddress(networkParameters) + ); + assertEquals(expectedAddress, address); + } + + @Test + void getRedeemScript() { + Script expectedScript = new Script(Hex.decode("58210245ef34f5ee218005c9c21227133e8568a4f3f11aeab919c66ff7b816ae1ffeea2102481f02b7140acbf3fcdd9f72cf9a7d9484d8125e6df7c9451cfa55ba3b0772652102550cc87fa9061162b1dd395a16662529c9d8094c0feca17905a3244713d65fe82102566d5ded7c7db1aa7ee4ef6f76989fb42527fcfdcddcd447d6793b7d869e46f721027319afb15481dbeb3c426bcc37f9a30e7f51ceff586936d85548d9395bcc2344210294c817150f78607566e961b3c71df53a22022a80acbb982f83c0c8baac040adc2102ac1901b6fba2c1dbd47d894d2bd76c8ba1d296d65f6ab47f1c6b22afb53e73eb2102c6018fcbd3e89f3cf9c7f48b3232ea3638eb8bf217e59ee290f5f0cfb2fb925921031aabbeb9b27258f98c2bf21f36677ae7bae09eb2d8c958ef41a20a6e88626d26210340df69f28d69eef60845da7d81ff60a9060d4da35c767f017b0dd4e20448fb44210355a2e9bf100c00fc0a214afd1bf272647c7824eb9cb055480962f0c382596a70210372cd46831f3b6afd4c044d160b7667e8ebf659d6cb51a825a3104df6ee0638c62103b53899c390573471ba30e5054f78376c5f797fda26dde7a760789f02908cbad22103b65694ccccda83cbb1e56b31308acd08e993114c33f66a456b627c2c1c68bed62103f909ae15558c70cc751aff9b1f495199c325b13a9e5b934fd6299cd30ec50be85fae")); + Script redeemScript = federation.getRedeemScript(); + assertEquals(expectedScript, redeemScript); + + int expectedChunks = sortedPublicKeys.size() + 3; // + 3 opcodes (OP_M, OP_N, OP_CHECKMULTISIG) + assertEquals(expectedChunks, redeemScript.getChunks().size()); + + int opM = ScriptOpCodes.getOpCode("" + federation.getNumberOfSignaturesRequired()); + assertEquals(opM, redeemScript.getChunks().get(0).opcode); + + for (int i = 0; i < sortedPublicKeys.size(); i++) { + assertArrayEquals(sortedPublicKeys.get(i).getPubKey(), redeemScript.getChunks().get(i+1).data); + } + + int opN = ScriptOpCodes.getOpCode("" + federation.getSize()); + assertEquals(opN, redeemScript.getChunks().get(redeemScript.getChunks().size() - 2).opcode); + assertEquals(ScriptOpCodes.OP_CHECKMULTISIG, redeemScript.getChunks().get(redeemScript.getChunks().size() - 1).opcode); + } + + @Test + void getBtcPublicKeyIndex() { + for (int i = 0; i < federation.getBtcPublicKeys().size(); i++) { + Optional index = federation.getBtcPublicKeyIndex(sortedPublicKeys.get(i)); + assertTrue(index.isPresent()); + assertEquals(i, index.get().intValue()); + } + assertFalse(federation.getBtcPublicKeyIndex(BtcECKey.fromPrivate(BigInteger.valueOf(1234))).isPresent()); + } + + @Test + void hasBtcPublicKey() { + for (int i = 0; i < federation.getBtcPublicKeys().size(); i++) { + assertTrue(federation.hasBtcPublicKey(sortedPublicKeys.get(i))); + } + assertFalse(federation.hasBtcPublicKey(BtcECKey.fromPrivate(BigInteger.valueOf(1234)))); + } + + @Test + void hasMemberWithRskAddress() { + for (int i = 0; i < federation.getBtcPublicKeys().size(); i++) { + assertTrue(federation.hasMemberWithRskAddress(rskAddresses.get(i))); + } + + byte[] nonFederateRskAddress = ECKey.fromPrivate(BigInteger.valueOf(1234)).getAddress(); + assertFalse(federation.hasMemberWithRskAddress(nonFederateRskAddress)); + } + + @Test + void testToString() { + assertEquals( + "Got 8 of 15 signatures federation with address 39AHNvUmzaYgewA8yCtBtNsfRz7QD7ZJYi", + federation.toString() + ); + } + + @Test + void isMember(){ + //Both valid params + FederationMember federationMember = federation.getMembers().get(0); + assertTrue(federation.isMember(federationMember)); + + byte[] b = TestUtils.generateBytes("b",20); + + ECKey invalidRskKey = ECKey.fromPrivate(b); + BtcECKey invalidBtcKey = BtcECKey.fromPrivate(b); + + // Valid PubKey, invalid rskAddress + FederationMember invalidRskPubKey = new FederationMember( + federationMember.getBtcPublicKey(), + invalidRskKey, + federationMember.getMstPublicKey() + ); + assertFalse(federation.isMember(invalidRskPubKey)); + + //Invalid PubKey, valid rskAddress + FederationMember invalidBtcPubKey = new FederationMember( + invalidBtcKey, + federationMember.getRskPublicKey(), + federationMember.getMstPublicKey() + ); + assertFalse(federation.isMember(invalidBtcPubKey)); + + //Valid btcKey & valid rskAddress, invalid mstKey + FederationMember invalidMstPubKey = new FederationMember( + federationMember.getBtcPublicKey(), + federationMember.getRskPublicKey(), + invalidRskKey + ); + assertFalse(federation.isMember(invalidMstPubKey)); + + //All invalid params + FederationMember invalidPubKeys = new FederationMember(invalidBtcKey, invalidRskKey, invalidRskKey); + assertFalse(federation.isMember(invalidPubKeys)); + } +} diff --git a/rskj-core/src/test/java/co/rsk/peg/performance/ActiveFederationTest.java b/rskj-core/src/test/java/co/rsk/peg/performance/ActiveFederationTest.java index 5ef18a595bc..96b4a111779 100644 --- a/rskj-core/src/test/java/co/rsk/peg/performance/ActiveFederationTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/performance/ActiveFederationTest.java @@ -20,10 +20,7 @@ import co.rsk.bitcoinj.core.BtcECKey; import co.rsk.bitcoinj.store.BtcBlockStore; -import co.rsk.peg.Bridge; -import co.rsk.peg.BridgeStorageProvider; -import co.rsk.peg.Federation; -import co.rsk.peg.FederationMember; +import co.rsk.peg.*; import org.ethereum.TestUtils; import org.ethereum.core.CallTransaction; import org.ethereum.core.Repository; @@ -117,7 +114,7 @@ private BridgeStorageProviderInitializer buildInitializer(boolean genesis) { int numFederators = Helper.randomInRange(minFederators, maxFederators); List members = getNRandomFederationMembers(numFederators); - federation = new Federation( + federation = new StandardMultisigFederation( members, Instant.ofEpochMilli(TestUtils.generateLong(String.valueOf(executionIndex))), Helper.randomInRange(1, 10), diff --git a/rskj-core/src/test/java/co/rsk/peg/performance/RetiringFederationTest.java b/rskj-core/src/test/java/co/rsk/peg/performance/RetiringFederationTest.java index 669478ce058..227f4d13f5a 100644 --- a/rskj-core/src/test/java/co/rsk/peg/performance/RetiringFederationTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/performance/RetiringFederationTest.java @@ -22,6 +22,7 @@ import co.rsk.peg.Bridge; import co.rsk.peg.BridgeStorageProvider; import co.rsk.peg.Federation; +import co.rsk.peg.StandardMultisigFederation; import org.ethereum.core.CallTransaction; import org.ethereum.core.Repository; import org.ethereum.vm.exception.VMException; @@ -103,7 +104,7 @@ private BridgeStorageProviderInitializer buildInitializer(boolean present) { return (BridgeStorageProvider provider, Repository repository, int executionIndex, BtcBlockStore blockStore) -> { if (present) { int numFederators = Helper.randomInRange(minFederators, maxFederators); - retiringFederation = new Federation( + retiringFederation = new StandardMultisigFederation( ActiveFederationTest.getNRandomFederationMembers(numFederators), Instant.ofEpochMilli(random.nextLong()), Helper.randomInRange(1, 10), diff --git a/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerImplTest.java b/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerImplTest.java index 7876cc65a4e..a83045a72a9 100644 --- a/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerImplTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerImplTest.java @@ -221,7 +221,7 @@ void logCommitFederation(boolean isRSKIP383Active) { List oldFederationMembers = FederationTestUtils.getFederationMembersWithBtcKeys(oldFederationKeys); - Federation oldFederation = new Federation( + Federation oldFederation = new StandardMultisigFederation( oldFederationMembers, Instant.ofEpochMilli(15005L), 15L, @@ -236,7 +236,7 @@ void logCommitFederation(boolean isRSKIP383Active) { List newFederationMembers = FederationTestUtils.getFederationMembersWithBtcKeys(newFederationKeys); - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( newFederationMembers, Instant.ofEpochMilli(5005L), 0L, diff --git a/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerLegacyImplTest.java b/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerLegacyImplTest.java index ea3473dfe26..dfc52e60c63 100644 --- a/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerLegacyImplTest.java +++ b/rskj-core/src/test/java/co/rsk/peg/utils/BridgeEventLoggerLegacyImplTest.java @@ -207,7 +207,7 @@ void testLogCommitFederationBeforeRskip146() { List oldFederationMembers = FederationTestUtils.getFederationMembersWithBtcKeys(oldFederationKeys); - Federation oldFederation = new Federation(oldFederationMembers, + Federation oldFederation = new StandardMultisigFederation(oldFederationMembers, Instant.ofEpochMilli(15005L), 15L, NetworkParameters.fromID(NetworkParameters.ID_REGTEST)); List newFederationKeys = Arrays.asList( @@ -218,7 +218,7 @@ void testLogCommitFederationBeforeRskip146() { List newFederationMembers = FederationTestUtils.getFederationMembersWithBtcKeys(newFederationKeys); - Federation newFederation = new Federation( + Federation newFederation = new StandardMultisigFederation( newFederationMembers, Instant.ofEpochMilli(5005L), 0L, diff --git a/rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleDSLTest.java b/rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleDSLTest.java index 79fea1f08bb..cad63aba4f2 100644 --- a/rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleDSLTest.java +++ b/rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleDSLTest.java @@ -26,7 +26,10 @@ import org.ethereum.core.TransactionReceipt; import org.ethereum.rpc.CallArguments; import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.BlockIdentifierParam; +import org.ethereum.rpc.parameters.CallArgumentsParam; import org.ethereum.util.EthModuleTestUtils; +import org.ethereum.util.TransactionFactoryHelper; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.jupiter.api.Assertions; @@ -62,15 +65,17 @@ void testCall_getRevertReason() throws FileNotFoundException, DslProcessorExcept args.setValue("0"); args.setNonce("1"); args.setGas("10000000"); + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("0x2"); try { - eth.call(args, "0x2"); + eth.call(callArgumentsParam, blockIdentifierParam); fail(); } catch (RskJsonRpcRequestException e) { MatcherAssert.assertThat(e.getMessage(), Matchers.containsString("Negative value.")); } args.setData("0xd96a094a0000000000000000000000000000000000000000000000000000000000000001"); // call to contract with param value = 1 - final String call = eth.call(args, "0x2"); + final String call = eth.call(TransactionFactoryHelper.toCallArgumentsParam(args), new BlockIdentifierParam("0x2")); assertEquals("0x", call); } } diff --git a/rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleGasEstimationDSLTest.java b/rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleGasEstimationDSLTest.java index d5cc63fc134..751ace983bd 100644 --- a/rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleGasEstimationDSLTest.java +++ b/rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleGasEstimationDSLTest.java @@ -31,8 +31,10 @@ import org.ethereum.core.genesis.BlockTag; import org.ethereum.crypto.HashUtil; import org.ethereum.rpc.CallArguments; +import org.ethereum.rpc.parameters.BlockIdentifierParam; import org.ethereum.util.ByteUtil; import org.ethereum.util.EthModuleTestUtils; +import org.ethereum.util.TransactionFactoryHelper; import org.ethereum.vm.GasCost; import org.ethereum.vm.LogInfo; import org.ethereum.vm.program.InternalTransaction; @@ -289,7 +291,7 @@ void estimateGas_gasCap() throws FileNotFoundException, DslProcessorException { callArguments.setGas(HexUtils.toQuantityJsonHex(gasEstimationCap + 1_000_000_000)); // exceeding the gas cap callArguments.setData("0x31fe52e8"); // call outOfGas() - String estimatedGas = eth.estimateGas(callArguments, BlockTag.LATEST.getTag()); + String estimatedGas = eth.estimateGas(TransactionFactoryHelper.toCallArgumentsParam(callArguments), new BlockIdentifierParam(BlockTag.LATEST.getTag())); assertEquals("0x67c280", estimatedGas); assertEquals(gasEstimationCap, Long.decode(estimatedGas).longValue()); @@ -786,7 +788,7 @@ public boolean runWithArgumentsAndBlock(EthModuleTestUtils.EthModuleGasEstimatio } private long estimateGas(EthModuleTestUtils.EthModuleGasEstimation eth, CallArguments args, String bnOrId) { - return Long.parseLong(eth.estimateGas(args, bnOrId).substring("0x".length()), 16); + return Long.parseLong(eth.estimateGas(TransactionFactoryHelper.toCallArgumentsParam(args), new BlockIdentifierParam(bnOrId)).substring("0x".length()), 16); } // todo this is duplicated code, should be extracted into a test util diff --git a/rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleTest.java b/rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleTest.java index 86713193d0d..e2e030935a0 100644 --- a/rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleTest.java +++ b/rskj-core/src/test/java/co/rsk/rpc/modules/eth/EthModuleTest.java @@ -36,6 +36,10 @@ import org.ethereum.datasource.HashMapDB; import org.ethereum.rpc.CallArguments; import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.BlockIdentifierParam; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.rpc.parameters.HexAddressParam; +import org.ethereum.rpc.parameters.HexDataParam; import org.ethereum.util.ByteUtil; import org.ethereum.util.TransactionFactoryHelper; import org.ethereum.vm.program.ProgramResult; @@ -43,18 +47,20 @@ import org.hamcrest.Matchers; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; class EthModuleTest { + public static final String TEST_DATA = "0x603d80600c6000396000f3007c01000000000000000000000000000000000000000000000000000000006000350463c6888fa18114602d57005b6007600435028060005260206000f3"; + private final TestSystemProperties config = new TestSystemProperties(); - private SignatureCache signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); + private final SignatureCache signatureCache = new BlockTxSignatureCache(new ReceivedTxSignatureCache()); @Test void callSmokeTest() { @@ -91,7 +97,7 @@ void callSmokeTest() { config.getCallGasCap()); String expectedResult = HexUtils.toUnformattedJsonHex(hReturn); - String actualResult = eth.call(args, "latest"); + String actualResult = eth.call(TransactionFactoryHelper.toCallArgumentsParam(args), new BlockIdentifierParam("latest")); assertEquals(expectedResult, actualResult); } @@ -131,7 +137,7 @@ void callWithoutReturn() { config.getCallGasCap()); String expectedResult = HexUtils.toUnformattedJsonHex(hReturn); - String actualResult = eth.call(args, "latest"); + String actualResult = eth.call(TransactionFactoryHelper.toCallArgumentsParam(args), new BlockIdentifierParam("latest")); assertEquals(expectedResult, actualResult); } @@ -176,7 +182,7 @@ void test_revertedTransaction() { config.getCallGasCap()); try { - eth.call(args, "latest"); + eth.call(TransactionFactoryHelper.toCallArgumentsParam(args), new BlockIdentifierParam("latest")); } catch (RskJsonRpcRequestException e) { assertThat(e.getMessage(), Matchers.containsString("deposit too big")); } @@ -207,7 +213,7 @@ void sendTransactionWithGasLimitTest() { EthModuleTransactionBase ethModuleTransaction = new EthModuleTransactionBase(constants, wallet, transactionPool, transactionGateway); // Hash of the actual transaction builded inside the sendTransaction - String txResult = ethModuleTransaction.sendTransaction(args); + String txResult = ethModuleTransaction.sendTransaction(TransactionFactoryHelper.toCallArgumentsParam(args)); assertEquals(txExpectedResult, txResult); } @@ -235,7 +241,8 @@ void sendTransactionThrowsErrorOnChainIdValidationTest() { EthModuleTransactionBase ethModuleTransaction = new EthModuleTransactionBase(constants, wallet, transactionPool, transactionGateway); - Assertions.assertThrows(RskJsonRpcRequestException.class, () -> ethModuleTransaction.sendTransaction(args)); + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + Assertions.assertThrows(RskJsonRpcRequestException.class, () -> ethModuleTransaction.sendTransaction(callArgumentsParam)); } @Test @@ -264,7 +271,8 @@ void sendRawTransactionThrowsErrorOnChainIdValidationTest() { EthModuleTransactionBase ethModuleTransaction = new EthModuleTransactionBase(constants, wallet, transactionPool, transactionGateway); String rawData = ByteUtil.toHexString(tx.getEncoded()); - Assertions.assertThrows(RskJsonRpcRequestException.class, () -> ethModuleTransaction.sendRawTransaction(rawData)); + HexDataParam hexDataParam = new HexDataParam(rawData); + Assertions.assertThrows(RskJsonRpcRequestException.class, () -> ethModuleTransaction.sendRawTransaction(hexDataParam)); } @Test @@ -281,12 +289,12 @@ void sendTransaction_invalidSenderAccount_throwsRskJsonRpcRequestException() { EthModuleTransactionBase ethModuleTransaction = new EthModuleTransactionBase(constants, wallet, transactionPoolMock, transactionGatewayMock); + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(argsMock); // Then try { - ethModuleTransaction.sendTransaction(argsMock); + ethModuleTransaction.sendTransaction(callArgumentsParam); fail("RskJsonRpcRequestException should be thrown"); } catch (RskJsonRpcRequestException ex) { - verify(argsMock, times(2)).getFrom(); assertEquals("Could not find account for address: " + addressFrom.toJsonString(), ex.getMessage()); } } @@ -321,7 +329,8 @@ void getCode() { config.getCallGasCap() ); - String addr = eth.getCode(TestUtils.generateAddress("addr").toHexString(), "pending"); + HexAddressParam addressParam = new HexAddressParam(TestUtils.generateAddress("addr").toHexString()); + String addr = eth.getCode(addressParam, "pending"); MatcherAssert.assertThat(Hex.decode(addr.substring("0x".length())), is(expectedCode)); } @@ -343,4 +352,383 @@ void chainId() { ); assertThat(eth.chainId(), is("0x21")); } + + @Test + void whenExecuteCallWithDataParameter_callExecutorWithData() { + CallArguments args = new CallArguments(); + args.setData(TEST_DATA); + ExecutionBlockRetriever.Result blockResult = mock(ExecutionBlockRetriever.Result.class); + Block block = mock(Block.class); + ExecutionBlockRetriever retriever = mock(ExecutionBlockRetriever.class); + when(retriever.retrieveExecutionBlock("latest")) + .thenReturn(blockResult); + when(blockResult.getBlock()).thenReturn(block); + + byte[] hReturn = HexUtils.stringToByteArray("hello"); + ProgramResult executorResult = mock(ProgramResult.class); + when(executorResult.getHReturn()) + .thenReturn(hReturn); + + ReversibleTransactionExecutor executor = mock(ReversibleTransactionExecutor.class); + when(executor.executeTransaction(eq(blockResult.getBlock()), any(), any(), any(), any(), any(), any(), any())) + .thenReturn(executorResult); + + EthModule eth = new EthModule( + null, + anyByte(), + null, + null, + executor, + retriever, + null, + null, + null, + new BridgeSupportFactory( + null, null, null, signatureCache), + config.getGasEstimationCap(), + config.getCallGasCap()); + + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("latest"); + + eth.call(callArgumentsParam, blockIdentifierParam); + + ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(byte[].class); + verify(executor, times(1)) + .executeTransaction(eq(blockResult.getBlock()), any(), any(), any(), any(), any(), dataCaptor.capture(), any()); + assertArrayEquals(HexUtils.strHexOrStrNumberToByteArray(args.getData()), dataCaptor.getValue()); + } + + @Test + void whenExecuteCallWithInputParameter_callExecutorWithInput() { + CallArguments args = new CallArguments(); + args.setInput(TEST_DATA); + ExecutionBlockRetriever.Result blockResult = mock(ExecutionBlockRetriever.Result.class); + Block block = mock(Block.class); + ExecutionBlockRetriever retriever = mock(ExecutionBlockRetriever.class); + when(retriever.retrieveExecutionBlock("latest")) + .thenReturn(blockResult); + when(blockResult.getBlock()).thenReturn(block); + + byte[] hReturn = HexUtils.stringToByteArray("hello"); + ProgramResult executorResult = mock(ProgramResult.class); + when(executorResult.getHReturn()) + .thenReturn(hReturn); + + ReversibleTransactionExecutor executor = mock(ReversibleTransactionExecutor.class); + when(executor.executeTransaction(eq(blockResult.getBlock()), any(), any(), any(), any(), any(), any(), any())) + .thenReturn(executorResult); + + EthModule eth = new EthModule( + null, + anyByte(), + null, + null, + executor, + retriever, + null, + null, + null, + new BridgeSupportFactory( + null, null, null, signatureCache), + config.getGasEstimationCap(), + config.getCallGasCap()); + + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("latest"); + + eth.call(callArgumentsParam, blockIdentifierParam); + + ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(byte[].class); + verify(executor, times(1)) + .executeTransaction(eq(blockResult.getBlock()), any(), any(), any(), any(), any(), dataCaptor.capture(), any()); + assertArrayEquals(HexUtils.strHexOrStrNumberToByteArray(args.getInput()), dataCaptor.getValue()); + } + + @Test + void whenExecuteCallWithInputAndDataParameters_callExecutorWithInput() { + CallArguments args = new CallArguments(); + args.setData(TEST_DATA); + args.setInput(TEST_DATA); + ExecutionBlockRetriever.Result blockResult = mock(ExecutionBlockRetriever.Result.class); + Block block = mock(Block.class); + ExecutionBlockRetriever retriever = mock(ExecutionBlockRetriever.class); + when(retriever.retrieveExecutionBlock("latest")) + .thenReturn(blockResult); + when(blockResult.getBlock()).thenReturn(block); + + byte[] hReturn = HexUtils.stringToByteArray("hello"); + ProgramResult executorResult = mock(ProgramResult.class); + when(executorResult.getHReturn()) + .thenReturn(hReturn); + + ReversibleTransactionExecutor executor = mock(ReversibleTransactionExecutor.class); + when(executor.executeTransaction(eq(blockResult.getBlock()), any(), any(), any(), any(), any(), any(), any())) + .thenReturn(executorResult); + + EthModule eth = new EthModule( + null, + anyByte(), + null, + null, + executor, + retriever, + null, + null, + null, + new BridgeSupportFactory( + null, null, null, signatureCache), + config.getGasEstimationCap(), + config.getCallGasCap()); + + + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("latest"); + + eth.call(callArgumentsParam, blockIdentifierParam); + + ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(byte[].class); + verify(executor, times(1)) + .executeTransaction(eq(blockResult.getBlock()), any(), any(), any(), any(), any(), dataCaptor.capture(), any()); + assertArrayEquals(HexUtils.strHexOrStrNumberToByteArray(args.getInput()), dataCaptor.getValue()); + } + + @Test + void whenExecuteEstimateGasWithDataParameter_callExecutorWithData() { + CallArguments args = new CallArguments(); + args.setData(TEST_DATA); + Block block = mock(Block.class); + ExecutionBlockRetriever.Result blockResult = mock(ExecutionBlockRetriever.Result.class); + when(blockResult.getBlock()).thenReturn(block); + ExecutionBlockRetriever retriever = mock(ExecutionBlockRetriever.class); + when(retriever.retrieveExecutionBlock("latest")).thenReturn(blockResult); + Blockchain blockchain = mock(Blockchain.class); + + ProgramResult executorResult = mock(ProgramResult.class); + TransactionExecutor transactionExecutor = mock(TransactionExecutor.class); + when(transactionExecutor.getResult()) + .thenReturn(executorResult); + + ReversibleTransactionExecutor reversibleTransactionExecutor = mock(ReversibleTransactionExecutor.class); + when(reversibleTransactionExecutor.estimateGas(eq(block), any(), any(), any(), any(), any(), any(), any(), any())) + .thenReturn(transactionExecutor); + + EthModule eth = new EthModule( + null, + Constants.REGTEST_CHAIN_ID, + blockchain, + null, + reversibleTransactionExecutor, + retriever, + mock(RepositoryLocator.class), + null, + null, + new BridgeSupportFactory( + null, null, null, signatureCache), + config.getGasEstimationCap(), + config.getCallGasCap()); + + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + + eth.estimateGas(callArgumentsParam, new BlockIdentifierParam("latest")); + + ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(byte[].class); + verify(reversibleTransactionExecutor, times(1)) + .estimateGas(eq(block), any(), any(), any(), any(), any(), dataCaptor.capture(), any(), any()); + assertArrayEquals(HexUtils.strHexOrStrNumberToByteArray(args.getData()), dataCaptor.getValue()); + } + + @Test + void whenExecuteEstimateGasWithInputParameter_callExecutorWithInput() { + CallArguments args = new CallArguments(); + args.setInput(TEST_DATA); + Block block = mock(Block.class); + ExecutionBlockRetriever.Result blockResult = mock(ExecutionBlockRetriever.Result.class); + when(blockResult.getBlock()).thenReturn(block); + ExecutionBlockRetriever retriever = mock(ExecutionBlockRetriever.class); + when(retriever.retrieveExecutionBlock("latest")).thenReturn(blockResult); + Blockchain blockchain = mock(Blockchain.class); + + ProgramResult executorResult = mock(ProgramResult.class); + TransactionExecutor transactionExecutor = mock(TransactionExecutor.class); + when(transactionExecutor.getResult()) + .thenReturn(executorResult); + + ReversibleTransactionExecutor reversibleTransactionExecutor = mock(ReversibleTransactionExecutor.class); + when(reversibleTransactionExecutor.estimateGas(eq(block), any(), any(), any(), any(), any(), any(), any(), any())) + .thenReturn(transactionExecutor); + + EthModule eth = new EthModule( + null, + Constants.REGTEST_CHAIN_ID, + blockchain, + null, + reversibleTransactionExecutor, + retriever, + mock(RepositoryLocator.class), + null, + null, + new BridgeSupportFactory( + null, null, null, signatureCache), + config.getGasEstimationCap(), + config.getCallGasCap()); + + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + + eth.estimateGas(callArgumentsParam, new BlockIdentifierParam("latest")); + + ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(byte[].class); + verify(reversibleTransactionExecutor, times(1)) + .estimateGas(eq(block), any(), any(), any(), any(), any(), dataCaptor.capture(), any(), any()); + assertArrayEquals(HexUtils.strHexOrStrNumberToByteArray(args.getInput()), dataCaptor.getValue()); + } + + @Test + void whenExecuteEstimateGasWithInputAndDataParameters_callExecutorWithInput() { + CallArguments args = new CallArguments(); + args.setData(TEST_DATA); + args.setInput(TEST_DATA); + Block block = mock(Block.class); + ExecutionBlockRetriever.Result blockResult = mock(ExecutionBlockRetriever.Result.class); + when(blockResult.getBlock()).thenReturn(block); + ExecutionBlockRetriever retriever = mock(ExecutionBlockRetriever.class); + when(retriever.retrieveExecutionBlock("latest")).thenReturn(blockResult); + Blockchain blockchain = mock(Blockchain.class); + + ProgramResult executorResult = mock(ProgramResult.class); + TransactionExecutor transactionExecutor = mock(TransactionExecutor.class); + when(transactionExecutor.getResult()) + .thenReturn(executorResult); + + ReversibleTransactionExecutor reversibleTransactionExecutor = mock(ReversibleTransactionExecutor.class); + when(reversibleTransactionExecutor.estimateGas(eq(block), any(), any(), any(), any(), any(), any(), any(), any())) + .thenReturn(transactionExecutor); + + EthModule eth = new EthModule( + null, + Constants.REGTEST_CHAIN_ID, + blockchain, + null, + reversibleTransactionExecutor, + retriever, + mock(RepositoryLocator.class), + null, + null, + new BridgeSupportFactory( + null, null, null, signatureCache), + config.getGasEstimationCap(), + config.getCallGasCap()); + + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + + eth.estimateGas(callArgumentsParam, new BlockIdentifierParam("latest")); + + ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(byte[].class); + verify(reversibleTransactionExecutor, times(1)) + .estimateGas(eq(block), any(), any(), any(), any(), any(), dataCaptor.capture(), any(), any()); + assertArrayEquals(HexUtils.strHexOrStrNumberToByteArray(args.getInput()), dataCaptor.getValue()); + } + + @Test + void whenExecuteSendTransactionWithDataParameter_callExecutorWithData() { + Constants constants = Constants.regtest(); + + Wallet wallet = new Wallet(new HashMapDB()); + RskAddress sender = wallet.addAccount(); + RskAddress receiver = wallet.addAccount(); + + // Hash of the expected transaction + CallArguments args = TransactionFactoryHelper.createArguments(sender, receiver); + args.setData(TEST_DATA); + + String expectedDataValue = args.getData().substring(2); + + TransactionPoolAddResult transactionPoolAddResult = mock(TransactionPoolAddResult.class); + when(transactionPoolAddResult.transactionsWereAdded()).thenReturn(true); + + TransactionGateway transactionGateway = mock(TransactionGateway.class); + when(transactionGateway.receiveTransaction(any(Transaction.class))).thenReturn(transactionPoolAddResult); + + TransactionPool transactionPool = mock(TransactionPool.class); + + EthModuleTransactionBase ethModuleTransaction = new EthModuleTransactionBase(constants, wallet, transactionPool, transactionGateway); + + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + + ethModuleTransaction.sendTransaction(callArgumentsParam); + + ArgumentCaptor transactionCaptor = ArgumentCaptor.forClass(Transaction.class); + verify(transactionGateway, times(1)) + .receiveTransaction(transactionCaptor.capture()); + assertArrayEquals(Hex.decode(expectedDataValue), transactionCaptor.getValue().getData()); + } + + @Test + void whenExecuteSendTransactionWithInputParameter_callExecutorWithInput() { + Constants constants = Constants.regtest(); + + Wallet wallet = new Wallet(new HashMapDB()); + RskAddress sender = wallet.addAccount(); + RskAddress receiver = wallet.addAccount(); + + // Hash of the expected transaction + CallArguments args = TransactionFactoryHelper.createArguments(sender, receiver); + args.setInput(TEST_DATA); + + String expectedDataValue = args.getInput().substring(2); + + TransactionPoolAddResult transactionPoolAddResult = mock(TransactionPoolAddResult.class); + when(transactionPoolAddResult.transactionsWereAdded()).thenReturn(true); + + TransactionGateway transactionGateway = mock(TransactionGateway.class); + when(transactionGateway.receiveTransaction(any(Transaction.class))).thenReturn(transactionPoolAddResult); + + TransactionPool transactionPool = mock(TransactionPool.class); + + EthModuleTransactionBase ethModuleTransaction = new EthModuleTransactionBase(constants, wallet, transactionPool, transactionGateway); + + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + + ethModuleTransaction.sendTransaction(callArgumentsParam); + + ArgumentCaptor transactionCaptor = ArgumentCaptor.forClass(Transaction.class); + verify(transactionGateway, times(1)) + .receiveTransaction(transactionCaptor.capture()); + assertArrayEquals(Hex.decode(expectedDataValue), transactionCaptor.getValue().getData()); + } + + @Test + void whenExecuteSendTransactionWithInputAndDataParameters_callExecutorWithInput() { + Constants constants = Constants.regtest(); + + Wallet wallet = new Wallet(new HashMapDB()); + RskAddress sender = wallet.addAccount(); + RskAddress receiver = wallet.addAccount(); + + // Hash of the expected transaction + CallArguments args = TransactionFactoryHelper.createArguments(sender, receiver); + args.setData(TEST_DATA); + args.setInput(TEST_DATA); + + String expectedDataValue = args.getInput().substring(2); + + TransactionPoolAddResult transactionPoolAddResult = mock(TransactionPoolAddResult.class); + when(transactionPoolAddResult.transactionsWereAdded()).thenReturn(true); + + TransactionGateway transactionGateway = mock(TransactionGateway.class); + when(transactionGateway.receiveTransaction(any(Transaction.class))).thenReturn(transactionPoolAddResult); + + TransactionPool transactionPool = mock(TransactionPool.class); + + EthModuleTransactionBase ethModuleTransaction = new EthModuleTransactionBase(constants, wallet, transactionPool, transactionGateway); + + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + + ethModuleTransaction.sendTransaction(callArgumentsParam); + + ArgumentCaptor transactionCaptor = ArgumentCaptor.forClass(Transaction.class); + verify(transactionGateway, times(1)) + .receiveTransaction(transactionCaptor.capture()); + assertArrayEquals(Hex.decode(expectedDataValue), transactionCaptor.getValue().getData()); + } } diff --git a/rskj-core/src/test/java/co/rsk/rpc/modules/personal/PersonalModuleTest.java b/rskj-core/src/test/java/co/rsk/rpc/modules/personal/PersonalModuleTest.java index 365dcdf6dc7..efcb16201a3 100644 --- a/rskj-core/src/test/java/co/rsk/rpc/modules/personal/PersonalModuleTest.java +++ b/rskj-core/src/test/java/co/rsk/rpc/modules/personal/PersonalModuleTest.java @@ -31,14 +31,11 @@ import org.ethereum.facade.Ethereum; import org.ethereum.rpc.CallArguments; import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.CallArgumentsParam; import org.ethereum.util.TransactionFactoryHelper; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - class PersonalModuleTest { private static final String PASS_FRASE = "passfrase"; @@ -54,6 +51,7 @@ void sendTransactionWithGasLimitTest() throws Exception { // Hash of the expected transaction CallArguments args = TransactionFactoryHelper.createArguments(sender, receiver); + CallArgumentsParam argsParam = TransactionFactoryHelper.toCallArgumentsParam(args); Transaction tx = TransactionFactoryHelper.createTransaction(args, props.getNetworkConstants().getChainId(), wallet.getAccount(sender, PASS_FRASE)); String txExpectedResult = tx.getHash().toJsonString(); @@ -66,7 +64,7 @@ void sendTransactionWithGasLimitTest() throws Exception { PersonalModuleWalletEnabled personalModuleWalletEnabled = new PersonalModuleWalletEnabled(props, ethereum, wallet, null); // Hash of the actual transaction builded inside the sendTransaction - String txResult = personalModuleWalletEnabled.sendTransaction(args, PASS_FRASE); + String txResult = personalModuleWalletEnabled.sendTransaction(argsParam, PASS_FRASE); assertEquals(txExpectedResult, txResult); } @@ -83,6 +81,7 @@ void sendTransactionThrowsErrorOnChainIdValidationTest() { // Hash of the expected transaction CallArguments args = TransactionFactoryHelper.createArguments(sender, receiver); args.setChainId("" + ((int) props.getNetworkConstants().getChainId() - 2)); + CallArgumentsParam argsParam = TransactionFactoryHelper.toCallArgumentsParam(args); TransactionPoolAddResult transactionPoolAddResult = mock(TransactionPoolAddResult.class); when(transactionPoolAddResult.transactionsWereAdded()).thenReturn(true); @@ -91,7 +90,7 @@ void sendTransactionThrowsErrorOnChainIdValidationTest() { PersonalModuleWalletEnabled personalModuleWalletEnabled = new PersonalModuleWalletEnabled(props, ethereum, wallet, null); - Assertions.assertThrows(RskJsonRpcRequestException.class, () -> personalModuleWalletEnabled.sendTransaction(args, PASS_FRASE)); + Assertions.assertThrows(RskJsonRpcRequestException.class, () -> personalModuleWalletEnabled.sendTransaction(argsParam, PASS_FRASE)); } } diff --git a/rskj-core/src/test/java/co/rsk/rpc/modules/personal/PersonalModuleWalletEnabledTest.java b/rskj-core/src/test/java/co/rsk/rpc/modules/personal/PersonalModuleWalletEnabledTest.java index 6a76c6a34d5..33bca0142b4 100644 --- a/rskj-core/src/test/java/co/rsk/rpc/modules/personal/PersonalModuleWalletEnabledTest.java +++ b/rskj-core/src/test/java/co/rsk/rpc/modules/personal/PersonalModuleWalletEnabledTest.java @@ -3,9 +3,10 @@ import co.rsk.config.TestSystemProperties; import co.rsk.core.RskAddress; import co.rsk.core.Wallet; -import org.bouncycastle.util.encoders.DecoderException; import org.bouncycastle.util.encoders.Hex; import org.ethereum.crypto.ECKey; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.HexKeyParam; import org.ethereum.util.ByteUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -25,7 +26,7 @@ class PersonalModuleWalletEnabledTest { @Test void importRawKey_KeyIsNull_ThrowsNullPointerException() { PersonalModuleWalletEnabled personalModuleWalletEnabled = createPersonalModuleWalletEnabled(null); - Assertions.assertThrows(DecoderException.class, () -> personalModuleWalletEnabled.importRawKey(null, "passphrase1")); + Assertions.assertThrows(RskJsonRpcRequestException.class, () -> personalModuleWalletEnabled.importRawKey(null, "passphrase1")); } @Test @@ -43,7 +44,8 @@ void importRawKey_KeyContains0xPrefix_OK() { doReturn(true).when(walletMock).unlockAccount(eq(addressMock), eq(passphrase), any(Long.class)); PersonalModuleWalletEnabled personalModuleWalletEnabled = createPersonalModuleWalletEnabled(walletMock); - String result = personalModuleWalletEnabled.importRawKey(String.format("0x%s", rawKey), passphrase); + HexKeyParam hexKeyParam = new HexKeyParam(String.format("0x%s", rawKey)); + String result = personalModuleWalletEnabled.importRawKey(hexKeyParam, passphrase); verify(walletMock, times(1)).addAccountWithPrivateKey(hexDecodedKey, passphrase); verify(walletMock, times(1)).unlockAccount(addressMock, passphrase, 1800000L); @@ -67,7 +69,8 @@ void importRawKey_KeyDoesNotContains0xPrefix_OK() { doReturn(true).when(walletMock).unlockAccount(eq(addressMock), eq(passphrase), any(Long.class)); PersonalModuleWalletEnabled personalModuleWalletEnabled = createPersonalModuleWalletEnabled(walletMock); - String result = personalModuleWalletEnabled.importRawKey(rawKey, passphrase); + HexKeyParam hexKeyParam = new HexKeyParam(rawKey); + String result = personalModuleWalletEnabled.importRawKey(hexKeyParam, passphrase); verify(walletMock, times(1)).addAccountWithPrivateKey(hexDecodedKey, passphrase); verify(walletMock, times(1)).unlockAccount(addressMock, passphrase, 1800000L); diff --git a/rskj-core/src/test/java/co/rsk/rpc/netty/JsonRPCParamValidationTest.java b/rskj-core/src/test/java/co/rsk/rpc/netty/JsonRPCParamValidationTest.java new file mode 100644 index 00000000000..a7bec0637a0 --- /dev/null +++ b/rskj-core/src/test/java/co/rsk/rpc/netty/JsonRPCParamValidationTest.java @@ -0,0 +1,241 @@ +/* + * This file is part of RskJ + * Copyright (C) 2023 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package co.rsk.rpc.netty; + +import co.rsk.rpc.Web3EthModule; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.googlecode.jsonrpc4j.AnnotationsErrorResolver; +import com.googlecode.jsonrpc4j.DefaultErrorResolver; +import com.googlecode.jsonrpc4j.JsonResponse; +import com.googlecode.jsonrpc4j.MultipleErrorResolver; +import org.ethereum.rpc.dto.BlockResultDTO; +import org.ethereum.rpc.dto.TransactionResultDTO; +import org.ethereum.rpc.exception.RskErrorResolver; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class JsonRPCParamValidationTest { + private final ObjectMapper objectMapper = new ObjectMapper(); + private JsonRpcCustomServer jsonRpcServer; + private Web3EthModule handler; + + @BeforeEach + void setUp() { + handler = mock(Web3EthModule.class); + this.jsonRpcServer = new JsonRpcCustomServer(handler, handler.getClass(), Collections.emptyList()); + jsonRpcServer.setErrorResolver(new MultipleErrorResolver(new RskErrorResolver(), AnnotationsErrorResolver.INSTANCE, DefaultErrorResolver.INSTANCE)); + } + + @Test + void eth_getBlockByHash() throws Exception { + BlockResultDTO blockResultDTO = mock(BlockResultDTO.class); + + String requestBody = "{\n" + + "\t\"jsonrpc\":\"2.0\",\n" + + "\t\"method\":\"eth_getBlockByHash\",\n" + + "\t\"params\":[\n" + + "\t\t\"0xad1328d13f833b8af722117afdc406a762033321df8e48c00cd372d462f48169\", \n" + + "\t\ttrue\n" + + "\t],\n" + + "\t\"id\":1\n" + + "}"; + JsonNode request = objectMapper.readTree(requestBody); + + when(handler.eth_getBlockByHash(any(), any())).thenReturn(blockResultDTO); + + JsonResponse response = jsonRpcServer.handleJsonNodeRequest(request); + assertNotNull(response); + assertEquals(0, response.getCode()); + } + + @Test + void eth_getBlockByHash_invalidHexCharInHash_returnsError() throws Exception { + BlockResultDTO blockResultDTO = mock(BlockResultDTO.class); + + String requestBody = "{\n" + + "\t\"jsonrpc\":\"2.0\",\n" + + "\t\"method\":\"eth_getBlockByHash\",\n" + + "\t\"params\":[\n" + + "\t\t\"0xc2b835zzz172db5bd051bb94fa123721eacac43b5cba2499b22c7583a35689b8\", \n" + + "\t\ttrue\n" + + "\t],\n" + + "\t\"id\":1\n" + + "}"; + JsonNode request = objectMapper.readTree(requestBody); + + when(handler.eth_getBlockByHash(any(), any())).thenReturn(blockResultDTO); + + JsonResponse response = jsonRpcServer.handleJsonNodeRequest(request); + assertEquals(-32602, response.getCode()); + String message = response.getResponse().get("error").get("message").asText(); + assertEquals("Invalid block hash format: invalid hex value", message); + } + + @Test + void eth_getBlockByHash_invalidHashLength_returnsError() throws Exception { + BlockResultDTO blockResultDTO = mock(BlockResultDTO.class); + String requestBody = "{\n" + + "\t\"jsonrpc\":\"2.0\",\n" + + "\t\"method\":\"eth_getBlockByHash\",\n" + + "\t\"params\":[\n" + + "\t\t\"0xec576f474ea123c581c08008bea2\", \n" + + "\t\ttrue\n" + + "\t],\n" + + "\t\"id\":1\n" + + "}"; + JsonNode request = objectMapper.readTree(requestBody); + + when(handler.eth_getBlockByHash(any(), any())).thenReturn(blockResultDTO); + + JsonResponse response = jsonRpcServer.handleJsonNodeRequest(request); + assertEquals(-32602, response.getCode()); + String message = response.getResponse().get("error").get("message").asText(); + assertEquals("Invalid block hash: incorrect length.", message); + + } + + @Test + void eth_getTransactionByBlockHashAndIndex_invalidHash_returnsError() throws Exception { + TransactionResultDTO resultDTO = mock(TransactionResultDTO.class); + String requestBody = "{\n" + + "\t\"jsonrpc\":\"2.0\",\n" + + "\t\"method\":\"eth_getTransactionByBlockHashAndIndex\",\n" + + "\t\"params\":[\n" + + "\t\t\"0x3c82bc62179602b6731037c49cba84e31ffe6e465a21c521a7\", \n" + + "\t\t\"0x0\"\n" + + "\t],\n" + + "\t\"id\":1\n" + + "}"; + JsonNode request = objectMapper.readTree(requestBody); + when(handler.eth_getTransactionByBlockHashAndIndex(any(), any())).thenReturn(resultDTO); + JsonResponse response = jsonRpcServer.handleJsonNodeRequest(request); + assertEquals(-32602, response.getCode()); + String message = response.getResponse().get("error").get("message").asText(); + assertEquals("Invalid block hash: incorrect length.", message); + } + + + @Test + void eth_getTransactionByBlockHashAndIndex_invalidIndex_returnsError() throws Exception { + TransactionResultDTO resultDTO = mock(TransactionResultDTO.class); + String requestBody = "{\n" + + "\t\"jsonrpc\":\"2.0\",\n" + + "\t\"method\":\"eth_getTransactionByBlockHashAndIndex\",\n" + + "\t\"params\":[\n" + + "\t\t\"0x3c82bc62179602b67318c013c10f99011037c49cba84e31ffe6e465a21c521a7\", \n" + + "\t\t\"abc\"\n" + + "\t],\n" + + "\t\"id\":1\n" + + "}"; + JsonNode request = objectMapper.readTree(requestBody); + when(handler.eth_getTransactionByBlockHashAndIndex(any(), any())).thenReturn(resultDTO); + JsonResponse response = jsonRpcServer.handleJsonNodeRequest(request); + assertEquals(-32602, response.getCode()); + String message = response.getResponse().get("error").get("message").asText(); + assertEquals("Invalid argument \"abc\": param should be a hex value string.", message); + } + + @Test + void eth_getBlockTransactionCountByHash_invalidHash_returnsError() throws Exception { + String requestBody = "{\n" + + "\t\"jsonrpc\":\"2.0\",\n" + + "\t\"method\":\"eth_getBlockTransactionCountByHash\",\n" + + "\t\"params\":[\n" + + "\t\t\"0x3c82bc62179602b6731037c49cba84e31ffe6e465a21c521a7\"\n" + + "\t],\n" + + "\t\"id\":1\n" + + "}"; + JsonNode request = objectMapper.readTree(requestBody); + when(handler.eth_getBlockTransactionCountByHash(any())).thenReturn("0x0"); + JsonResponse response = jsonRpcServer.handleJsonNodeRequest(request); + assertEquals(-32602, response.getCode()); + String message = response.getResponse().get("error").get("message").asText(); + assertEquals("Invalid block hash: incorrect length.", message); + } + + @Test + void eth_getTransactionByHash_invalidHash_returnsError() throws Exception { + TransactionResultDTO resultDTO = mock(TransactionResultDTO.class); + String requestBody = "{\n" + + "\t\"jsonrpc\":\"2.0\",\n" + + "\t\"method\":\"eth_getTransactionByHash\",\n" + + "\t\"params\":[\n" + + "\t\t\"0xc2b835zzz172db5bd051bb94fa123721eacac43b5cba2499b22c7583a35689b8\"\n" + + "\t],\n" + + "\t\"id\":1\n" + + "}"; + JsonNode request = objectMapper.readTree(requestBody); + JsonResponse response = jsonRpcServer.handleJsonNodeRequest(request); + assertEquals(-32602, response.getCode()); + String message = response.getResponse().get("error").get("message").asText(); + assertEquals("Invalid transaction hash format: invalid hex value", message); + } + + @Test + void eth_getUncleByBlockHashAndIndex_invalidHash_returnsError() throws Exception { + BlockResultDTO blockResultDTO = mock(BlockResultDTO.class); + String requestBody = "{\n" + + "\t\"jsonrpc\":\"2.0\",\n" + + "\t\"method\":\"eth_getUncleByBlockHashAndIndex\",\n" + + "\t\"params\":[\n" + + "\t\t\"0x3c82bc62179602b6731037c49cba84e31ffe6e465a21c521a7\", \n" + + "\t\t\"0x0\"\n" + + "\t],\n" + + "\t\"id\":1\n" + + "}"; + JsonNode request = objectMapper.readTree(requestBody); + + when(handler.eth_getUncleByBlockHashAndIndex(any(), any())).thenReturn(blockResultDTO); + + JsonResponse response = jsonRpcServer.handleJsonNodeRequest(request); + assertEquals(-32602, response.getCode()); + String message = response.getResponse().get("error").get("message").asText(); + assertEquals("Invalid block hash: incorrect length.", message); + } + + @Test + void eth_getUncleByBlockHashAndIndex_invalidIndex_returnsError() throws Exception { + BlockResultDTO blockResultDTO = mock(BlockResultDTO.class); + String requestBody = "{\n" + + "\t\"jsonrpc\":\"2.0\",\n" + + "\t\"method\":\"eth_getUncleByBlockHashAndIndex\",\n" + + "\t\"params\":[\n" + + "\t\t\"0x3c82bc62179602b67318c013c10f99011037c49cba84e31ffe6e465a21c521a7\", \n" + + "\t\t\"122\"\n" + + "\t],\n" + + "\t\"id\":1\n" + + "}"; + JsonNode request = objectMapper.readTree(requestBody); + + when(handler.eth_getUncleByBlockHashAndIndex(any(), any())).thenReturn(blockResultDTO); + + JsonResponse response = jsonRpcServer.handleJsonNodeRequest(request); + assertEquals(-32602, response.getCode()); + String message = response.getResponse().get("error").get("message").asText(); + assertEquals("Invalid argument \"122\": param should be a hex value string.", message); + } +} \ No newline at end of file diff --git a/rskj-core/src/test/java/org/ethereum/config/ConstantsTest.java b/rskj-core/src/test/java/org/ethereum/config/ConstantsTest.java index 7f1e6211783..e08b2514786 100644 --- a/rskj-core/src/test/java/org/ethereum/config/ConstantsTest.java +++ b/rskj-core/src/test/java/org/ethereum/config/ConstantsTest.java @@ -18,23 +18,22 @@ package org.ethereum.config; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import co.rsk.bitcoinj.core.BtcECKey; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; import org.ethereum.config.blockchain.upgrades.ActivationConfig; import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.crypto.HashUtil; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; - -import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; - class ConstantsTest { private static final List TEST_FED_KEYS = Arrays.asList( diff --git a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplLogsTest.java b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplLogsTest.java index 8bc31189770..92731ad2938 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplLogsTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplLogsTest.java @@ -18,44 +18,11 @@ package org.ethereum.rpc; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; - -import java.math.BigInteger; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; - import co.rsk.blockchain.utils.BlockGenerator; -import org.ethereum.config.Constants; -import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; -import org.ethereum.config.blockchain.upgrades.ConsensusRule; -import org.ethereum.core.Account; -import org.ethereum.core.Block; -import org.ethereum.core.Blockchain; -import org.ethereum.core.CallTransaction; -import org.ethereum.core.ImportResult; -import org.ethereum.core.Transaction; -import org.ethereum.core.TransactionPool; -import org.ethereum.core.*; -import org.ethereum.datasource.HashMapDB; -import org.ethereum.db.BlockStore; -import org.ethereum.db.ReceiptStore; -import org.ethereum.facade.Ethereum; -import org.ethereum.rpc.Simples.SimpleConfigCapabilities; -import org.ethereum.rpc.dto.TransactionReceiptDTO; -import org.ethereum.rpc.exception.RskJsonRpcRequestException; -import org.ethereum.util.ByteUtil; -import org.ethereum.util.RskTestFactory; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - import co.rsk.config.TestSystemProperties; import co.rsk.core.Coin; import co.rsk.core.Wallet; import co.rsk.core.WalletFactory; -import co.rsk.core.bc.MiningMainchainView; import co.rsk.crypto.Keccak256; import co.rsk.db.RepositoryLocator; import co.rsk.logfilter.BlocksBloomStore; @@ -76,8 +43,33 @@ import co.rsk.test.builders.TransactionBuilder; import co.rsk.trie.TrieStore; import co.rsk.util.HexUtils; +import org.ethereum.config.Constants; +import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; +import org.ethereum.config.blockchain.upgrades.ConsensusRule; +import org.ethereum.core.*; +import org.ethereum.datasource.HashMapDB; +import org.ethereum.db.BlockStore; +import org.ethereum.db.ReceiptStore; +import org.ethereum.facade.Ethereum; +import org.ethereum.rpc.Simples.SimpleConfigCapabilities; +import org.ethereum.rpc.dto.TransactionReceiptDTO; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.*; +import org.ethereum.util.ByteUtil; +import org.ethereum.util.RskTestFactory; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import java.math.BigInteger; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; + /** * Created by ajlopez on 30/11/2016. */ @@ -146,8 +138,7 @@ void setUp() { @Test void newFilterInEmptyBlockchain() throws Exception { - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); String id = web3.eth_newFilter(fr); assertNotNull(id); @@ -155,10 +146,9 @@ void newFilterInEmptyBlockchain() throws Exception { @Test void newFilterGetLogsInEmptyBlockchain() throws Exception { - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); String id = web3.eth_newFilter(fr); - Object[] logs = web3.eth_getFilterLogs(id); + Object[] logs = web3.eth_getFilterLogs(new HexIndexParam(id)); assertNotNull(id); assertNotNull(logs); @@ -168,12 +158,11 @@ void newFilterGetLogsInEmptyBlockchain() throws Exception { @Test void newFilterGetLogsAfterBlock() throws Exception { Account acc1 = new AccountBuilder(blockChain, - blockStore, - repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); + blockStore, + repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); web3.personal_newAccountWithSeed("notDefault"); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("latest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("latest"), null, null, null, null); String id = web3.eth_newFilter(fr); Block genesis = blockChain.getBlockByNumber(0); @@ -183,24 +172,24 @@ void newFilterGetLogsAfterBlock() throws Exception { List txs = new ArrayList<>(); txs.add(tx); Block block1 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(genesis).transactions(txs).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); - Object[] logs = web3.eth_getFilterLogs(id); + Object[] logs = web3.eth_getFilterLogs(new HexIndexParam(id)); assertNotNull(id); assertNotNull(logs); assertEquals(1, logs.length); - assertEquals("0x" + tx.getContractAddress().toString(),((LogFilterElement)logs[0]).address); + assertEquals("0x" + tx.getContractAddress().toString(), ((LogFilterElement) logs[0]).address); } @Test void newFilterWithAccountAndTopicsCreatedAfterBlockAndGetLogs() throws Exception { Account acc1 = new AccountBuilder(blockChain, - blockStore, - repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); + blockStore, + repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); web3.personal_newAccountWithSeed("notDefault"); @@ -211,34 +200,34 @@ void newFilterWithAccountAndTopicsCreatedAfterBlockAndGetLogs() throws Exception List txs = new ArrayList<>(); txs.add(tx); Block block1 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(genesis).transactions(txs).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); - FilterRequest fr = new FilterRequest(); - fr.setAddress( ByteUtil.toHexString(tx.getContractAddress().getBytes())); - fr.setTopics(new Object[] { "06acbfb32bcf8383f3b0a768b70ac9ec234ea0f2d3b9c77fa6a2de69b919aad1" }); + HexAddressParam[] hexAddressParam = new HexAddressParam[]{new HexAddressParam((tx.getContractAddress().toJsonString()))}; + TopicParam[][] topics = initTopicsArray("06acbfb32bcf8383f3b0a768b70ac9ec234ea0f2d3b9c77fa6a2de69b919aad1"); + FilterRequestParam fr = new FilterRequestParam(null, null, hexAddressParam, topics, null); + String id = web3.eth_newFilter(fr); - Object[] logs = web3.eth_getFilterLogs(id); + Object[] logs = web3.eth_getFilterLogs(new HexIndexParam(id)); assertNotNull(id); assertNotNull(logs); assertEquals(1, logs.length); - assertEquals("0x" + tx.getContractAddress().toString(),((LogFilterElement)logs[0]).address); + assertEquals("0x" + tx.getContractAddress().toString(), ((LogFilterElement) logs[0]).address); } @Test void newFilterGetLogsTwiceAfterBlock() throws Exception { Account acc1 = new AccountBuilder(blockChain, - blockStore, - repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); + blockStore, + repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); web3.personal_newAccountWithSeed("notDefault"); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); String id = web3.eth_newFilter(fr); Block genesis = blockChain.getBlockByNumber(0); @@ -248,26 +237,27 @@ void newFilterGetLogsTwiceAfterBlock() throws Exception { List txs = new ArrayList<>(); txs.add(tx); Block block1 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(genesis).transactions(txs).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); - web3.eth_getFilterLogs(id); - Object[] logs = web3.eth_getFilterLogs(id); + HexIndexParam idParam = new HexIndexParam(id); + web3.eth_getFilterLogs(idParam); + Object[] logs = web3.eth_getFilterLogs(idParam); assertNotNull(id); assertNotNull(logs); assertEquals(1, logs.length); - assertEquals("0x" + tx.getContractAddress().toString(),((LogFilterElement)logs[0]).address); + assertEquals("0x" + tx.getContractAddress().toString(), ((LogFilterElement) logs[0]).address); } @Test void newFilterGetChangesInEmptyBlockchain() throws Exception { - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); String id = web3.eth_newFilter(fr); - Object[] logs = web3.eth_getFilterChanges(id); + HexIndexParam hexIndexParam = new HexIndexParam(id); + Object[] logs = web3.eth_getFilterChanges(hexIndexParam); assertNotNull(id); assertNotNull(logs); @@ -277,13 +267,12 @@ void newFilterGetChangesInEmptyBlockchain() throws Exception { @Test void newFilterGetChangesAfterBlock() throws Exception { Account acc1 = new AccountBuilder(blockChain, - blockStore, - repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); + blockStore, + repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); web3.personal_newAccountWithSeed("notDefault"); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); String id = web3.eth_newFilter(fr); Block genesis = blockChain.getBlockByNumber(0); @@ -293,23 +282,22 @@ void newFilterGetChangesAfterBlock() throws Exception { List txs = new ArrayList<>(); txs.add(tx); Block block1 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(genesis).transactions(txs).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); - Object[] logs = web3.eth_getFilterChanges(id); + Object[] logs = web3.eth_getFilterChanges(new HexIndexParam(id)); assertNotNull(id); assertNotNull(logs); assertEquals(1, logs.length); - assertEquals("0x" + tx.getContractAddress().toString(),((LogFilterElement)logs[0]).address); + assertEquals("0x" + tx.getContractAddress().toString(), ((LogFilterElement) logs[0]).address); } @Test void getLogsFromEmptyBlockchain() throws Exception { - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); @@ -320,8 +308,7 @@ void getLogsFromEmptyBlockchain() throws Exception { void getLogsFromBlockchainWithThreeEmptyBlocks() throws Exception { addTwoEmptyBlocks(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); @@ -332,8 +319,7 @@ void getLogsFromBlockchainWithThreeEmptyBlocks() throws Exception { void getLogsTwiceFromBlockchainWithThreeEmptyBlocks() throws Exception { addTwoEmptyBlocks(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); @@ -345,8 +331,7 @@ void getLogsTwiceFromBlockchainWithThreeEmptyBlocks() throws Exception { void getLogsFromBlockchainWithContractCreation() throws Exception { addContractCreationWithoutEvents(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); @@ -357,8 +342,8 @@ void getLogsFromBlockchainWithContractCreation() throws Exception { void getLogsTwiceFromBlockchainWithContractCreation() throws Exception { addContractCreationWithoutEvents(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); + web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); @@ -370,69 +355,67 @@ void getLogsTwiceFromBlockchainWithContractCreation() throws Exception { void getLogsFromBlockchainWithEventInContractCreation() throws Exception { addEventInContractCreation(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setToBlock("latest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), new BlockIdentifierParam("latest"), null, null, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); assertEquals(1, logs.length); - String txhash = ((LogFilterElement)logs[0]).transactionHash; - TransactionReceiptDTO txdto = web3.eth_getTransactionReceipt(txhash); + String txhash = ((LogFilterElement) logs[0]).transactionHash; + TransactionReceiptDTO txdto = web3.eth_getTransactionReceipt(new TxHashParam(txhash)); - assertEquals(txdto.getContractAddress(),((LogFilterElement)logs[0]).address); + assertEquals(txdto.getContractAddress(), ((LogFilterElement) logs[0]).address); } @Test void getLogsTwiceFromBlockchainWithEventInContractCreation() throws Exception { addEventInContractCreation(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); + web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); assertEquals(1, logs.length); - String txhash = ((LogFilterElement)logs[0]).transactionHash; - TransactionReceiptDTO txdto = web3.eth_getTransactionReceipt(txhash); + String txhash = ((LogFilterElement) logs[0]).transactionHash; + TransactionReceiptDTO txdto = web3.eth_getTransactionReceipt(new TxHashParam(txhash)); - assertEquals(txdto.getContractAddress(),((LogFilterElement)logs[0]).address); + assertEquals(txdto.getContractAddress(), ((LogFilterElement) logs[0]).address); } @Test void getLogsFromBlockchainWithInvokeContract() throws Exception { addContractInvoke(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); + Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); assertEquals(2, logs.length); - String txhash = ((LogFilterElement)logs[0]).transactionHash; - TransactionReceiptDTO txdto = web3.eth_getTransactionReceipt(txhash); + String txhash = ((LogFilterElement) logs[0]).transactionHash; + TransactionReceiptDTO txdto = web3.eth_getTransactionReceipt(new TxHashParam(txhash)); - assertEquals(txdto.getContractAddress(),((LogFilterElement)logs[0]).address); - assertEquals(txdto.getContractAddress(),((LogFilterElement)logs[1]).address); + assertEquals(txdto.getContractAddress(), ((LogFilterElement) logs[0]).address); + assertEquals(txdto.getContractAddress(), ((LogFilterElement) logs[1]).address); } @Test void getLogsKeepsCorrectOrderForReverseSearch() throws Exception { List transactions = addContractInvokeManyTxPerBlock(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); + Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); assertEquals(3, logs.length); String txHash1 = "0x" + transactions.get(0).getHash().toHexString(); - TransactionReceiptDTO txReceipt1 = web3.eth_getTransactionReceipt(txHash1); + TransactionReceiptDTO txReceipt1 = web3.eth_getTransactionReceipt(new TxHashParam(txHash1)); String contractAddress = txReceipt1.getContractAddress(); LogFilterElement logs1 = (LogFilterElement) logs[0]; assertEquals(contractAddress, logs1.address); @@ -443,7 +426,7 @@ void getLogsKeepsCorrectOrderForReverseSearch() throws Exception { assertArrayEquals(receipt1Logs.topics, logs1.topics); String txHash2 = "0x" + transactions.get(1).getHash().toHexString(); - TransactionReceiptDTO txReceipt2 = web3.eth_getTransactionReceipt(txHash2); + TransactionReceiptDTO txReceipt2 = web3.eth_getTransactionReceipt(new TxHashParam(txHash2)); LogFilterElement logs2 = (LogFilterElement) logs[1]; assertEquals(contractAddress, logs2.address); assertEquals(txHash2, logs2.transactionHash); @@ -453,7 +436,7 @@ void getLogsKeepsCorrectOrderForReverseSearch() throws Exception { assertArrayEquals(receipt2Logs.topics, logs2.topics); String txHash3 = "0x" + transactions.get(2).getHash().toHexString(); - TransactionReceiptDTO txReceipt3 = web3.eth_getTransactionReceipt(txHash3); + TransactionReceiptDTO txReceipt3 = web3.eth_getTransactionReceipt(new TxHashParam(txHash3)); LogFilterElement logs3 = (LogFilterElement) logs[2]; assertEquals(contractAddress, logs3.address); assertEquals(txHash3, logs3.transactionHash); @@ -474,27 +457,26 @@ void getLogsKeepsCorrectOrderForReverseSearch() throws Exception { void getLogsTwiceFromBlockchainWithInvokeContract() throws Exception { addContractInvoke(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); assertEquals(2, logs.length); - String txhash = ((LogFilterElement)logs[0]).transactionHash; - TransactionReceiptDTO txdto = web3.eth_getTransactionReceipt(txhash); + String txhash = ((LogFilterElement) logs[0]).transactionHash; + TransactionReceiptDTO txdto = web3.eth_getTransactionReceipt(new TxHashParam(txhash)); - assertEquals(txdto.getContractAddress(),((LogFilterElement)logs[0]).address); - assertEquals(txdto.getContractAddress(),((LogFilterElement)logs[1]).address); + assertEquals(txdto.getContractAddress(), ((LogFilterElement) logs[0]).address); + assertEquals(txdto.getContractAddress(), ((LogFilterElement) logs[1]).address); } @Test void getLogsFromBlockchainWithCallContract() throws Exception { addContractCall(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); + Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); @@ -505,8 +487,8 @@ void getLogsFromBlockchainWithCallContract() throws Exception { void getLogsTwiceFromBlockchainWithCallContract() throws Exception { addContractCall(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); + web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); @@ -518,50 +500,51 @@ void getLogsTwiceFromBlockchainWithCallContract() throws Exception { void getLogsFromBlockchainWithCallContractAndFilterByContractAddress() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setAddress( ByteUtil.toHexString(block1.getTransactionsList().get(0).getContractAddress().getBytes())); + HexAddressParam[] addressParam = new HexAddressParam[]{new HexAddressParam(block1.getTransactionsList().get(0).getContractAddress().toJsonString())}; + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, addressParam, null, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); assertEquals(3, logs.length); - String address = "0x" + fr.getAddress(); + String address = fr.getAddress()[0].getAddress().toJsonString(); - assertEquals(address,((LogFilterElement)logs[0]).address); - assertEquals(address,((LogFilterElement)logs[1]).address); - assertEquals(address,((LogFilterElement)logs[2]).address); + assertEquals(address, ((LogFilterElement) logs[0]).address); + assertEquals(address, ((LogFilterElement) logs[1]).address); + assertEquals(address, ((LogFilterElement) logs[2]).address); } @Test void getLogsTwoceFromBlockchainWithCallContractAndFilterByContractAddress() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setAddress( ByteUtil.toHexString(block1.getTransactionsList().get(0).getContractAddress().getBytes())); + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + HexAddressParam[] hexAddressParam = new HexAddressParam[]{ + new HexAddressParam(block1.getTransactionsList().get(0).getContractAddress().toJsonString()) + }; + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, hexAddressParam, null, null); web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); assertEquals(3, logs.length); - String address = "0x" + fr.getAddress(); + String address = fr.getAddress()[0].getAddress().toJsonString(); - assertEquals(address,((LogFilterElement)logs[0]).address); - assertEquals(address,((LogFilterElement)logs[1]).address); - assertEquals(address,((LogFilterElement)logs[2]).address); + assertEquals(address, ((LogFilterElement) logs[0]).address); + assertEquals(address, ((LogFilterElement) logs[1]).address); + assertEquals(address, ((LogFilterElement) logs[2]).address); } @Test void getLogsFromBlockchainWithCallContractAndFilterByUnknownContractAddress() throws Exception { addContractCall(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - List addresses = new ArrayList<>(); - addresses.add(ByteUtil.toHexString(new byte[20])); - fr.setAddress(addresses); + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + HexAddressParam[] hexAddressParam = new HexAddressParam[]{ + new HexAddressParam(ByteUtil.toHexString(new byte[20])) + }; + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, hexAddressParam, null, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); @@ -572,11 +555,11 @@ void getLogsFromBlockchainWithCallContractAndFilterByUnknownContractAddress() th void getLogsTwiceFromBlockchainWithCallContractAndFilterByUnknownContractAddress() throws Exception { addContractCall(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - List addresses = new ArrayList<>(); - addresses.add(ByteUtil.toHexString(new byte[20])); - fr.setAddress(addresses); + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + HexAddressParam[] hexAddressParam = new HexAddressParam[]{ + new HexAddressParam(ByteUtil.toHexString(new byte[20])) + }; + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, hexAddressParam, null, null); web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); @@ -588,10 +571,9 @@ void getLogsTwiceFromBlockchainWithCallContractAndFilterByUnknownContractAddress void getLogsFromBlockchainWithCallContractAndFilterByUnknownTopic() throws Exception { addContractCall(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[1]); - fr.getTopics()[0] = "0102030405060102030405060102030405060102030405060102030405060102"; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = initTopicsArray("0102030405060102030405060102030405060102030405060102030405060102"); + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); @@ -602,10 +584,9 @@ void getLogsFromBlockchainWithCallContractAndFilterByUnknownTopic() throws Excep void getLogsTwiceFromBlockchainWithCallContractAndFilterByUnknownTopic() throws Exception { addContractCall(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[1]); - fr.getTopics()[0] = "0102030405060102030405060102030405060102030405060102030405060102"; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = initTopicsArray("0102030405060102030405060102030405060102030405060102030405060102"); + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); @@ -618,16 +599,15 @@ void getLogsFromBlockchainWithCallContractAndFilterByKnownTopic() throws Excepti addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[1]); - fr.getTopics()[0] = GET_VALUED_EVENT_SIGNATURE; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = initTopicsArray(GET_VALUED_EVENT_SIGNATURE); + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); String address = "0x" + ByteUtil.toHexString(block1.getTransactionsList().get(0).getContractAddress().getBytes()); assertEquals(1, logs.length); - assertEquals(address,((LogFilterElement)logs[0]).address); + assertEquals(address, ((LogFilterElement) logs[0]).address); } @Test @@ -635,67 +615,56 @@ void getLogsTwiceFromBlockchainWithCallContractAndFilterByKnownTopic() throws Ex addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[1]); - fr.getTopics()[0] = GET_VALUED_EVENT_SIGNATURE; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = initTopicsArray(GET_VALUED_EVENT_SIGNATURE); + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); String address = "0x" + ByteUtil.toHexString(block1.getTransactionsList().get(0).getContractAddress().getBytes()); assertEquals(1, logs.length); - assertEquals(address,((LogFilterElement)logs[0]).address); + assertEquals(address, ((LogFilterElement) logs[0]).address); } @Test void getLogsFromBlockchainWithCallContractAndFilterByKnownTopicInList() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[1]); - List topics = new ArrayList<>(); - topics.add(GET_VALUED_EVENT_SIGNATURE); - fr.getTopics()[0] = topics; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = initTopicsArray(GET_VALUED_EVENT_SIGNATURE); + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); String address = "0x" + ByteUtil.toHexString(block1.getTransactionsList().get(0).getContractAddress().getBytes()); assertEquals(1, logs.length); - assertEquals(address,((LogFilterElement)logs[0]).address); + assertEquals(address, ((LogFilterElement) logs[0]).address); } @Test void getLogsTwiceFromBlockchainWithCallContractAndFilterByKnownTopicInList() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[1]); - List topics = new ArrayList<>(); - topics.add(GET_VALUED_EVENT_SIGNATURE); - fr.getTopics()[0] = topics; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = initTopicsArray(GET_VALUED_EVENT_SIGNATURE); + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); String address = "0x" + ByteUtil.toHexString(block1.getTransactionsList().get(0).getContractAddress().getBytes()); assertEquals(1, logs.length); - assertEquals(address,((LogFilterElement)logs[0]).address); + assertEquals(address, ((LogFilterElement) logs[0]).address); } @Test void getLogsFromBlockchainWithCallContractAndFilterByKnownsTopicInList() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[1]); - List topics = new ArrayList<>(); - topics.add(GET_VALUED_EVENT_SIGNATURE); - topics.add(INC_EVENT_SIGNATURE); - fr.getTopics()[0] = topics; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = new TopicParam[][]{{new TopicParam(GET_VALUED_EVENT_SIGNATURE),new TopicParam(INC_EVENT_SIGNATURE)}}; + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); @@ -711,13 +680,9 @@ void getLogsFromBlockchainWithCallContractAndFilterByKnownsTopicInList() throws void getLogsTwiceFromBlockchainWithCallContractAndFilterByKnownsTopicInList() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[1]); - List topics = new ArrayList<>(); - topics.add(GET_VALUED_EVENT_SIGNATURE); - topics.add(INC_EVENT_SIGNATURE); - fr.getTopics()[0] = topics; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = new TopicParam[][]{{new TopicParam(GET_VALUED_EVENT_SIGNATURE),new TopicParam(INC_EVENT_SIGNATURE)}}; + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); @@ -734,45 +699,41 @@ void getLogsTwiceFromBlockchainWithCallContractAndFilterByKnownsTopicInList() th void getLogsFromBlockchainWithCallContractAndFilterByKnownTopicInListWithNull() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[2]); - fr.getTopics()[0] = GET_VALUED_EVENT_SIGNATURE; - fr.getTopics()[1] = null; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = new TopicParam[][]{{new TopicParam(GET_VALUED_EVENT_SIGNATURE)},{null}}; + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); String address = "0x" + ByteUtil.toHexString(block1.getTransactionsList().get(0).getContractAddress().getBytes()); assertEquals(1, logs.length); - assertEquals(address,((LogFilterElement)logs[0]).address); + assertEquals(address, ((LogFilterElement) logs[0]).address); } @Test void getLogsTwiceFromBlockchainWithCallContractAndFilterByKnownTopicInListWithNull() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[2]); - fr.getTopics()[0] = GET_VALUED_EVENT_SIGNATURE; - fr.getTopics()[1] = null; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = new TopicParam[][]{{new TopicParam(GET_VALUED_EVENT_SIGNATURE)},{null}}; + + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); String address = "0x" + ByteUtil.toHexString(block1.getTransactionsList().get(0).getContractAddress().getBytes()); assertEquals(1, logs.length); - assertEquals(address,((LogFilterElement)logs[0]).address); + assertEquals(address, ((LogFilterElement) logs[0]).address); } @Test void getLogsFromBlockchainWithCallContractAndFilterWithNullTopic() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[1]); - fr.getTopics()[0] = null; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = new TopicParam[][]{{null}}; + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); @@ -788,10 +749,9 @@ void getLogsFromBlockchainWithCallContractAndFilterWithNullTopic() throws Except void getLogsTwiceFromBlockchainWithCallContractAndFilterWithNullTopic() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[1]); - fr.getTopics()[0] = null; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = new TopicParam[][]{{null}}; + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); @@ -808,11 +768,9 @@ void getLogsTwiceFromBlockchainWithCallContractAndFilterWithNullTopic() throws E void getLogsFromBlockchainWithCallContractAndFilterWithTwoTopics() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[2]); - fr.getTopics()[0] = INC_EVENT_SIGNATURE; - fr.getTopics()[1] = ONE_TOPIC; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = new TopicParam[][]{{new TopicParam(INC_EVENT_SIGNATURE)},{new TopicParam(ONE_TOPIC)}}; + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); @@ -828,11 +786,9 @@ void getLogsFromBlockchainWithCallContractAndFilterWithTwoTopics() throws Except void getLogsTwiceFromBlockchainWithCallContractAndFilterWithTwoTopics() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[2]); - fr.getTopics()[0] = INC_EVENT_SIGNATURE; - fr.getTopics()[1] = ONE_TOPIC; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = new TopicParam[][]{{new TopicParam(INC_EVENT_SIGNATURE)},{new TopicParam(ONE_TOPIC)}}; + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); @@ -849,11 +805,9 @@ void getLogsTwiceFromBlockchainWithCallContractAndFilterWithTwoTopics() throws E void getLogsFromBlockchainWithCallContractAndFilterBySecondTopic() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[2]); - fr.getTopics()[0] = null; - fr.getTopics()[1] = ONE_TOPIC; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = new TopicParam[][]{{null},{new TopicParam(ONE_TOPIC)}}; + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); @@ -869,11 +823,9 @@ void getLogsFromBlockchainWithCallContractAndFilterBySecondTopic() throws Except void getLogsTwiceFromBlockchainWithCallContractAndFilterBySecondTopic() throws Exception { addContractCall(); Block block1 = blockChain.getBlockByNumber(1l); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setTopics(new Object[2]); - fr.getTopics()[0] = null; - fr.getTopics()[1] = ONE_TOPIC; + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("earliest"); + TopicParam[][] topics = new TopicParam[][]{{null},{new TopicParam(ONE_TOPIC)}}; + FilterRequestParam fr = new FilterRequestParam(blockIdentifierParam, null, null, topics, null); web3.eth_getLogs(fr); Object[] logs = web3.eth_getLogs(fr); @@ -889,18 +841,17 @@ void getLogsTwiceFromBlockchainWithCallContractAndFilterBySecondTopic() throws E @Test void getLogsFromBlockchainWithEventInContractCreationReturnsAsExpectedWithBlockHashFilter() throws Exception { addEventInContractCreation(); - FilterRequest fr = new FilterRequest(); final String blockHash = TRACKED_TEST_BLOCK_HASH; - fr.setBlockHash(blockHash); + FilterRequestParam fr = new FilterRequestParam(null, null, null, null, new BlockHashParam(blockHash)); Object[] logs = web3.eth_getLogs(fr); assertNotNull(logs); assertEquals(1, logs.length); assertEquals(blockHash, ((LogFilterElement) logs[0]).blockHash); - String txhash = ((LogFilterElement)logs[0]).transactionHash; - TransactionReceiptDTO txdto = web3.eth_getTransactionReceipt(txhash); - assertEquals(txdto.getContractAddress(),((LogFilterElement)logs[0]).address); + String txhash = ((LogFilterElement) logs[0]).transactionHash; + TransactionReceiptDTO txdto = web3.eth_getTransactionReceipt(new TxHashParam(txhash)); + assertEquals(txdto.getContractAddress(), ((LogFilterElement) logs[0]).address); } @Test @@ -908,8 +859,8 @@ void getLogsWithBlockHashFilterForNonexistentBlockThrowsException() throws Excep final String blockHash = UNTRACKED_TEST_BLOCK_HASH; byte[] blockHashBytes = new Keccak256(HexUtils.stringHexToByteArray(blockHash)).getBytes(); assertFalse(blockChain.hasBlockInSomeBlockchain(blockHashBytes)); - FilterRequest fr = new FilterRequest(); - fr.setBlockHash(blockHash); + FilterRequestParam fr = new FilterRequestParam(null, null, null, null, new BlockHashParam(blockHash)); + Object[] logs = web3.eth_getLogs(fr); @@ -920,19 +871,14 @@ void getLogsWithBlockHashFilterForNonexistentBlockThrowsException() throws Excep @Test void getLogsThrowsExceptionWhenBlockHashIsUsedCombinedWithFromBlock() { addEventInContractCreation(); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); - fr.setBlockHash(TRACKED_TEST_BLOCK_HASH); - + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, new BlockHashParam(TRACKED_TEST_BLOCK_HASH)); Assertions.assertThrows(RskJsonRpcRequestException.class, () -> web3.eth_getLogs(fr)); } @Test void getLogsThrowsExceptionWhenBlockHashIsUsedCombinedWithToBlock() { addEventInContractCreation(); - FilterRequest fr = new FilterRequest(); - fr.setToBlock("latest"); - fr.setBlockHash(TRACKED_TEST_BLOCK_HASH); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("latest"), null, null, null, new BlockHashParam(TRACKED_TEST_BLOCK_HASH)); Assertions.assertThrows(RskJsonRpcRequestException.class, () -> web3.eth_getLogs(fr)); } @@ -940,12 +886,11 @@ void getLogsThrowsExceptionWhenBlockHashIsUsedCombinedWithToBlock() { @Test void createMainContractWithoutEvents() throws Exception { Account acc1 = new AccountBuilder(blockChain, - blockStore, - repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); + blockStore, + repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); web3.personal_newAccountWithSeed("notDefault"); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); String id = web3.eth_newFilter(fr); Block genesis = blockChain.getBlockByNumber(0); @@ -955,11 +900,11 @@ void createMainContractWithoutEvents() throws Exception { List txs = new ArrayList<>(); txs.add(tx); Block block1 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(genesis).transactions(txs).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); - Object[] logs = web3.eth_getFilterChanges(id); + Object[] logs = web3.eth_getFilterChanges(new HexIndexParam(id)); assertNotNull(id); assertNotNull(logs); @@ -969,12 +914,11 @@ void createMainContractWithoutEvents() throws Exception { @Test void createCallerContractWithEvents() throws Exception { Account acc1 = new AccountBuilder(blockChain, - blockStore, - repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); + blockStore, + repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); web3.personal_newAccountWithSeed("notDefault"); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); String id = web3.eth_newFilter(fr); Block genesis = blockChain.getBlockByNumber(0); @@ -984,7 +928,7 @@ void createCallerContractWithEvents() throws Exception { List txs = new ArrayList<>(); txs.add(tx); Block block1 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(genesis).transactions(txs).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); @@ -997,29 +941,28 @@ void createCallerContractWithEvents() throws Exception { List txs2 = new ArrayList<>(); txs2.add(tx2); Block block2 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(block1).transactions(txs2).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block2)); - Object[] logs = web3.eth_getFilterChanges(id); + Object[] logs = web3.eth_getFilterChanges(new HexIndexParam(id)); assertNotNull(id); assertNotNull(logs); assertEquals(2, logs.length); - assertEquals("0x" + mainAddress, ((LogFilterElement)logs[0]).address); - assertEquals("0x" + callerAddress, ((LogFilterElement)logs[1]).address); + assertEquals("0x" + mainAddress, ((LogFilterElement) logs[0]).address); + assertEquals("0x" + callerAddress, ((LogFilterElement) logs[1]).address); } @Test void createCallerContractWithEventsOnInvoke() throws Exception { Account acc1 = new AccountBuilder(blockChain, - blockStore, - repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); + blockStore, + repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); web3.personal_newAccountWithSeed("notDefault"); - FilterRequest fr = new FilterRequest(); - fr.setFromBlock("earliest"); + FilterRequestParam fr = new FilterRequestParam(new BlockIdentifierParam("earliest"), null, null, null, null); String id = web3.eth_newFilter(fr); Block genesis = blockChain.getBlockByNumber(0); @@ -1029,7 +972,7 @@ void createCallerContractWithEventsOnInvoke() throws Exception { List txs = new ArrayList<>(); txs.add(tx); Block block1 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(genesis).transactions(txs).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); @@ -1042,7 +985,7 @@ void createCallerContractWithEventsOnInvoke() throws Exception { List txs2 = new ArrayList<>(); txs2.add(tx2); Block block2 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(block1).transactions(txs2).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block2)); @@ -1052,26 +995,26 @@ void createCallerContractWithEventsOnInvoke() throws Exception { List txs3 = new ArrayList<>(); txs3.add(tx3); Block block3 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(block2).transactions(txs3).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block3)); - Object[] logs = web3.eth_getFilterChanges(id); + Object[] logs = web3.eth_getFilterChanges(new HexIndexParam(id)); assertNotNull(id); assertNotNull(logs); assertEquals(3, logs.length); - assertEquals("0x" + mainAddress, ((LogFilterElement)logs[0]).address); - assertEquals("0x" + callerAddress, ((LogFilterElement)logs[1]).address); - assertEquals("0x" + mainAddress, ((LogFilterElement)logs[2]).address); + assertEquals("0x" + mainAddress, ((LogFilterElement) logs[0]).address); + assertEquals("0x" + callerAddress, ((LogFilterElement) logs[1]).address); + assertEquals("0x" + mainAddress, ((LogFilterElement) logs[2]).address); } @Test void createCallerContractWithEventsOnInvokeUsingGetFilterLogs() throws Exception { Account acc1 = new AccountBuilder(blockChain, - blockStore, - repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); + blockStore, + repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); web3.personal_newAccountWithSeed("notDefault"); Block genesis = blockChain.getBlockByNumber(0); @@ -1081,7 +1024,7 @@ void createCallerContractWithEventsOnInvokeUsingGetFilterLogs() throws Exception List txs = new ArrayList<>(); txs.add(tx); Block block1 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(genesis).transactions(txs).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); @@ -1093,7 +1036,7 @@ void createCallerContractWithEventsOnInvokeUsingGetFilterLogs() throws Exception List txs2 = new ArrayList<>(); txs2.add(tx2); Block block2 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(block1).transactions(txs2).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block2)); @@ -1103,21 +1046,21 @@ void createCallerContractWithEventsOnInvokeUsingGetFilterLogs() throws Exception List txs3 = new ArrayList<>(); txs3.add(tx3); Block block3 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(block2).transactions(txs3).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block3)); - FilterRequest fr = new FilterRequest(); - fr.setAddress( "0x" + mainAddress); + HexAddressParam[] address = new HexAddressParam[]{new HexAddressParam("0x" + mainAddress)}; + FilterRequestParam fr = new FilterRequestParam(null, null, address, null, null); String id = web3.eth_newFilter(fr); - Object[] logs = web3.eth_getFilterLogs(id); + Object[] logs = web3.eth_getFilterLogs(new HexIndexParam(id)); assertNotNull(id); assertNotNull(logs); assertEquals(1, logs.length); - assertEquals("0x" + mainAddress, ((LogFilterElement)logs[0]).address); + assertEquals("0x" + mainAddress, ((LogFilterElement) logs[0]).address); } private Web3Impl createWeb3() { @@ -1167,11 +1110,11 @@ null, new EthModuleWalletEnabled(wallet), null, private void addTwoEmptyBlocks() { Block genesis = blockChain.getBlockByNumber(0); Block block1 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(genesis).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); Block block2 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(block1).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block2)); assertEquals(3, blockChain.getSize()); @@ -1181,8 +1124,8 @@ private void addTwoEmptyBlocks() { private void addContractCreationWithoutEvents() { Account acc1 = new AccountBuilder(blockChain, - blockStore, - repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); + blockStore, + repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); Block genesis = blockChain.getBlockByNumber(0); @@ -1209,7 +1152,7 @@ function greet(string param) onlyOwner constant returns (string) { List txs = new ArrayList<>(); txs.add(tx); Block block1 = new BlockBuilder(blockChain, null, - blockStore + blockStore ).trieStore(trieStore).parent(genesis).transactions(txs).build(); assertEquals(ImportResult.IMPORTED_BEST, blockChain.tryToConnect(block1)); @@ -1227,7 +1170,7 @@ public static void addEmptyBlockToBlockchain( BlockStore blockStore, RepositoryLocator repositoryLocator, TrieStore trieStore) { - Account acc1 = new AccountBuilder(blockChain,blockStore,repositoryLocator) + Account acc1 = new AccountBuilder(blockChain, blockStore, repositoryLocator) .name("notDefault").balance(Coin.valueOf(10000000)).build(); Block genesis = blockChain.getBlockByNumber(0); @@ -1243,8 +1186,8 @@ public static void addEmptyBlockToBlockchain( private void addContractInvoke() { Account acc1 = new AccountBuilder(blockChain, - blockStore, - repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); + blockStore, + repositoryLocator).name("notDefault").balance(Coin.valueOf(10000000)).build(); Block genesis = blockChain.getBlockByNumber(0); Transaction tx; @@ -1349,14 +1292,14 @@ private void addContractCall() { } private static Transaction getContractTransaction(Account acc1) { - return getContractTransaction(acc1,false); + return getContractTransaction(acc1, false); } //0.4.11+commit.68ef5810.Emscripten.clang WITH optimizations static final String compiled_0_4_11 = "6060604052341561000c57fe5b5b60466000819055507f06acbfb32bcf8383f3b0a768b70ac9ec234ea0f2d3b9c77fa6a2de69b919aad16000546040518082815260200191505060405180910390a15b5b61014e8061005f6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632096525514610046578063371303c01461006c575bfe5b341561004e57fe5b61005661007e565b6040518082815260200191505060405180910390f35b341561007457fe5b61007c6100c2565b005b60007f1ee041944547858a75ebef916083b6d4f5ae04bea9cd809334469dd07dbf441b6000546040518082815260200191505060405180910390a160005490505b90565b60006000815460010191905081905550600160026000548115156100e257fe5b061415157f6e61ef44ac2747ff8b84d353a908eb8bd5c3fb118334d57698c5cfc7041196ad6000546040518082815260200191505060405180910390a25b5600a165627a7a7230582092c7b2c0483b85227396e18149993b33243059af0f3bd0364f1dc36b8bbbcdae0029"; static final String compiled_unknown = "60606040526046600081905560609081527f06acbfb32bcf8383f3b0a768b70ac9ec234ea0f2d3b9c77fa6a2de69b919aad190602090a160aa8060426000396000f3606060405260e060020a60003504632096525581146024578063371303c0146060575b005b60a36000805460609081527f1ee041944547858a75ebef916083b6d4f5ae04bea9cd809334469dd07dbf441b90602090a1600060005054905090565b6022600080546001908101918290556060828152600290920614907f6e61ef44ac2747ff8b84d353a908eb8bd5c3fb118334d57698c5cfc7041196ad90602090a2565b5060206060f3"; - private static Transaction getContractTransaction(Account acc1,boolean withEvent) { + private static Transaction getContractTransaction(Account acc1, boolean withEvent) { /* contract compiled in data attribute of tx contract counter { event Incremented(bool indexed odd, uint x); @@ -1410,7 +1353,8 @@ private static Transaction getContractTransactionWithCall(Account acc1, byte[] r .build(); } - String compiledLogExample ="606060405234610000575b60bd806100186000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063195977a614603c575b6000565b34600057605460048080359060200190919050506056565b005b7ffd99bb34477b313b3e3b452b34d012d8315db36a1d63949d9d8f9d2573b05aff816040518082815260200191505060405180910390a15b505600a165627a7a72305820fb2550735b0655fb2fe03738be375a4c29ef1b6ff51004f869be19de0301f30b0029"; + String compiledLogExample = "606060405234610000575b60bd806100186000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063195977a614603c575b6000565b34600057605460048080359060200190919050506056565b005b7ffd99bb34477b313b3e3b452b34d012d8315db36a1d63949d9d8f9d2573b05aff816040518082815260200191505060405180910390a15b505600a165627a7a72305820fb2550735b0655fb2fe03738be375a4c29ef1b6ff51004f869be19de0301f30b0029"; + private Transaction getMainContractTransaction(Account acc1) { /* contract compiled in data attribute of tx contract main { @@ -1456,7 +1400,7 @@ function doSomething(address mainAddr) { .sender(acc1) .gasLimit(BigInteger.valueOf(500000)) .gasPrice(BigInteger.ONE) - .data( compiledCaller + address) + .data(compiledCaller + address) .nonce(1) .build(); } @@ -1467,7 +1411,7 @@ private static Transaction getCallerContractTransactionWithInvoke(Account acc1, while (address.length() < 64) address = "0" + address; - CallTransaction.Function func = CallTransaction.Function.fromSignature("doSomething", new String[] { "address" }, new String[0]); + CallTransaction.Function func = CallTransaction.Function.fromSignature("doSomething", new String[]{"address"}, new String[0]); return new TransactionBuilder() .sender(acc1) @@ -1478,4 +1422,8 @@ private static Transaction getCallerContractTransactionWithInvoke(Account acc1, .nonce(2) .build(); } + + private TopicParam[][] initTopicsArray(String topic) { + return new TopicParam[][]{{new TopicParam(topic)}}; + } } diff --git a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java index 18f17126a3f..e4881325439 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplTest.java @@ -18,8 +18,8 @@ package org.ethereum.rpc; -import co.rsk.blockchain.utils.BlockGenerator; import co.rsk.Flusher; +import co.rsk.blockchain.utils.BlockGenerator; import co.rsk.config.RskSystemProperties; import co.rsk.config.TestSystemProperties; import co.rsk.core.*; @@ -27,8 +27,6 @@ import co.rsk.core.bc.TransactionPoolImpl; import co.rsk.crypto.Keccak256; import co.rsk.db.RepositoryLocator; -import co.rsk.logfilter.BlocksBloomStore; -import co.rsk.metrics.HashRateCalculator; import co.rsk.mine.MinerClient; import co.rsk.mine.MinerServer; import co.rsk.net.BlockProcessor; @@ -45,17 +43,13 @@ import co.rsk.rpc.modules.eth.EthModule; import co.rsk.rpc.modules.eth.EthModuleTransactionBase; import co.rsk.rpc.modules.eth.EthModuleWalletEnabled; -import co.rsk.rpc.modules.evm.EvmModule; -import co.rsk.rpc.modules.mnr.MnrModule; import co.rsk.rpc.modules.personal.PersonalModule; import co.rsk.rpc.modules.personal.PersonalModuleWalletDisabled; import co.rsk.rpc.modules.personal.PersonalModuleWalletEnabled; import co.rsk.rpc.modules.rsk.RskModule; import co.rsk.rpc.modules.rsk.RskModuleImpl; -import co.rsk.rpc.modules.trace.TraceModule; import co.rsk.rpc.modules.txpool.TxPoolModule; import co.rsk.rpc.modules.txpool.TxPoolModuleImpl; -import co.rsk.scoring.PeerScoringManager; import co.rsk.test.World; import co.rsk.test.builders.AccountBuilder; import co.rsk.test.builders.BlockBuilder; @@ -66,9 +60,6 @@ import com.typesafe.config.ConfigValueFactory; import org.bouncycastle.util.encoders.Hex; import org.ethereum.TestUtils; -import org.ethereum.config.Constants; -import org.ethereum.config.blockchain.upgrades.ActivationConfigsForTest; -import org.ethereum.config.blockchain.upgrades.ConsensusRule; import org.ethereum.core.*; import org.ethereum.core.genesis.BlockTag; import org.ethereum.crypto.ECKey; @@ -89,8 +80,10 @@ import org.ethereum.rpc.dto.TransactionReceiptDTO; import org.ethereum.rpc.dto.TransactionResultDTO; import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.*; import org.ethereum.util.BuildInfo; import org.ethereum.util.ByteUtil; +import org.ethereum.util.TransactionFactoryHelper; import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.program.ProgramResult; import org.ethereum.vm.program.invoke.ProgramInvokeFactoryImpl; @@ -227,7 +220,7 @@ void getBalanceWithAccount() { Web3Impl web3 = createWeb3(world); - assertEquals(BALANCE_10K_HEX, web3.eth_getBalance(ByteUtil.toHexString(acc1.getAddress().getBytes()))); + assertEquals(BALANCE_10K_HEX, web3.eth_getBalance(new HexAddressParam(ByteUtil.toHexString(acc1.getAddress().getBytes())))); } @Test @@ -237,7 +230,9 @@ void getBalanceWithAccountAndLatestBlock() { Web3Impl web3 = createWeb3(world); - assertEquals(BALANCE_10K_HEX, web3.eth_getBalance(ByteUtil.toHexString(acc1.getAddress().getBytes()), "latest")); + assertEquals(BALANCE_10K_HEX, web3.eth_getBalance( + new HexAddressParam(ByteUtil.toHexString(acc1.getAddress().getBytes())), + new BlockRefParam("latest"))); } @Test @@ -249,7 +244,7 @@ void getBalanceWithAccountAndGenesisBlock() { String accountAddress = ByteUtil.toHexString(acc1.getAddress().getBytes()); - assertEquals(BALANCE_10K_HEX, web3.eth_getBalance(accountAddress, "0x0")); + assertEquals(BALANCE_10K_HEX, web3.eth_getBalance(new HexAddressParam(accountAddress), new BlockRefParam("0x0"))); } @Test @@ -262,42 +257,42 @@ void getBalanceWithAccountAndBlock() { String accountAddress = ByteUtil.toHexString(acc1.getAddress().getBytes()); - assertEquals(BALANCE_10K_HEX, web3.eth_getBalance(accountAddress, "0x1")); + assertEquals(BALANCE_10K_HEX, web3.eth_getBalance(new HexAddressParam(accountAddress), new BlockRefParam("0x1"))); } @Test //[ "0x
", { "blockNumber": "0x0" } -> return balance at given address in genesis block void getBalanceWithAccountAndBlockNumber() { final ChainParams chain = chainWithAccount10kBalance(false); - assertByBlockNumber(BALANCE_10K_HEX, blockRef -> chain.web3.eth_getBalance(chain.accountAddress, blockRef)); + assertByBlockNumber(BALANCE_10K_HEX, blockRef -> chain.web3.eth_getBalance(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "invalidInput": "0x0" } -> throw RskJsonRpcRequestException void getBalanceWithAccountAndInvalidInputThrowsException() { final ChainParams chain = chainWithAccount10kBalance(false); - assertInvalidInput(blockRef -> chain.web3.eth_getBalance(chain.accountAddress, blockRef)); + assertInvalidInput(blockRef -> chain.web3.eth_getBalance(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" } -> return balance at given address in genesis block void getBalanceWithAccountAndBlockHash() { final ChainParams chain = chainWithAccount10kBalance(false); - assertByBlockHash(BALANCE_10K_HEX, chain.block, blockRef -> chain.web3.eth_getBalance(chain.accountAddress, blockRef)); + assertByBlockHash(BALANCE_10K_HEX, chain.block, blockRef -> chain.web3.eth_getBalance(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0x" } -> raise block-not-found error void getBalanceWithAccountAndNonExistentBlockHash() { final ChainParams chain = chainWithAccount10kBalance(false); - assertNonExistentBlockHash(blockRef -> chain.web3.eth_getBalance(chain.accountAddress, blockRef)); + assertNonExistentBlockHash(blockRef -> chain.web3.eth_getBalance(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0x", "requireCanonical": true } -> raise block-not-found error void getBalanceWithAccountAndNonExistentBlockHashWhenCanonicalIsRequired() { final ChainParams chain = chainWithAccount10kBalance(false); - assertNonBlockHashWhenCanonical(blockRef -> chain.web3.eth_getBalance(chain.accountAddress, blockRef)); + assertNonBlockHashWhenCanonical(blockRef -> chain.web3.eth_getBalance(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @@ -305,14 +300,14 @@ void getBalanceWithAccountAndNonExistentBlockHashWhenCanonicalIsRequired() { //[ "0x
", { "blockHash": "0x", "requireCanonical": false } -> raise block-not-found error void getBalanceWithAccountAndNonExistentBlockHashWhenCanonicalIsNotRequired() { final ChainParams chain = chainWithAccount10kBalance(false); - assertNonBlockHashWhenIsNotCanonical(blockRef -> chain.web3.eth_getBalance(chain.accountAddress, blockRef)); + assertNonBlockHashWhenIsNotCanonical(blockRef -> chain.web3.eth_getBalance(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test // [ "0x
", { "blockHash": "0x", "requireCanonical": true } -> raise block-not-canonical error void getBalanceWithAccountAndNonCanonicalBlockHashWhenCanonicalIsRequired() { final ChainParams chain = chainWithAccount10kBalance(true); - assertNonCanonicalBlockHashWhenCanonical(chain.block, blockRef -> chain.web3.eth_getBalance(chain.accountAddress, blockRef)); + assertNonCanonicalBlockHashWhenCanonical(chain.block, blockRef -> chain.web3.eth_getBalance(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @@ -320,28 +315,28 @@ void getBalanceWithAccountAndNonCanonicalBlockHashWhenCanonicalIsRequired() { //[ "0x
", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": true } -> return balance at given address in genesis block void getBalanceWithAccountAndCanonicalBlockHashWhenCanonicalIsRequired() { final ChainParams chain = chainWithAccount10kBalance(false); - assertCanonicalBlockHashWhenCanonical(BALANCE_10K_HEX, chain.block, blockRef -> chain.web3.eth_getBalance(chain.accountAddress, blockRef)); + assertCanonicalBlockHashWhenCanonical(BALANCE_10K_HEX, chain.block, blockRef -> chain.web3.eth_getBalance(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": false } -> return balance at given address in genesis block void getBalanceWithAccountAndCanonicalBlockHashWhenCanonicalIsNotRequired() { final ChainParams chain = chainWithAccount10kBalance(false); - assertCanonicalBlockHashWhenNotCanonical(BALANCE_10K_HEX, chain.block, blockRef -> chain.web3.eth_getBalance(chain.accountAddress, blockRef)); + assertCanonicalBlockHashWhenNotCanonical(BALANCE_10K_HEX, chain.block, blockRef -> chain.web3.eth_getBalance(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test // [ "0x
", { "blockHash": "0x", "requireCanonical": false } -> return balance at given address in specified block void getBalanceWithAccountAndNonCanonicalBlockHashWhenCanonicalIsNotRequired() { final ChainParams chain = chainWithAccount10kBalance(true); - assertNonCanonicalBlockHashWhenNotCanonical(BALANCE_10K_HEX, chain.block, blockRef -> chain.web3.eth_getBalance(chain.accountAddress, blockRef)); + assertNonCanonicalBlockHashWhenNotCanonical(BALANCE_10K_HEX, chain.block, blockRef -> chain.web3.eth_getBalance(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test // [ "0x
", { "blockHash": "0x" } -> return balance at given address in specified bloc void getBalanceWithAccountAndNonCanonicalBlockHash() { final ChainParams chain = chainWithAccount10kBalance(true); - assertNonCanonicalBlockHash(BALANCE_10K_HEX, chain.block, blockRef -> chain.web3.eth_getBalance(chain.accountAddress, blockRef)); + assertNonCanonicalBlockHash(BALANCE_10K_HEX, chain.block, blockRef -> chain.web3.eth_getBalance(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test @@ -365,30 +360,39 @@ void getBalanceWithAccountAndBlockWithTransaction() { String accountAddress = ByteUtil.toHexString(acc2.getAddress().getBytes()); String balanceString = BALANCE_10K_HEX; - assertEquals("0x0", web3.eth_getBalance(accountAddress, "0x0")); - assertEquals(balanceString, web3.eth_getBalance(accountAddress, "0x1")); - assertEquals(balanceString, web3.eth_getBalance(accountAddress, "pending")); + assertEquals("0x0", web3.eth_getBalance(new HexAddressParam(accountAddress), new BlockRefParam("0x0"))); + assertEquals(balanceString, web3.eth_getBalance(new HexAddressParam(accountAddress), new BlockRefParam("0x1"))); + assertEquals(balanceString, web3.eth_getBalance(new HexAddressParam(accountAddress), new BlockRefParam("pending"))); } @Test //[ "0x
", { "blockNumber": "0x0" } -> return storage at given address in genesis block void getStorageAtAccountAndBlockNumber() { final ChainParams chain = chainWithAccount10kBalance(false); - assertByBlockNumber("0x0", blockRef -> chain.web3.eth_getStorageAt(chain.accountAddress, "0x0", blockRef)); + assertByBlockNumber("0x0", blockRef -> chain.web3.eth_getStorageAt( + new HexAddressParam(chain.accountAddress), + new HexNumberParam("0x0"), + new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" } -> return storage at given address in genesis block void getStorageAtAccountAndBlockHash() { final ChainParams chain = chainWithAccount10kBalance(false); - assertByBlockHash("0x0", chain.block, blockRef -> chain.web3.eth_getStorageAt(chain.accountAddress, "0x0", blockRef)); + assertByBlockHash("0x0", chain.block, blockRef -> chain.web3.eth_getStorageAt( + new HexAddressParam(chain.accountAddress), + new HexNumberParam("0x0"), + new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0x" } -> raise block-not-found error void getStorageAtAccountAndNonExistentBlockHash() { final ChainParams chain = chainWithAccount10kBalance(false); - assertNonExistentBlockHash(blockRef -> chain.web3.eth_getStorageAt(chain.accountAddress, "0x0", blockRef)); + assertNonExistentBlockHash(blockRef -> chain.web3.eth_getStorageAt( + new HexAddressParam(chain.accountAddress), + new HexNumberParam("0x0"), + new BlockRefParam(blockRef))); } @@ -396,49 +400,70 @@ void getStorageAtAccountAndNonExistentBlockHash() { //[ "0x
", { "blockHash": "0x", "requireCanonical": true } -> raise block-not-found error void getStorageAtAccountAndNonExistentBlockHashWhenCanonicalIsRequired() { final ChainParams chain = chainWithAccount10kBalance(false); - assertNonBlockHashWhenCanonical(blockRef -> chain.web3.eth_getStorageAt(chain.accountAddress, "0x0", blockRef)); + assertNonBlockHashWhenCanonical(blockRef -> chain.web3.eth_getStorageAt( + new HexAddressParam(chain.accountAddress), + new HexNumberParam("0x0"), + new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0x", "requireCanonical": false } -> raise block-not-found error void getStorageAtAccountAndNonExistentBlockHashWhenCanonicalIsNotRequired() { final ChainParams chain = chainWithAccount10kBalance(false); - assertNonBlockHashWhenIsNotCanonical(blockRef -> chain.web3.eth_getStorageAt(chain.accountAddress, "0x0", blockRef)); + assertNonBlockHashWhenIsNotCanonical(blockRef -> chain.web3.eth_getStorageAt( + new HexAddressParam(chain.accountAddress), + new HexNumberParam("0x0"), + new BlockRefParam(blockRef))); } @Test // [ "0x
", { "blockHash": "0x", "requireCanonical": true } -> raise block-not-canonical error void getStorageAtAccountAndNonCanonicalBlockHashWhenCanonicalIsRequired() { final ChainParams chain = chainWithAccount10kBalance(true); - assertNonCanonicalBlockHashWhenCanonical(chain.block, blockRef -> chain.web3.eth_getStorageAt(chain.accountAddress, "0x0", blockRef)); + assertNonCanonicalBlockHashWhenCanonical(chain.block, blockRef -> chain.web3.eth_getStorageAt( + new HexAddressParam(chain.accountAddress), + new HexNumberParam("0x0"), + new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": true } -> return storage at given address in genesis block void getStorageAtAccountAndCanonicalBlockHashWhenCanonicalIsRequired() { final ChainParams chain = chainWithAccount10kBalance(false); - assertCanonicalBlockHashWhenCanonical("0x0", chain.block, blockRef -> chain.web3.eth_getStorageAt(chain.accountAddress, "0x0", blockRef)); + assertCanonicalBlockHashWhenCanonical("0x0", chain.block, blockRef -> chain.web3.eth_getStorageAt( + new HexAddressParam(chain.accountAddress), + new HexNumberParam("0x0"), + new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": false } -> return storage at given address in genesis block void getStorageAtAccountAndCanonicalBlockHashWhenCanonicalIsNotRequired() { final ChainParams chain = chainWithAccount10kBalance(false); - assertCanonicalBlockHashWhenNotCanonical("0x0", chain.block, blockRef -> chain.web3.eth_getStorageAt(chain.accountAddress, "0x0", blockRef)); + assertCanonicalBlockHashWhenNotCanonical("0x0", chain.block, blockRef -> chain.web3.eth_getStorageAt( + new HexAddressParam(chain.accountAddress), + new HexNumberParam("0x0"), + new BlockRefParam(blockRef))); } @Test // [ "0x
", { "blockHash": "0x", "requireCanonical": false } -> return storage at given address in specified block void getStorageAtAccountAndNonCanonicalBlockHashWhenCanonicalIsNotRequired() { final ChainParams chain = chainWithAccount10kBalance(true); - assertNonCanonicalBlockHashWhenNotCanonical("0x0", chain.block, blockRef -> chain.web3.eth_getStorageAt(chain.accountAddress, "0x0", blockRef)); + assertNonCanonicalBlockHashWhenNotCanonical("0x0", chain.block, blockRef -> chain.web3.eth_getStorageAt( + new HexAddressParam(chain.accountAddress), + new HexNumberParam("0x0"), + new BlockRefParam(blockRef))); } @Test // [ "0x
", { "blockHash": "0x" } -> return storage at given address in specified bloc void getStorageAtAccountAndNonCanonicalBlockHash() { final ChainParams chain = chainWithAccount10kBalance(true); - assertNonCanonicalBlockHash("0x0", chain.block, blockRef -> chain.web3.eth_getStorageAt(chain.accountAddress, "0x0", blockRef)); + assertNonCanonicalBlockHash("0x0", chain.block, blockRef -> chain.web3.eth_getStorageAt( + new HexAddressParam(chain.accountAddress), + new HexNumberParam("0x0"), + new BlockRefParam(blockRef))); } @@ -446,140 +471,140 @@ void getStorageAtAccountAndNonCanonicalBlockHash() { //[ "0x
", { "blockNumber": "0x0" } -> return code at given address in genesis block void getCodeAtAccountAndBlockNumber() { final ChainParams chain = createChainWithAContractCode(false); - assertByBlockNumber("0x010203", blockRef -> chain.web3.eth_getCode(chain.accountAddress, blockRef)); + assertByBlockNumber("0x010203", blockRef -> chain.web3.eth_getCode(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" } -> return code at given address in genesis block void getCodeAtAccountAndBlockHash() { final ChainParams chain = createChainWithAContractCode(false); - assertByBlockHash("0x010203", chain.block, blockRef -> chain.web3.eth_getCode(chain.accountAddress, blockRef)); + assertByBlockHash("0x010203", chain.block, blockRef -> chain.web3.eth_getCode(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0x" } -> raise block-not-found error void getCodeAtAccountAndNonExistentBlockHash() { final ChainParams chain = createChainWithAContractCode(false); - assertNonExistentBlockHash(blockRef -> chain.web3.eth_getCode(chain.accountAddress, blockRef)); + assertNonExistentBlockHash(blockRef -> chain.web3.eth_getCode(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0x", "requireCanonical": true } -> raise block-not-found error void getCodeAtAccountAndNonExistentBlockHashWhenCanonicalIsRequired() { final ChainParams chain = createChainWithAContractCode(false); - assertNonBlockHashWhenCanonical(blockRef -> chain.web3.eth_getCode(chain.accountAddress, blockRef)); + assertNonBlockHashWhenCanonical(blockRef -> chain.web3.eth_getCode(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0x", "requireCanonical": false } -> raise block-not-found error void getCodeAtAccountAndNonExistentBlockHashWhenCanonicalIsNotRequired() { final ChainParams chain = createChainWithAContractCode(false); - assertNonBlockHashWhenIsNotCanonical(blockRef -> chain.web3.eth_getCode(chain.accountAddress, blockRef)); + assertNonBlockHashWhenIsNotCanonical(blockRef -> chain.web3.eth_getCode(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test // [ "0x
", { "blockHash": "0x", "requireCanonical": true } -> raise block-not-canonical error void getCodeAtAccountAndNonCanonicalBlockHashWhenCanonicalIsRequired() { final ChainParams chain = createChainWithAContractCode(true); - assertNonCanonicalBlockHashWhenCanonical(chain.block, blockRef -> chain.web3.eth_getCode(chain.accountAddress, blockRef)); + assertNonCanonicalBlockHashWhenCanonical(chain.block, blockRef -> chain.web3.eth_getCode(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": true } -> return code at given address in genesis block void getCodeAtAccountAndCanonicalBlockHashWhenCanonicalIsRequired() { final ChainParams chain = createChainWithAContractCode(false); - assertCanonicalBlockHashWhenCanonical("0x010203", chain.block, blockRef -> chain.web3.eth_getCode(chain.accountAddress, blockRef)); + assertCanonicalBlockHashWhenCanonical("0x010203", chain.block, blockRef -> chain.web3.eth_getCode(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": false } -> return code at given address in genesis block void getCodeAtAccountAndCanonicalBlockHashWhenCanonicalIsNotRequired() { final ChainParams chain = createChainWithAContractCode(false); - assertCanonicalBlockHashWhenNotCanonical("0x010203", chain.block, blockRef -> chain.web3.eth_getCode(chain.accountAddress, blockRef)); + assertCanonicalBlockHashWhenNotCanonical("0x010203", chain.block, blockRef -> chain.web3.eth_getCode(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test // [ "0x
", { "blockHash": "0x", "requireCanonical": false } -> return code at given address in specified block void getCodeAtAccountAndNonCanonicalBlockHashWhenCanonicalIsNotRequired() { final ChainParams chain = createChainWithAContractCode(true); - assertNonCanonicalBlockHashWhenNotCanonical("0x010203", chain.block, blockRef -> chain.web3.eth_getCode(chain.accountAddress, blockRef)); + assertNonCanonicalBlockHashWhenNotCanonical("0x010203", chain.block, blockRef -> chain.web3.eth_getCode(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test // [ "0x
", { "blockHash": "0x" } -> return code at given address in specified bloc void getCodeAtAccountAndNonCanonicalBlockHash() { final ChainParams chain = createChainWithAContractCode(true); - assertNonCanonicalBlockHash("0x010203", chain.block, blockRef -> chain.web3.eth_getCode(chain.accountAddress, blockRef)); + assertNonCanonicalBlockHash("0x010203", chain.block, blockRef -> chain.web3.eth_getCode(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ {argsForCall}, { "blockNumber": "0x0" } -> return contract call respond at given args for call in genesis block void callByBlockNumber() { final ChainParams chain = createChainWithACall(false); - assertByBlockNumber(CALL_RESPOND, blockRef -> chain.web3.eth_call(chain.argsForCall, blockRef)); + assertByBlockNumber(CALL_RESPOND, blockRef -> chain.web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(chain.argsForCall), blockRef)); } @Test //[ {argsForCall}, { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" } -> return contract call respond at given address in genesis block void callByBlockHash() { final ChainParams chain = createChainWithACall(false); - assertByBlockHash(CALL_RESPOND, chain.block, blockRef -> chain.web3.eth_call(chain.argsForCall, blockRef)); + assertByBlockHash(CALL_RESPOND, chain.block, blockRef -> chain.web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(chain.argsForCall), blockRef)); } @Test //[ {argsForCall}, { "blockHash": "0x" } -> raise block-not-found error void callByNonExistentBlockHash() { final ChainParams chain = createChainWithACall(false); - assertNonExistentBlockHash(blockRef -> chain.web3.eth_call(chain.argsForCall, blockRef)); + assertNonExistentBlockHash(blockRef -> chain.web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(chain.argsForCall), blockRef)); } @Test //[ {argsForCall}, { "blockHash": "0x", "requireCanonical": true } -> raise block-not-found error void callByNonExistentBlockHashWhenCanonicalIsRequired() { final ChainParams chain = createChainWithACall(false); - assertNonBlockHashWhenCanonical(blockRef -> chain.web3.eth_call(chain.argsForCall, blockRef)); + assertNonBlockHashWhenCanonical(blockRef -> chain.web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(chain.argsForCall), blockRef)); } @Test //[ {argsForCall}, { "blockHash": "0x", "requireCanonical": false } -> raise block-not-found error void callByNonExistentBlockHashWhenCanonicalIsNotRequired() { final ChainParams chain = createChainWithACall(false); - assertNonBlockHashWhenIsNotCanonical(blockRef -> chain.web3.eth_call(chain.argsForCall, blockRef)); + assertNonBlockHashWhenIsNotCanonical(blockRef -> chain.web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(chain.argsForCall), blockRef)); } @Test // [ {argsForCall} { "blockHash": "0x", "requireCanonical": true } -> raise block-not-canonical error void callByNonCanonicalBlockHashWhenCanonicalIsRequired() { final ChainParams chain = createChainWithACall(true); - assertNonCanonicalBlockHashWhenCanonical(chain.block, blockRef -> chain.web3.eth_call(chain.argsForCall, blockRef)); + assertNonCanonicalBlockHashWhenCanonical(chain.block, blockRef -> chain.web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(chain.argsForCall), blockRef)); } @Test //[ {argsForCall}, { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": true } -> return contract call respond at given address in genesis block void callByCanonicalBlockHashWhenCanonicalIsRequired() { final ChainParams chain = createChainWithACall(false); - assertCanonicalBlockHashWhenCanonical(CALL_RESPOND, chain.block, blockRef -> chain.web3.eth_call(chain.argsForCall, blockRef)); + assertCanonicalBlockHashWhenCanonical(CALL_RESPOND, chain.block, blockRef -> chain.web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(chain.argsForCall), blockRef)); } @Test //[ {argsForCall}, { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "requireCanonical": false } -> return contract call respond at given address in genesis block void callByCanonicalBlockHashWhenCanonicalIsNotRequired() { final ChainParams chain = createChainWithACall(false); - assertCanonicalBlockHashWhenNotCanonical(CALL_RESPOND, chain.block, blockRef -> chain.web3.eth_call(chain.argsForCall, blockRef)); + assertCanonicalBlockHashWhenNotCanonical(CALL_RESPOND, chain.block, blockRef -> chain.web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(chain.argsForCall), blockRef)); } @Test // [ {argsForCall}, { "blockHash": "0x", "requireCanonical": false } -> return contract call respond at given address in specified block void callByNonCanonicalBlockHashWhenCanonicalIsNotRequired() { final ChainParams chain = createChainWithACall(true); - assertNonCanonicalBlockHashWhenNotCanonical(CALL_RESPOND, chain.block, blockRef -> chain.web3.eth_call(chain.argsForCall, blockRef)); + assertNonCanonicalBlockHashWhenNotCanonical(CALL_RESPOND, chain.block, blockRef -> chain.web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(chain.argsForCall), blockRef)); } @Test // [ {argsForCall}, { "blockHash": "0x" } -> return contract call respond at given address in specified bloc void callByNonCanonicalBlockHash() { final ChainParams chain = createChainWithACall(true); - assertNonCanonicalBlockHash(CALL_RESPOND, chain.block, blockRef -> chain.web3.eth_call(chain.argsForCall, blockRef)); + assertNonCanonicalBlockHash(CALL_RESPOND, chain.block, blockRef -> chain.web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(chain.argsForCall), blockRef)); } @Test @@ -729,7 +754,7 @@ void getUnknownTransactionReceipt() { String hashString = tx.getHash().toHexString(); - Assertions.assertNull(web3.eth_getTransactionReceipt(hashString)); + Assertions.assertNull(web3.eth_getTransactionReceipt(new TxHashParam(hashString))); Assertions.assertNull(web3.rsk_getRawTransactionReceiptByHash(hashString)); } @@ -748,7 +773,7 @@ void getTransactionReceipt() { String hashString = tx.getHash().toHexString(); - TransactionReceiptDTO tr = web3.eth_getTransactionReceipt(hashString); + TransactionReceiptDTO tr = web3.eth_getTransactionReceipt(new TxHashParam(hashString)); assertNotNull(tr); assertEquals("0x" + hashString, tr.getTransactionHash()); @@ -799,7 +824,7 @@ void getTransactionReceiptNotInMainBlockchain() { String hashString = tx.getHash().toHexString(); - TransactionReceiptDTO tr = web3.eth_getTransactionReceipt(hashString); + TransactionReceiptDTO tr = web3.eth_getTransactionReceipt(new TxHashParam(hashString)); Assertions.assertNull(tr); } @@ -819,8 +844,8 @@ void getTransactionByHash() { Block block1 = createCanonicalBlock(world, txs); String hashString = tx.getHash().toHexString(); - - TransactionResultDTO tr = web3.eth_getTransactionByHash(hashString); + TxHashParam txHashParam = new TxHashParam(hashString); + TransactionResultDTO tr = web3.eth_getTransactionByHash(txHashParam); assertNotNull(tr); assertEquals("0x" + hashString, tr.getHash()); @@ -857,8 +882,8 @@ void getPendingTransactionByHash() { transactionPool.addTransaction(tx); String hashString = tx.getHash().toHexString(); - - TransactionResultDTO tr = web3.eth_getTransactionByHash(hashString); + TxHashParam txHashParam = new TxHashParam(hashString); + TransactionResultDTO tr = web3.eth_getTransactionByHash(txHashParam); assertNotNull(tr); @@ -894,8 +919,8 @@ void getTransactionByHashNotInMainBlockchain() { assertEquals(ImportResult.IMPORTED_BEST, world.getBlockChain().tryToConnect(block2b)); String hashString = tx.getHash().toHexString(); - - TransactionResultDTO tr = web3.eth_getTransactionByHash(hashString); + TxHashParam txHashParam = new TxHashParam(hashString); + TransactionResultDTO tr = web3.eth_getTransactionByHash(txHashParam); Assertions.assertNull(tr); } @@ -915,8 +940,9 @@ void getTransactionByBlockHashAndIndex() { String hashString = tx.getHash().toHexString(); String blockHashString = block1.getHash().toHexString(); - - TransactionResultDTO tr = web3.eth_getTransactionByBlockHashAndIndex(blockHashString, "0x0"); + BlockHashParam blockHashParam = new BlockHashParam(blockHashString); + HexIndexParam hexIndexParam = new HexIndexParam("0x0"); + TransactionResultDTO tr = web3.eth_getTransactionByBlockHashAndIndex(blockHashParam, hexIndexParam); assertNotNull(tr); assertEquals("0x" + hashString, tr.getHash()); @@ -936,8 +962,9 @@ void getUnknownTransactionByBlockHashAndIndex() { assertEquals(ImportResult.IMPORTED_BEST, world.getBlockChain().tryToConnect(block1)); String blockHashString = block1.getHash().toString(); - - TransactionResultDTO tr = web3.eth_getTransactionByBlockHashAndIndex(blockHashString, "0x0"); + BlockHashParam blockHashParam = new BlockHashParam(blockHashString); + HexIndexParam hexIndexParam = new HexIndexParam("0x0"); + TransactionResultDTO tr = web3.eth_getTransactionByBlockHashAndIndex(blockHashParam, hexIndexParam); Assertions.assertNull(tr); } @@ -958,7 +985,7 @@ void getTransactionByBlockNumberAndIndex() { String hashString = tx.getHash().toHexString(); String blockHashString = block1.getHash().toHexString(); - TransactionResultDTO tr = web3.eth_getTransactionByBlockNumberAndIndex("0x01", "0x0"); + TransactionResultDTO tr = web3.eth_getTransactionByBlockNumberAndIndex(new BlockIdentifierParam("0x01"), new HexIndexParam("0x0")); assertNotNull(tr); assertEquals("0x" + hashString, tr.getHash()); @@ -977,7 +1004,7 @@ void getUnknownTransactionByBlockNumberAndIndex() { world.getBlockStore()).trieStore(world.getTrieStore()).parent(genesis).build(); assertEquals(ImportResult.IMPORTED_BEST, world.getBlockChain().tryToConnect(block1)); - TransactionResultDTO tr = web3.eth_getTransactionByBlockNumberAndIndex("0x1", "0x0"); + TransactionResultDTO tr = web3.eth_getTransactionByBlockNumberAndIndex(new BlockIdentifierParam("0x1"), new HexIndexParam("0x0")); Assertions.assertNull(tr); } @@ -997,12 +1024,12 @@ void getTransactionCount() { String accountAddress = ByteUtil.toHexString(acc1.getAddress().getBytes()); - String count = web3.eth_getTransactionCount(accountAddress, "0x1"); + String count = web3.eth_getTransactionCount(new HexAddressParam(accountAddress), new BlockRefParam("0x1")); assertNotNull(count); assertEquals("0x1", count); - count = web3.eth_getTransactionCount(accountAddress, "0x0"); + count = web3.eth_getTransactionCount(new HexAddressParam(accountAddress), new BlockRefParam("0x0")); assertNotNull(count); assertEquals("0x0", count); @@ -1012,42 +1039,42 @@ void getTransactionCount() { //[ "0x
", { "blockNumber": "0x0" } -> return tx count at given address in genesis block void getTransactionCountByBlockNumber() { final ChainParams chain = createChainWithATransaction(false); - assertByBlockNumber("0x1", blockRef -> chain.web3.eth_getTransactionCount(chain.accountAddress, blockRef)); + assertByBlockNumber("0x1", blockRef -> chain.web3.eth_getTransactionCount(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "invalidInput": "0x0" } -> throw RskJsonRpcRequestException void getTransactionCountAndInvalidInputThrowsException() { final ChainParams chain = createChainWithATransaction(false); - assertInvalidInput(blockRef -> chain.web3.eth_getTransactionCount(chain.accountAddress, blockRef)); + assertInvalidInput(blockRef -> chain.web3.eth_getTransactionCount(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" } -> return tx count at given address in genesis block void getTransactionCountByBlockHash() { final ChainParams chain = createChainWithATransaction(false); - assertByBlockHash("0x1", chain.block, blockRef -> chain.web3.eth_getTransactionCount(chain.accountAddress, blockRef)); + assertByBlockHash("0x1", chain.block, blockRef -> chain.web3.eth_getTransactionCount(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test //[ "0x
", { "blockHash": "0x" } -> raise block-not-found error void getTransactionCountByNonExistentBlockHash() { final ChainParams chain = chainWithAccount10kBalance(false); - assertNonExistentBlockHash(blockRef -> chain.web3.eth_getTransactionCount(chain.accountAddress, blockRef)); + assertNonExistentBlockHash(blockRef -> chain.web3.eth_getTransactionCount(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test // [ "0x
", { "blockHash": "0x", "requireCanonical": true } -> raise block-not-canonical error void getTransactionCountByNonCanonicalBlockHashWhenCanonicalIsRequired() { final ChainParams chain = createChainWithATransaction(true); - assertNonCanonicalBlockHashWhenCanonical(chain.block, blockRef -> chain.web3.eth_getTransactionCount(chain.accountAddress, blockRef)); + assertNonCanonicalBlockHashWhenCanonical(chain.block, blockRef -> chain.web3.eth_getTransactionCount(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } @Test // [ "0x
", { "blockHash": "0x" } -> return tx count at given address in specified bloc void getTransactionCountByNonCanonicalBlockHash() { final ChainParams chain = createChainWithATransaction(true); - assertNonCanonicalBlockHash("0x1", chain.block, blockRef -> chain.web3.eth_getTransactionCount(chain.accountAddress, blockRef)); + assertNonCanonicalBlockHash("0x1", chain.block, blockRef -> chain.web3.eth_getTransactionCount(new HexAddressParam(chain.accountAddress), new BlockRefParam(blockRef))); } private BlockBuilder createBlockBuilder(World world) { @@ -1079,14 +1106,14 @@ void testBlockByNumber(RskSystemProperties config) { assertEquals(ImportResult.IMPORTED_NOT_BEST, world.getBlockChain().tryToConnect(block1b)); assertEquals(ImportResult.IMPORTED_BEST, world.getBlockChain().tryToConnect(block2b)); - BlockResultDTO bresult = web3.eth_getBlockByNumber("0x1", false); + BlockResultDTO bresult = web3.eth_getBlockByNumber(new BlockIdentifierParam("0x1"), false); assertNotNull(bresult); String blockHash = "0x" + block1b.getHash(); assertEquals(blockHash, bresult.getHash()); String bnOrId = "0x2"; - bresult = web3.eth_getBlockByNumber("0x2", true); + bresult = web3.eth_getBlockByNumber(new BlockIdentifierParam("0x2"), true); assertNotNull(bresult); blockHash = "0x" + block2b.getHash(); @@ -1152,7 +1179,7 @@ void getBlockByNumberRetrieveLatestBlock() { block1.setBitcoinMergedMiningHeader(new byte[]{0x01}); assertEquals(ImportResult.IMPORTED_BEST, world.getBlockChain().tryToConnect(block1)); - BlockResultDTO blockResult = web3.eth_getBlockByNumber("latest", false); + BlockResultDTO blockResult = web3.eth_getBlockByNumber(new BlockIdentifierParam("latest"), false); assertNotNull(blockResult); String blockHash = HexUtils.toJsonHex(block1.getHash().toString()); @@ -1172,7 +1199,7 @@ void getBlockByNumberRetrieveEarliestBlock() { assertEquals(ImportResult.IMPORTED_BEST, world.getBlockChain().tryToConnect(block1)); String bnOrId = "earliest"; - BlockResultDTO blockResult = web3.eth_getBlockByNumber(bnOrId, false); + BlockResultDTO blockResult = web3.eth_getBlockByNumber(new BlockIdentifierParam(bnOrId), false); assertNotNull(blockResult); @@ -1191,7 +1218,7 @@ void getBlockByNumberBlockDoesNotExists() { Web3Impl web3 = createWeb3(world); String bnOrId = "0x1234"; - BlockResultDTO blockResult = web3.eth_getBlockByNumber(bnOrId, false); + BlockResultDTO blockResult = web3.eth_getBlockByNumber(new BlockIdentifierParam(bnOrId), false); Assertions.assertNull(blockResult); @@ -1221,7 +1248,7 @@ void getBlockByNumberWhenNumberIsInvalidThrowsException() { String bnOrId = "991234"; - Assertions.assertThrows(org.ethereum.rpc.exception.RskJsonRpcRequestException.class, () -> web3.eth_getBlockByNumber(bnOrId, false)); + Assertions.assertThrows(org.ethereum.rpc.exception.RskJsonRpcRequestException.class, () -> web3.eth_getBlockByNumber(new BlockIdentifierParam(bnOrId), false)); } @Test @@ -1258,8 +1285,11 @@ void testGetBlockByHash(RskSystemProperties config) { String block1HashString = "0x" + block1.getHash(); String block1bHashString = "0x" + block1b.getHash(); String block2bHashString = "0x" + block2b.getHash(); + BlockHashParam blockHashParam1 = new BlockHashParam(block1HashString); + BlockHashParam blockHashParam1b = new BlockHashParam(block1bHashString); + BlockHashParam blockHashParam2 = new BlockHashParam(block2bHashString); - BlockResultDTO bresult = web3.eth_getBlockByHash(block1HashString, false); + BlockResultDTO bresult = web3.eth_getBlockByHash(blockHashParam1, false); assertNotNull(bresult); assertEquals(block1HashString, bresult.getHash()); @@ -1268,7 +1298,7 @@ void testGetBlockByHash(RskSystemProperties config) { assertEquals(0, bresult.getUncles().size()); assertEquals("0xa", bresult.getDifficulty()); assertEquals("0xb", bresult.getTotalDifficulty()); - bresult = web3.eth_getBlockByHash(block1bHashString, true); + bresult = web3.eth_getBlockByHash(blockHashParam1b, true); assertNotNull(bresult); assertEquals(block1bHashString, bresult.getHash()); @@ -1276,7 +1306,7 @@ void testGetBlockByHash(RskSystemProperties config) { String hexString = web3.rsk_getRawBlockHeaderByHash(block1bHashString).replace("0x", ""); assertArrayEquals(block1b.getHeader().getEncoded(), Hex.decode(hexString)); - bresult = web3.eth_getBlockByHash(block2bHashString, true); + bresult = web3.eth_getBlockByHash(blockHashParam2, true); assertNotNull(bresult); assertEquals(block2bHashString, bresult.getHash()); @@ -1316,8 +1346,8 @@ void getBlockByHashWithFullTransactionsAsResult() { assertEquals(ImportResult.IMPORTED_BEST, world.getBlockChain().tryToConnect(block1)); String block1HashString = block1.getHashJsonString(); - - BlockResultDTO bresult = web3.eth_getBlockByHash(block1HashString, true); + BlockHashParam blockHashParam = new BlockHashParam(block1HashString); + BlockResultDTO bresult = web3.eth_getBlockByHash(blockHashParam, true); assertNotNull(bresult); assertEquals(block1HashString, bresult.getHash()); @@ -1346,8 +1376,9 @@ void getBlockByHashWithTransactionsHashAsResult() { assertEquals(ImportResult.IMPORTED_BEST, world.getBlockChain().tryToConnect(block1)); String block1HashString = block1.getHashJsonString(); + BlockHashParam blockHashParam = new BlockHashParam(block1HashString); - BlockResultDTO bresult = web3.eth_getBlockByHash(block1HashString, false); + BlockResultDTO bresult = web3.eth_getBlockByHash(blockHashParam, false); assertNotNull(bresult); assertEquals(block1HashString, bresult.getHash()); @@ -1363,7 +1394,9 @@ void getBlockByHashBlockDoesNotExists() { Web3Impl web3 = createWeb3(world); String blockHash = "0x1234000000000000000000000000000000000000000000000000000000000000"; - BlockResultDTO blockResult = web3.eth_getBlockByHash(blockHash, false); + BlockHashParam blockHashParam = new BlockHashParam(blockHash); + + BlockResultDTO blockResult = web3.eth_getBlockByHash(blockHashParam, false); Assertions.assertNull(blockResult); @@ -1418,8 +1451,8 @@ void getBlockByHashBlockWithUncles() { String block1bHashString = "0x" + block1b.getHash(); String block1cHashString = "0x" + block1c.getHash(); String block2HashString = "0x" + block2.getHash(); - - BlockResultDTO result = web3.eth_getBlockByHash(block2HashString, false); + BlockHashParam block2HashStringParam = new BlockHashParam(block2HashString); + BlockResultDTO result = web3.eth_getBlockByHash(block2HashStringParam, false); assertEquals(block2HashString, result.getHash()); assertEquals(block1HashString, result.getParentHash()); @@ -1476,7 +1509,7 @@ void getBlockByNumberBlockWithUncles() { String block1cHashString = "0x" + block1c.getHash(); String block2HashString = "0x" + block2.getHash(); - BlockResultDTO result = web3.eth_getBlockByNumber("0x02", false); + BlockResultDTO result = web3.eth_getBlockByNumber(new BlockIdentifierParam("0x02"), false); assertEquals(block2HashString, result.getHash()); assertEquals(block1HashString, result.getParentHash()); @@ -1541,8 +1574,10 @@ void getUncleByBlockHashAndIndexBlockWithUncles() { String blockEhash = "0x" + blockE.getHash(); String blockBhash = "0x" + blockB.getHash(); String blockChash = "0x" + blockC.getHash(); + BlockHashParam blockFhashParam = new BlockHashParam(blockFhash); + HexIndexParam hexIndexParam = new HexIndexParam("0x00"); - BlockResultDTO result = web3.eth_getUncleByBlockHashAndIndex(blockFhash, "0x00"); + BlockResultDTO result = web3.eth_getUncleByBlockHashAndIndex(blockFhashParam, hexIndexParam); assertEquals(blockEhash, result.getHash()); assertEquals(2, result.getUncles().size()); @@ -1606,8 +1641,10 @@ void getUncleByBlockHashAndIndexBlockWithUnclesCorrespondingToAnUnknownBlock() { String blockFhash = "0x" + blockF.getHash(); String blockEhash = "0x" + blockE.getHash(); + BlockHashParam blockFhashParam = new BlockHashParam(blockFhash); + HexIndexParam hexIndexParam = new HexIndexParam("0x00"); - BlockResultDTO result = web3.eth_getUncleByBlockHashAndIndex(blockFhash, "0x00"); + BlockResultDTO result = web3.eth_getUncleByBlockHashAndIndex(blockFhashParam, hexIndexParam); assertEquals(blockEhash, result.getHash()); assertEquals(0, result.getUncles().size()); @@ -1671,7 +1708,7 @@ void getUncleByBlockNumberAndIndexBlockWithUncles() { String blockBhash = "0x" + blockB.getHash(); String blockChash = "0x" + blockC.getHash(); - BlockResultDTO result = web3.eth_getUncleByBlockNumberAndIndex("0x03", "0x00"); + BlockResultDTO result = web3.eth_getUncleByBlockNumberAndIndex(new BlockIdentifierParam("0x03"), new HexIndexParam("0x00")); assertEquals(blockEhash, result.getHash()); assertEquals(2, result.getUncles().size()); @@ -1735,7 +1772,7 @@ void getUncleByBlockNumberAndIndexBlockWithUnclesCorrespondingToAnUnknownBlock() String blockEhash = "0x" + blockE.getHash(); - BlockResultDTO result = web3.eth_getUncleByBlockNumberAndIndex("0x" + blockF.getNumber(), "0x00"); + BlockResultDTO result = web3.eth_getUncleByBlockNumberAndIndex(new BlockIdentifierParam("0x" + blockF.getNumber()), new HexIndexParam("0x00")); assertEquals(blockEhash, result.getHash()); assertEquals(0, result.getUncles().size()); @@ -1762,7 +1799,7 @@ void getCode() { String accountAddress = ByteUtil.toHexString(acc1.getAddress().getBytes()); - String scode = web3.eth_getCode(accountAddress, "0x1"); + String scode = web3.eth_getCode(new HexAddressParam(accountAddress), new BlockRefParam("0x1")); assertNotNull(scode); assertEquals("0x" + ByteUtil.toHexString(code), scode); @@ -1807,7 +1844,7 @@ function greet(string memory param) public pure returns (string memory) { argsForCall.setTo(HexUtils.toJsonHex(tx.getContractAddress().getBytes())); argsForCall.setData("0xead710c40000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000"); - String result = web3.eth_call(argsForCall, "latest"); + String result = web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(argsForCall), new BlockIdentifierParam("latest")); assertEquals("0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000", result); } @@ -1854,7 +1891,7 @@ function greet(string memory param) public pure returns (string memory) { argsForCall.setTo(HexUtils.toJsonHex(tx.getContractAddress().getBytes())); argsForCall.setData("0xead710c40000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000"); - String result = web3.eth_call(argsForCall, "latest"); + String result = web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(argsForCall), new BlockIdentifierParam("latest")); assertEquals("0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000", result); } @@ -1887,7 +1924,7 @@ void callNoneContractReturn() { argsForCall.setTo(HexUtils.toUnformattedJsonHex(tx.getContractAddress().getBytes())); argsForCall.setData(HexUtils.toUnformattedJsonHex(func.encode())); - String result = web3.eth_call(argsForCall, "latest"); + String result = web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(argsForCall), new BlockIdentifierParam("latest")); assertEquals("0x", result); } @@ -1904,7 +1941,7 @@ void getCodeBlockDoesNotExist() { String accountAddress = ByteUtil.toHexString(acc1.getAddress().getBytes()); - String resultCode = web3.eth_getCode(accountAddress, "0x100"); + String resultCode = web3.eth_getCode(new HexAddressParam(accountAddress), new BlockRefParam("0x100")); assertNull(resultCode); } @@ -1991,7 +2028,7 @@ void eth_sign() { byte[] hash = Keccak256Helper.keccak256("this is the data to hash".getBytes()); - String signature = web3.eth_sign(addr1, "0x" + ByteUtil.toHexString(hash)); + String signature = web3.eth_sign(new HexAddressParam(addr1), new HexDataParam("0x" + ByteUtil.toHexString(hash))); MatcherAssert.assertThat( signature, @@ -2017,7 +2054,7 @@ void eth_sign_testSignatureGenerationToBeAlways32BytesLength() { byte[] hash = Keccak256Helper.keccak256("this is the data to hash".getBytes()); - String signature = web3.eth_sign(addr1, "0x" + ByteUtil.toHexString(hash)); + String signature = web3.eth_sign(new HexAddressParam(addr1), new HexDataParam("0x" + ByteUtil.toHexString(hash))); MatcherAssert.assertThat( signature, @@ -2077,7 +2114,9 @@ void importAccountUsingRawKey() { assertNull(account); - String address = web3.personal_importRawKey(ByteUtil.toHexString(privKeyBytes), "passphrase1"); + HexKeyParam hexKeyParam = new HexKeyParam(ByteUtil.toHexString(privKeyBytes)); + + String address = web3.personal_importRawKey(hexKeyParam, "passphrase1"); assertNotNull(address); @@ -2104,7 +2143,9 @@ void importAccountUsingRawKeyContaining0xPrefix() { assertNull(account); - String address = web3.personal_importRawKey(String.format("0x%s", ByteUtil.toHexString(privKeyBytes)), "passphrase1"); + HexKeyParam hexKeyParam = new HexKeyParam(String.format("0x%s", ByteUtil.toHexString(privKeyBytes))); + + String address = web3.personal_importRawKey(hexKeyParam, "passphrase1"); assertNotNull(address); @@ -2121,10 +2162,14 @@ void dumpRawKey() throws Exception { ECKey eckey = new ECKey(); - String address = web3.personal_importRawKey(ByteUtil.toHexString(eckey.getPrivKeyBytes()), "passphrase1"); - assertTrue(web3.personal_unlockAccount(address, "passphrase1", "")); + HexKeyParam hexKeyParam = new HexKeyParam(ByteUtil.toHexString(eckey.getPrivKeyBytes())); + + String address = web3.personal_importRawKey(hexKeyParam, "passphrase1"); + HexAddressParam hexAddressParam = new HexAddressParam(address); - String rawKey = web3.personal_dumpRawKey(address).substring(2); + assertTrue(web3.personal_unlockAccount(hexAddressParam, "passphrase1", new HexDurationParam(""))); + + String rawKey = web3.personal_dumpRawKey(hexAddressParam).substring(2); assertArrayEquals(eckey.getPrivKeyBytes(), Hex.decode(rawKey)); } @@ -2135,10 +2180,14 @@ void dumpRawKeyContaining0xPrefix() throws Exception { ECKey eckey = new ECKey(); - String address = web3.personal_importRawKey(String.format("0x%s", ByteUtil.toHexString(eckey.getPrivKeyBytes())), "passphrase1"); - assertTrue(web3.personal_unlockAccount(address, "passphrase1", "")); + HexKeyParam hexKeyParam = new HexKeyParam(String.format("0x%s", ByteUtil.toHexString(eckey.getPrivKeyBytes()))); + + String address = web3.personal_importRawKey(hexKeyParam, "passphrase1"); + HexAddressParam hexAddressParam = new HexAddressParam(address); + + assertTrue(web3.personal_unlockAccount(hexAddressParam, "passphrase1", new HexDurationParam(""))); - String rawKey = web3.personal_dumpRawKey(address).substring(2); + String rawKey = web3.personal_dumpRawKey(hexAddressParam).substring(2); assertArrayEquals(eckey.getPrivKeyBytes(), Hex.decode(rawKey)); } @@ -2170,6 +2219,8 @@ void sendPersonalTransaction() throws Exception { args.setNonce(nonce.toString()); args.setChainId(HexUtils.toJsonHex(new byte[]{chainId})); + CallArgumentsParam argsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + // ***** Verifies tx hash Transaction expectedTx = Transaction .builder() @@ -2189,7 +2240,7 @@ void sendPersonalTransaction() throws Exception { when(ethereumMock.submitTransaction(expectedTx)).thenReturn(pendingTransactionResult); // ***** Executes the transaction ******************* - String txHash = web3.personal_sendTransaction(args, "passphrase1"); + String txHash = web3.personal_sendTransaction(argsParam, "passphrase1"); // ***** Checking expected result ******************* @@ -2220,6 +2271,8 @@ void sendPersonalTransactionFailsIfTransactionIsNotQueued() { args.setValue(value.toString()); args.setNonce(nonce.toString()); + CallArgumentsParam argsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + Transaction expectedTx = Transaction .builder() .destination(toAddress.substring(2)) @@ -2238,7 +2291,7 @@ void sendPersonalTransactionFailsIfTransactionIsNotQueued() { // ***** Executes the transaction ******************* RskJsonRpcRequestException thrownEx = Assertions.assertThrows(RskJsonRpcRequestException.class, () -> { - web3.personal_sendTransaction(args, "passphrase1"); + web3.personal_sendTransaction(argsParam, "passphrase1"); }); assertEquals(-32010, thrownEx.getCode(), "Unexpected exception code"); @@ -2252,9 +2305,11 @@ void unlockAccount() { String addr = web3.personal_newAccount("passphrase1"); - web3.personal_lockAccount(addr); + HexAddressParam hexAddressParam = new HexAddressParam(addr); + + web3.personal_lockAccount(hexAddressParam); - assertTrue(web3.personal_unlockAccount(addr, "passphrase1", "")); + assertTrue(web3.personal_unlockAccount(hexAddressParam, "passphrase1", new HexDurationParam(""))); Account account = wallet.getAccount(new RskAddress(addr)); @@ -2267,10 +2322,12 @@ void unlockAccountInvalidDuration() { String addr = web3.personal_newAccount("passphrase1"); - web3.personal_lockAccount(addr); + HexAddressParam hexAddressParam = new HexAddressParam(addr); + + web3.personal_lockAccount(hexAddressParam); RskJsonRpcRequestException e = TestUtils.assertThrows(RskJsonRpcRequestException.class, - () -> web3.personal_unlockAccount(addr, "passphrase1", "K")); + () -> web3.personal_unlockAccount(hexAddressParam, "passphrase1", new HexDurationParam("K"))); assertEquals(-32602, (int) e.getCode()); } @@ -2284,7 +2341,9 @@ void lockAccount() { assertNotNull(account); - assertTrue(web3.personal_lockAccount(addr)); + HexAddressParam hexAddressParam = new HexAddressParam(addr); + + assertTrue(web3.personal_lockAccount(hexAddressParam)); Account account1 = wallet.getAccount(new RskAddress(addr)); @@ -2327,18 +2386,18 @@ void createNewAccountWithoutDuplicates() { } @Test - void estimateGasWithNoBlock(){ - CallArguments args = Mockito.mock(CallArguments.class); + void estimateGasWithNoBlock() { + CallArgumentsParam args = Mockito.mock(CallArgumentsParam.class); Web3TestBuilder builder = new Web3TestBuilder(); Web3Impl web3 = builder.build(); EthModule ethModule = builder.getEthModule(); String estimatedCost = "0x5c"; - ArgumentCaptor blockCaptor = ArgumentCaptor.forClass(String.class); + ArgumentCaptor blockCaptor = ArgumentCaptor.forClass(BlockIdentifierParam.class); when(ethModule.estimateGas(eq(args),blockCaptor.capture())).thenReturn(estimatedCost); String result = web3.eth_estimateGas(args); - String capturedBlock = blockCaptor.getValue(); - assertEquals(BlockTag.LATEST.getTag(),capturedBlock); + BlockIdentifierParam capturedBlock = blockCaptor.getValue(); + assertEquals(BlockTag.LATEST.getTag(), capturedBlock.getIdentifier()); assertEquals(estimatedCost,result); } @@ -2376,8 +2435,9 @@ private void checkSendTransaction(Byte chainId) { if (chainId != null) { args.setChainId(HexUtils.toJsonHex(new byte[]{chainId})); } + CallArgumentsParam argsParam = TransactionFactoryHelper.toCallArgumentsParam(args); - String txHash = web3.eth_sendTransaction(args); + String txHash = web3.eth_sendTransaction(argsParam); // ***** Verifies tx hash String to = toAddress.substring(2); @@ -2387,7 +2447,7 @@ private void checkSendTransaction(Byte chainId) { .gasPrice(gasPrice) .gasLimit(gasLimit) .destination(Hex.decode(to)) - .data(args.getData() == null ? null : Hex.decode(args.getData())) + .data(args.getData() == null ? null : Hex.decode(args.getData().substring(2))) .chainId(config.getNetworkConstants().getChainId()) .value(value) .build(); @@ -2415,7 +2475,7 @@ void getNoCode() throws Exception { String accountAddress = Hex.toHexString(acc1.getAddress().getBytes()); - String scode = web3.eth_getCode(accountAddress, "0x1"); + String scode = web3.eth_getCode(new HexAddressParam(accountAddress), new BlockRefParam("0x1")); assertNotNull(scode); Assertions.assertEquals("0x", scode); @@ -2446,7 +2506,7 @@ void callWithoutReturn() { argsForCall.setTo(HexUtils.toJsonHex(tx.getContractAddress().getBytes())); argsForCall.setData(HexUtils.toJsonHex(noreturn.functions.get("noreturn").encodeSignature())); - String result = web3.eth_call(argsForCall, "latest"); + String result = web3.eth_call(TransactionFactoryHelper.toCallArgumentsParam(argsForCall), new BlockIdentifierParam("latest")); Assertions.assertEquals("0x", result); } @@ -2462,9 +2522,11 @@ void whenEthGetFilterChanges_throwFilterNotFoundException() { Web3RskImpl web3 = (Web3RskImpl) createWeb3(); + HexIndexParam hexIndexParam = new HexIndexParam("0x01"); + RskJsonRpcRequestException exception = Assertions.assertThrowsExactly( expectedException.getClass(), - () -> web3.eth_getFilterChanges("0x01"), + () -> web3.eth_getFilterChanges(hexIndexParam), "filter not found" ); @@ -2482,9 +2544,11 @@ void whenEthGetFilterLogs_throwFilterNotFoundException() { Web3RskImpl web3 = (Web3RskImpl) createWeb3(); + HexIndexParam hexIndexParam = new HexIndexParam("0x01"); + RskJsonRpcRequestException exception = Assertions.assertThrowsExactly( expectedException.getClass(), - () -> web3.eth_getFilterLogs("0x01"), + () -> web3.eth_getFilterLogs(hexIndexParam), "filter not found" ); @@ -2764,7 +2828,6 @@ private Web3Impl createWeb3CallNoReturn( signatureCache); } - private TransactionExecutorFactory buildTransactionExecutorFactory( BlockStore blockStore, BlockTxSignatureCache blockTxSignatureCache) { return new TransactionExecutorFactory( @@ -3079,9 +3142,9 @@ void transactionReceiptAndResultHasTypeField() { Block block1 = createCanonicalBlock(world, txs); String hashString = tx.getHash().toHexString(); - - TransactionReceiptDTO txReceipt = web3.eth_getTransactionReceipt(hashString); - TransactionResultDTO txResult = web3.eth_getTransactionByHash(hashString); + TxHashParam txHashParam = new TxHashParam(hashString); + TransactionReceiptDTO txReceipt = web3.eth_getTransactionReceipt(new TxHashParam(hashString)); + TransactionResultDTO txResult = web3.eth_getTransactionByHash(txHashParam); assertEquals("0x0", txReceipt.getType()); assertEquals("0x0", txResult.getType()); diff --git a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplUnitTest.java b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplUnitTest.java index 752d0d05d5f..6dfe17b61fd 100644 --- a/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplUnitTest.java +++ b/rskj-core/src/test/java/org/ethereum/rpc/Web3ImplUnitTest.java @@ -25,7 +25,13 @@ import org.ethereum.net.server.ChannelManager; import org.ethereum.net.server.PeerServer; import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.BlockHashParam; +import org.ethereum.rpc.parameters.BlockIdentifierParam; +import org.ethereum.rpc.parameters.BlockRefParam; +import org.ethereum.rpc.parameters.HexAddressParam; +import org.ethereum.rpc.parameters.HexNumberParam; import org.ethereum.util.BuildInfo; +import org.ethereum.util.TransactionFactoryHelper; import org.ethereum.vm.DataWord; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -101,12 +107,12 @@ void eth_getBalance_stateCannotBeRetrieved() { when(retriever.getInformationProvider(id)) .thenThrow(RskJsonRpcRequestException.blockNotFound("Block not found")); TestUtils.assertThrows(RskJsonRpcRequestException.class, - () -> target.eth_getBalance(addr, id)); + () -> target.eth_getBalance(new HexAddressParam(addr), new BlockRefParam(id))); } @Test void eth_getBalance() { - String id = "id"; + String id = "0x00"; String addr = "0x0011223344556677880011223344556677889900"; RskAddress expectedAddress = new RskAddress(addr); @@ -115,7 +121,7 @@ void eth_getBalance() { when(aip.getBalance(expectedAddress)) .thenReturn(new Coin(BigInteger.ONE)); - String result = target.eth_getBalance(addr, id); + String result = target.eth_getBalance(new HexAddressParam(addr),new BlockRefParam(id)); assertEquals("0x1", result); } @@ -125,43 +131,51 @@ void eth_getBalanceByBlockRef() { String addr = "0x0011223344556677880011223344556677889900"; Map blockRef = new HashMap() { { - put("blockHash", "0x0011223344556677880011223344556677889900"); + put("blockHash", "0xc2b835124172db5bd051bb94fa123721eacac43b5cba2499b22c7583a35689b8"); } }; final Web3Impl spyTarget = spy(target); doReturn("0x1").when(spyTarget).invokeByBlockRef(eq(blockRef),any()); - String result = spyTarget.eth_getBalance(addr, blockRef); + String result = spyTarget.eth_getBalance(new HexAddressParam(addr), new BlockRefParam(blockRef)); assertEquals("0x1", result); verify(spyTarget).invokeByBlockRef(eq(blockRef),any()); } @Test void eth_getStorageAt_stateCannotBeRetrieved() { - String id = "id"; + String id = "0x00"; String addr = "0x0011223344556677880011223344556677889900"; String storageIdx = "0x01"; + HexAddressParam hexAddressParam = new HexAddressParam(addr); + HexNumberParam hexNumberParam = new HexNumberParam(storageIdx); + BlockRefParam blockRefParam = new BlockRefParam(id); + when(retriever.getInformationProvider(id)) .thenThrow(RskJsonRpcRequestException.blockNotFound("Block not found")); TestUtils.assertThrows(RskJsonRpcRequestException.class, - () -> target.eth_getStorageAt(addr, storageIdx, id)); + () -> target.eth_getStorageAt(hexAddressParam, hexNumberParam, blockRefParam)); } @Test void eth_getStorageAt() { - String id = "id"; + String id = "0x00"; String addr = "0x0011223344556677880011223344556677889900"; RskAddress expectedAddress = new RskAddress(addr); String storageIdx = "0x01"; DataWord expectedIdx = DataWord.valueOf(HexUtils.stringHexToByteArray(storageIdx)); + HexAddressParam hexAddressParam = new HexAddressParam(addr); + HexNumberParam hexNumberParam = new HexNumberParam(storageIdx); + BlockRefParam blockRefParam = new BlockRefParam(id); + AccountInformationProvider aip = mock(AccountInformationProvider.class); when(retriever.getInformationProvider(id)).thenReturn(aip); when(aip.getStorageValue(expectedAddress, expectedIdx)) .thenReturn(DataWord.ONE); - String result = target.eth_getStorageAt(addr, storageIdx, id); + String result = target.eth_getStorageAt(hexAddressParam, hexNumberParam, blockRefParam); assertEquals("0x0000000000000000000000000000000000000000000000000000000000000001", result); } @@ -173,13 +187,18 @@ void eth_getStorageAtByBlockRef() { final String storageIdx = "0x01"; Map blockRef = new HashMap() { { - put("blockHash", "0x0011223344556677880011223344556677889900"); + put("blockHash", "0xc2b835124172db5bd051bb94fa123721eacac43b5cba2499b22c7583a35689b8"); } }; final Web3Impl spyTarget = spy(target); final String expectedData = "0x0000000000000000000000000000000000000000000000000000000000000001"; + + HexAddressParam hexAddressParam = new HexAddressParam(addr); + HexNumberParam hexNumberParam = new HexNumberParam(storageIdx); + BlockRefParam blockRefParam = new BlockRefParam(blockRef); + doReturn(expectedData).when(spyTarget).invokeByBlockRef(eq(blockRef),any()); - String result = spyTarget.eth_getStorageAt(addr, storageIdx, blockRef); + String result = spyTarget.eth_getStorageAt(hexAddressParam, hexNumberParam, blockRefParam); assertEquals(expectedData, result); verify(spyTarget).invokeByBlockRef(eq(blockRef),any()); } @@ -187,42 +206,46 @@ void eth_getStorageAtByBlockRef() { @Test void eth_getStorageAtEmptyCell() { - String id = "id"; + String id = "0x00"; String addr = "0x0011223344556677880011223344556677889900"; RskAddress expectedAddress = new RskAddress(addr); String storageIdx = "0x01"; DataWord expectedIdx = DataWord.valueOf(HexUtils.stringHexToByteArray(storageIdx)); + HexAddressParam hexAddressParam = new HexAddressParam(addr); + HexNumberParam hexNumberParam = new HexNumberParam(storageIdx); + BlockRefParam blockRefParam = new BlockRefParam(id); + AccountInformationProvider aip = mock(AccountInformationProvider.class); when(retriever.getInformationProvider(id)).thenReturn(aip); when(aip.getStorageValue(expectedAddress, expectedIdx)) .thenReturn(null); - String result = target.eth_getStorageAt(addr, storageIdx, id); + String result = target.eth_getStorageAt(hexAddressParam, hexNumberParam, blockRefParam); assertEquals("0x0", result); } @Test void eth_getBlockTransactionCountByNumber_blockNotFound() { - String id = "id"; + String id = "0x00"; when(retriever.getTransactions(id)).thenThrow(RskJsonRpcRequestException.blockNotFound("Block not found")); TestUtils.assertThrows(RskJsonRpcRequestException.class, - () -> target.eth_getBlockTransactionCountByNumber(id)); + () -> target.eth_getBlockTransactionCountByNumber(new BlockIdentifierParam(id))); } @Test void eth_getBlockTransactionCountByNumber() { - String id = "id"; + String id = "0x00"; List txs = new LinkedList<>(); txs.add(mock(Transaction.class)); txs.add(mock(Transaction.class)); when(retriever.getTransactions(id)).thenReturn(txs); - String result = target.eth_getBlockTransactionCountByNumber(id); + String result = target.eth_getBlockTransactionCountByNumber(new BlockIdentifierParam(id)); assertEquals("0x2", result); } @@ -233,13 +256,13 @@ void eth_getCode() { final String addr = "0x0011223344556677880011223344556677889900"; Map blockRef = new HashMap() { { - put("blockHash", "0x0011223344556677880011223344556677889900"); + put("blockHash", "0xc2b835124172db5bd051bb94fa123721eacac43b5cba2499b22c7583a35689b8"); } }; final Web3Impl spyTarget = spy(target); final String expectedData = "0x010203"; doReturn(expectedData).when(spyTarget).invokeByBlockRef(eq(blockRef),any()); - String result = spyTarget.eth_getCode(addr,blockRef); + String result = spyTarget.eth_getCode(new HexAddressParam(addr), new BlockRefParam(blockRef)); assertEquals(expectedData, result); verify(spyTarget).invokeByBlockRef(eq(blockRef),any()); } @@ -253,14 +276,14 @@ void eth_callAtByBlockRef() { argsForCall.setData("ead710c40000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000"); Map blockRef = new HashMap() { { - put("blockHash", "0x0011223344556677880011223344556677889900"); + put("blockHash", "0xc2b835124172db5bd051bb94fa123721eacac43b5cba2499b22c7583a35689b8"); } }; final Web3Impl spyTarget = spy(target); final String expectedData = "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000568656c6c6f000000000000000000000000000000000000000000000000000000"; doReturn(expectedData).when(spyTarget).invokeByBlockRef(eq(blockRef),any()); - String result = spyTarget.eth_call(argsForCall,blockRef); + String result = spyTarget.eth_call(TransactionFactoryHelper.toCallArgumentsParam(argsForCall),blockRef); assertEquals(expectedData, result); verify(spyTarget).invokeByBlockRef(eq(blockRef),any()); } @@ -271,12 +294,12 @@ void eth_getBlockTransactionCountByBlockRef() { String addr = "0x0011223344556677880011223344556677889900"; Map blockRef = new HashMap() { { - put("blockHash", "0x0011223344556677880011223344556677889900"); + put("blockHash", "0xc2b835124172db5bd051bb94fa123721eacac43b5cba2499b22c7583a35689b8"); } }; final Web3Impl spyTarget = spy(target); doReturn("0x1").when(spyTarget).invokeByBlockRef(eq(blockRef),any()); - String result = spyTarget.eth_getTransactionCount(addr, blockRef); + String result = spyTarget.eth_getTransactionCount(new HexAddressParam(addr), new BlockRefParam(blockRef)); assertEquals("0x1", result); verify(spyTarget).invokeByBlockRef(eq(blockRef),any()); } @@ -289,7 +312,7 @@ void eth_getUncleCountByBlockHash_blockNotFound() { when(blockchain.getBlockByHash(bytesHash)).thenReturn(null); RskJsonRpcRequestException exception = TestUtils - .assertThrows(RskJsonRpcRequestException.class, () -> target.eth_getUncleCountByBlockHash(hash)); + .assertThrows(RskJsonRpcRequestException.class, () -> target.eth_getUncleCountByBlockHash(new BlockHashParam(hash))); assertEquals(-32602, (int) exception.getCode()); } @@ -308,22 +331,22 @@ void eth_getUncleCountByBlockHash() { when(block.getUncleList()).thenReturn(uncles); when(blockchain.getBlockByHash(bytesHash)).thenReturn(block); - String result = target.eth_getUncleCountByBlockHash(hash); + String result = target.eth_getUncleCountByBlockHash(new BlockHashParam(hash)); assertEquals("0x2", result); } @Test void eth_getUncleCountByBlockNumber_notFound() { - String identifier = "notFoundable"; + String identifier = "0x00"; when(retriever.getBlock(identifier)).thenReturn(Optional.empty()); TestUtils.assertThrows(RskJsonRpcRequestException.class, - () -> target.eth_getUncleCountByBlockNumber(identifier)); + () -> target.eth_getUncleCountByBlockNumber(new BlockIdentifierParam(identifier))); } @Test void eth_getUncleCountByBlockNumber() { - String identifier = "notFoundable"; + String identifier = "0x00"; Block block = mock(Block.class); List uncles = new LinkedList<>(); uncles.add(mock(BlockHeader.class)); @@ -332,7 +355,7 @@ void eth_getUncleCountByBlockNumber() { when(block.getUncleList()).thenReturn(uncles); when(retriever.getBlock(identifier)).thenReturn(Optional.of(block)); - String result = target.eth_getUncleCountByBlockNumber(identifier); + String result = target.eth_getUncleCountByBlockNumber(new BlockIdentifierParam(identifier)); assertEquals("0x2", result); } diff --git a/rskj-core/src/test/java/org/ethereum/rpc/parameters/BlockIdentifierParamTest.java b/rskj-core/src/test/java/org/ethereum/rpc/parameters/BlockIdentifierParamTest.java new file mode 100644 index 00000000000..c733f465c8f --- /dev/null +++ b/rskj-core/src/test/java/org/ethereum/rpc/parameters/BlockIdentifierParamTest.java @@ -0,0 +1,65 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import org.ethereum.core.genesis.BlockTag; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class BlockIdentifierParamTest { + @Test + public void testValidStringBlockIdentifier() { + String validBlockIdentifier = BlockTag.LATEST.getTag(); + + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam(validBlockIdentifier); + + assertEquals(validBlockIdentifier, blockIdentifierParam.getIdentifier()); + } + + @Test + public void testValidHexBlockIdentifier() { + String validBlockIdentifier = "0xf892038609184e"; + + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam(validBlockIdentifier); + + assertEquals(validBlockIdentifier, blockIdentifierParam.getIdentifier()); + } + + @Test + public void testValidDecimalBlockIdentifier() { + String validBlockIdentifier = "1028"; + + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam(validBlockIdentifier); + + assertEquals(validBlockIdentifier, blockIdentifierParam.getIdentifier()); + } + + @Test + public void testInvalidHexAddressParam() { + String invalidStringIdentifier = "first"; + String invalidHexIdentifier = "0xf89203860918sv"; + + assertThrows(RskJsonRpcRequestException.class, () -> new BlockIdentifierParam(invalidStringIdentifier)); + assertThrows(RskJsonRpcRequestException.class, () -> new BlockIdentifierParam(invalidHexIdentifier)); + assertThrows(RskJsonRpcRequestException.class, () -> new BlockIdentifierParam(null)); + assertThrows(RskJsonRpcRequestException.class, () -> new BlockIdentifierParam("")); + } +} diff --git a/rskj-core/src/test/java/org/ethereum/rpc/parameters/BlockRefParamTest.java b/rskj-core/src/test/java/org/ethereum/rpc/parameters/BlockRefParamTest.java new file mode 100644 index 00000000000..65a055668ed --- /dev/null +++ b/rskj-core/src/test/java/org/ethereum/rpc/parameters/BlockRefParamTest.java @@ -0,0 +1,115 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class BlockRefParamTest { + @Test + public void testValidIdentifier() { + String identifier = "latest"; + + BlockRefParam blockRefParam = new BlockRefParam(identifier); + + assertEquals(identifier, blockRefParam.getIdentifier()); + assertNull(blockRefParam.getInputs()); + } + + @Test + public void testValidInputs() { + Map inputs = new HashMap() { + { + put("blockHash", "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"); + } + }; + + BlockRefParam blockRefParam = new BlockRefParam(inputs); + + assertEquals(inputs, blockRefParam.getInputs()); + assertNull(blockRefParam.getIdentifier()); + } + + @Test + public void testInvalidIdentifierString() { + String invalidStringIdentifier = "first"; + + assertThrows(RskJsonRpcRequestException.class, () -> new BlockRefParam(invalidStringIdentifier)); + } + + @Test + public void testInvalidIdentifierHexString() { + String invalidStringIdentifier = "0x1aw"; + + assertThrows(RskJsonRpcRequestException.class, () -> new BlockRefParam(invalidStringIdentifier)); + } + + @Test + public void testInvalidInputsInvalidKey() { + Map inputs = new HashMap() { + { + put("invalidKey", "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"); + } + }; + + assertThrows(RskJsonRpcRequestException.class, () -> new BlockRefParam(inputs)); + } + + @Test + public void testInvalidInputsInvalidBlockHash() { + Map inputs = new HashMap() { + { + put("blockHash", "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fxk"); + put("requireCanonical", "false"); + } + }; + + assertThrows(RskJsonRpcRequestException.class, () -> new BlockRefParam(inputs)); + } + + @Test + public void testInvalidInputsInvalidBlockNumber() { + Map inputs = new HashMap() { + { + put("blockNumber", "0x76ty"); + put("requireCanonical", "false"); + } + }; + + assertThrows(RskJsonRpcRequestException.class, () -> new BlockRefParam(inputs)); + } + + @Test + public void testInvalidInputsInvalidRequireCanonical() { + Map inputs = new HashMap() { + { + put("blockNumber", "0x76c0"); + put("requireCanonical", "first"); + } + }; + + assertThrows(RskJsonRpcRequestException.class, () -> new BlockRefParam(inputs)); + } +} diff --git a/rskj-core/src/test/java/org/ethereum/rpc/parameters/CallArgumentsParamTest.java b/rskj-core/src/test/java/org/ethereum/rpc/parameters/CallArgumentsParamTest.java new file mode 100644 index 00000000000..599272d26aa --- /dev/null +++ b/rskj-core/src/test/java/org/ethereum/rpc/parameters/CallArgumentsParamTest.java @@ -0,0 +1,175 @@ +package org.ethereum.rpc.parameters; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.ethereum.rpc.CallArguments; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class CallArgumentsParamTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + private final String FROM = "0x7986b3df570230288501eea3d890bd66948c9b79"; + private final String TO = "0xe7b8e91401bf4d1669f54dc5f98109d7efbc4eea"; + private final String GAS = "0x76c0"; + private final String GAS_PRICE = "0x9184e72a000"; + private final String VALUE = "0x9184e72a"; + private final String DATA = "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"; + private final String NONCE = "0x1"; + private final String CHAIN_ID = "0x539"; + + @Test + public void testValidCallArgumentsParam() throws JsonProcessingException { + String callArgumentsInput = "{\n" + + " \"from\": \"" + FROM + "\"," + + " \"to\" : \"" + TO + "\"," + + " \"gas\": \"" + GAS + "\"," + + " \"gasPrice\":\"" + GAS_PRICE + "\"," + + " \"value\":\"" + VALUE + "\"," + + " \"data\": \"" + DATA + "\", " + + " \"nonce\": \"" + NONCE + "\", " + + " \"chainId\": \"" + CHAIN_ID + "\"}"; + + JsonNode jsonNode = objectMapper.readTree(callArgumentsInput); + CallArgumentsParam callArgumentsParam = objectMapper.convertValue(jsonNode, CallArgumentsParam.class); + + assertNotNull(callArgumentsParam); + + assertEquals(FROM, callArgumentsParam.getFrom().getAddress().toJsonString()); + assertEquals(TO, callArgumentsParam.getTo().getAddress().toJsonString()); + assertEquals(GAS, callArgumentsParam.getGas().getHexNumber()); + assertEquals(GAS_PRICE, callArgumentsParam.getGasPrice().getHexNumber()); + assertEquals(VALUE, callArgumentsParam.getValue().getHexNumber()); + assertEquals(DATA, callArgumentsParam.getData().getAsHexString()); + assertEquals(NONCE, callArgumentsParam.getNonce().getHexNumber()); + assertEquals(CHAIN_ID, callArgumentsParam.getChainId().getHexNumber()); + } + + @Test + public void testInvalidFromInCallArgumentsParam() throws JsonProcessingException { + String from = "0x7986b3df570230288501eea3d890bd66948c9b7s"; + + String callArgumentsInput = "{\n" + + " \"from\": \"" + from + "\"}"; + + JsonNode jsonNode = objectMapper.readTree(callArgumentsInput); + + assertThrows(RskJsonRpcRequestException.class, () -> objectMapper.convertValue(jsonNode, CallArgumentsParam.class)); + } + + @Test + public void testInvalidToInCallArgumentsParam() throws JsonProcessingException { + String to = "0xe7b8e91401bf4d1669f54dc5f98109d7efbc4esw"; + + String callArgumentsInput = "{\n" + + " \"to\": \"" + to + "\"}"; + + JsonNode jsonNode = objectMapper.readTree(callArgumentsInput); + + assertThrows(RskJsonRpcRequestException.class, () -> objectMapper.convertValue(jsonNode, CallArgumentsParam.class)); + } + + @Test + public void testInvalidGasInCallArgumentsParam() throws JsonProcessingException { + String gas = "0x76cz"; + + String callArgumentsInput = "{\n" + + " \"gas\": \"" + gas + "\"}"; + + JsonNode jsonNode = objectMapper.readTree(callArgumentsInput); + + assertThrows(RskJsonRpcRequestException.class, () -> objectMapper.convertValue(jsonNode, CallArgumentsParam.class)); + } + + @Test + public void testInvalidGasPriceInCallArgumentsParam() throws JsonProcessingException { + String gasPrice = "0x9184e72a0zq"; + + String callArgumentsInput = "{\n" + + " \"gasPrice\": \"" + gasPrice + "\"}"; + + JsonNode jsonNode = objectMapper.readTree(callArgumentsInput); + + assertThrows(RskJsonRpcRequestException.class, () -> objectMapper.convertValue(jsonNode, CallArgumentsParam.class)); + } + + @Test + public void testInvalidValueInCallArgumentsParam() throws JsonProcessingException { + String value = "0x9184e7tq"; + + String callArgumentsInput = "{\n" + + " \"value\": \"" + value + "\"}"; + + JsonNode jsonNode = objectMapper.readTree(callArgumentsInput); + + assertThrows(RskJsonRpcRequestException.class, () -> objectMapper.convertValue(jsonNode, CallArgumentsParam.class)); + } + + @Test + public void testInvalidDataInCallArgumentsParam() throws JsonProcessingException { + String data = "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f0724456pl"; + + String callArgumentsInput = "{\n" + + " \"data\": \"" + data + "\"}"; + + JsonNode jsonNode = objectMapper.readTree(callArgumentsInput); + + assertThrows(RskJsonRpcRequestException.class, () -> objectMapper.convertValue(jsonNode, CallArgumentsParam.class)); + } + + @Test + public void testInvalidNonceInCallArgumentsParam() throws JsonProcessingException { + String nonce = "0xj"; + + String callArgumentsInput = "{\n" + + " \"nonce\": \"" + nonce + "\"}"; + + JsonNode jsonNode = objectMapper.readTree(callArgumentsInput); + + assertThrows(RskJsonRpcRequestException.class, () -> objectMapper.convertValue(jsonNode, CallArgumentsParam.class)); + } + + @Test + public void testInvalidChainIdInCallArgumentsParam() throws JsonProcessingException { + String chainId = "0xb2r"; + + String callArgumentsInput = "{\n" + + " \"chainId\": \"" + chainId + "\"}"; + + JsonNode jsonNode = objectMapper.readTree(callArgumentsInput); + + assertThrows(RskJsonRpcRequestException.class, () -> objectMapper.convertValue(jsonNode, CallArgumentsParam.class)); + } + + @Test + public void testToCallArguments() { + CallArgumentsParam callArgumentsParam = new CallArgumentsParam( + new HexAddressParam(FROM), + new HexAddressParam(TO), + new HexNumberParam(GAS), + new HexNumberParam(GAS_PRICE), + null, + new HexNumberParam(NONCE), + new HexNumberParam(CHAIN_ID), + new HexNumberParam(VALUE), + new HexDataParam(DATA) + ); + + CallArguments callArguments = callArgumentsParam.toCallArguments(); + + assertEquals(FROM, callArguments.getFrom()); + assertEquals(TO, callArguments.getTo()); + assertEquals(GAS, callArguments.getGas()); + assertEquals(GAS_PRICE, callArguments.getGasPrice()); + assertEquals(NONCE, callArguments.getNonce()); + assertEquals(CHAIN_ID, callArguments.getChainId()); + assertEquals(VALUE, callArguments.getValue()); + assertEquals(DATA, callArguments.getData()); + } +} diff --git a/rskj-core/src/test/java/org/ethereum/rpc/parameters/FilterRequestParamTest.java b/rskj-core/src/test/java/org/ethereum/rpc/parameters/FilterRequestParamTest.java new file mode 100644 index 00000000000..acf2f7c55b3 --- /dev/null +++ b/rskj-core/src/test/java/org/ethereum/rpc/parameters/FilterRequestParamTest.java @@ -0,0 +1,155 @@ +/* + * This file is part of RskJ + * Copyright (C) 2023 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.ethereum.rpc.FilterRequest; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Collection; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class FilterRequestParamTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void validInput() throws JsonProcessingException { + String filterRequestInput = "{\n" + + " \"fromBlock\": \"0x1\"," + + " \"toBlock\" : \"0x2\"," + + " \"address\": \"0x7857288e171c6159c5576d1bd9ac40c0c48a771c\"," + + " \"topics\":[\"0x000000000000000000000000000000006d696e696e675f6665655f746f706963\"]," + + " \"blockHash\": \"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3\"}"; + JsonNode jsonNode = objectMapper.readTree(filterRequestInput); + FilterRequestParam filterRequestParam = objectMapper.convertValue(jsonNode, FilterRequestParam.class); + assertNotNull(filterRequestParam); + assertEquals("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", filterRequestParam.getBlockHash().getHash().toJsonString()); + assertEquals("0x1", filterRequestParam.getFromBlock().getIdentifier()); + assertEquals("0x2", filterRequestParam.getToBlock().getIdentifier()); + assertEquals("0x7857288e171c6159c5576d1bd9ac40c0c48a771c", filterRequestParam.getAddress()[0].getAddress().toJsonString()); + assertEquals("0x000000000000000000000000000000006d696e696e675f6665655f746f706963", filterRequestParam.getTopics()[0][0].getHash().toJsonString()); + } + + @Test + void filterRequestParsesArrayOfTopic() throws JsonProcessingException { + String filterRequestInput = "{\n" + + " \"topics\":[\"0x000000000000000000000000000000006d696e696e675f6665655f746f706963\", " + + " [\"0x0000000000000000000000000000000000000000000000000000000000001111\",\"0x000000000000000000000000000000006d696e696e675f6665655f746f706963\"]]" + + "}"; + JsonNode jsonNode = objectMapper.readTree(filterRequestInput); + FilterRequestParam filterRequestParam = objectMapper.convertValue(jsonNode, FilterRequestParam.class); + assertNotNull(filterRequestParam); + TopicParam[][] topics = filterRequestParam.getTopics(); + assertEquals(2, topics.length); + TopicParam[] topicParam = topics[1]; + assertEquals(2, topicParam.length); + assertEquals("0x0000000000000000000000000000000000000000000000000000000000001111", topicParam[0].getHash().toJsonString()); + } + + @Test + void invalidTopicFails() throws JsonProcessingException { + String filterRequestInput = "{\n" + + " \"topics\":[\"0x000000000000000000000000000000006d696e696e675f6665655f746f706963\", " + + " [\"0x0000000000000000000000000000000000000000000000000000000000001111\",\"0x0000w0000000000000000000000000006d696e696e675f6665655f746f706963\"]]" + + "}"; + JsonNode jsonNode = objectMapper.readTree(filterRequestInput); + Assertions.assertThrows(RskJsonRpcRequestException.class, () -> objectMapper.convertValue(jsonNode, FilterRequestParam.class)); + } + + @Test + void filterRequestParsesSingleTopic() throws JsonProcessingException { + String filterRequestInput = "{\n" + + " \"topics\":\"0x000000000000000000000000000000006d696e696e675f6665655f746f706963\"" + + "}"; + JsonNode jsonNode = objectMapper.readTree(filterRequestInput); + FilterRequestParam filterRequestParam = objectMapper.convertValue(jsonNode, FilterRequestParam.class); + assertNotNull(filterRequestParam); + TopicParam[][] topics = filterRequestParam.getTopics(); + assertEquals(1, topics.length); + TopicParam[] topicParam = topics[0]; + assertEquals(1, topicParam.length); + assertEquals("0x000000000000000000000000000000006d696e696e675f6665655f746f706963", topicParam[0].getHash().toJsonString()); + } + + @Test + void invalidFromBlockFails() throws JsonProcessingException { + String filterRequestInput = "{\"fromBlock\" : \"0x2w\"}"; + JsonNode jsonNode = objectMapper.readTree(filterRequestInput); + Assertions.assertThrows(RskJsonRpcRequestException.class, () -> objectMapper.convertValue(jsonNode, FilterRequestParam.class)); + } + + @Test + void invalidToBlockFails() throws JsonProcessingException { + String filterRequestInput = "{\"toBlock\" : \"ab\"}"; + JsonNode jsonNode = objectMapper.readTree(filterRequestInput); + Assertions.assertThrows(RskJsonRpcRequestException.class, () -> objectMapper.convertValue(jsonNode, FilterRequestParam.class)); + } + + @Test + void toFilterRequestProducesValidObject() { + FilterRequestParam filterRequestParam = new FilterRequestParam( + new BlockIdentifierParam("0x1"), + new BlockIdentifierParam("0x2"), + new HexAddressParam[]{new HexAddressParam("0x7857288e171c6159c5576d1bd9ac40c0c48a771c")}, + new TopicParam[][]{ + new TopicParam[]{ + new TopicParam("0x000000000000000000000000000000006d696e696e675f6665655f746f706963"), + new TopicParam("0x000000000000000000000000000000006d696e696e675f6665655f746f711111") + }, + new TopicParam[]{ + new TopicParam("0x000000000000000000000000000000006d696e696e675f6665655f746f706963") + } + }, + new BlockHashParam("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")); + FilterRequest filterRequest = filterRequestParam.toFilterRequest(); + assertEquals("0x1", filterRequest.getFromBlock()); + assertEquals("0x2", filterRequest.getToBlock()); + assertEquals("0x7857288e171c6159c5576d1bd9ac40c0c48a771c", filterRequest.getAddress()); + assertEquals(2, filterRequest.getTopics().length); + assertTrue(filterRequest.getTopics()[0] instanceof Collection); + assertEquals("0x000000000000000000000000000000006d696e696e675f6665655f746f711111", ((List) filterRequest.getTopics()[0]).get(1)); + assertTrue(filterRequest.getTopics()[1] instanceof String); + assertEquals("0x000000000000000000000000000000006d696e696e675f6665655f746f706963", filterRequest.getTopics()[1]); + + } + + @Test + void canHandleNullTopics() throws JsonProcessingException { + String filterRequestInput = "{\n" + + " \"topics\":[\"0x000000000000000000000000000000006d696e696e675f6665655f746f706963\", null, [\"0x000000000000000000000000000000006d696e696e675f6665655f746f706963\",null]]}"; + JsonNode jsonNode = objectMapper.readTree(filterRequestInput); + FilterRequestParam filterRequestParam = objectMapper.convertValue(jsonNode, FilterRequestParam.class); + FilterRequest fr = objectMapper.convertValue(jsonNode, FilterRequest.class); + + assertNotNull(filterRequestParam); + assertEquals("0x000000000000000000000000000000006d696e696e675f6665655f746f706963", filterRequestParam.getTopics()[0][0].getHash().toJsonString()); + FilterRequest filterRequest = filterRequestParam.toFilterRequest(); + assertNotNull(filterRequest); + assertEquals(3, filterRequest.getTopics().length); + assertEquals(2, ((List) filterRequest.getTopics()[2]).size()); + + } +} \ No newline at end of file diff --git a/rskj-core/src/test/java/org/ethereum/rpc/parameters/HashParamTest.java b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HashParamTest.java new file mode 100644 index 00000000000..446ab0ef7b6 --- /dev/null +++ b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HashParamTest.java @@ -0,0 +1,63 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class HashParamTest { + + @Test + void testBlockHashParam() { + String validHash = "0xc2b835124172db5bd051bb94fa123721eacac43b5cba2499b22c7583a35689b8"; + String invalidHash = "invalidhash"; + String shorterHash = "0xc2b835124172db5bd051bb94fa123721eacac43b5cba2499b22c7583a3568"; + String invalidCharHash = "0xc2b835124172db5bdzz1bb94fa123721eacac43b5cba2499b22c7583a3568"; + + BlockHashParam blockHashParam = new BlockHashParam(validHash); + + assertEquals(validHash, blockHashParam.getHash().toJsonString()); + + assertThrows(RskJsonRpcRequestException.class, () -> new BlockHashParam(null)); + assertThrows(RskJsonRpcRequestException.class, () -> new BlockHashParam("")); + assertThrows(RskJsonRpcRequestException.class, () -> new BlockHashParam(invalidHash)); + assertThrows(RskJsonRpcRequestException.class, () -> new BlockHashParam(shorterHash)); + assertThrows(RskJsonRpcRequestException.class, () -> new BlockHashParam(invalidCharHash)); + } + + @Test + void testTxHashParam() { + String validHash = "0xc2b835124172db5bd051bb94fa123721eacac43b5cba2499b22c7583a35689b8"; + String invalidHash = "invalidhash"; + String shorterHash = "0xc2b835124172db5bd051bb94fa123721eacac43b5cba2499b22c7583a3568"; + String invalidCharHash = "0xc2b835124172db5bdzz1bb94fa123721eacac43b5cba2499b22c7583a3568"; + + TxHashParam txHashParam = new TxHashParam(validHash); + + assertEquals(validHash, txHashParam.getHash().toJsonString()); + + assertThrows(RskJsonRpcRequestException.class, () -> new BlockHashParam(null)); + assertThrows(RskJsonRpcRequestException.class, () -> new BlockHashParam("")); + assertThrows(RskJsonRpcRequestException.class, () -> new BlockHashParam(invalidHash)); + assertThrows(RskJsonRpcRequestException.class, () -> new BlockHashParam(shorterHash)); + assertThrows(RskJsonRpcRequestException.class, () -> new BlockHashParam(invalidCharHash)); + } +} \ No newline at end of file diff --git a/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexAddressParamTest.java b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexAddressParamTest.java new file mode 100644 index 00000000000..76b2e7838c5 --- /dev/null +++ b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexAddressParamTest.java @@ -0,0 +1,46 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class HexAddressParamTest { + + @Test + public void testValidHexAddressParam() { + String validHexAddress = "0x407d73d8a49eeb85d32cf465507dd71d507100c1"; + + HexAddressParam hexAddressParam = new HexAddressParam(validHexAddress); + + assertEquals(validHexAddress, hexAddressParam.getAddress().toJsonString()); + } + + @Test + public void testInvalidHexAddressParam() { + String invalidHexAddress = "0x407d73d8a4sseb85d32cf465507dd71d507100c1"; + String shorterHexAddress = "0x407d73"; + + assertThrows(RskJsonRpcRequestException.class, () -> new HexAddressParam(null)); + assertThrows(RskJsonRpcRequestException.class, () -> new HexAddressParam(invalidHexAddress)); + assertThrows(RskJsonRpcRequestException.class, () -> new HexAddressParam(shorterHexAddress)); + } +} diff --git a/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexDataParamTest.java b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexDataParamTest.java new file mode 100644 index 00000000000..9953dd1b219 --- /dev/null +++ b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexDataParamTest.java @@ -0,0 +1,43 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import co.rsk.util.HexUtils; +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class HexDataParamTest { + @Test + public void testValidHexDataParam() { + String validHexRawData = "0xf892038609184e72a0008276c094e7b8e91401bf4d1669f54dc5f98109d7efbc4eea849184e72aa9d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f07244567565a0ea179f22ab9149013f3330a0921cef8fc8fddc84f3e51746ef8d5a35e04bfd8ba020e5640606a3257f32b9ef2f706c7294666d4bf759093769d40e7fdd2ac2f49e"; + + HexDataParam hexDataParam = new HexDataParam(validHexRawData); + + assertEquals(validHexRawData, HexUtils.toUnformattedJsonHex(hexDataParam.getRawDataBytes())); + } + + @Test + public void testInvalidHexDataParam() { + String invalidHexRawData = "0xsv92038609184e72a0008276c094e7b8e91401bf4d1669f54dc5f98109d7efbc4eea849184e72aa9d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f07244567565a0ea179f22ab9149013f3330a0921cef8fc8fddc84f3e51746ef8d5a35e04bfd8ba020e5640606a3257f32b9ef2f706c7294666d4bf759093769d40e7fdd2ac2f49e"; + + assertThrows(RskJsonRpcRequestException.class, () -> new HexDataParam(invalidHexRawData)); + } +} diff --git a/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexDurationParamTest.java b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexDurationParamTest.java new file mode 100644 index 00000000000..b85612e8ee6 --- /dev/null +++ b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexDurationParamTest.java @@ -0,0 +1,47 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class HexDurationParamTest { + @Test + void testValidHexDurationParam() { + String validHexValue = "0x1e"; + HexDurationParam hexDurationParam = new HexDurationParam(validHexValue); + + assertNotNull(hexDurationParam); + assertEquals(30, hexDurationParam.getDuration()); + } + + @Test + void testInvalidHexDurationParam() { + String invalidHexValue = "1e"; // Missing hex prefix + String nonNumericHexValue = "0x1t"; // Non-valid hex value + String invalidDuration = "0xf1652d8322a880e520f996f7d28b645814a58a202d7d2ab7f058e5566fe4f9f3"; // invalid duration + + assertThrows(RskJsonRpcRequestException.class, () -> new HexDurationParam(invalidHexValue)); + assertThrows(RskJsonRpcRequestException.class, () -> new HexDurationParam(nonNumericHexValue)); + assertThrows(RskJsonRpcRequestException.class, () -> new HexDurationParam(invalidDuration)); + } +} diff --git a/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexIndexParamTest.java b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexIndexParamTest.java new file mode 100644 index 00000000000..7b0b81058cf --- /dev/null +++ b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexIndexParamTest.java @@ -0,0 +1,49 @@ +/* + * This file is part of RskJ + * Copyright (C) 2023 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class HexIndexParamTest { + + @Test + void testValidHexIndexParam() { + String validHexValue = "0x123"; + HexIndexParam hexIndexParam = new HexIndexParam(validHexValue); + + assertNotNull(hexIndexParam); + assertEquals(291, hexIndexParam.getIndex()); + } + + @Test + void testInvalidHexIndexParam() { + String invalidHexValue = "123"; // Missing hex prefix + String nonNumericHexValue = "0xabcz"; // Non-valid hex value + String emptyString = ""; // empty value + String invalidIndex = "0xf1652d8322a880e520f996f7d28b645814a58a202d7d2ab7f058e5566fe4f9f3"; // Invalid index + + assertThrows(RskJsonRpcRequestException.class, () -> new HexIndexParam(invalidHexValue)); + assertThrows(RskJsonRpcRequestException.class, () -> new HexIndexParam(nonNumericHexValue)); + assertThrows(RskJsonRpcRequestException.class, () -> new HexIndexParam(emptyString)); + assertThrows(RskJsonRpcRequestException.class, () -> new HexIndexParam(invalidIndex)); + } + +} \ No newline at end of file diff --git a/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexKeyParamTest.java b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexKeyParamTest.java new file mode 100644 index 00000000000..58305c00278 --- /dev/null +++ b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexKeyParamTest.java @@ -0,0 +1,43 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class HexKeyParamTest { + @Test + void testValidHexKeyParam() { + String validHexValue = "0xcd3376bb711cb332ee3fb2ca04c6a8b9f70c316fcdf7a1f44ef4c7999483295e"; + HexKeyParam hexKeyParam = new HexKeyParam(validHexValue); + + assertNotNull(hexKeyParam); + assertEquals(validHexValue, hexKeyParam.getHexKey()); + } + + @Test + void testInvalidHexKeyParam() { + String invalidHexValue = "0xcd3376bb711cb332ee3fb2ca04c6a8b9f70c316fcdf7a1f44ef4c79994832zxt"; + + assertThrows(RskJsonRpcRequestException.class, () -> new HexKeyParam(invalidHexValue)); + } +} diff --git a/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexNumberParamTest.java b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexNumberParamTest.java new file mode 100644 index 00000000000..ad819283fec --- /dev/null +++ b/rskj-core/src/test/java/org/ethereum/rpc/parameters/HexNumberParamTest.java @@ -0,0 +1,53 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package org.ethereum.rpc.parameters; + +import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class HexNumberParamTest { + + @Test + public void testValidHexNumberParam() { + String validHexNumber = "0x76c0"; + HexNumberParam hexNumberParam = new HexNumberParam(validHexNumber); + + assertNotNull(hexNumberParam); + assertEquals(validHexNumber, hexNumberParam.getHexNumber()); + } + + @Test + public void testValidHexNumberParamAsStringNumber() { + String validStringNumber = "1500"; + HexNumberParam hexNumberParam = new HexNumberParam(validStringNumber); + + assertNotNull(hexNumberParam); + assertEquals(validStringNumber, hexNumberParam.getHexNumber()); + } + + @Test + public void testInvalidHexNumberParam() { + String invalidHexNumber = "0x76ty"; + + assertThrows(RskJsonRpcRequestException.class, () -> new HexNumberParam(invalidHexNumber)); + } +} diff --git a/rskj-core/src/test/java/org/ethereum/util/TransactionFactoryHelper.java b/rskj-core/src/test/java/org/ethereum/util/TransactionFactoryHelper.java index a92f7cd8176..bea56c4e635 100644 --- a/rskj-core/src/test/java/org/ethereum/util/TransactionFactoryHelper.java +++ b/rskj-core/src/test/java/org/ethereum/util/TransactionFactoryHelper.java @@ -1,6 +1,7 @@ package org.ethereum.util; import java.math.BigInteger; +import java.util.Optional; import org.ethereum.core.Account; import org.ethereum.core.Transaction; @@ -10,6 +11,10 @@ import co.rsk.test.builders.AccountBuilder; import co.rsk.test.builders.TransactionBuilder; import co.rsk.util.HexUtils; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.rpc.parameters.HexAddressParam; +import org.ethereum.rpc.parameters.HexDataParam; +import org.ethereum.rpc.parameters.HexNumberParam; /** * Created by ajlopez on 28/02/2018. @@ -116,4 +121,18 @@ public static Transaction createTransaction(CallArguments args, byte chainId, Ac return tx; } + public static CallArgumentsParam toCallArgumentsParam(CallArguments args) { + return new CallArgumentsParam( + Optional.ofNullable(args.getFrom()).filter(p -> !p.isEmpty()).map(HexAddressParam::new).orElse(null), + Optional.ofNullable(args.getTo()).filter(p -> !p.isEmpty()).map(HexAddressParam::new).orElse(null), + Optional.ofNullable(args.getGas()).filter(p -> !p.isEmpty()).map(HexNumberParam::new).orElse(null), + Optional.ofNullable(args.getGasPrice()).filter(p -> !p.isEmpty()).map(HexNumberParam::new).orElse(null), + Optional.ofNullable(args.getGasLimit()).filter(p -> !p.isEmpty()).map(HexNumberParam::new).orElse(null), + Optional.ofNullable(args.getNonce()).filter(p -> !p.isEmpty()).map(HexNumberParam::new).orElse(null), + Optional.ofNullable(args.getChainId()).filter(p -> !p.isEmpty()).map(HexNumberParam::new).orElse(null), + Optional.ofNullable(args.getValue()).filter(p -> !p.isEmpty()).map(HexNumberParam::new).orElse(null), + Optional.ofNullable(args.getData()).filter(p -> !p.isEmpty()).map(HexDataParam::new).orElse(null) + ); + } + } diff --git a/rskj-core/src/test/java/org/ethereum/vm/program/NestedContractsTest.java b/rskj-core/src/test/java/org/ethereum/vm/program/NestedContractsTest.java index acff8d03dfd..dada3866b25 100644 --- a/rskj-core/src/test/java/org/ethereum/vm/program/NestedContractsTest.java +++ b/rskj-core/src/test/java/org/ethereum/vm/program/NestedContractsTest.java @@ -34,6 +34,9 @@ import org.ethereum.core.ReceivedTxSignatureCache; import org.ethereum.rpc.CallArguments; import org.ethereum.rpc.exception.RskJsonRpcRequestException; +import org.ethereum.rpc.parameters.BlockIdentifierParam; +import org.ethereum.rpc.parameters.CallArgumentsParam; +import org.ethereum.util.TransactionFactoryHelper; import org.ethereum.vm.DataWord; import org.ethereum.vm.PrecompiledContracts; import org.ethereum.vm.program.invoke.ProgramInvokeFactoryImpl; @@ -110,8 +113,10 @@ void testNested_interfaceCall_require() throws FileNotFoundException, DslProcess //Failed Call ContractA.buy(0) -> 0 > 0 final String contractA = getContractAddressString(TX_CONTRACTA); CallArguments args = buildArgs(contractA, Hex.toHexString(BUY_FUNCTION.encode(0))); + CallArgumentsParam callArgumentsParam = TransactionFactoryHelper.toCallArgumentsParam(args); + BlockIdentifierParam blockIdentifierParam = new BlockIdentifierParam("latest"); try { - ethModule.call(args, "latest"); + ethModule.call(callArgumentsParam, blockIdentifierParam); fail(); } catch (RskJsonRpcRequestException e) { MatcherAssert.assertThat(e.getMessage(), Matchers.containsString("Negative value")); @@ -119,7 +124,7 @@ void testNested_interfaceCall_require() throws FileNotFoundException, DslProcess //Success Call -> 2 > 0 args = buildArgs(contractA, Hex.toHexString(BUY_FUNCTION.encode(2))); - final String call = ethModule.call(args, "latest"); + final String call = ethModule.call(TransactionFactoryHelper.toCallArgumentsParam(args), new BlockIdentifierParam("latest")); //assertEquals("0x" + DataWord.valueOf(2).toString(), call); } @@ -151,12 +156,12 @@ void testNested_ABICall_require() throws FileNotFoundException, DslProcessorExce //Failed Call ContractA.buy(0) -> 0 > 0 final String contractA = getContractAddressString("tx03"); CallArguments args = buildArgs(contractA, Hex.toHexString(BUY_FUNCTION.encode(0))); - String call = ethModule.call(args, "latest"); + String call = ethModule.call(TransactionFactoryHelper.toCallArgumentsParam(args), new BlockIdentifierParam("latest")); assertEquals("0x" + DataWord.valueOf(0).toString(), call); //Success Call -> 2 > 0 args = buildArgs(contractA, Hex.toHexString(BUY_FUNCTION.encode(2))); - call = ethModule.call(args, "latest"); + call = ethModule.call(TransactionFactoryHelper.toCallArgumentsParam(args), new BlockIdentifierParam("latest")); assertEquals("0x" + DataWord.valueOf(2).toString(), call); }