@ -32,7 +32,7 @@ import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.enclave.Enclave ;
import org.hyperledger.besu.enclave.Enclave ;
import org.hyperledger.besu.enclave.EnclaveFactory ;
import org.hyperledger.besu.enclave.EnclaveFactory ;
import org.hyperledger.besu.enclave.types.PrivacyGroup ;
import org.hyperledger.besu.enclave.types.PrivacyGroup ;
import org.hyperledger.besu.enclave.types.Send Response ;
import org.hyperledger.besu.enclave.types.Receive Response ;
import org.hyperledger.besu.ethereum.GasLimitCalculator ;
import org.hyperledger.besu.ethereum.GasLimitCalculator ;
import org.hyperledger.besu.ethereum.ProtocolContext ;
import org.hyperledger.besu.ethereum.ProtocolContext ;
import org.hyperledger.besu.ethereum.chain.DefaultBlockchain ;
import org.hyperledger.besu.ethereum.chain.DefaultBlockchain ;
@ -61,25 +61,19 @@ import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.data.Restriction ;
import org.hyperledger.besu.plugin.data.Restriction ;
import org.hyperledger.besu.plugin.data.TransactionType ;
import org.hyperledger.besu.plugin.data.TransactionType ;
import org.hyperledger.besu.testutil.TestClock ;
import org.hyperledger.besu.testutil.TestClock ;
import org.hyperledger.enclave.testutil.EnclaveKeyConfiguration ;
import org.hyperledger.enclave.testutil.EnclaveTestHarness ;
import org.hyperledger.enclave.testutil.OrionTestHarnessFactory ;
import java.io.IOException ;
import java.io.IOException ;
import java.math.BigInteger ;
import java.math.BigInteger ;
import java.net.URI ;
import java.net.URI ;
import java.nio.charset.StandardCharsets ;
import java.nio.file.Path ;
import java.nio.file.Path ;
import java.util.Collections ;
import java.util.Collections ;
import java.util.List ;
import java.util.Optional ;
import java.util.Optional ;
import java.util.stream.Collectors ;
import com.google.common.base.Supplier ;
import com.google.common.base.Supplier ;
import com.google.common.base.Suppliers ;
import com.google.common.base.Suppliers ;
import io.vertx.core.Vertx ;
import org.apache.tuweni.bytes.Bytes ;
import org.apache.tuweni.bytes.Bytes ;
import org.apache.tuweni.bytes.Bytes32 ;
import org.apache.tuweni.bytes.Bytes32 ;
import org.junit.After ;
import org.junit.Before ;
import org.junit.Before ;
import org.junit.Rule ;
import org.junit.Rule ;
import org.junit.Test ;
import org.junit.Test ;
@ -136,31 +130,52 @@ public class PrivacyReorgTest {
private final BlockDataGenerator gen = new BlockDataGenerator ( ) ;
private final BlockDataGenerator gen = new BlockDataGenerator ( ) ;
private BesuController besuController ;
private BesuController besuController ;
private EnclaveTestHarness enclave ;
private PrivateStateRootResolver privateStateRootResolver ;
private PrivateStateRootResolver privateStateRootResolver ;
private PrivacyParameters privacyParameters ;
private PrivacyParameters privacyParameters ;
private RestrictedDefaultPrivacyController privacyController ;
private RestrictedDefaultPrivacyController privacyController ;
private Enclave mockEnclave ;
private Transaction privacyMarkerTransaction ;
@Before
@Before
public void setUp ( ) throws IOException {
public void setUp ( ) throws IOException {
enclave =
mockEnclave = mock ( Enclave . class ) ;
OrionTestHarnessFactory . create (
final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput ( ) ;
"orion" ,
PRIVATE_TRANSACTION . writeTo ( rlpOutput ) ;
folder . newFolder ( ) . toPath ( ) ,
new EnclaveKeyConfiguration ( "enclavePublicKey" , "enclavePrivateKey" ) ) ;
when ( mockEnclave . receive ( any ( ) ) )
enclave . start ( ) ;
. thenReturn (
new ReceiveResponse (
rlpOutput . encoded ( ) . toBase64String ( ) . getBytes ( StandardCharsets . UTF_8 ) ,
PRIVACY_GROUP_BYTES32 . toBase64String ( ) ,
ENCLAVE_PUBLIC_KEY . toBase64String ( ) ) ) ;
privacyMarkerTransaction =
Transaction . builder ( )
. type ( TransactionType . FRONTIER )
. chainId ( BigInteger . valueOf ( 1337 ) )
. gasLimit ( 60000 )
. gasPrice ( Wei . of ( 1000 ) )
. nonce ( 0 )
. payload ( Bytes32 . random ( ) )
. to ( DEFAULT_PRIVACY )
. value ( Wei . ZERO )
. signAndBuild ( KEY_PAIR ) ;
// Create Storage
// Create Storage
final Path dataDir = folder . newFolder ( ) . toPath ( ) ;
final Path dataDir = folder . newFolder ( ) . toPath ( ) ;
// Configure Privacy
// Configure Privacy
EnclaveFactory enclaveFactory = mock ( EnclaveFactory . class ) ;
when ( enclaveFactory . createVertxEnclave ( any ( ) ) ) . thenReturn ( mockEnclave ) ;
privacyParameters =
privacyParameters =
new PrivacyParameters . Builder ( )
new PrivacyParameters . Builder ( )
. setEnabled ( true )
. setEnabled ( true )
. setStorageProvider ( createKeyValueStorageProvider ( ) )
. setStorageProvider ( createKeyValueStorageProvider ( ) )
. setEnclaveUrl ( enclave . clientUrl ( ) )
. setEnclaveUrl ( URI . create ( "http//1.1.1.1:1234" ) )
. setEnclaveFactory ( new EnclaveFactory ( Vertx . vertx ( ) ) )
. setEnclaveFactory ( enclaveFactory )
. build ( ) ;
. build ( ) ;
privacyParameters . setPrivacyUserId ( ENCLAVE_PUBLIC_KEY . toBase64String ( ) ) ;
privacyParameters . setPrivacyUserId ( ENCLAVE_PUBLIC_KEY . toBase64String ( ) ) ;
privacyController = mock ( RestrictedDefaultPrivacyController . class ) ;
privacyController = mock ( RestrictedDefaultPrivacyController . class ) ;
when ( privacyController . findPrivacyGroupByGroupId ( any ( ) , any ( ) ) )
when ( privacyController . findPrivacyGroupByGroupId ( any ( ) , any ( ) ) )
@ -192,11 +207,6 @@ public class PrivacyReorgTest {
. build ( ) ;
. build ( ) ;
}
}
@After
public void tearDown ( ) {
enclave . stop ( ) ;
}
@Test
@Test
public void privacyGroupHeadIsTracked ( ) {
public void privacyGroupHeadIsTracked ( ) {
// Setup an initial blockchain with one private transaction
// Setup an initial blockchain with one private transaction
@ -204,13 +214,11 @@ public class PrivacyReorgTest {
final DefaultBlockchain blockchain = ( DefaultBlockchain ) protocolContext . getBlockchain ( ) ;
final DefaultBlockchain blockchain = ( DefaultBlockchain ) protocolContext . getBlockchain ( ) ;
final PrivateStateStorage privateStateStorage = privacyParameters . getPrivateStateStorage ( ) ;
final PrivateStateStorage privateStateStorage = privacyParameters . getPrivateStateStorage ( ) ;
final Transaction privateMarkerTransaction =
buildMarkerTransaction ( getEnclaveKey ( enclave . clientUrl ( ) ) ) ;
final Block firstBlock =
final Block firstBlock =
gen . block (
gen . block (
getBlockOptionsWithTransaction (
getBlockOptionsWithTransaction (
blockchain . getGenesisBlock ( ) ,
blockchain . getGenesisBlock ( ) ,
private MarkerTransaction ,
privacy MarkerTransaction ,
FIRST_BLOCK_WITH_SINGLE_TRANSACTION_STATE_ROOT ) ) ;
FIRST_BLOCK_WITH_SINGLE_TRANSACTION_STATE_ROOT ) ) ;
appendBlock ( besuController , blockchain , protocolContext , firstBlock ) ;
appendBlock ( besuController , blockchain , protocolContext , firstBlock ) ;
@ -249,7 +257,7 @@ public class PrivacyReorgTest {
gen . block (
gen . block (
getBlockOptionsWithTransaction (
getBlockOptionsWithTransaction (
blockchain . getGenesisBlock ( ) ,
blockchain . getGenesisBlock ( ) ,
buildMarkerTransaction ( getEnclaveKey ( enclave . clientUrl ( ) ) ) ,
privacyMarkerTransaction ,
FIRST_BLOCK_WITH_SINGLE_TRANSACTION_STATE_ROOT ) ) ;
FIRST_BLOCK_WITH_SINGLE_TRANSACTION_STATE_ROOT ) ) ;
appendBlock ( besuController , blockchain , protocolContext , firstBlock ) ;
appendBlock ( besuController , blockchain , protocolContext , firstBlock ) ;
@ -288,9 +296,7 @@ public class PrivacyReorgTest {
final Block secondBlock =
final Block secondBlock =
gen . block (
gen . block (
getBlockOptionsWithTransaction (
getBlockOptionsWithTransaction (
firstBlock ,
firstBlock , privacyMarkerTransaction , secondBlockStateRoot ) ) ;
buildMarkerTransaction ( getEnclaveKey ( enclave . clientUrl ( ) ) ) ,
secondBlockStateRoot ) ) ;
appendBlock ( besuController , blockchain , protocolContext , firstBlock ) ;
appendBlock ( besuController , blockchain , protocolContext , firstBlock ) ;
appendBlock ( besuController , blockchain , protocolContext , secondBlock ) ;
appendBlock ( besuController , blockchain , protocolContext , secondBlock ) ;
@ -337,7 +343,7 @@ public class PrivacyReorgTest {
gen . block (
gen . block (
getBlockOptionsWithTransaction (
getBlockOptionsWithTransaction (
blockchain . getGenesisBlock ( ) ,
blockchain . getGenesisBlock ( ) ,
buildMarkerTransaction ( getEnclaveKey ( enclave . clientUrl ( ) ) ) ,
privacyMarkerTransaction ,
FIRST_BLOCK_WITH_SINGLE_TRANSACTION_STATE_ROOT ) ) ;
FIRST_BLOCK_WITH_SINGLE_TRANSACTION_STATE_ROOT ) ) ;
appendBlock ( besuController , blockchain , protocolContext , firstBlock ) ;
appendBlock ( besuController , blockchain , protocolContext , firstBlock ) ;
@ -384,7 +390,7 @@ public class PrivacyReorgTest {
gen . block (
gen . block (
getBlockOptionsWithTransactionAndDifficulty (
getBlockOptionsWithTransactionAndDifficulty (
secondForkBlock ,
secondForkBlock ,
buildMarkerTransaction ( getEnclaveKey ( enclave . clientUrl ( ) ) ) ,
privacyMarkerTransaction ,
secondForkBlock . getHeader ( ) . getDifficulty ( ) . plus ( 10L ) ,
secondForkBlock . getHeader ( ) . getDifficulty ( ) . plus ( 10L ) ,
thirdForkBlockStateRoot ) ) ;
thirdForkBlockStateRoot ) ) ;
@ -412,62 +418,6 @@ public class PrivacyReorgTest {
return new InMemoryPrivacyStorageProvider ( ) ;
return new InMemoryPrivacyStorageProvider ( ) ;
}
}
private Bytes getEnclaveKey ( final URI enclaveURI ) {
final Enclave enclave = new EnclaveFactory ( Vertx . vertx ( ) ) . createVertxEnclave ( enclaveURI ) ;
final SendResponse sendResponse =
sendRequest ( enclave , PRIVATE_TRANSACTION , ENCLAVE_PUBLIC_KEY . toBase64String ( ) ) ;
final Bytes payload = Bytes . fromBase64String ( sendResponse . getKey ( ) ) ;
// If the key has 0 bytes generate a new key.
// This is to keep the gasUsed constant allowing
// hard-coded receipt roots in the block headers
for ( int i = 0 ; i < payload . size ( ) ; i + + ) {
if ( payload . get ( i ) = = 0 ) {
return getEnclaveKey ( enclaveURI ) ;
}
}
return payload ;
}
private SendResponse sendRequest (
final Enclave enclave ,
final PrivateTransaction privateTransaction ,
final String privacyUserId ) {
final BytesValueRLPOutput rlpOutput = new BytesValueRLPOutput ( ) ;
privateTransaction . writeTo ( rlpOutput ) ;
final String payload = rlpOutput . encoded ( ) . toBase64String ( ) ;
if ( privateTransaction . getPrivacyGroupId ( ) . isPresent ( ) ) {
return enclave . send (
payload , privacyUserId , privateTransaction . getPrivacyGroupId ( ) . get ( ) . toBase64String ( ) ) ;
} else {
final List < String > privateFor =
privateTransaction . getPrivateFor ( ) . get ( ) . stream ( )
. map ( Bytes : : toBase64String )
. collect ( Collectors . toList ( ) ) ;
if ( privateFor . isEmpty ( ) ) {
privateFor . add ( privateTransaction . getPrivateFrom ( ) . toBase64String ( ) ) ;
}
return enclave . send (
payload , privateTransaction . getPrivateFrom ( ) . toBase64String ( ) , privateFor ) ;
}
}
private Transaction buildMarkerTransaction ( final Bytes payload ) {
return Transaction . builder ( )
. type ( TransactionType . FRONTIER )
. chainId ( BigInteger . valueOf ( 1337 ) )
. gasLimit ( 60000 )
. gasPrice ( Wei . of ( 1000 ) )
. nonce ( 0 )
. payload ( payload )
. to ( DEFAULT_PRIVACY )
. value ( Wei . ZERO )
. signAndBuild ( KEY_PAIR ) ;
}
private void assertPrivateStateRoot (
private void assertPrivateStateRoot (
final PrivateStateRootResolver privateStateRootResolver ,
final PrivateStateRootResolver privateStateRootResolver ,
final DefaultBlockchain blockchain ,
final DefaultBlockchain blockchain ,