diff --git a/src/main/java/hlf/java/rest/client/service/impl/NetworkStatusImpl.java b/src/main/java/hlf/java/rest/client/service/impl/NetworkStatusImpl.java index 337789b..93c96d1 100644 --- a/src/main/java/hlf/java/rest/client/service/impl/NetworkStatusImpl.java +++ b/src/main/java/hlf/java/rest/client/service/impl/NetworkStatusImpl.java @@ -8,6 +8,7 @@ import hlf.java.rest.client.exception.ErrorConstants; import hlf.java.rest.client.exception.FabricTransactionException; import hlf.java.rest.client.exception.ServiceException; +import hlf.java.rest.client.model.AnchorPeerDTO; import hlf.java.rest.client.model.ChannelUpdateParamsDTO; import hlf.java.rest.client.model.ClientResponseModel; import hlf.java.rest.client.model.CommitChannelParamsDTO; @@ -15,7 +16,9 @@ import hlf.java.rest.client.service.NetworkStatus; import hlf.java.rest.client.service.UpdateChannel; import java.io.IOException; +import java.util.ArrayList; import java.util.Base64; +import java.util.List; import lombok.extern.slf4j.Slf4j; import org.hyperledger.fabric.gateway.Gateway; import org.hyperledger.fabric.gateway.Network; @@ -79,7 +82,7 @@ public ResponseEntity getChannelFromNetwork(String channelN "One or more arguments included in the config update are invalid", e); } catch (TransactionException e) { - log.warn("Error retrieving channel config: " + e.getMessage()); + log.warn("Error retrieving channel config: {} ", e.getMessage()); throw new FabricTransactionException( ErrorCode.HYPERLEDGER_FABRIC_TRANSACTION_ERROR, ErrorCode.HYPERLEDGER_FABRIC_TRANSACTION_ERROR.name(), @@ -91,7 +94,7 @@ public ResponseEntity getChannelFromNetwork(String channelN "Error while establishing connection to the gateway", e); } - log.warn("Error getting channel config: Network cannot be NULL: " + "Network = " + network); + log.warn("Error getting channel config: Network cannot be NULL: Network: {}", network); return new ResponseEntity<>( new ClientResponseModel(ErrorCode.NOT_FOUND.getValue(), ErrorCode.NOT_FOUND.name()), HttpStatus.OK); @@ -110,9 +113,8 @@ public ResponseEntity generateConfigUpdate( HttpStatus.OK); } else { log.warn( - "Error generating the Config Update: Network and User cannot be NULL: " - + "Network = " - + network); + "Error generating the Config Update: Network and User cannot be NULL: Network: {}", + network); return new ResponseEntity<>( new ClientResponseModel( ErrorCode.NOT_FOUND.getValue(), @@ -124,7 +126,7 @@ public ResponseEntity generateConfigUpdate( private ConfigUpdate createConfigUpdate( String channelName, ChannelUpdateParamsDTO organizationDetails) { Network network = gateway.getNetwork(channelName); - if (network != null) { + if (network != null && organizationDetails.getMspDTO() != null) { try { Channel selectedChannel = network.getChannel(); byte[] channelConfigBytes = selectedChannel.getChannelConfigurationBytes(); @@ -161,7 +163,7 @@ private ConfigUpdate createConfigUpdate( "Channel has no peer or orderers defined. Can not get configuration block", e); } catch (TransactionException e) { - log.warn("Error while fetching channel config: " + e.getMessage()); + log.warn("Error while fetching channel config: {} ", e.getMessage()); throw new FabricTransactionException( ErrorCode.HYPERLEDGER_FABRIC_TRANSACTION_ERROR, ErrorCode.HYPERLEDGER_FABRIC_TRANSACTION_ERROR.name(), @@ -175,7 +177,9 @@ private ConfigUpdate createConfigUpdate( } } else { log.warn( - "Error fetching the channel config: Network cannot be NULL: " + "Network = " + network); + "Error fetching the channel config: Network and MSP details cannot be NULL: Network: {} and MSP details: {} ", + network, + organizationDetails.getMspDTO()); return ConfigUpdate.newBuilder().build(); } } @@ -227,11 +231,9 @@ public ResponseEntity signChannelConfigTransaction( } } else { log.warn( - "Error while signing channel config: Network and User cannot be NULL: " - + "Network = " - + network - + "and User = " - + user); + "Error while signing channel config: Network and User cannot be NULL: Network: {} and User: {}", + network, + user); return new ResponseEntity<>( new ClientResponseModel( ErrorCode.NOT_FOUND.getValue(), @@ -287,7 +289,7 @@ public ResponseEntity commitChannelConfigTransaction( "One or more arguments included in the config update are invalid", e); } catch (TransactionException e) { - log.warn("Error while committing channel config: " + e.getMessage()); + log.warn("Error while committing channel config: {} ", e.getMessage()); throw new FabricTransactionException( ErrorCode.HYPERLEDGER_FABRIC_TRANSACTION_ERROR, ErrorCode.HYPERLEDGER_FABRIC_TRANSACTION_ERROR.name(), @@ -301,11 +303,9 @@ public ResponseEntity commitChannelConfigTransaction( } } else { log.warn( - "Error while committing channel config: Network and User cannot be NULL: " - + "Network = " - + network - + "and User = " - + user); + "Error while committing channel config: Network and User cannot be NULL: Network: {} and User:{}", + network, + user); return new ResponseEntity<>( new ClientResponseModel( ErrorCode.NOT_FOUND.getValue(), @@ -318,7 +318,7 @@ public ResponseEntity commitChannelConfigTransaction( public ResponseEntity addOrgToChannel( String channelName, ChannelUpdateParamsDTO organizationDetails) { Network network = gateway.getNetwork(channelName); - if (network != null && user != null) { + if (network != null && user != null && organizationDetails.getMspDTO() != null) { try { Channel selectedChannel = network.getChannel(); ConfigUpdate configUpdate = createConfigUpdate(channelName, organizationDetails); @@ -339,7 +339,7 @@ public ResponseEntity addOrgToChannel( "One or more arguments included in the config update are invalid", e); } catch (TransactionException e) { - log.warn("Error while committing channel config: " + e.getMessage()); + log.warn("Error while committing channel config: {} ", e.getMessage()); throw new FabricTransactionException( ErrorCode.HYPERLEDGER_FABRIC_TRANSACTION_ERROR, ErrorCode.HYPERLEDGER_FABRIC_TRANSACTION_ERROR.name(), @@ -355,15 +355,34 @@ public ResponseEntity addOrgToChannel( new ClientResponseModel(ErrorConstants.NO_ERROR, ErrorCode.SUCCESS.getReason()), HttpStatus.OK); } else { - log.warn("Network and User cannot be NULL: " + "Network = " + network + "and User = " + user); + log.warn( + "Network, User and MSP details cannot be NULL: Network: {}, User: {} and MSP details: {}", + network, + user, + organizationDetails.getMspDTO()); return new ResponseEntity<>( new ClientResponseModel( ErrorCode.NOT_FOUND.getValue(), - "Network and User cannot be NULL: " + "Network = " + network + "and User = " + user), + "Network, User and MSP details cannot be NULL: " + + "Network = " + + network + + " User = " + + user + + " and MSP details = " + + organizationDetails.getMspDTO()), HttpStatus.OK); } } + private List getAnchorPeersToAdd(ChannelUpdateParamsDTO channelUpdateParamsDTO) { + // Anchor peers are required as Host:Port + List anchorPeerList = new ArrayList<>(); + for (AnchorPeerDTO anchorPeerDTO : channelUpdateParamsDTO.getAnchorPeerDTOs()) { + anchorPeerList.add(anchorPeerDTO.getHostname() + ":" + anchorPeerDTO.getPort()); + } + return anchorPeerList; + } + @Override public ResponseEntity addAnchorPeersToChannel( String channelName, ChannelUpdateParamsDTO channelUpdateParamsDTO) { @@ -371,16 +390,16 @@ public ResponseEntity addAnchorPeersToChannel( if (network != null && user != null) { try { Channel selectedChannel = network.getChannel(); - ConfigUpdate configUpdate = createConfigUpdate(channelName, channelUpdateParamsDTO); - String channelConfigString = JsonFormat.printer().print(configUpdate); - log.info(channelConfigDeserialization.deserializeValueFields(channelConfigString)); - UpdateChannelConfiguration updateChannelConfiguration = new UpdateChannelConfiguration(); - updateChannelConfiguration.setUpdateChannelConfiguration( - configUpdate.toByteString().toByteArray()); + Channel.AnchorPeersConfigUpdateResult configUpdateAnchorPeers = + selectedChannel.getConfigUpdateAnchorPeers( + selectedChannel.getPeers().iterator().next(), + user, + getAnchorPeersToAdd(channelUpdateParamsDTO), + null); selectedChannel.updateChannelConfiguration( - updateChannelConfiguration, + configUpdateAnchorPeers.getUpdateChannelConfiguration(), selectedChannel.getUpdateChannelConfigurationSignature( - updateChannelConfiguration, user)); + configUpdateAnchorPeers.getUpdateChannelConfiguration(), user)); } catch (InvalidArgumentException e) { log.warn( "Error while committing channel config: One or more arguments included in the config update are invalid"); @@ -389,23 +408,23 @@ public ResponseEntity addAnchorPeersToChannel( "One or more arguments included in the config update are invalid", e); } catch (TransactionException e) { - log.warn("Error while committing channel config: " + e.getMessage()); + log.warn("Error while committing channel config: {}", e.getMessage()); throw new FabricTransactionException( ErrorCode.HYPERLEDGER_FABRIC_TRANSACTION_ERROR, ErrorCode.HYPERLEDGER_FABRIC_TRANSACTION_ERROR.name(), e); - } catch (IOException e) { - log.warn("Error while establishing connection to the gateway"); - throw new ServiceException( - ErrorCode.HYPERLEDGER_FABRIC_CONNECTION_ERROR, - "Error while establishing connection to the gateway", + } catch (Exception e) { + log.warn("Error while channel configuration update: {}", e.getMessage()); + throw new FabricTransactionException( + ErrorCode.HYPERLEDGER_FABRIC_TRANSACTION_ERROR, + ErrorCode.HYPERLEDGER_FABRIC_TRANSACTION_ERROR.name(), e); } return new ResponseEntity<>( new ClientResponseModel(ErrorConstants.NO_ERROR, ErrorCode.SUCCESS.getReason()), HttpStatus.OK); } else { - log.warn("Network and User cannot be NULL: " + "Network = " + network + "and User = " + user); + log.warn("Network and User cannot be NULL: Network: {} and User: {}", network, user); return new ResponseEntity<>( new ClientResponseModel( ErrorCode.NOT_FOUND.getValue(), diff --git a/src/main/java/hlf/java/rest/client/service/impl/UpdateChannelImpl.java b/src/main/java/hlf/java/rest/client/service/impl/UpdateChannelImpl.java index aceafcd..23ee742 100644 --- a/src/main/java/hlf/java/rest/client/service/impl/UpdateChannelImpl.java +++ b/src/main/java/hlf/java/rest/client/service/impl/UpdateChannelImpl.java @@ -32,42 +32,21 @@ public ConfigGroup buildWriteset(ConfigGroup readset, ChannelUpdateParamsDTO org Map existingOrganizations = FabricChannelUtil.getExistingOrgsFromReadset(readset); - ConfigGroup applicationGroup; - - if (organizationDetails.getMspDTO() != null) { - // New org addition scenario - // The "Application" group - applicationGroup = - ConfigGroup.newBuilder() - .setModPolicy(FabricClientConstants.CHANNEL_CONFIG_MOD_POLICY_ADMINS) - .putAllPolicies(FabricChannelUtil.setApplicationPolicies(readset)) - .putGroups(newOrgMspId, setNewOrgGroup(newOrgMspId, organizationDetails)) - // putAllGroups excludes new organization - .putAllGroups(existingOrganizations) - // Application group version - .setVersion( - FabricChannelUtil.retrieveMSPGroupVersionFromReadset( - readset, FabricClientConstants.CHANNEL_CONFIG_GROUP_APPLICATION) - + 1) // will be tied to current version + 1 for this level - .build(); - } else { - // The "Application" group - applicationGroup = - ConfigGroup.newBuilder() - .setModPolicy(FabricClientConstants.CHANNEL_CONFIG_MOD_POLICY_ADMINS) - .putAllPolicies(FabricChannelUtil.setApplicationPolicies(readset)) - .putGroups( - newOrgMspId, setAnchorPeerInGroup(newOrgMspId, readset, organizationDetails)) - // putAllGroups excludes new organization - .putAllGroups(existingOrganizations) - // Application group version - .setVersion( - FabricChannelUtil.retrieveMSPGroupVersionFromReadset( - readset, FabricClientConstants.CHANNEL_CONFIG_GROUP_APPLICATION) - + 1) // will be tied to current version + 1 for this level - .build(); - } - + // New org addition scenario + // The "Application" group + ConfigGroup applicationGroup = + ConfigGroup.newBuilder() + .setModPolicy(FabricClientConstants.CHANNEL_CONFIG_MOD_POLICY_ADMINS) + .putAllPolicies(FabricChannelUtil.setApplicationPolicies(readset)) + .putGroups(newOrgMspId, setNewOrgGroup(newOrgMspId, organizationDetails)) + // putAllGroups excludes new organization + .putAllGroups(existingOrganizations) + // Application group version + .setVersion( + FabricChannelUtil.retrieveMSPGroupVersionFromReadset( + readset, FabricClientConstants.CHANNEL_CONFIG_GROUP_APPLICATION) + + 1) // will be tied to current version + 1 for this level + .build(); // the "/Channel" group return ConfigGroup.newBuilder() .putGroups(FabricClientConstants.CHANNEL_CONFIG_GROUP_APPLICATION, applicationGroup) diff --git a/src/test/java/hlf/java/rest/client/service/impl/NetworkStatusImplTest.java b/src/test/java/hlf/java/rest/client/service/impl/NetworkStatusImplTest.java index eafdc55..eaefa11 100644 --- a/src/test/java/hlf/java/rest/client/service/impl/NetworkStatusImplTest.java +++ b/src/test/java/hlf/java/rest/client/service/impl/NetworkStatusImplTest.java @@ -13,8 +13,10 @@ import hlf.java.rest.client.model.ChannelUpdateParamsDTO; import hlf.java.rest.client.model.ClientResponseModel; import hlf.java.rest.client.model.CommitChannelParamsDTO; +import hlf.java.rest.client.model.MSPDTO; import hlf.java.rest.client.service.ChannelConfigDeserialization; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.hyperledger.fabric.gateway.Network; import org.hyperledger.fabric.gateway.impl.GatewayImpl; @@ -24,6 +26,7 @@ import org.hyperledger.fabric.protos.common.Configtx.ConfigUpdate.Builder; import org.hyperledger.fabric.sdk.Channel; import org.hyperledger.fabric.sdk.HFClient; +import org.hyperledger.fabric.sdk.Peer; import org.hyperledger.fabric.sdk.UpdateChannelConfiguration; import org.hyperledger.fabric.sdk.User; import org.hyperledger.fabric.sdk.exception.InvalidArgumentException; @@ -48,8 +51,10 @@ public class NetworkStatusImplTest { @Mock private Network network; @Mock private Channel channel; + @Mock private Peer peer; @Mock private Config channelConfig; + @Mock Channel.AnchorPeersConfigUpdateResult anchorPeersConfigUpdateResult; @Mock private MockedStatic staticConfig; @@ -68,6 +73,7 @@ public class NetworkStatusImplTest { @Mock private ConfigGroup readset; @Mock private ConfigGroup writeset; + @Mock private MSPDTO mspdto; @Mock private Builder builder; @@ -78,6 +84,7 @@ public class NetworkStatusImplTest { @Mock private Parser parser; @Mock private UpdateChannelConfiguration updateChannelConfiguration; + @Mock private ChannelUpdateParamsDTO channelUpdateParamsDTO; @Mock private ByteString byteString; @@ -101,26 +108,15 @@ public void getChannelFromNetworkTest() } @Test - public void generateConfigUpdateTest() - throws InvalidProtocolBufferException, InvalidArgumentException, TransactionException { + public void generateConfigUpdateTest() throws InvalidProtocolBufferException { ResponseEntity responseEntity = new ResponseEntity<>( new ClientResponseModel(ErrorConstants.NO_ERROR, "dGhlX2NvbmZpZw=="), HttpStatus.OK); Mockito.when(gateway.getNetwork(Mockito.anyString())).thenReturn(network); - Mockito.when(network.getChannel()).thenReturn(channel); - - Mockito.when(channel.getChannelConfigurationBytes()).thenReturn(new byte[0]); staticConfigUpdate .when(() -> ConfigUpdate.parseFrom(Mockito.any(byte[].class))) .thenReturn(configUpdate); staticConfigUpdate.when(() -> ConfigUpdate.newBuilder()).thenReturn(builder); - Mockito.when(configUpdate.getReadSet()).thenReturn(readset); - Mockito.when(builder.setChannelId(Mockito.anyString())).thenReturn(builder); - Mockito.when(builder.setReadSet(Mockito.any(ConfigGroup.class))).thenReturn(builder); - Mockito.when( - updateChannel.buildWriteset(Mockito.any(), Mockito.any(ChannelUpdateParamsDTO.class))) - .thenReturn(readset); - Mockito.when(builder.setWriteSet(Mockito.any(ConfigGroup.class))).thenReturn(builder); Mockito.when(builder.build()).thenReturn(configUpdate); staticJsonFormat.when(JsonFormat::printer).thenReturn(printer); Mockito.when(printer.print(Mockito.any(MessageOrBuilder.class))).thenReturn("the_config"); @@ -196,7 +192,6 @@ public void addOrgToChannelTest() throws InvalidArgumentException, TransactionEx Mockito.when(gateway.getNetwork(Mockito.anyString())).thenReturn(network); Mockito.when(network.getChannel()).thenReturn(channel); - Mockito.when(channel.getChannelConfigurationBytes()).thenReturn(new byte[0]); staticConfigUpdate .when(() -> ConfigUpdate.parseFrom(Mockito.any(byte[].class))) @@ -219,18 +214,18 @@ public void addOrgToChannelTest() throws InvalidArgumentException, TransactionEx Mockito.any(UpdateChannelConfiguration.class), Mockito.any(User.class))) .thenReturn(outputByteArray); + Mockito.when(channelUpdateParamsDTO.getMspDTO()).thenReturn(mspdto); + assertEquals( responseEntity.getBody().getMessage(), networkStatus - .addOrgToChannel("some_channel_name", new ChannelUpdateParamsDTO()) + .addOrgToChannel("some_channel_name", channelUpdateParamsDTO) .getBody() .getMessage()); } @Test - public void addAnchorPeersToChannelTest() - throws InvalidArgumentException, TransactionException, InvalidProtocolBufferException { - byte[] outputByteArray = new byte[0]; + public void addAnchorPeersToChannelTest() throws Exception { ResponseEntity responseEntity = new ResponseEntity<>( new ClientResponseModel(ErrorConstants.NO_ERROR, ErrorCode.SUCCESS.getReason()), @@ -238,34 +233,16 @@ public void addAnchorPeersToChannelTest() Mockito.when(gateway.getNetwork(Mockito.anyString())).thenReturn(network); Mockito.when(network.getChannel()).thenReturn(channel); - - Mockito.when(channel.getChannelConfigurationBytes()).thenReturn(new byte[0]); - staticConfigUpdate - .when(() -> ConfigUpdate.parseFrom(Mockito.any(byte[].class))) - .thenReturn(configUpdate); - staticConfigUpdate.when(() -> ConfigUpdate.newBuilder()).thenReturn(builder); - Mockito.when(configUpdate.getReadSet()).thenReturn(readset); - Mockito.when(builder.setChannelId(Mockito.anyString())).thenReturn(builder); - Mockito.when(builder.setReadSet(Mockito.any(ConfigGroup.class))).thenReturn(builder); - Mockito.doReturn(writeset) - .when(updateChannel) - .buildWriteset(Mockito.any(), Mockito.any(ChannelUpdateParamsDTO.class)); - Mockito.when(builder.setWriteSet(writeset)).thenReturn(builder); - Mockito.when(builder.build()).thenReturn(configUpdate); - staticJsonFormat.when(JsonFormat::printer).thenReturn(printer); - Mockito.when(printer.print(Mockito.any(MessageOrBuilder.class))).thenReturn("the_config"); - Mockito.when(configUpdate.toByteString()).thenReturn(byteString); - Mockito.when(byteString.toByteArray()).thenReturn(new byte[1]); - Mockito.when(builder.build()).thenReturn(configUpdate); + Mockito.when(channel.getPeers()).thenReturn(Collections.singleton(peer)); Mockito.when( - channel.getUpdateChannelConfigurationSignature( - Mockito.any(UpdateChannelConfiguration.class), Mockito.any(User.class))) - .thenReturn(outputByteArray); + channel.getConfigUpdateAnchorPeers( + Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(anchorPeersConfigUpdateResult); assertEquals( responseEntity.getBody().getMessage(), networkStatus - .addAnchorPeersToChannel("some_channel_name", new ChannelUpdateParamsDTO()) + .addAnchorPeersToChannel("some_channel_name", channelUpdateParamsDTO) .getBody() .getMessage()); }