Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

Commit

Permalink
Store Private State Root Hash in DB.
Browse files Browse the repository at this point in the history
  • Loading branch information
Puneetha17 committed Mar 4, 2019
1 parent 45dc009 commit b18d5a5
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import tech.pegasys.pantheon.ethereum.privacy.PrivateStateStorage;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionProcessor;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionStorage;
import tech.pegasys.pantheon.ethereum.vm.BlockHashLookup;
import tech.pegasys.pantheon.ethereum.vm.MessageFrame;
import tech.pegasys.pantheon.ethereum.vm.OperationTracer;
Expand Down Expand Up @@ -79,8 +80,10 @@ public class PrivacyPrecompiledContractIntegrationTest {

private static OrionTestHarness testHarness;
private static WorldStateArchive worldStateArchive;
private static PrivateTransactionStorage privateTransactionStorage;
private static PrivateTransactionStorage.Updater updater;
private static PrivateStateStorage privateStateStorage;
private static PrivateStateStorage.Updater updater;
private static PrivateStateStorage.Updater storageUpdater;

private PrivateTransactionProcessor mockPrivateTxProcessor() {
PrivateTransactionProcessor mockPrivateTransactionProcessor =
Expand Down Expand Up @@ -116,11 +119,17 @@ public static void setUpOnce() throws Exception {
when(mutableWorldState.updater()).thenReturn(mock(WorldUpdater.class));
when(worldStateArchive.getMutable()).thenReturn(mutableWorldState);
when(worldStateArchive.getMutable(any())).thenReturn(Optional.of(mutableWorldState));
privateStateStorage = mock(PrivateStateStorage.class);
updater = mock(PrivateStateStorage.Updater.class);
privateTransactionStorage = mock(PrivateTransactionStorage.class);
updater = mock(PrivateTransactionStorage.Updater.class);
when(updater.putTransactionLogs(nullable(Bytes32.class), any())).thenReturn(updater);
when(updater.putTransactionResult(nullable(Bytes32.class), any())).thenReturn(updater);
when(privateStateStorage.updater()).thenReturn(updater);
when(privateTransactionStorage.updater()).thenReturn(updater);

privateStateStorage = mock(PrivateStateStorage.class);
storageUpdater = mock(PrivateStateStorage.Updater.class);
when(storageUpdater.putPrivateAccountState(nullable(Bytes32.class), any()))
.thenReturn(storageUpdater);
when(privateStateStorage.updater()).thenReturn(storageUpdater);
}

@AfterClass
Expand All @@ -147,6 +156,7 @@ public void testSendAndReceive() throws IOException {
publicKeys.get(0),
enclave,
worldStateArchive,
privateTransactionStorage,
privateStateStorage);

privacyPrecompiledContract.setPrivateTransactionProcessor(mockPrivateTxProcessor());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;

import tech.pegasys.pantheon.ethereum.privacy.PrivateStateStorage;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionStorage;
import tech.pegasys.pantheon.ethereum.storage.StorageProvider;
import tech.pegasys.pantheon.ethereum.storage.keyvalue.RocksDbStorageProvider;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateArchive;
Expand All @@ -41,6 +42,7 @@ public class PrivacyParameters {
private File publicKeyFile;
private WorldStateArchive privateWorldStateArchive;

private PrivateTransactionStorage privateTransactionStorage;
private PrivateStateStorage privateStateStorage;

public String getPublicKey() {
Expand Down Expand Up @@ -104,9 +106,14 @@ public void enablePrivateDB(final Path path) throws IOException {
final Path privateStateDbPath = path.resolve(PRIVATE_STATE_DATABASE_PATH);
final StorageProvider privateStateStorageProvider =
RocksDbStorageProvider.create(privateStateDbPath, new NoOpMetricsSystem());
this.privateTransactionStorage = privateStateStorageProvider.createPrivateTransactionStorage();
this.privateStateStorage = privateStateStorageProvider.createPrivateStateStorage();
}

public PrivateTransactionStorage getPrivateTransactionStorage() {
return privateTransactionStorage;
}

public PrivateStateStorage getPrivateStateStorage() {
return privateStateStorage;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import tech.pegasys.pantheon.ethereum.privacy.PrivateStateStorage;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionProcessor;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionStorage;
import tech.pegasys.pantheon.ethereum.rlp.BytesValueRLPInput;
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.ethereum.trie.MerklePatriciaTrie;
Expand All @@ -39,7 +40,6 @@

import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand All @@ -48,10 +48,10 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract {
private final Enclave enclave;
private final String enclavePublicKey;
private final WorldStateArchive privateWorldStateArchive;
private final PrivateTransactionStorage privateTransactionStorage;
private final PrivateStateStorage privateStateStorage;
private PrivateTransactionProcessor privateTransactionProcessor;

private final HashMap<BytesValue, Hash> temp = new HashMap<>();
private static final Hash EMPTY_ROOT_HASH = Hash.wrap(MerklePatriciaTrie.EMPTY_TRIE_NODE_HASH);

private static final Logger LOG = LogManager.getLogger();

Expand All @@ -62,6 +62,7 @@ public PrivacyPrecompiledContract(
privacyParameters.getPublicKey(),
new Enclave(privacyParameters.getUrl()),
privacyParameters.getPrivateWorldStateArchive(),
privacyParameters.getPrivateTransactionStorage(),
privacyParameters.getPrivateStateStorage());
}

Expand All @@ -70,11 +71,13 @@ public PrivacyPrecompiledContract(
final String publicKey,
final Enclave enclave,
final WorldStateArchive worldStateArchive,
final PrivateTransactionStorage privateTransactionStorage,
final PrivateStateStorage privateStateStorage) {
super("Privacy", gasCalculator);
this.enclave = enclave;
this.enclavePublicKey = publicKey;
this.privateWorldStateArchive = worldStateArchive;
this.privateTransactionStorage = privateTransactionStorage;
this.privateStateStorage = privateStateStorage;
}

Expand Down Expand Up @@ -104,8 +107,9 @@ public BytesValue compute(final BytesValue input, final MessageFrame messageFram
WorldUpdater publicWorldState = messageFrame.getWorldState();
// get the last world state root hash - or create a new one
BytesValue privacyGroupId = BytesValue.wrap("0".getBytes(UTF_8));

Hash lastRootHash =
temp.getOrDefault(privacyGroupId, Hash.wrap(MerklePatriciaTrie.EMPTY_TRIE_NODE_HASH));
privateStateStorage.getPrivateAccountState(privacyGroupId).orElse(EMPTY_ROOT_HASH);
MutableWorldState disposablePrivateState =
privateWorldStateArchive.getMutable(lastRootHash).get();

Expand All @@ -124,11 +128,13 @@ public BytesValue compute(final BytesValue input, final MessageFrame messageFram

privateWorldStateUpdater.commit();
disposablePrivateState.persist();
temp.put(privacyGroupId, disposablePrivateState.rootHash());
PrivateStateStorage.Updater privateStateUpdater = privateStateStorage.updater();
privateStateUpdater.putPrivateAccountState(privacyGroupId, disposablePrivateState.rootHash());
privateStateUpdater.commit();

BytesValue rlpEncoded = RLP.encode(privateTransaction::writeTo);
Bytes32 txHash = tech.pegasys.pantheon.crypto.Hash.keccak256(rlpEncoded);
PrivateStateStorage.Updater privateUpdater = privateStateStorage.updater();
PrivateTransactionStorage.Updater privateUpdater = privateTransactionStorage.updater();
privateUpdater.putTransactionLogs(txHash, result.getLogs());
privateUpdater.putTransactionResult(txHash, result.getOutput());
privateUpdater.commit();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import java.util.List;
import java.util.Optional;

public class PrivateKeyValueStorage implements PrivateStateStorage {
public class PrivateKeyValueStorage implements PrivateTransactionStorage {

private final KeyValueStorage keyValueStorage;

Expand Down Expand Up @@ -63,7 +63,7 @@ public Updater updater() {
return new Updater(keyValueStorage.startTransaction());
}

public static class Updater implements PrivateStateStorage.Updater {
public static class Updater implements PrivateTransactionStorage.Updater {

private final KeyValueStorage.Transaction transaction;

Expand All @@ -72,14 +72,14 @@ private Updater(final KeyValueStorage.Transaction transaction) {
}

@Override
public PrivateStateStorage.Updater putTransactionLogs(
public PrivateTransactionStorage.Updater putTransactionLogs(
final Bytes32 transactionHash, final LogSeries logs) {
set(LOGS_PREFIX, transactionHash, RLP.encode(logs::writeTo));
return this;
}

@Override
public PrivateStateStorage.Updater putTransactionResult(
public PrivateTransactionStorage.Updater putTransactionResult(
final Bytes32 transactionHash, final BytesValue events) {
set(EVENTS_PREFIX, transactionHash, events);
return this;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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 tech.pegasys.pantheon.ethereum.privacy;

import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.services.kvstore.KeyValueStorage;
import tech.pegasys.pantheon.util.bytes.Bytes32;
import tech.pegasys.pantheon.util.bytes.BytesValue;

import java.util.Optional;

public class PrivateStateKeyValueStorage implements PrivateStateStorage {

private final KeyValueStorage keyValueStorage;

public PrivateStateKeyValueStorage(final KeyValueStorage keyValueStorage) {
this.keyValueStorage = keyValueStorage;
}

@Override
public Optional<Hash> getPrivateAccountState(final BytesValue privacyId) {
if (keyValueStorage.get(privacyId).isPresent())
return Optional.of(
Hash.wrap(Bytes32.wrap(keyValueStorage.get(privacyId).get().extractArray())));
else return Optional.empty();
}

@Override
public boolean isWorldStateAvailable(final Bytes32 rootHash) {
return false;
}

@Override
public PrivateStateStorage.Updater updater() {
return new PrivateStateKeyValueStorage.Updater(keyValueStorage.startTransaction());
}

public static class Updater implements PrivateStateStorage.Updater {
private final KeyValueStorage.Transaction transaction;

private Updater(final KeyValueStorage.Transaction transaction) {
this.transaction = transaction;
}

@Override
public PrivateStateStorage.Updater putPrivateAccountState(
final BytesValue privacyId, final Hash privateStateHash) {
transaction.put(privacyId, BytesValue.wrap(privateStateHash.extractArray()));
return this;
}

@Override
public void commit() {
transaction.commit();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,24 @@
*/
package tech.pegasys.pantheon.ethereum.privacy;

import tech.pegasys.pantheon.ethereum.core.Log;
import tech.pegasys.pantheon.ethereum.core.LogSeries;
import tech.pegasys.pantheon.ethereum.core.Hash;
import tech.pegasys.pantheon.util.bytes.Bytes32;
import tech.pegasys.pantheon.util.bytes.BytesValue;

import java.util.List;
import java.util.Optional;

public interface PrivateStateStorage {

Optional<List<Log>> getEvents(Bytes32 transactionHash);
Optional<Hash> getPrivateAccountState(BytesValue privacyId);

Optional<BytesValue> getOutput(Bytes32 transactionHash);
boolean isWorldStateAvailable(Bytes32 rootHash);

boolean isPrivateStateAvailable(Bytes32 transactionHash);

Updater updater();
PrivateStateStorage.Updater updater();

interface Updater {

Updater putTransactionLogs(Bytes32 transactionHash, LogSeries logs);

Updater putTransactionResult(Bytes32 transactionHash, BytesValue events);
PrivateStateStorage.Updater putPrivateAccountState(BytesValue privacyId, Hash privateStateHash);

void commit();

void rollback();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2019 ConsenSys AG.
*
* 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 tech.pegasys.pantheon.ethereum.privacy;

import tech.pegasys.pantheon.ethereum.core.Log;
import tech.pegasys.pantheon.ethereum.core.LogSeries;
import tech.pegasys.pantheon.util.bytes.Bytes32;
import tech.pegasys.pantheon.util.bytes.BytesValue;

import java.util.List;
import java.util.Optional;

public interface PrivateTransactionStorage {

Optional<List<Log>> getEvents(Bytes32 transactionHash);

Optional<BytesValue> getOutput(Bytes32 transactionHash);

boolean isPrivateStateAvailable(Bytes32 transactionHash);

Updater updater();

interface Updater {

Updater putTransactionLogs(Bytes32 transactionHash, LogSeries logs);

Updater putTransactionResult(Bytes32 transactionHash, BytesValue events);

void commit();

void rollback();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import tech.pegasys.pantheon.ethereum.chain.BlockchainStorage;
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.privacy.PrivateStateStorage;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionStorage;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateStorage;

import java.io.Closeable;
Expand All @@ -25,5 +26,7 @@ public interface StorageProvider extends Closeable {

WorldStateStorage createWorldStateStorage();

PrivateTransactionStorage createPrivateTransactionStorage();

PrivateStateStorage createPrivateStateStorage();
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule;
import tech.pegasys.pantheon.ethereum.mainnet.ScheduleBasedBlockHashFunction;
import tech.pegasys.pantheon.ethereum.privacy.PrivateKeyValueStorage;
import tech.pegasys.pantheon.ethereum.privacy.PrivateStateKeyValueStorage;
import tech.pegasys.pantheon.ethereum.privacy.PrivateStateStorage;
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransactionStorage;
import tech.pegasys.pantheon.ethereum.storage.StorageProvider;
import tech.pegasys.pantheon.ethereum.worldstate.WorldStateStorage;
import tech.pegasys.pantheon.services.kvstore.KeyValueStorage;
Expand All @@ -43,10 +45,15 @@ public WorldStateStorage createWorldStateStorage() {
}

@Override
public PrivateStateStorage createPrivateStateStorage() {
public PrivateTransactionStorage createPrivateTransactionStorage() {
return new PrivateKeyValueStorage(keyValueStorage);
}

@Override
public PrivateStateStorage createPrivateStateStorage() {
return new PrivateStateKeyValueStorage(keyValueStorage);
}

@Override
public void close() throws IOException {
keyValueStorage.close();
Expand Down
Loading

0 comments on commit b18d5a5

Please sign in to comment.