| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.tuweni.trie |
| |
| import kotlinx.coroutines.CoroutineDispatcher |
| import kotlinx.coroutines.Dispatchers |
| import kotlinx.coroutines.GlobalScope |
| import org.apache.tuweni.bytes.Bytes |
| import org.apache.tuweni.bytes.Bytes32 |
| import org.apache.tuweni.concurrent.AsyncCompletion |
| import org.apache.tuweni.concurrent.AsyncResult |
| import org.apache.tuweni.concurrent.coroutines.asyncCompletion |
| import org.apache.tuweni.concurrent.coroutines.asyncResult |
| import org.apache.tuweni.crypto.Hash |
| import org.apache.tuweni.rlp.RLP |
| |
| // Workaround for a javadoc generation issue - extracting these method bodies out of the default method and into |
| // private funcs appears to resolve it. It would be good to remove this workaround one day. |
| private fun <K, V> getAsync(dispatcher: CoroutineDispatcher, key: K, trie: MerkleTrie<K, V>): AsyncResult<V?> = |
| GlobalScope.asyncResult(dispatcher) { trie.get(key) } |
| private fun <K, V> putAsync( |
| dispatcher: CoroutineDispatcher, |
| key: K, |
| value: V?, |
| trie: MerkleTrie<K, V> |
| ): AsyncCompletion = GlobalScope.asyncCompletion(dispatcher) { trie.put(key, value) } |
| |
| /** |
| * A Merkle Trie. |
| */ |
| interface MerkleTrie<in K, V> { |
| companion object { |
| /** |
| * The root hash of an empty tree. |
| */ |
| val EMPTY_TRIE_ROOT_HASH: Bytes32 = Hash.keccak256(RLP.encodeValue(Bytes.EMPTY)) |
| } |
| |
| /** |
| * Returns the value that corresponds to the specified key, or an empty byte array if no such value exists. |
| * |
| * @param key The key of the value to be returned. |
| * @return The value that corresponds to the specified key, or {@code null} if no such value exists. |
| * @throws MerkleStorageException If there is an error while accessing or decoding data from storage. |
| */ |
| suspend fun get(key: K): V? |
| |
| /** |
| * Returns the value that corresponds to the specified key, or an empty byte array if no such value exists. |
| * |
| * @param key The key of the value to be returned. |
| * @return A value that corresponds to the specified key, or {@code null} if no such value exists. |
| */ |
| fun getAsync(key: K): AsyncResult<V?> = getAsync(Dispatchers.Default, key) |
| |
| /** |
| * Returns the value that corresponds to the specified key, or an empty byte array if no such value exists. |
| * |
| * @param key The key of the value to be returned. |
| * @param dispatcher The co-routine dispatcher for asynchronous tasks. |
| * @return A value that corresponds to the specified key, or {@code null} if no such value exists. |
| */ |
| fun getAsync(dispatcher: CoroutineDispatcher, key: K): AsyncResult<V?> = getAsync(dispatcher, key, this) |
| |
| /** |
| * Updates the value that corresponds to the specified key, creating the value if one does not already exist. |
| * |
| * If the value is null, deletes the value that corresponds to the specified key, if such a value exists. |
| * |
| * @param key The key that corresponds to the value to be updated. |
| * @param value The value to associate the key with. |
| * @throws MerkleStorageException If there is an error while writing to storage. |
| */ |
| suspend fun put(key: K, value: V?) |
| |
| /** |
| * Updates the value that corresponds to the specified key, creating the value if one does not already exist. |
| * |
| * If the value is null, deletes the value that corresponds to the specified key, if such a value exists. |
| * |
| * @param key The key that corresponds to the value to be updated. |
| * @param value The value to associate the key with. |
| * @return A completion that will complete when the value has been put into the trie. |
| */ |
| fun putAsync(key: K, value: V?): AsyncCompletion = putAsync(Dispatchers.Default, key, value) |
| |
| /** |
| * Updates the value that corresponds to the specified key, creating the value if one does not already exist. |
| * |
| * If the value is null, deletes the value that corresponds to the specified key, if such a value exists. |
| * |
| * @param key The key that corresponds to the value to be updated. |
| * @param value The value to associate the key with. |
| * @param dispatcher The co-routine dispatcher for asynchronous tasks. |
| * @return A completion that will complete when the value has been put into the trie. |
| */ |
| fun putAsync(dispatcher: CoroutineDispatcher, key: K, value: V?): AsyncCompletion = |
| putAsync(dispatcher, key, value, this) |
| |
| /** |
| * Deletes the value that corresponds to the specified key, if such a value exists. |
| * |
| * @param key The key of the value to be deleted. |
| * @throws MerkleStorageException If there is an error while writing to storage. |
| */ |
| suspend fun remove(key: K) |
| |
| /** |
| * Deletes the value that corresponds to the specified key, if such a value exists. |
| * |
| * @param key The key of the value to be deleted. |
| * @return A completion that will complete when the value has been removed. |
| */ |
| fun removeAsync(key: K): AsyncCompletion = removeAsync(Dispatchers.Default, key) |
| |
| /** |
| * Deletes the value that corresponds to the specified key, if such a value exists. |
| * |
| * @param key The key of the value to be deleted. |
| * @param dispatcher The co-routine dispatcher for asynchronous tasks. |
| * @return A completion that will complete when the value has been removed. |
| */ |
| fun removeAsync(dispatcher: CoroutineDispatcher, key: K): AsyncCompletion = |
| GlobalScope.asyncCompletion(dispatcher) { remove(key) } |
| |
| /** |
| * Returns the KECCAK256 hash of the root node of the trie. |
| * |
| * @return The KECCAK256 hash of the root node of the trie. |
| */ |
| fun rootHash(): Bytes32 |
| } |