Skip to content

Commit

Permalink
FABJ-448 Provide access to system channel configuration
Browse files Browse the repository at this point in the history
Change-Id: I7b03fa702096b35af36c3808b1a342d99f31b163
Signed-off-by: rickr <cr22rc@gmail.com>
  • Loading branch information
cr22rc committed Jun 7, 2019
1 parent 0f77959 commit db22412
Show file tree
Hide file tree
Showing 2 changed files with 363 additions and 116 deletions.
195 changes: 163 additions & 32 deletions src/main/java/org/hyperledger/fabric/sdk/Channel.java
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ private Channel(String name, HFClient hfClient, Orderer orderer, ChannelConfigur
final ConfigUpdateEnvelope configUpdateEnv = ConfigUpdateEnvelope.parseFrom(ccPayload.getData());
ByteString configUpdate = configUpdateEnv.getConfigUpdate();

sendUpdateChannel(configUpdate.toByteArray(), signers, orderer);
sendUpdateChannel(client.getUserContext(), configUpdate.toByteArray(), signers, orderer);
// final ConfigUpdateEnvelope.Builder configUpdateEnvBuilder = configUpdateEnv.toBuilder();`

//---------------------------------------
Expand Down Expand Up @@ -393,8 +393,9 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE
}

/**
* Update channel with specified channel configuration
* Update channel with specified channel configuration.
*
* <P></P>Note This is not a thread safe operation
* @param updateChannelConfiguration Updated Channel configuration
* @param signers signers
* @throws TransactionException
Expand All @@ -403,12 +404,13 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE

public void updateChannelConfiguration(UpdateChannelConfiguration updateChannelConfiguration, byte[]... signers) throws TransactionException, InvalidArgumentException {

updateChannelConfiguration(updateChannelConfiguration, getRandomOrderer(), signers);
updateChannelConfiguration(client.getUserContext(), updateChannelConfiguration, getRandomOrderer(), signers);

}

/**
* Update channel with specified channel configuration
* <P></P>Note This is not a thread safe operation
*
* @param updateChannelConfiguration Channel configuration
* @param signers signers
Expand All @@ -418,24 +420,41 @@ public void updateChannelConfiguration(UpdateChannelConfiguration updateChannelC
*/

public void updateChannelConfiguration(UpdateChannelConfiguration updateChannelConfiguration, Orderer orderer, byte[]... signers) throws TransactionException, InvalidArgumentException {
updateChannelConfiguration(client.getUserContext(), updateChannelConfiguration, orderer, signers);
}

/**
* Update channel with specified channel configuration
*
* @param userContext The specific user to use.
* @param updateChannelConfiguration Channel configuration
* @param signers signers
* @param orderer The specific orderer to use.
* @throws TransactionException
* @throws InvalidArgumentException
*/

public void updateChannelConfiguration(User userContext, UpdateChannelConfiguration updateChannelConfiguration, Orderer orderer, byte[]... signers) throws TransactionException, InvalidArgumentException {

checkChannelState();

checkOrderer(orderer);

User.userContextCheck(userContext);

try {
final long startLastConfigIndex = getLastConfigIndex(orderer);
final long startLastConfigIndex = getLastConfigIndex(getTransactionContext(userContext), orderer);
logger.trace(format("startLastConfigIndex: %d. Channel config wait time is: %d",
startLastConfigIndex, CHANNEL_CONFIG_WAIT_TIME));

sendUpdateChannel(updateChannelConfiguration.getUpdateChannelConfigurationAsBytes(), signers, orderer);
sendUpdateChannel(userContext, updateChannelConfiguration.getUpdateChannelConfigurationAsBytes(), signers, orderer);

long currentLastConfigIndex = -1;
final long nanoTimeStart = System.nanoTime();

//Try to wait to see the channel got updated but don't fail if we don't see it.
do {
currentLastConfigIndex = getLastConfigIndex(orderer);
currentLastConfigIndex = getLastConfigIndex(getTransactionContext(userContext), orderer);
if (currentLastConfigIndex == startLastConfigIndex) {

final long duration = TimeUnit.MILLISECONDS.convert(System.nanoTime() - nanoTimeStart, TimeUnit.NANOSECONDS);
Expand Down Expand Up @@ -474,7 +493,7 @@ public void updateChannelConfiguration(UpdateChannelConfiguration updateChannelC

}

private void sendUpdateChannel(byte[] configupdate, byte[][] signers, Orderer orderer) throws TransactionException, InvalidArgumentException {
private void sendUpdateChannel(User userContext, byte[] configupdate, byte[][] signers, Orderer orderer) throws TransactionException, InvalidArgumentException {

logger.debug(format("Channel %s sendUpdateChannel", name));
checkOrderer(orderer);
Expand All @@ -487,7 +506,7 @@ private void sendUpdateChannel(byte[] configupdate, byte[][] signers, Orderer or
do {

//Make sure we have fresh transaction context for each try just to be safe.
TransactionContext transactionContext = getTransactionContext();
TransactionContext transactionContext = getTransactionContext(userContext);

ConfigUpdateEnvelope.Builder configUpdateEnvBuilder = ConfigUpdateEnvelope.newBuilder();

Expand Down Expand Up @@ -890,7 +909,11 @@ public Channel joinPeer(Orderer orderer, Peer peer, PeerOptions peerOptions) thr
return this;
}

private Block getConfigBlock(List<Peer> peers) throws ProposalException {
private Block getConfigBlock(List<Peer> peers) throws ProposalException, InvalidArgumentException {
return getConfigBlock(getTransactionContext(), peers);
}

private Block getConfigBlock(TransactionContext transactionContext, List<Peer> peers) throws ProposalException {

if (shutdown) {
throw new ProposalException(format("Channel %s has been shutdown.", name));
Expand All @@ -900,10 +923,9 @@ private Block getConfigBlock(List<Peer> peers) throws ProposalException {
throw new ProposalException("No peers go get config block");
}

TransactionContext transactionContext = null;
SignedProposal signedProposal = null;
try {
transactionContext = getTransactionContext();

transactionContext.verify(false); // can't verify till we get the config block.

FabricProposal.Proposal proposal = GetConfigBlockBuilder.newBuilder()
Expand All @@ -930,7 +952,7 @@ private Block getConfigBlock(List<Peer> peers) throws ProposalException {
ProposalResponse pro = resp.iterator().next();

if (pro.getStatus() == ProposalResponse.Status.SUCCESS) {
logger.trace(format("getConfigBlock from peer %s on channel %s success", peer.getName(), name));
logger.trace(format("getConfigBlock from peer %s on channel %s success", peer, name));
return Block.parseFrom(pro.getProposalResponse().getResponse().getPayload().toByteArray());
} else {
lastException = new ProposalException(format("getConfigBlock for channel %s failed with peer %s. Status %s, details: %s",
Expand Down Expand Up @@ -1198,10 +1220,15 @@ public Channel initialize() throws InvalidArgumentException, TransactionExceptio

}

try {
loadCACertificates(false); // put all MSP certs into cryptoSuite if this fails here we'll try again later.
} catch (Exception e) {
logger.warn(format("Channel %s could not load peer CA certificates from any peers.", name));
if (peers.isEmpty()) {
logger.warn(format("Channel %s has no peers during initialization.", name));

} else {
try {
loadCACertificates(false); // put all MSP certs into cryptoSuite if this fails here we'll try again later.
} catch (Exception e) {
logger.warn(format("Channel %s could not load peer CA certificates from any peers.", name));
}
}
Collection<Peer> serviceDiscoveryPeers = getServiceDiscoveryPeers();
if (!serviceDiscoveryPeers.isEmpty()) {
Expand Down Expand Up @@ -1823,7 +1850,7 @@ private Block getGenesisBlock(Orderer orderer) throws TransactionException {

ArrayList<DeliverResponse> deliverResponses = new ArrayList<>();

seekBlock(seekInfo, deliverResponses, orderer);
seekBlock(getTransactionContext(), seekInfo, deliverResponses, orderer);

DeliverResponse blockresp = deliverResponses.get(1);
Block configBlock = blockresp.getBlock();
Expand Down Expand Up @@ -2333,22 +2360,22 @@ public AnchorPeersConfigUpdateResult getConfigUpdateAnchorPeers(Peer peer, User
/**
* Provide the Channel's latest raw Configuration Block.
*
* @param orderer
* @return Channel configuration block.
* @throws TransactionException
*/

private Block getConfigurationBlock() throws TransactionException {
private Block getConfigurationBlock(TransactionContext transactionContext, Orderer orderer) throws TransactionException {

logger.debug(format("getConfigurationBlock for channel %s", name));

try {
Orderer orderer = getRandomOrderer();

long lastConfigIndex = getLastConfigIndex(orderer);
long lastConfigIndex = getLastConfigIndex(transactionContext, orderer);

logger.debug(format("Last config index is %d", lastConfigIndex));

Block configBlock = getBlockByNumber(lastConfigIndex);
Block configBlock = getBlockByNumber(transactionContext, orderer, lastConfigIndex);

//Little extra parsing but make sure this really is a config block for this channel.
Envelope envelopeRet = Envelope.parseFrom(configBlock.getData().getData(0));
Expand Down Expand Up @@ -2415,8 +2442,70 @@ private String[] parseEndpoint(String endPoint) throws InvalidArgumentException

}

/**
* Get channel configuration from a specific Orderer
*
* @param userContext The user to sign the action.
* @param orderer To retrieve the configuration from.
* @return Configuration block.
* @throws InvalidArgumentException
* @throws TransactionException
*/

public byte[] getChannelConfigurationBytes(User userContext, Orderer orderer) throws InvalidArgumentException, TransactionException {

try {
Block configBlock = getConfigurationBlock(getTransactionContext(userContext), orderer);

Envelope envelopeRet = Envelope.parseFrom(configBlock.getData().getData(0));

Payload payload = Payload.parseFrom(envelopeRet.getPayload());

ConfigEnvelope configEnvelope = ConfigEnvelope.parseFrom(payload.getData());
return configEnvelope.getConfig().toByteArray();

} catch (Exception e) {
throw new TransactionException(e);
}

}

/**
* Get channel configuration from a specific peer
*
* @param userContext The user to sign the action.
* @param peer To retrieve the configuration from.
* @return Configuration block.
* @throws InvalidArgumentException
* @throws TransactionException
*/

public byte[] getChannelConfigurationBytes(User userContext, Peer peer) throws InvalidArgumentException, TransactionException {

try {
Block configBlock = getConfigBlock(getTransactionContext(userContext), Arrays.asList(peer));

Envelope envelopeRet = Envelope.parseFrom(configBlock.getData().getData(0));

Payload payload = Payload.parseFrom(envelopeRet.getPayload());

ConfigEnvelope configEnvelope = ConfigEnvelope.parseFrom(payload.getData());
return configEnvelope.getConfig().toByteArray();

} catch (Exception e) {
throw new TransactionException(e);
}

}

public byte[] getChannelConfigurationBytes() throws InvalidArgumentException, TransactionException {
return getChannelConfigurationBytes(client.getUserContext());
}

/**
* Channel Configuration bytes. Bytes that can be used with configtxlator tool to upgrade the channel.
* If Peers exist on the channel config block will be retrieved from them.
* If only Orderers exist the configblock is retrieved from them.
* Convert to Json for editing with:
* {@code
* <p>
Expand All @@ -2429,9 +2518,45 @@ private String[] parseEndpoint(String endPoint) throws InvalidArgumentException
* @throws TransactionException
*/

public byte[] getChannelConfigurationBytes() throws TransactionException {
public byte[] getChannelConfigurationBytes(User userContext) throws InvalidArgumentException, TransactionException {
Block configBlock = null;
try {
final Block configBlock = getConfigBlock(getShuffledPeers());

Collection<Peer> peers = getShuffledPeers();

if (!peers.isEmpty()) { // prefer peers.
configBlock = getConfigBlock(getTransactionContext(userContext), new ArrayList<>(peers));

} else { // no peers so look to orderers.

List<Orderer> shuffledOrderers = getShuffledOrderers();
if (shuffledOrderers.isEmpty()) {
throw new InvalidArgumentException(format("Channel %s has no peer or orderers defined. Can not get configuration block", name));
}
StringBuilder sb = new StringBuilder(1000);
Exception fe = null;
String sep = "";
for (Orderer orderer : shuffledOrderers) {
try {
configBlock = getConfigurationBlock(getTransactionContext(userContext), orderer);
fe = null; // looks good.
break;
} catch (Exception e) {
fe = e;
sb.append(sep).append(orderer.toString()).append("-").append(e.getMessage());
sep = ", ";

}

}
if (fe != null) {
throw new TransactionException(sb.toString(), fe);
}

}
if (configBlock == null) {
throw new TransactionException("Transaction block could not be retrieved.");
}

Envelope envelopeRet = Envelope.parseFrom(configBlock.getData().getData(0));

Expand All @@ -2446,8 +2571,9 @@ public byte[] getChannelConfigurationBytes() throws TransactionException {

}

private long getLastConfigIndex(Orderer orderer) throws TransactionException, InvalidProtocolBufferException {
Block latestBlock = getLatestBlock(orderer);
private long getLastConfigIndex(TransactionContext transactionContext, Orderer orderer) throws TransactionException, InvalidProtocolBufferException {
Block latestBlock;
latestBlock = getLatestBlock(orderer, transactionContext);

BlockMetadata blockMetadata = latestBlock.getMetadata();

Expand All @@ -2458,7 +2584,7 @@ private long getLastConfigIndex(Orderer orderer) throws TransactionException, In
return lastConfig.getIndex();
}

private Block getBlockByNumber(final long number) throws TransactionException {
private Block getBlockByNumber(TransactionContext transactionContext, Orderer orderer, final long number) throws TransactionException {

logger.trace(format("getConfigurationBlock for channel %s", name));

Expand All @@ -2480,7 +2606,7 @@ private Block getBlockByNumber(final long number) throws TransactionException {

ArrayList<DeliverResponse> deliverResponses = new ArrayList<>();

seekBlock(seekInfo, deliverResponses, getRandomOrderer());
seekBlock(transactionContext, seekInfo, deliverResponses, orderer);

DeliverResponse blockresp = deliverResponses.get(1);

Expand Down Expand Up @@ -2509,7 +2635,7 @@ private Block getBlockByNumber(final long number) throws TransactionException {

}

private int seekBlock(SeekInfo seekInfo, List<DeliverResponse> deliverResponses, Orderer ordererIn) throws TransactionException {
private int seekBlock(TransactionContext txContext, SeekInfo seekInfo, List<DeliverResponse> deliverResponses, Orderer ordererIn) throws TransactionException {

logger.trace(format("seekBlock for channel %s", name));
final long start = System.currentTimeMillis();
Expand All @@ -2524,8 +2650,6 @@ private int seekBlock(SeekInfo seekInfo, List<DeliverResponse> deliverResponses,

final Orderer orderer = ordererIn != null ? ordererIn : getRandomOrderer();

TransactionContext txContext = getTransactionContext();

DeliverResponse[] deliver = orderer.sendDeliver(createSeekInfoEnvelope(txContext, seekInfo, orderer.getClientTLSCertificateDigest()));

if (deliver.length < 1) {
Expand Down Expand Up @@ -2586,7 +2710,7 @@ private int seekBlock(SeekInfo seekInfo, List<DeliverResponse> deliverResponses,

}

private Block getLatestBlock(Orderer orderer) throws TransactionException {
private Block getLatestBlock(Orderer orderer, TransactionContext transactionContext) throws TransactionException {

logger.debug(format("getConfigurationBlock for channel %s", name));

Expand All @@ -2602,7 +2726,7 @@ private Block getLatestBlock(Orderer orderer) throws TransactionException {

ArrayList<DeliverResponse> deliverResponses = new ArrayList<>();

seekBlock(seekInfo, deliverResponses, orderer);
seekBlock(transactionContext, seekInfo, deliverResponses, orderer);

DeliverResponse blockresp = deliverResponses.get(1);

Expand Down Expand Up @@ -2978,6 +3102,13 @@ private List<Peer> getShuffledPeers(EnumSet<PeerRole> roles) {
return peers;
}

private List<Orderer> getShuffledOrderers() {

ArrayList<Orderer> orderers = new ArrayList<>(getOrderers());
Collections.shuffle(orderers);
return orderers;
}

private Orderer getRandomOrderer() throws InvalidArgumentException {

final ArrayList<Orderer> randPicks = new ArrayList<>(new HashSet<>(getOrderers())); //copy to avoid unlikely changes
Expand Down
Loading

0 comments on commit db22412

Please sign in to comment.