Skip to content

Commit

Permalink
Implement MirrorNodeState
Browse files Browse the repository at this point in the history
Signed-off-by: Bilyana Gospodinova <[email protected]>
  • Loading branch information
bilyana-gospodinova committed Nov 5, 2024
1 parent 1df049c commit dda0c80
Show file tree
Hide file tree
Showing 8 changed files with 974 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2024 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.hedera.mirror.web3.state;

import com.hedera.mirror.web3.state.utils.MapReadableStates;
import com.hedera.mirror.web3.state.utils.MapWritableKVState;
import com.hedera.mirror.web3.state.utils.MapWritableStates;
import com.hedera.node.app.service.contract.ContractService;
import com.hedera.node.app.service.file.FileService;
import com.hedera.node.app.service.token.TokenService;
import com.swirlds.state.State;
import com.swirlds.state.spi.ReadableKVState;
import com.swirlds.state.spi.ReadableStates;
import com.swirlds.state.spi.WritableStates;
import jakarta.annotation.Nonnull;
import jakarta.inject.Named;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Named
public class MirrorNodeState implements State {
private final Map<String, ReadableKVState<?, ?>> tokenReadableServiceStates = new HashMap<>();
private final Map<String, ReadableKVState<?, ?>> contractReadableServiceStates = new HashMap<>();
private final Map<String, ReadableKVState<?, ?>> fileReadableServiceStates = new HashMap<>();

private final Map<String, ReadableStates> readableStates = new ConcurrentHashMap<>();

public MirrorNodeState(
final AccountReadableKVState accountReadableKVState,
final AirdropsReadableKVState airdropsReadableKVState,
final AliasesReadableKVState aliasesReadableKVState,
final ContractBytecodeReadableKVState contractBytecodeReadableKVState,
final ContractStorageReadableKVState contractStorageReadableKVState,
final FileReadableKVState fileReadableKVState,
final NftReadableKVState nftReadableKVState,
final TokenReadableKVState tokenReadableKVState,
final TokenRelationshipReadableKVState tokenRelationshipReadableKVState) {

tokenReadableServiceStates.put("ACCOUNTS", accountReadableKVState);
tokenReadableServiceStates.put("PENDING_AIRDROPS", airdropsReadableKVState);
tokenReadableServiceStates.put("ALIASES", aliasesReadableKVState);
tokenReadableServiceStates.put("NFTS", nftReadableKVState);
tokenReadableServiceStates.put("TOKENS", tokenReadableKVState);
tokenReadableServiceStates.put("TOKEN_RELS", tokenRelationshipReadableKVState);

contractReadableServiceStates.put("BYTECODE", contractBytecodeReadableKVState);
contractReadableServiceStates.put("STORAGE", contractStorageReadableKVState);

fileReadableServiceStates.put("FILES", fileReadableKVState);
}

@Nonnull
@Override
public ReadableStates getReadableStates(@Nonnull String serviceName) {
return readableStates.computeIfAbsent(serviceName, s -> {
switch (s) {
case TokenService.NAME -> {
return new MapReadableStates(tokenReadableServiceStates);
}
case ContractService.NAME -> {
return new MapReadableStates(contractReadableServiceStates);
}
case FileService.NAME -> {
return new MapReadableStates(fileReadableServiceStates);
}
default -> {
return new MapReadableStates(Collections.emptyMap());
}
}
});
}

@Nonnull
@Override
public WritableStates getWritableStates(@Nonnull String serviceName) {
return switch (serviceName) {
case TokenService.NAME -> new MapWritableStates(getWritableStates(tokenReadableServiceStates));
case ContractService.NAME -> new MapWritableStates(getWritableStates(contractReadableServiceStates));
case FileService.NAME -> new MapWritableStates(getWritableStates(fileReadableServiceStates));
default -> new MapWritableStates(Collections.emptyMap());
};
}

private Map<String, ?> getWritableStates(final Map<String, ReadableKVState<?, ?>> readableStates) {
final Map<String, Object> data = new HashMap<>();
readableStates.forEach(((s, readableKVState) ->
data.put(s, new MapWritableKVState<>(readableKVState.getStateKey(), readableKVState))));
return data;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright (C) 2024 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.hedera.mirror.web3.state.utils;

import com.swirlds.state.spi.ReadableKVState;
import com.swirlds.state.spi.ReadableQueueState;
import com.swirlds.state.spi.ReadableSingletonState;
import com.swirlds.state.spi.ReadableStates;
import jakarta.annotation.Nonnull;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

@SuppressWarnings("unchecked")
public class MapReadableStates implements ReadableStates {

private final Map<String, ?> states;

public MapReadableStates(@Nonnull final Map<String, ?> states) {
this.states = Objects.requireNonNull(states);
}

@Nonnull
@Override
public <K, V> ReadableKVState<K, V> get(@Nonnull String stateKey) {
final var state = states.get(Objects.requireNonNull(stateKey));
if (state == null) {
throw new IllegalArgumentException("Unknown k/v state key: " + stateKey);
}
if (!(state instanceof ReadableKVState)) {
throw new IllegalArgumentException("State is not an instance of ReadableKVState: " + stateKey);
}

return (ReadableKVState<K, V>) state;
}

@Nonnull
@Override
public <T> ReadableSingletonState<T> getSingleton(@Nonnull String stateKey) {
final var state = states.get(Objects.requireNonNull(stateKey));
if (state == null) {
throw new IllegalArgumentException("Unknown singleton state key: " + stateKey);
}

if (!(state instanceof ReadableSingletonState)) {
throw new IllegalArgumentException("State is not an instance of ReadableSingletonState: " + stateKey);
}

return (ReadableSingletonState<T>) state;
}

@Nonnull
@Override
public <E> ReadableQueueState<E> getQueue(@Nonnull String stateKey) {
final var state = states.get(Objects.requireNonNull(stateKey));
if (state == null) {
throw new IllegalArgumentException("Unknown queue state key: " + stateKey);
}

if (!(state instanceof ReadableQueueState)) {
throw new IllegalArgumentException("State is not an instance of ReadableQueueState: " + stateKey);
}

return (ReadableQueueState<E>) state;
}

@Override
public boolean contains(@Nonnull String stateKey) {
return states.containsKey(stateKey);
}

@Nonnull
@Override
public Set<String> stateKeys() {
return Collections.unmodifiableSet(states.keySet());
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MapReadableStates that = (MapReadableStates) o;
return Objects.equals(states, that.states);
}

@Override
public int hashCode() {
return Objects.hash(states);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (C) 2024 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.hedera.mirror.web3.state.utils;

import com.swirlds.state.spi.ReadableKVState;
import com.swirlds.state.spi.WritableKVStateBase;
import jakarta.annotation.Nonnull;
import java.util.Collections;
import java.util.Iterator;
import java.util.Objects;

public class MapWritableKVState<K, V> extends WritableKVStateBase<K, V> {

private final ReadableKVState<K, V> readableKVState;

public MapWritableKVState(@Nonnull String stateKey, @Nonnull ReadableKVState<K, V> readableKVState) {
super(stateKey);
this.readableKVState = readableKVState;
}

// The readable state's values are immutable, hence callers would not be able
// to modify the readable state's objects.
@Override
protected V getForModifyFromDataSource(@Nonnull K key) {
return readableKVState.get(key);
}

@Override
protected void putIntoDataSource(@Nonnull K key, @Nonnull V value) {
put(key, value); // put only in memory
}

@Override
protected void removeFromDataSource(@Nonnull K key) {
remove(key); // remove only in memory
}

@Override
protected long sizeOfDataSource() {
return readableKVState.size();
}

@Override
protected V readFromDataSource(@Nonnull K key) {
return readableKVState.get(key);
}

@Nonnull
@Override
protected Iterator<K> iterateFromDataSource() {
return Collections.emptyIterator();
}

@Override
public void commit() {
reset();
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MapWritableKVState<?, ?> that = (MapWritableKVState<?, ?>) o;
return Objects.equals(getStateKey(), that.getStateKey())
&& Objects.equals(readableKVState, that.readableKVState);
}

@Override
public int hashCode() {
return Objects.hash(getStateKey(), readableKVState);
}
}
Loading

0 comments on commit dda0c80

Please sign in to comment.