Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement getProposedFederation in FederationProviderFromFederatorSupport #329

Open
wants to merge 33 commits into
base: feat/powpeg_validation_protocol-phase4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
493d605
feat(federate): add getProposedFederationSize to FederatorSupport
apancorb Oct 25, 2024
3f34e6f
feat(federate): add getProposedFederatorPublicKeyOfType to FederatorS…
apancorb Oct 25, 2024
de08dff
feat(federate): add getProposedFederationCreationTime to FederatorSup…
apancorb Oct 25, 2024
7aaac68
feat(federate): add getProposedFederationCreationBlockNumber to Feder…
apancorb Oct 25, 2024
e3f9281
feat(federate): add getProposedFederation to FederationProvider inter…
apancorb Oct 25, 2024
d9b22f0
feat(federate): add implementation of getProposedFederation to Federa…
apancorb Oct 25, 2024
cf67d6d
refactor(federate): use FEDERATION_NON_EXISTENT enum code in conditio…
apancorb Oct 25, 2024
3701805
feat(federate): add unit tests for getProposedFederationSize
apancorb Oct 25, 2024
0c0cd75
feat(federate): add unit tests for getProposedFederatorPublicKeyOfType
apancorb Oct 25, 2024
ba9e51f
feat(federate): add unit tests for getProposedFederationCreationTime
apancorb Oct 25, 2024
cda8673
feat(federate): add unit tests for getProposedFederationCreationBlock…
apancorb Oct 25, 2024
f91e644
feat(federate): add unit tests for getProposedFederation
apancorb Oct 25, 2024
7fb3754
fix(federate): use proper activation rule for svp
apancorb Oct 25, 2024
9b883fd
refactor(federate): improve javadocs for FederationProvider interface
apancorb Oct 30, 2024
23c0dea
refactor(federate): use isEmpty when checking if retiring federation …
apancorb Oct 30, 2024
9f6499e
feat(federate): throw exception if after proving that the proposed fe…
apancorb Oct 30, 2024
b4c5cf2
refactor(federate): method call consistent with all the other propose…
apancorb Oct 30, 2024
88515c5
feat(federate): after rskip419 the only possible type of federation i…
apancorb Oct 30, 2024
5b6b6d8
feat(federate): remove unit tests for proposed federation that are un…
apancorb Oct 30, 2024
d8f5ac1
fix(federate): update var name to not shadow global federator support…
apancorb Oct 30, 2024
6fcf573
refactor(federate): replace lambda with method reference 'IllegalStat…
apancorb Oct 30, 2024
ef5f2b3
refactor(federate): improve sonar complaints of FederateSupport
apancorb Oct 30, 2024
a710693
refactor(federate): make FederationProvider javadoc more concise
apancorb Oct 31, 2024
9342f3a
feat(federate): remove checking the proposed federation addr to valid…
apancorb Oct 31, 2024
11174e5
feat(federate): remove unit tests verifying if proposed fed addr is b…
apancorb Oct 31, 2024
78a6d40
feat(federate): add try-catch block in case proposed federation is un…
apancorb Oct 31, 2024
ff2a59a
feat(federate): add unit test when proposed federation cannot be buil…
apancorb Oct 31, 2024
3889525
refactor(federate): rename unit tests
apancorb Nov 1, 2024
d39960f
refactor(federate): use ECKey class to build pub key in unit tests
apancorb Nov 1, 2024
e2d9b98
feat(federate): change catch exception class to catch all possible ex…
apancorb Nov 4, 2024
5f116c1
refactor(federate): remove checking if RSKIP419 is activated for prop…
apancorb Nov 4, 2024
d14d1ba
feat(federate): remove RSKIP419 reference for unit tests
apancorb Nov 4, 2024
656fa35
feat(federate): remove unit tests related with proposed fed and rskip419
apancorb Nov 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 45 additions & 12 deletions src/main/java/co/rsk/federate/FederationProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,60 @@
import java.util.Optional;

/**
* Implementors of this interface must be able to provide
* federation instances.
*
* @author Ariel Mendelzon
* Provides access to various federation instances, including the active, retiring, and proposed federations.
* Implementations of this interface must define how to retrieve the federations and their respective addresses.
* These methods allow clients to manage and monitor federations in different lifecycle stages within the bridge.
*/
public interface FederationProvider {
// The currently "active" federation

/**
* Retrieves the currently active federation, which is responsible for processing transactions.
julia-zack marked this conversation as resolved.
Show resolved Hide resolved
*
* @return the active {@link Federation} instance
*/
Federation getActiveFederation();
// The currently "active" federation's address

/**
* Retrieves the address of the currently active federation.
*
* @return the {@link Address} of the active federation
*/
Address getActiveFederationAddress();

// The currently "retiring" federation
/**
* Retrieves the currently retiring federation, if one exists. This federation is in transition
* and will soon be replaced by a new active federation.
*
* @return an {@link Optional} containing the retiring {@link Federation}, or {@link Optional#empty()} if none exists
*/
Optional<Federation> getRetiringFederation();
// The currently "retiring" federation's address

/**
* Retrieves the address of the currently retiring federation, if one exists.
*
* @return an {@link Optional} containing the {@link Address} of the retiring federation, or {@link Optional#empty()} if none exists
*/
Optional<Address> getRetiringFederationAddress();

// The currently "proposed" federation's address
/**
* Retrieves the currently proposed federation, if one exists. This federation is awaiting activation.
julia-zack marked this conversation as resolved.
Show resolved Hide resolved
*
* @return an {@link Optional} containing the proposed {@link Federation}, or {@link Optional#empty()} if none exists
*/
Optional<Federation> getProposedFederation();

/**
* Retrieves the address of the currently proposed federation, if one exists.
*
* @return an {@link Optional} containing the {@link Address} of the proposed federation, or {@link Optional#empty()} if none exists
*/
Optional<Address> getProposedFederationAddress();

// The federations that are "live", that is, are still
// operational. This should be the active federation
// plus the retiring federation, if one exists
/**
* Retrieves a list of live federations, which includes both the active federation
* and the retiring federation, if one exists.
*
* @return a {@link List} of live {@link Federation} instances
*/
List<Federation> getLiveFederations();
Copy link
Contributor Author

@apancorb apancorb Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably remove this method, is not being used anywhere at the moment. Maybe in another PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets create a task for that

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
*/
package co.rsk.federate;

import static co.rsk.peg.federation.FederationChangeResponseCode.FEDERATION_NON_EXISTENT;
import static co.rsk.peg.federation.FederationMember.KeyType;
import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP123;
import static org.ethereum.config.blockchain.upgrades.ConsensusRule.RSKIP419;

import co.rsk.bitcoinj.core.Address;
import co.rsk.bitcoinj.core.BtcECKey;
Expand All @@ -30,6 +33,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.IntStream;

/**
* Provides a federation using a FederatorSupport instance, which in turn
Expand All @@ -39,13 +43,13 @@
* @author Ariel Mendelzon
*/
public class FederationProviderFromFederatorSupport implements FederationProvider {

private final FederatorSupport federatorSupport;
private final FederationConstants federationConstants;

public FederationProviderFromFederatorSupport(
FederatorSupport federatorSupport,
FederationConstants federationConstants) {

this.federatorSupport = federatorSupport;
this.federationConstants = federationConstants;
}
Expand Down Expand Up @@ -93,7 +97,7 @@ public Optional<Federation> getRetiringFederation() {
Integer federationSize = federatorSupport.getRetiringFederationSize();
Optional<Address> optionalRetiringFederationAddress = getRetiringFederationAddress();

if (federationSize == -1 || !optionalRetiringFederationAddress.isPresent()) {
if (federationSize == FEDERATION_NON_EXISTENT.getCode() || optionalRetiringFederationAddress.isEmpty()) {
return Optional.empty();
}

Expand Down Expand Up @@ -135,9 +139,54 @@ public Optional<Address> getRetiringFederationAddress() {
return federatorSupport.getRetiringFederationAddress();
}

@Override
public Optional<Federation> getProposedFederation() {
if (!federatorSupport.getConfigForBestBlock().isActive(RSKIP419)) {
return Optional.empty();
}
julia-zack marked this conversation as resolved.
Show resolved Hide resolved

Optional<Address> proposedFederationAddress = getProposedFederationAddress();
Integer federationSize = federatorSupport.getProposedFederationSize()
nathanieliov marked this conversation as resolved.
Show resolved Hide resolved
.orElse(FEDERATION_NON_EXISTENT.getCode());
julia-zack marked this conversation as resolved.
Show resolved Hide resolved
if (federationSize == FEDERATION_NON_EXISTENT.getCode() || proposedFederationAddress.isEmpty()) {
return Optional.empty();
}

List<FederationMember> federationMembers = IntStream.range(0, federationSize)
.mapToObj(i -> new FederationMember(
federatorSupport.getProposedFederatorPublicKeyOfType(i, KeyType.BTC)
.map(ECKey::getPubKey)
.map(BtcECKey::fromPublicOnly)
.orElseThrow(IllegalStateException::new),
federatorSupport.getProposedFederatorPublicKeyOfType(i, KeyType.RSK)
nathanieliov marked this conversation as resolved.
Show resolved Hide resolved
.orElseThrow(IllegalStateException::new),
federatorSupport.getProposedFederatorPublicKeyOfType(i, KeyType.MST)
.orElseThrow(IllegalStateException::new)
))
.toList();

FederationArgs federationArgs = new FederationArgs(
federationMembers,
federatorSupport.getProposedFederationCreationTime()
.orElseThrow(IllegalStateException::new),
nathanieliov marked this conversation as resolved.
Show resolved Hide resolved
federatorSupport.getProposedFederationCreationBlockNumber()
.orElseThrow(IllegalStateException::new),
federatorSupport.getBtcParams()
);

Federation federation = FederationFactory.buildP2shErpFederation(
federationArgs,
federationConstants.getErpFedPubKeysList(),
federationConstants.getErpFedActivationDelay());

return Optional.of(federation);
}

@Override
public Optional<Address> getProposedFederationAddress() {
return federatorSupport.getProposedFederationAddress();
return Optional.of(federatorSupport)
.filter(fedSupport -> fedSupport.getConfigForBestBlock().isActive(RSKIP419))
.flatMap(FederatorSupport::getProposedFederationAddress);
julia-zack marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
Expand Down
53 changes: 43 additions & 10 deletions src/main/java/co/rsk/federate/FederatorSupport.java
apancorb marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.net.UnknownHostException;
import java.time.Instant;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
Expand All @@ -31,17 +32,14 @@
*/
public class FederatorSupport {

private static final Logger LOGGER = LoggerFactory.getLogger(FederatorSupport.class);
private static final Logger logger = LoggerFactory.getLogger(FederatorSupport.class);

private final Blockchain blockchain;
private final PowpegNodeSystemProperties config;

private final NetworkParameters parameters;

private final BridgeTransactionSender bridgeTransactionSender;

private ECDSASigner signer;

private FederationMember federationMember;
private RskAddress federatorAddress;

Expand All @@ -51,9 +49,7 @@ public FederatorSupport(
BridgeTransactionSender bridgeTransactionSender) {
this.blockchain = blockchain;
this.config = config;

this.parameters = config.getNetworkConstants().getBridgeConstants().getBtcParams();

this.bridgeTransactionSender = bridgeTransactionSender;
}

Expand Down Expand Up @@ -98,7 +94,7 @@ public Long getRskBestChainHeight() {
}

public void sendReceiveHeaders(org.bitcoinj.core.Block[] headers) {
LOGGER.debug("About to send to the bridge headers from {} to {}", headers[0].getHash(), headers[headers.length - 1].getHash());
logger.debug("About to send to the bridge headers from {} to {}", headers[0].getHash(), headers[headers.length - 1].getHash());

Object[] objectArray = new Object[headers.length];

Expand All @@ -118,15 +114,15 @@ public Long getBtcTxHashProcessedHeight(Sha256Hash btcTxHash) {
}

public void sendRegisterBtcTransaction(org.bitcoinj.core.Transaction tx, int blockHeight, PartialMerkleTree pmt) {
LOGGER.debug("About to send to the bridge btc tx hash {}. Block height {}", tx.getWTxId(), blockHeight);
logger.debug("About to send to the bridge btc tx hash {}. Block height {}", tx.getWTxId(), blockHeight);

byte[] txSerialized = tx.bitcoinSerialize();
byte[] pmtSerialized = pmt.bitcoinSerialize();
this.bridgeTransactionSender.sendRskTx(federatorAddress, signer, Bridge.REGISTER_BTC_TRANSACTION, txSerialized, blockHeight, pmtSerialized);
}

public void sendRegisterCoinbaseTransaction(CoinbaseInformation coinbaseInformation) {
LOGGER.debug("About to send to the bridge btc coinbase tx hash {}. Block hash {}", coinbaseInformation.getCoinbaseTransaction().getTxId(), coinbaseInformation.getBlockHash());
logger.debug("About to send to the bridge btc coinbase tx hash {}. Block hash {}", coinbaseInformation.getCoinbaseTransaction().getTxId(), coinbaseInformation.getBlockHash());

byte[] txSerialized = coinbaseInformation.getSerializedCoinbaseTransactionWithoutWitness();
byte[] pmtSerialized = coinbaseInformation.getPmt().bitcoinSerialize();
Expand Down Expand Up @@ -197,7 +193,7 @@ public long getFederationCreationBlockNumber() {
public Optional<Address> getRetiringFederationAddress() {
String addressString = this.bridgeTransactionSender.callTx(federatorAddress, Bridge.GET_RETIRING_FEDERATION_ADDRESS);

if (addressString.equals("")) {
if (addressString.isEmpty()) {
return Optional.empty();
}

Expand Down Expand Up @@ -261,6 +257,43 @@ public Optional<Address> getProposedFederationAddress() {
.map(addr -> Address.fromBase58(getBtcParams(), addr));
}

public Optional<Integer> getProposedFederationSize() {
BigInteger size = bridgeTransactionSender.callTx(
federatorAddress, Bridge.GET_PROPOSED_FEDERATION_SIZE);

return Optional.ofNullable(size)
.map(BigInteger::intValue);
}

public Optional<ECKey> getProposedFederatorPublicKeyOfType(int index, FederationMember.KeyType keyType) {
Objects.requireNonNull(keyType);

byte[] publicKeyBytes = bridgeTransactionSender.callTx(
federatorAddress,
Bridge.GET_PROPOSED_FEDERATOR_PUBLIC_KEY_OF_TYPE,
new Object[]{ index, keyType.getValue() });

return Optional.ofNullable(publicKeyBytes)
.map(ECKey::fromPublicOnly);
}

public Optional<Instant> getProposedFederationCreationTime() {
BigInteger creationTime = bridgeTransactionSender.callTx(
federatorAddress, Bridge.GET_PROPOSED_FEDERATION_CREATION_TIME);

return Optional.ofNullable(creationTime)
.map(BigInteger::longValue)
.map(Instant::ofEpochMilli);
}

public Optional<Long> getProposedFederationCreationBlockNumber() {
BigInteger creationBlockNumber = bridgeTransactionSender.callTx(
federatorAddress, Bridge.GET_PROPOSED_FEDERATION_CREATION_BLOCK_NUMBER);

return Optional.ofNullable(creationBlockNumber)
.map(BigInteger::longValue);
}

public int getBtcBlockchainBestChainHeight() {
BigInteger btcBlockchainBestChainHeight = this.bridgeTransactionSender.callTx(federatorAddress, Bridge.GET_BTC_BLOCKCHAIN_BEST_CHAIN_HEIGHT);
return btcBlockchainBestChainHeight.intValue();
Expand Down
Loading