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

fix: cherry-pick: FileService address book and node details should be updated at genesis #17368

Open
wants to merge 1 commit into
base: release/0.58
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023-2024 Hedera Hashgraph, LLC
* Copyright (C) 2023-2025 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -133,7 +133,8 @@ public SystemSetup(
*/
public void doGenesisSetup(@NonNull final Dispatch dispatch) {
final var systemContext = systemContextFor(dispatch);
fileService.createSystemEntities(systemContext);
final var nodeStore = dispatch.handleContext().storeFactory().readableStore(ReadableNodeStore.class);
fileService.createSystemEntities(systemContext, nodeStore);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@
import com.hedera.node.app.ids.EntityIdService;
import com.hedera.node.app.info.NodeInfoImpl;
import com.hedera.node.app.records.BlockRecordService;
import com.hedera.node.app.service.addressbook.AddressBookService;
import com.hedera.node.app.service.addressbook.ReadableNodeStore;
import com.hedera.node.app.service.addressbook.impl.AddressBookServiceImpl;
import com.hedera.node.app.service.addressbook.impl.ReadableNodeStoreImpl;
import com.hedera.node.app.service.consensus.impl.ConsensusServiceImpl;
import com.hedera.node.app.service.contract.impl.ContractServiceImpl;
import com.hedera.node.app.service.file.FileService;
Expand Down Expand Up @@ -283,8 +286,10 @@ private State genesisState(@NonNull final Map<String, String> overrides) {
NO_OP_METRICS,
startupNetworks);
final var writableStates = state.getWritableStates(FileService.NAME);
final var readableStates = state.getReadableStates(AddressBookService.NAME);
final var nodeStore = new ReadableNodeStoreImpl(readableStates);
final var files = writableStates.<FileID, File>get(V0490FileSchema.BLOBS_KEY);
genesisContentProviders(networkInfo, config).forEach((fileNum, provider) -> {
genesisContentProviders(nodeStore, config).forEach((fileNum, provider) -> {
final var fileId = createFileID(fileNum, config);
files.put(
fileId,
Expand All @@ -299,12 +304,12 @@ private State genesisState(@NonNull final Map<String, String> overrides) {
}

private Map<Long, Function<Configuration, Bytes>> genesisContentProviders(
@NonNull final NetworkInfo networkInfo, @NonNull final Configuration config) {
@NonNull final ReadableNodeStore nodeStore, @NonNull final Configuration config) {
final var genesisSchema = new V0490FileSchema();
final var filesConfig = config.getConfigData(FilesConfig.class);
return Map.of(
filesConfig.addressBook(), ignore -> genesisSchema.genesisAddressBook(networkInfo),
filesConfig.nodeDetails(), ignore -> genesisSchema.genesisNodeDetails(networkInfo),
filesConfig.addressBook(), ignore -> genesisSchema.nodeStoreAddressBook(nodeStore),
filesConfig.nodeDetails(), ignore -> genesisSchema.nodeStoreNodeDetails(nodeStore),
filesConfig.feeSchedules(), genesisSchema::genesisFeeSchedules,
filesConfig.exchangeRates(), genesisSchema::genesisExchangeRates,
filesConfig.networkProperties(), genesisSchema::genesisNetworkProperties,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020-2024 Hedera Hashgraph, LLC
* Copyright (C) 2020-2025 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -49,12 +49,13 @@ public void registerSchemas(@NonNull final SchemaRegistry registry) {
}

/**
* Creates the system files in the given genesis context.
* Creates the system files in the given genesis context and the nodeStore data.
*
* @param context the genesis context
* @param nodeStore the ReadableNodeStore
*/
public void createSystemEntities(@NonNull final SystemContext context) {
fileSchema.createGenesisAddressBookAndNodeDetails(context);
public void createSystemEntities(@NonNull final SystemContext context, @NonNull final ReadableNodeStore nodeStore) {
fileSchema.createGenesisAddressBookAndNodeDetails(context, nodeStore);
fileSchema.createGenesisFeeSchedule(context);
fileSchema.createGenesisExchangeRate(context);
fileSchema.createGenesisNetworkProperties(context);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022-2024 Hedera Hashgraph, LLC
* Copyright (C) 2022-2025 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -34,6 +34,7 @@
import com.hedera.hapi.node.transaction.Response;
import com.hedera.node.app.hapi.utils.CommonPbjConverters;
import com.hedera.node.app.hapi.utils.fee.FileFeeBuilder;
import com.hedera.node.app.service.addressbook.ReadableNodeStore;
import com.hedera.node.app.service.file.ReadableFileStore;
import com.hedera.node.app.service.file.impl.base.FileQueryBase;
import com.hedera.node.app.service.file.impl.schemas.V0490FileSchema;
Expand All @@ -45,7 +46,6 @@
import com.hederahashgraph.api.proto.java.FeeData;
import com.hederahashgraph.api.proto.java.ResponseType;
import com.swirlds.config.api.Configuration;
import com.swirlds.state.lifecycle.info.NetworkInfo;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.util.Map;
Expand All @@ -60,20 +60,16 @@
public class FileGetContentsHandler extends FileQueryBase {
private final FileFeeBuilder usageEstimator;
private final V0490FileSchema genesisSchema;
private final NetworkInfo networkInfo;

/**
* Constructs a {@link FileGetContentsHandler} with the given {@link FileFeeBuilder}.
* @param usageEstimator the file fee builder to be used for fee calculation
*/
@Inject
public FileGetContentsHandler(
@NonNull final FileFeeBuilder usageEstimator,
@NonNull final V0490FileSchema genesisSchema,
@NonNull final NetworkInfo networkInfo) {
@NonNull final FileFeeBuilder usageEstimator, @NonNull final V0490FileSchema genesisSchema) {
this.usageEstimator = requireNonNull(usageEstimator);
this.genesisSchema = requireNonNull(genesisSchema);
this.networkInfo = networkInfo;
}

@Override
Expand Down Expand Up @@ -102,10 +98,11 @@ public void validate(@NonNull final QueryContext context) throws PreCheckExcepti
public @NonNull Fees computeFees(@NonNull QueryContext queryContext) {
final var query = queryContext.query();
final var fileStore = queryContext.createStore(ReadableFileStore.class);
final var nodeStore = queryContext.createStore(ReadableNodeStore.class);
final var op = query.fileGetContentsOrThrow();
final var fileId = op.fileIDOrElse(FileID.DEFAULT);
final var responseType = op.headerOrElse(QueryHeader.DEFAULT).responseType();
final FileContents fileContents = contentFile(fileId, fileStore, queryContext.configuration());
final FileContents fileContents = contentFile(fileId, fileStore, queryContext.configuration(), nodeStore);
return queryContext
.feeCalculator()
.legacyCalculate(sigValueObj ->
Expand All @@ -117,14 +114,15 @@ public void validate(@NonNull final QueryContext context) throws PreCheckExcepti
requireNonNull(header);
final var query = context.query();
final var fileStore = context.createStore(ReadableFileStore.class);
final var nodeStore = context.createStore(ReadableNodeStore.class);
final var op = query.fileGetContentsOrThrow();
final var responseBuilder = FileGetContentsResponse.newBuilder();
final var fileId = op.fileIDOrThrow();

final var responseType = op.headerOrElse(QueryHeader.DEFAULT).responseType();
responseBuilder.header(header);
if (header.nodeTransactionPrecheckCode() == OK && responseType != COST_ANSWER) {
final var content = contentFile(fileId, fileStore, context.configuration());
final var content = contentFile(fileId, fileStore, context.configuration(), nodeStore);
if (content == null) {
responseBuilder.header(header.copyBuilder()
.nodeTransactionPrecheckCode(INVALID_FILE_ID)
Expand All @@ -143,18 +141,20 @@ public void validate(@NonNull final QueryContext context) throws PreCheckExcepti
* @param fileID the file to get information about
* @param fileStore the file store
* @param config the configuration
* @param nodeStore the ReadableNodeStore
* @return the content about the file
*/
private @Nullable FileContents contentFile(
@NonNull final FileID fileID,
@NonNull final ReadableFileStore fileStore,
@NonNull final Configuration config) {
@NonNull final Configuration config,
@NonNull final ReadableNodeStore nodeStore) {
final var meta = fileStore.getFileMetadata(fileID);
if (meta == null) {
if (notGenesisCreation(fileID, config)) {
return null;
} else {
final var genesisContent = genesisContentProviders(config)
final var genesisContent = genesisContentProviders(config, nodeStore)
.getOrDefault(fileID.fileNum(), ignore -> EMPTY)
.apply(config);
return new FileContents(fileID, genesisContent);
Expand All @@ -167,11 +167,12 @@ public void validate(@NonNull final QueryContext context) throws PreCheckExcepti
}
}

private Map<Long, Function<Configuration, Bytes>> genesisContentProviders(@NonNull final Configuration config) {
private Map<Long, Function<Configuration, Bytes>> genesisContentProviders(
@NonNull final Configuration config, @NonNull final ReadableNodeStore nodeStore) {
final var filesConfig = config.getConfigData(FilesConfig.class);
return Map.of(
filesConfig.addressBook(), ignore -> genesisSchema.genesisAddressBook(networkInfo),
filesConfig.nodeDetails(), ignore -> genesisSchema.genesisNodeDetails(networkInfo),
filesConfig.addressBook(), ignore -> genesisSchema.nodeStoreAddressBook(nodeStore),
filesConfig.nodeDetails(), ignore -> genesisSchema.nodeStoreNodeDetails(nodeStore),
filesConfig.feeSchedules(), genesisSchema::genesisFeeSchedules,
filesConfig.exchangeRates(), genesisSchema::genesisExchangeRates,
filesConfig.networkProperties(), genesisSchema::genesisNetworkProperties,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
import com.hedera.hapi.node.transaction.ThrottleDefinitions;
import com.hedera.hapi.node.transaction.TransactionBody;
import com.hedera.node.app.service.addressbook.ReadableNodeStore;
import com.hedera.node.app.service.addressbook.impl.schemas.V053AddressBookSchema;
import com.hedera.node.app.spi.workflows.SystemContext;
import com.hedera.node.config.ConfigProvider;
import com.hedera.node.config.data.BootstrapConfig;
Expand All @@ -64,8 +63,6 @@
import com.swirlds.state.lifecycle.MigrationContext;
import com.swirlds.state.lifecycle.Schema;
import com.swirlds.state.lifecycle.StateDefinition;
import com.swirlds.state.lifecycle.info.NetworkInfo;
import com.swirlds.state.lifecycle.info.NodeInfo;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.io.ByteArrayInputStream;
Expand Down Expand Up @@ -166,9 +163,9 @@ public void migrate(@NonNull final MigrationContext ctx) {
// ================================================================================================================
// Creates and loads the Address Book into state

public void createGenesisAddressBookAndNodeDetails(@NonNull final SystemContext systemContext) {
public void createGenesisAddressBookAndNodeDetails(
@NonNull final SystemContext systemContext, @NonNull final ReadableNodeStore nodeStore) {
requireNonNull(systemContext);
final var networkInfo = systemContext.networkInfo();
final var filesConfig = systemContext.configuration().getConfigData(FilesConfig.class);
final var bootstrapConfig = systemContext.configuration().getConfigData(BootstrapConfig.class);

Expand All @@ -184,7 +181,7 @@ public void createGenesisAddressBookAndNodeDetails(@NonNull final SystemContext
systemContext.dispatchCreation(
TransactionBody.newBuilder()
.fileCreate(FileCreateTransactionBody.newBuilder()
.contents(genesisAddressBook(networkInfo))
.contents(nodeStoreAddressBook(nodeStore))
.keys(masterKey)
.expirationTime(maxLifetimeExpiry(systemContext))
.build())
Expand All @@ -195,44 +192,14 @@ public void createGenesisAddressBookAndNodeDetails(@NonNull final SystemContext
systemContext.dispatchCreation(
TransactionBody.newBuilder()
.fileCreate(FileCreateTransactionBody.newBuilder()
.contents(genesisNodeDetails(networkInfo))
.contents(nodeStoreNodeDetails(nodeStore))
.keys(masterKey)
.expirationTime(maxLifetimeExpiry(systemContext))
.build())
.build(),
nodeInfoFileNum);
}

public Bytes genesisAddressBook(@NonNull final NetworkInfo networkInfo) {
final var nodeAddresses = networkInfo.addressBook().stream()
.sorted(Comparator.comparingLong(NodeInfo::nodeId))
.map(nodeInfo -> NodeAddress.newBuilder()
.nodeId(nodeInfo.nodeId())
.nodeAccountId(nodeInfo.accountId())
.rsaPubKey(nodeInfo.hexEncodedPublicKey())
.serviceEndpoint(V053AddressBookSchema.endpointFor("1.0.0.0", 1))
.build())
.toList();
return NodeAddressBook.PROTOBUF.toBytes(
NodeAddressBook.newBuilder().nodeAddress(nodeAddresses).build());
}

public Bytes genesisNodeDetails(@NonNull final NetworkInfo networkInfo) {
final var nodeDetails = networkInfo.addressBook().stream()
.sorted(Comparator.comparingLong(NodeInfo::nodeId))
.map(nodeInfo -> NodeAddress.newBuilder()
.stake(nodeInfo.weight())
.nodeAccountId(nodeInfo.accountId())
.nodeId(nodeInfo.nodeId())
.rsaPubKey(nodeInfo.hexEncodedPublicKey())
.serviceEndpoint(V053AddressBookSchema.endpointFor("1.0.0.0", 1))
.build())
.toList();

return NodeAddressBook.PROTOBUF.toBytes(
NodeAddressBook.newBuilder().nodeAddress(nodeDetails).build());
}

public void updateAddressBookAndNodeDetailsAfterFreeze(
@NonNull final SystemContext systemContext, @NonNull final ReadableNodeStore nodeStore) {
requireNonNull(systemContext);
Expand Down Expand Up @@ -262,7 +229,7 @@ public static void dispatchSynthFileUpdate(
.build()));
}

private Bytes nodeStoreNodeDetails(@NonNull final ReadableNodeStore nodeStore) {
public Bytes nodeStoreNodeDetails(@NonNull final ReadableNodeStore nodeStore) {
final var nodeDetails = new ArrayList<NodeAddress>();
StreamSupport.stream(Spliterators.spliterator(nodeStore.keys(), nodeStore.sizeOfState(), DISTINCT), false)
.mapToLong(EntityNumber::number)
Expand All @@ -288,7 +255,7 @@ private Bytes getHexStringBytesFromBytes(final Bytes rawBytes) {
return Bytes.wrap(Normalizer.normalize(hexString, Normalizer.Form.NFD).getBytes(UTF_8));
}

private Bytes nodeStoreAddressBook(@NonNull final ReadableNodeStore nodeStore) {
public Bytes nodeStoreAddressBook(@NonNull final ReadableNodeStore nodeStore) {
final var nodeAddresses = new ArrayList<NodeAddress>();
StreamSupport.stream(Spliterators.spliterator(nodeStore.keys(), nodeStore.sizeOfState(), DISTINCT), false)
.mapToLong(EntityNumber::number)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@
requires transitive com.hedera.node.app.spi;
requires transitive com.hedera.node.config;
requires transitive com.hedera.node.hapi;
requires transitive com.hedera.pbj.runtime;
requires transitive com.swirlds.config.api;
requires transitive com.swirlds.state.api;
requires transitive com.hedera.pbj.runtime;
requires transitive dagger;
requires transitive static java.compiler; // javax.annotation.processing.Generated
requires transitive java.compiler; // javax.annotation.processing.Generated
requires transitive javax.inject;
requires com.hedera.node.app.service.addressbook.impl;
requires com.swirlds.common;
requires com.fasterxml.jackson.databind;
requires com.google.protobuf;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023-2024 Hedera Hashgraph, LLC
* Copyright (C) 2023-2025 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -49,7 +49,6 @@
import com.hedera.node.app.spi.workflows.QueryContext;
import com.hedera.node.config.data.FilesConfig;
import com.hedera.pbj.runtime.io.buffer.Bytes;
import com.swirlds.state.lifecycle.info.NetworkInfo;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
Expand All @@ -68,14 +67,11 @@ class FileGetContentsHandlerTest extends FileTestBase {
@Mock
private V0490FileSchema genesisSchema;

@Mock
private NetworkInfo networkInfo;

private FileGetContentsHandler subject;

@BeforeEach
void setUp() {
subject = new FileGetContentsHandler(usageEstimator, genesisSchema, networkInfo);
subject = new FileGetContentsHandler(usageEstimator, genesisSchema);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2024 Hedera Hashgraph, LLC
* Copyright (C) 2024-2025 Hedera Hashgraph, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -44,4 +44,19 @@ private GroupingVerbs() {
public static SysFileLookups getSystemFiles(@NonNull final Consumer<Map<FileID, Bytes>> observer) {
return new SysFileLookups(fileNum -> true, observer);
}

/**
* Returns a utility operation to retrieve the contents of specific system files and pass them to an observer.
*
* @param sysfileNub the system file number
* @param observer the consumer of the system file contents
* @return the utility operation
*/
public static SysFileLookups getSystemFiles(final long sysfileNub, @NonNull final Consumer<Bytes> observer) {
final Consumer<Map<FileID, Bytes>> temp = map -> {
final Bytes contents = map.get(new FileID(0, 0, sysfileNub));
observer.accept(contents);
};
return new SysFileLookups(fileNum -> fileNum == sysfileNub, temp);
}
}
Loading
Loading