From 0551e4fe33129ba9647754b1af745f9d76f67ba0 Mon Sep 17 00:00:00 2001 From: Kasper Ziemianek Date: Thu, 12 Nov 2020 16:16:16 +0100 Subject: [PATCH] Lookup newly added keys * make sure newly added keys are used to sign transactions --- .../core/AddressIndexedSignerProvider.java | 15 ++- .../AddressIndexedSignerProviderTest.java | 101 ++++++++++++++++++ 2 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 ethsigner/core/src/test/java/tech/pegasys/ethsigner/core/AddressIndexedSignerProviderTest.java diff --git a/ethsigner/core/src/main/java/tech/pegasys/ethsigner/core/AddressIndexedSignerProvider.java b/ethsigner/core/src/main/java/tech/pegasys/ethsigner/core/AddressIndexedSignerProvider.java index 56b618b75..3c827e6f1 100644 --- a/ethsigner/core/src/main/java/tech/pegasys/ethsigner/core/AddressIndexedSignerProvider.java +++ b/ethsigner/core/src/main/java/tech/pegasys/ethsigner/core/AddressIndexedSignerProvider.java @@ -43,6 +43,13 @@ public AddressIndexedSignerProvider( public static AddressIndexedSignerProvider create(final SignerProvider signerProvider) { final Map addrToPubKeyMap = new HashMap<>(); + addKeysToAddrToPubKeyMap(signerProvider, addrToPubKeyMap); + + return new AddressIndexedSignerProvider(signerProvider, addrToPubKeyMap); + } + + private static void addKeysToAddrToPubKeyMap( + SignerProvider signerProvider, Map addrToPubKeyMap) { signerProvider .availablePublicKeys() .forEach( @@ -54,13 +61,15 @@ public static AddressIndexedSignerProvider create(final SignerProvider signerPro .toLowerCase(); addrToPubKeyMap.put(address, pubKey); }); - - return new AddressIndexedSignerProvider(signerProvider, addrToPubKeyMap); } /* Gets a signer from its address, NOTE address MUST have 0x hex prefix */ public Optional getSigner(final String address) { - final ECPublicKey publicKey = addressToPublicKeyMap.get(address.toLowerCase()); + ECPublicKey publicKey = addressToPublicKeyMap.get(address.toLowerCase()); + if (publicKey == null) { + addKeysToAddrToPubKeyMap(signerProvider, this.addressToPublicKeyMap); + publicKey = addressToPublicKeyMap.get(address.toLowerCase()); + } if (publicKey == null) { return Optional.empty(); } diff --git a/ethsigner/core/src/test/java/tech/pegasys/ethsigner/core/AddressIndexedSignerProviderTest.java b/ethsigner/core/src/test/java/tech/pegasys/ethsigner/core/AddressIndexedSignerProviderTest.java new file mode 100644 index 000000000..3eb50be46 --- /dev/null +++ b/ethsigner/core/src/test/java/tech/pegasys/ethsigner/core/AddressIndexedSignerProviderTest.java @@ -0,0 +1,101 @@ +/* + * Copyright 2020 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.ethsigner.core; + +import static org.assertj.core.api.Assertions.assertThat; + +import tech.pegasys.signers.secp256k1.EthPublicKeyUtils; +import tech.pegasys.signers.secp256k1.api.Signer; +import tech.pegasys.signers.secp256k1.api.SignerProvider; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.interfaces.ECPublicKey; +import java.util.Optional; +import java.util.Set; + +import org.apache.tuweni.bytes.Bytes; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.web3j.crypto.Keys; + +public class AddressIndexedSignerProviderTest { + + @Test + public void returnsSignerForAddress() + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException { + SignerProvider signerProvider = Mockito.mock(SignerProvider.class); + + ECPublicKey key1 = EthPublicKeyUtils.createPublicKey(Keys.createEcKeyPair().getPublicKey()); + + Mockito.doReturn(Set.of(key1)).when(signerProvider).availablePublicKeys(); + Mockito.doReturn(Optional.of(Mockito.mock(Signer.class))).when(signerProvider).getSigner(key1); + AddressIndexedSignerProvider addressIndexedSignerProvider = + AddressIndexedSignerProvider.create(signerProvider); + assertThat( + addressIndexedSignerProvider + .getSigner( + "0x" + + Keys.getAddress( + Bytes.wrap(EthPublicKeyUtils.toByteArray(key1)).toHexString())) + .isPresent()); + } + + @Test + public void returnsSignerForAddedAddress() + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException { + SignerProvider signerProvider = Mockito.mock(SignerProvider.class); + + ECPublicKey key1 = EthPublicKeyUtils.createPublicKey(Keys.createEcKeyPair().getPublicKey()); + ECPublicKey key2 = EthPublicKeyUtils.createPublicKey(Keys.createEcKeyPair().getPublicKey()); + + Mockito.doReturn(Set.of(key1)).when(signerProvider).availablePublicKeys(); + Mockito.doReturn(Optional.of(Mockito.mock(Signer.class))).when(signerProvider).getSigner(key1); + + AddressIndexedSignerProvider addressIndexedSignerProvider = + AddressIndexedSignerProvider.create(signerProvider); + assertThat( + addressIndexedSignerProvider + .getSigner( + "0x" + + Keys.getAddress( + Bytes.wrap(EthPublicKeyUtils.toByteArray(key1)).toHexString())) + .isPresent()); + assertThat( + !addressIndexedSignerProvider + .getSigner( + "0x" + + Keys.getAddress( + Bytes.wrap(EthPublicKeyUtils.toByteArray(key2)).toHexString())) + .isPresent()); + + Mockito.doReturn(Set.of(key1, key2)).when(signerProvider).availablePublicKeys(); + Mockito.doReturn(Optional.of(Mockito.mock(Signer.class))).when(signerProvider).getSigner(key2); + + assertThat( + addressIndexedSignerProvider + .getSigner( + "0x" + + Keys.getAddress( + Bytes.wrap(EthPublicKeyUtils.toByteArray(key1)).toHexString())) + .isPresent()); + assertThat( + addressIndexedSignerProvider + .getSigner( + "0x" + + Keys.getAddress( + Bytes.wrap(EthPublicKeyUtils.toByteArray(key2)).toHexString())) + .isPresent()); + } +}