mirror of https://github.com/hyperledger/besu
PrivacyMarkerTransaction to be signed with a randomly generated key (#1844)
Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>pull/2/head
parent
407dcbf33d
commit
5df733e83e
@ -0,0 +1,45 @@ |
||||
/* |
||||
* 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.markertransaction; |
||||
|
||||
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; |
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Transaction; |
||||
import tech.pegasys.pantheon.ethereum.core.Util; |
||||
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction; |
||||
import tech.pegasys.pantheon.ethereum.util.NonceProvider; |
||||
|
||||
public class FixedKeySigningPrivateMarkerTransactionFactory |
||||
extends PrivateMarkerTransactionFactory { |
||||
|
||||
private final NonceProvider nonceProvider; |
||||
private final KeyPair signingKey; |
||||
private final Address sender; |
||||
|
||||
public FixedKeySigningPrivateMarkerTransactionFactory( |
||||
final Address privacyPrecompileAddress, |
||||
final NonceProvider nonceProvider, |
||||
final KeyPair signingKey) { |
||||
super(privacyPrecompileAddress); |
||||
this.nonceProvider = nonceProvider; |
||||
this.signingKey = signingKey; |
||||
this.sender = Util.publicKeyToAddress(signingKey.getPublicKey()); |
||||
} |
||||
|
||||
@Override |
||||
public Transaction create( |
||||
final String transactionEnclaveKey, final PrivateTransaction privateTransaction) { |
||||
return create( |
||||
transactionEnclaveKey, privateTransaction, nonceProvider.getNonce(sender), signingKey); |
||||
} |
||||
} |
@ -0,0 +1,50 @@ |
||||
/* |
||||
* 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.markertransaction; |
||||
|
||||
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; |
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Transaction; |
||||
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction; |
||||
import tech.pegasys.pantheon.util.bytes.BytesValues; |
||||
|
||||
public abstract class PrivateMarkerTransactionFactory { |
||||
|
||||
private final Address privacyPrecompileAddress; |
||||
|
||||
public PrivateMarkerTransactionFactory(final Address privacyPrecompileAddress) { |
||||
this.privacyPrecompileAddress = privacyPrecompileAddress; |
||||
} |
||||
|
||||
private Address getPrivacyPrecompileAddress() { |
||||
return privacyPrecompileAddress; |
||||
} |
||||
|
||||
public abstract Transaction create( |
||||
final String transactionEnclaveKey, final PrivateTransaction privateTransaction); |
||||
|
||||
protected Transaction create( |
||||
final String transactionEnclaveKey, |
||||
final PrivateTransaction privateTransaction, |
||||
final long nonce, |
||||
final KeyPair signingKey) { |
||||
return Transaction.builder() |
||||
.nonce(nonce) |
||||
.gasPrice(privateTransaction.getGasPrice()) |
||||
.gasLimit(privateTransaction.getGasLimit()) |
||||
.to(getPrivacyPrecompileAddress()) |
||||
.value(privateTransaction.getValue()) |
||||
.payload(BytesValues.fromBase64(transactionEnclaveKey)) |
||||
.signAndBuild(signingKey); |
||||
} |
||||
} |
@ -0,0 +1,32 @@ |
||||
/* |
||||
* 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.markertransaction; |
||||
|
||||
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; |
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Transaction; |
||||
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction; |
||||
|
||||
public class RandomSigningPrivateMarkerTransactionFactory extends PrivateMarkerTransactionFactory { |
||||
|
||||
public RandomSigningPrivateMarkerTransactionFactory(final Address privacyPrecompileAddress) { |
||||
super(privacyPrecompileAddress); |
||||
} |
||||
|
||||
@Override |
||||
public Transaction create( |
||||
final String transactionEnclaveKey, final PrivateTransaction privateTransaction) { |
||||
final KeyPair signingKey = KeyPair.generate(); |
||||
return create(transactionEnclaveKey, privateTransaction, 0, signingKey); |
||||
} |
||||
} |
@ -0,0 +1,21 @@ |
||||
/* |
||||
* 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.util; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
|
||||
@FunctionalInterface |
||||
public interface NonceProvider { |
||||
|
||||
long getNonce(final Address address); |
||||
} |
@ -0,0 +1,75 @@ |
||||
/* |
||||
* 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.markertransaction; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair; |
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Transaction; |
||||
import tech.pegasys.pantheon.ethereum.core.Util; |
||||
import tech.pegasys.pantheon.ethereum.core.Wei; |
||||
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction; |
||||
import tech.pegasys.pantheon.util.bytes.BytesValue; |
||||
|
||||
import java.util.Base64; |
||||
import java.util.Optional; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
public class FixedKeySigningPrivateMarkerTransactionFactoryTest { |
||||
|
||||
private final PrivateTransaction privTransaction = mock(PrivateTransaction.class); |
||||
|
||||
private final Wei gasPrice = Wei.of(100); |
||||
private final long gasLimit = 500; |
||||
private final Wei value = Wei.ZERO; |
||||
private final long providedNonce = 100; |
||||
private final String enclaveKey = "enclaveKey"; |
||||
|
||||
@Before |
||||
public void setup() { |
||||
when(privTransaction.getGasPrice()).thenReturn(gasPrice); |
||||
when(privTransaction.getGasLimit()).thenReturn(gasLimit); |
||||
when(privTransaction.getValue()).thenReturn(value); |
||||
} |
||||
|
||||
@Test |
||||
public void createsFullyPopulatedPrivateMarkerTransactionUsingProvidedNonce() { |
||||
|
||||
final KeyPair signingKeys = KeyPair.generate(); |
||||
final Address precompiledAddress = Address.fromHexString("1"); |
||||
|
||||
final FixedKeySigningPrivateMarkerTransactionFactory factory = |
||||
new FixedKeySigningPrivateMarkerTransactionFactory( |
||||
precompiledAddress, (address) -> providedNonce, signingKeys); |
||||
|
||||
final Transaction transaction = factory.create(enclaveKey, privTransaction); |
||||
|
||||
assertThat(transaction.getNonce()).isEqualTo(providedNonce); |
||||
assertThat(transaction.getGasLimit()).isEqualTo(privTransaction.getGasLimit()); |
||||
assertThat(transaction.getGasPrice()).isEqualTo(privTransaction.getGasPrice()); |
||||
assertThat(transaction.getValue()).isEqualTo(privTransaction.getValue()); |
||||
assertThat(transaction.getSender()) |
||||
.isEqualTo(Util.publicKeyToAddress(signingKeys.getPublicKey())); |
||||
assertThat(transaction.getTo()).isEqualTo(Optional.of(precompiledAddress)); |
||||
assertThat(transaction.getPayload()) |
||||
.isEqualTo(BytesValue.wrap(Base64.getDecoder().decode(enclaveKey))); |
||||
|
||||
final Transaction nextTransaction = factory.create("enclaveKey", privTransaction); |
||||
assertThat(nextTransaction.getSender()).isEqualTo(transaction.getSender()); |
||||
} |
||||
} |
@ -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.markertransaction; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.core.Transaction; |
||||
import tech.pegasys.pantheon.ethereum.core.Wei; |
||||
import tech.pegasys.pantheon.ethereum.privacy.PrivateTransaction; |
||||
import tech.pegasys.pantheon.util.bytes.BytesValue; |
||||
|
||||
import java.util.Base64; |
||||
import java.util.Optional; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
public class RandomSigningPrivateMarkerTransactionFactoryTest { |
||||
|
||||
private final PrivateTransaction privTransaction = mock(PrivateTransaction.class); |
||||
|
||||
private final Wei gasPrice = Wei.of(100); |
||||
private final long gasLimit = 500; |
||||
private final Wei value = Wei.ZERO; |
||||
private final String enclaveKey = "enclaveKey"; |
||||
|
||||
@Before |
||||
public void setup() { |
||||
when(privTransaction.getGasPrice()).thenReturn(gasPrice); |
||||
when(privTransaction.getGasLimit()).thenReturn(gasLimit); |
||||
when(privTransaction.getValue()).thenReturn(value); |
||||
} |
||||
|
||||
@Test |
||||
public void producedTransactionHasZeroNonceAndDifferentSendThanPrior() { |
||||
final Address precompiledAddress = Address.fromHexString("1"); |
||||
|
||||
final RandomSigningPrivateMarkerTransactionFactory factory = |
||||
new RandomSigningPrivateMarkerTransactionFactory(precompiledAddress); |
||||
|
||||
final Transaction transaction = factory.create(enclaveKey, privTransaction); |
||||
|
||||
assertThat(transaction.getNonce()).isEqualTo(0); |
||||
assertThat(transaction.getGasLimit()).isEqualTo(privTransaction.getGasLimit()); |
||||
assertThat(transaction.getGasPrice()).isEqualTo(privTransaction.getGasPrice()); |
||||
assertThat(transaction.getValue()).isEqualTo(privTransaction.getValue()); |
||||
assertThat(transaction.getTo()).isEqualTo(Optional.of(precompiledAddress)); |
||||
assertThat(transaction.getPayload()) |
||||
.isEqualTo(BytesValue.wrap(Base64.getDecoder().decode(enclaveKey))); |
||||
|
||||
final Transaction nextTransaction = factory.create("enclaveKey", privTransaction); |
||||
assertThat(nextTransaction.getSender()).isNotEqualTo(transaction.getSender()); |
||||
} |
||||
} |
@ -0,0 +1,39 @@ |
||||
/* |
||||
* 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.jsonrpc; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.eth.transactions.PendingTransactions; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries; |
||||
import tech.pegasys.pantheon.ethereum.util.NonceProvider; |
||||
|
||||
import java.util.OptionalLong; |
||||
|
||||
public class LatestNonceProvider implements NonceProvider { |
||||
|
||||
private final BlockchainQueries blockchainQueries; |
||||
private final PendingTransactions pendingTransactions; |
||||
|
||||
public LatestNonceProvider( |
||||
final BlockchainQueries blockchainQueries, final PendingTransactions pendingTransactions) { |
||||
this.blockchainQueries = blockchainQueries; |
||||
this.pendingTransactions = pendingTransactions; |
||||
} |
||||
|
||||
@Override |
||||
public long getNonce(final Address address) { |
||||
final OptionalLong pendingNonce = pendingTransactions.getNextNonceForSender(address); |
||||
return pendingNonce.orElseGet( |
||||
() -> blockchainQueries.getTransactionCount(address, blockchainQueries.headBlockNumber())); |
||||
} |
||||
} |
@ -0,0 +1,54 @@ |
||||
/* |
||||
* 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.jsonrpc; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
import tech.pegasys.pantheon.ethereum.core.Address; |
||||
import tech.pegasys.pantheon.ethereum.eth.transactions.PendingTransactions; |
||||
import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries; |
||||
|
||||
import java.util.OptionalLong; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
public class LatestNonceProviderTest { |
||||
|
||||
private final Address senderAdress = Address.fromHexString("1"); |
||||
|
||||
private PendingTransactions pendingTransactions = mock(PendingTransactions.class); |
||||
private BlockchainQueries blockchainQueries = mock(BlockchainQueries.class); |
||||
private LatestNonceProvider nonceProvider = |
||||
new LatestNonceProvider(blockchainQueries, pendingTransactions); |
||||
|
||||
@Test |
||||
public void nextNonceUsesTxPool() { |
||||
final long highestNonceInPendingTransactions = 123; |
||||
when(pendingTransactions.getNextNonceForSender(senderAdress)) |
||||
.thenReturn(OptionalLong.of(highestNonceInPendingTransactions)); |
||||
assertThat(nonceProvider.getNonce(senderAdress)).isEqualTo(highestNonceInPendingTransactions); |
||||
} |
||||
|
||||
@Test |
||||
public void nextNonceIsTakenFromBlockchainIfNoPendingTransactionResponse() { |
||||
final long headBlockNumber = 8; |
||||
final long nonceInBLockchain = 56; |
||||
when(pendingTransactions.getNextNonceForSender(senderAdress)).thenReturn(OptionalLong.empty()); |
||||
when(blockchainQueries.headBlockNumber()).thenReturn(headBlockNumber); |
||||
when(blockchainQueries.getTransactionCount(senderAdress, headBlockNumber)) |
||||
.thenReturn(nonceInBLockchain); |
||||
assertThat(nonceProvider.getNonce(senderAdress)).isEqualTo(nonceInBLockchain); |
||||
} |
||||
} |
Loading…
Reference in new issue