@ -16,13 +16,18 @@ package org.hyperledger.besu.ethereum.mainnet.precompiles.privacy;
import static java.nio.charset.StandardCharsets.UTF_8 ;
import static java.nio.charset.StandardCharsets.UTF_8 ;
import static org.assertj.core.api.Assertions.assertThat ;
import static org.assertj.core.api.Assertions.assertThat ;
import static org.assertj.core.api.Assertions.assertThatThrownBy ;
import static org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture.privateTransactionBesu ;
import static org.mockito.ArgumentMatchers.any ;
import static org.mockito.ArgumentMatchers.any ;
import static org.mockito.ArgumentMatchers.eq ;
import static org.mockito.ArgumentMatchers.nullable ;
import static org.mockito.ArgumentMatchers.nullable ;
import static org.mockito.Mockito.mock ;
import static org.mockito.Mockito.mock ;
import static org.mockito.Mockito.spy ;
import static org.mockito.Mockito.when ;
import static org.mockito.Mockito.when ;
import org.hyperledger.besu.enclave.Enclave ;
import org.hyperledger.besu.enclave.Enclave ;
import org.hyperledger.besu.enclave.EnclaveClientException ;
import org.hyperledger.besu.enclave.EnclaveClientException ;
import org.hyperledger.besu.enclave.EnclaveConfigurationException ;
import org.hyperledger.besu.enclave.types.ReceiveResponse ;
import org.hyperledger.besu.enclave.types.ReceiveResponse ;
import org.hyperledger.besu.ethereum.chain.Blockchain ;
import org.hyperledger.besu.ethereum.chain.Blockchain ;
import org.hyperledger.besu.ethereum.core.Address ;
import org.hyperledger.besu.ethereum.core.Address ;
@ -31,7 +36,6 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.Hash ;
import org.hyperledger.besu.ethereum.core.Hash ;
import org.hyperledger.besu.ethereum.core.Log ;
import org.hyperledger.besu.ethereum.core.Log ;
import org.hyperledger.besu.ethereum.core.MutableWorldState ;
import org.hyperledger.besu.ethereum.core.MutableWorldState ;
import org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture ;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader ;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader ;
import org.hyperledger.besu.ethereum.core.WorldUpdater ;
import org.hyperledger.besu.ethereum.core.WorldUpdater ;
import org.hyperledger.besu.ethereum.mainnet.SpuriousDragonGasCalculator ;
import org.hyperledger.besu.ethereum.mainnet.SpuriousDragonGasCalculator ;
@ -62,7 +66,7 @@ public class PrivacyPrecompiledContractTest {
@Rule public final TemporaryFolder temp = new TemporaryFolder ( ) ;
@Rule public final TemporaryFolder temp = new TemporaryFolder ( ) ;
private final String actual = "Test String" ;
private final String actual = "Test String" ;
private final Bytes k ey = Bytes . wrap ( actual . getBytes ( UTF_8 ) ) ;
private final Bytes txEnclaveK ey = Bytes . wrap ( actual . getBytes ( UTF_8 ) ) ;
private MessageFrame messageFrame ;
private MessageFrame messageFrame ;
private Blockchain blockchain ;
private Blockchain blockchain ;
private final String DEFAULT_OUTPUT = "0x01" ;
private final String DEFAULT_OUTPUT = "0x01" ;
@ -133,26 +137,18 @@ public class PrivacyPrecompiledContractTest {
@Test
@Test
public void testPayloadFoundInEnclave ( ) {
public void testPayloadFoundInEnclave ( ) {
final Enclave enclave = mock ( Enclave . class ) ;
final Enclave enclave = mock ( Enclave . class ) ;
final PrivacyPrecompiledContract contract =
final PrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract ( enclave ) ;
new PrivacyPrecompiledContract (
new SpuriousDragonGasCalculator ( ) ,
enclave ,
worldStateArchive ,
privateStateStorage ,
privateStateRootResolver ) ;
contract . setPrivateTransactionProcessor ( mockPrivateTxProcessor ( ) ) ;
contract . setPrivateTransactionProcessor ( mockPrivateTxProcessor ( ) ) ;
BytesValueRLPOutput bytesValueRLPOutput = new BytesValueRLPOutput ( ) ;
final PrivateTransaction privateTransaction = privateTransactionBesu ( ) ;
PrivateTransactionDataFixture . privateTransactionBesu ( ) . writeTo ( bytesValueRLPOutput ) ;
byte [ ] payload = convertPrivateTransactionToBytes ( privateTransaction ) ;
final String privateFrom = privateTransaction . getPrivateFrom ( ) . toBase64String ( ) ;
final ReceiveResponse response =
final ReceiveResponse response =
new ReceiveResponse (
new ReceiveResponse ( payload , PAYLOAD_TEST_PRIVACY_GROUP_ID , privateFrom ) ;
bytesValueRLPOutput . encoded ( ) . toBase64String ( ) . getBytes ( UTF_8 ) ,
PAYLOAD_TEST_PRIVACY_GROUP_ID ,
null ) ;
when ( enclave . receive ( any ( String . class ) ) ) . thenReturn ( response ) ;
when ( enclave . receive ( any ( String . class ) ) ) . thenReturn ( response ) ;
final Bytes actual = contract . compute ( k ey, messageFrame ) ;
final Bytes actual = contract . compute ( txEnclaveKey , messageFrame ) ;
assertThat ( actual ) . isEqualTo ( Bytes . fromHexString ( DEFAULT_OUTPUT ) ) ;
assertThat ( actual ) . isEqualTo ( Bytes . fromHexString ( DEFAULT_OUTPUT ) ) ;
}
}
@ -160,35 +156,86 @@ public class PrivacyPrecompiledContractTest {
@Test
@Test
public void testPayloadNotFoundInEnclave ( ) {
public void testPayloadNotFoundInEnclave ( ) {
final Enclave enclave = mock ( Enclave . class ) ;
final Enclave enclave = mock ( Enclave . class ) ;
final PrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract ( enclave ) ;
final PrivacyPrecompiledContract contract =
new PrivacyPrecompiledContract (
new SpuriousDragonGasCalculator ( ) ,
enclave ,
worldStateArchive ,
privateStateStorage ,
privateStateRootResolver ) ;
when ( enclave . receive ( any ( String . class ) ) ) . thenThrow ( EnclaveClientException . class ) ;
when ( enclave . receive ( any ( String . class ) ) ) . thenThrow ( EnclaveClientException . class ) ;
final Bytes expected = contract . compute ( k ey, messageFrame ) ;
final Bytes expected = contract . compute ( txEnclaveKey , messageFrame ) ;
assertThat ( expected ) . isEqualTo ( Bytes . EMPTY ) ;
assertThat ( expected ) . isEqualTo ( Bytes . EMPTY ) ;
}
}
@Test ( expected = RuntimeException . class )
@Test ( expected = RuntimeException . class )
public void testEnclaveDown ( ) {
public void testEnclaveDown ( ) {
final Enclave enclave = mock ( Enclave . class ) ;
final Enclave enclave = mock ( Enclave . class ) ;
final PrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract ( enclave ) ;
when ( enclave . receive ( any ( String . class ) ) ) . thenThrow ( new RuntimeException ( ) ) ;
contract . compute ( txEnclaveKey , messageFrame ) ;
}
@Test
public void testEnclaveBelowRequiredVersion ( ) {
final Enclave enclave = mock ( Enclave . class ) ;
final PrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract ( enclave ) ;
final PrivateTransaction privateTransaction = privateTransactionBesu ( ) ;
final byte [ ] payload = convertPrivateTransactionToBytes ( privateTransaction ) ;
final ReceiveResponse responseWithoutSenderKey =
new ReceiveResponse ( payload , PAYLOAD_TEST_PRIVACY_GROUP_ID , null ) ;
when ( enclave . receive ( eq ( txEnclaveKey . toBase64String ( ) ) ) ) . thenReturn ( responseWithoutSenderKey ) ;
assertThatThrownBy ( ( ) - > contract . compute ( txEnclaveKey , messageFrame ) )
. isInstanceOf ( EnclaveConfigurationException . class )
. hasMessage ( "Incompatible Orion version. Orion version must be 1.6.0 or greater." ) ;
}
@Test
public void testPrivateTransactionWithoutPrivateFrom ( ) {
final Enclave enclave = mock ( Enclave . class ) ;
final PrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract ( enclave ) ;
final PrivateTransaction privateTransaction = spy ( privateTransactionBesu ( ) ) ;
when ( privateTransaction . getPrivateFrom ( ) ) . thenReturn ( Bytes . EMPTY ) ;
final byte [ ] payload = convertPrivateTransactionToBytes ( privateTransaction ) ;
final String senderKey = privateTransaction . getPrivateFrom ( ) . toBase64String ( ) ;
final ReceiveResponse response =
new ReceiveResponse ( payload , PAYLOAD_TEST_PRIVACY_GROUP_ID , senderKey ) ;
when ( enclave . receive ( eq ( txEnclaveKey . toBase64String ( ) ) ) ) . thenReturn ( response ) ;
final Bytes expected = contract . compute ( txEnclaveKey , messageFrame ) ;
assertThat ( expected ) . isEqualTo ( Bytes . EMPTY ) ;
}
@Test
public void testPayloadNotMatchingPrivateFrom ( ) {
final Enclave enclave = mock ( Enclave . class ) ;
final PrivacyPrecompiledContract contract = buildPrivacyPrecompiledContract ( enclave ) ;
final PrivateTransaction privateTransaction = privateTransactionBesu ( ) ;
final byte [ ] payload = convertPrivateTransactionToBytes ( privateTransaction ) ;
final PrivacyPrecompiledContract contract =
final String wrongSenderKey = Bytes . random ( 32 ) . toBase64String ( ) ;
new PrivacyPrecompiledContract (
final ReceiveResponse responseWithWrongSenderKey =
new ReceiveResponse ( payload , PAYLOAD_TEST_PRIVACY_GROUP_ID , wrongSenderKey ) ;
when ( enclave . receive ( eq ( txEnclaveKey . toBase64String ( ) ) ) ) . thenReturn ( responseWithWrongSenderKey ) ;
final Bytes expected = contract . compute ( txEnclaveKey , messageFrame ) ;
assertThat ( expected ) . isEqualTo ( Bytes . EMPTY ) ;
}
private byte [ ] convertPrivateTransactionToBytes ( final PrivateTransaction privateTransaction ) {
final BytesValueRLPOutput bytesValueRLPOutput = new BytesValueRLPOutput ( ) ;
privateTransaction . writeTo ( bytesValueRLPOutput ) ;
return bytesValueRLPOutput . encoded ( ) . toBase64String ( ) . getBytes ( UTF_8 ) ;
}
private PrivacyPrecompiledContract buildPrivacyPrecompiledContract ( final Enclave enclave ) {
return new PrivacyPrecompiledContract (
new SpuriousDragonGasCalculator ( ) ,
new SpuriousDragonGasCalculator ( ) ,
enclave ,
enclave ,
worldStateArchive ,
worldStateArchive ,
privateStateStorage ,
privateStateStorage ,
privateStateRootResolver ) ;
privateStateRootResolver ) ;
when ( enclave . receive ( any ( String . class ) ) ) . thenThrow ( new RuntimeException ( ) ) ;
contract . compute ( key , messageFrame ) ;
}
}
}
}