diff --git a/btc-address-generation/src/main/kotlin/com/d3/btc/generation/config/BtcAddressGenerationAppConfiguration.kt b/btc-address-generation/src/main/kotlin/com/d3/btc/generation/config/BtcAddressGenerationAppConfiguration.kt index eae0e2a8..daca17d3 100644 --- a/btc-address-generation/src/main/kotlin/com/d3/btc/generation/config/BtcAddressGenerationAppConfiguration.kt +++ b/btc-address-generation/src/main/kotlin/com/d3/btc/generation/config/BtcAddressGenerationAppConfiguration.kt @@ -7,8 +7,6 @@ package com.d3.btc.generation.config import com.d3.btc.generation.BTC_ADDRESS_GENERATION_SERVICE_NAME import com.d3.btc.provider.BtcChangeAddressProvider -import com.d3.btc.provider.network.BtcNetworkConfigProvider -import com.d3.btc.wallet.createWalletIfAbsent import com.d3.commons.config.loadLocalConfigs import com.d3.commons.expansion.ServiceExpansion import com.d3.commons.model.IrohaCredential @@ -22,10 +20,8 @@ import com.d3.commons.util.createPrettySingleThreadPool import io.grpc.ManagedChannelBuilder import jp.co.soramitsu.iroha.java.IrohaAPI import jp.co.soramitsu.iroha.java.Utils -import org.bitcoinj.wallet.Wallet import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import java.io.File val btcAddressGenerationConfig = loadLocalConfigs( @@ -101,13 +97,6 @@ class BtcAddressGenerationAppConfiguration { @Bean fun btcAddressGenerationConfig() = btcAddressGenerationConfig - @Bean - fun keysWallet(networkProvider: BtcNetworkConfigProvider): Wallet { - val walletPath = btcAddressGenerationConfig.btcKeysWalletPath - createWalletIfAbsent(walletPath, networkProvider) - return Wallet.loadFromFile(File(walletPath))!! - } - @Bean fun notaryPeerListProvider(): NotaryPeerListProvider { return NotaryPeerListProviderImpl( diff --git a/btc-address-generation/src/main/kotlin/com/d3/btc/generation/config/BtcAddressGenerationConfig.kt b/btc-address-generation/src/main/kotlin/com/d3/btc/generation/config/BtcAddressGenerationConfig.kt index 80a1a64e..b440e341 100644 --- a/btc-address-generation/src/main/kotlin/com/d3/btc/generation/config/BtcAddressGenerationConfig.kt +++ b/btc-address-generation/src/main/kotlin/com/d3/btc/generation/config/BtcAddressGenerationConfig.kt @@ -20,9 +20,6 @@ interface BtcAddressGenerationConfig { //Iroha config val iroha: IrohaConfig - //Path to BTC wallet file - val btcKeysWalletPath: String - //TODO the only purpose of this account is creating PeerListProvider. This account must be removed from config. //Account that is used to register BTC addresses val registrationAccount: IrohaCredentialRawConfig diff --git a/btc-address-generation/src/main/kotlin/com/d3/btc/generation/init/BtcAddressGenerationInitialization.kt b/btc-address-generation/src/main/kotlin/com/d3/btc/generation/init/BtcAddressGenerationInitialization.kt index ef1883c9..ae37890f 100644 --- a/btc-address-generation/src/main/kotlin/com/d3/btc/generation/init/BtcAddressGenerationInitialization.kt +++ b/btc-address-generation/src/main/kotlin/com/d3/btc/generation/init/BtcAddressGenerationInitialization.kt @@ -17,8 +17,6 @@ import com.d3.btc.provider.generation.ADDRESS_GENERATION_NODE_ID_KEY import com.d3.btc.provider.generation.ADDRESS_GENERATION_TIME_KEY import com.d3.btc.provider.generation.BtcPublicKeyProvider import com.d3.btc.provider.network.BtcNetworkConfigProvider -import com.d3.btc.wallet.checkWalletNetwork -import com.d3.btc.wallet.safeSave import com.d3.commons.sidechain.iroha.CLIENT_DOMAIN import com.d3.commons.sidechain.iroha.IrohaChainListener import com.d3.commons.sidechain.iroha.util.IrohaQueryHelper @@ -34,7 +32,6 @@ import io.reactivex.schedulers.Schedulers import iroha.protocol.BlockOuterClass import iroha.protocol.Commands import mu.KLogging -import org.bitcoinj.wallet.Wallet import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component @@ -43,7 +40,6 @@ import org.springframework.stereotype.Component */ @Component class BtcAddressGenerationInitialization( - private val keysWallet: Wallet, @Qualifier("registrationQueryHelper") private val registrationQueryHelper: IrohaQueryHelper, private val btcAddressGenerationConfig: BtcAddressGenerationConfig, @@ -59,10 +55,7 @@ class BtcAddressGenerationInitialization( * @param onIrohaFail - function that will be called on Iroha failure */ fun init(onIrohaFail: () -> Unit): Result { - //Check wallet network - return keysWallet.checkWalletNetwork(btcNetworkConfigProvider.getConfig()).flatMap { - irohaChainListener.getBlockObservable() - }.map { irohaObservable -> + return irohaChainListener.getBlockObservable().map { irohaObservable -> initIrohaObservable(irohaObservable, onIrohaFail) }.flatMap { // Start free address generation at initial phase @@ -174,7 +167,7 @@ class BtcAddressGenerationInitialization( // Generates new key private fun onGenerateKey(sessionAccountName: String): Result { - return btcPublicKeyProvider.createKey(sessionAccountName) { saveWallet() } + return btcPublicKeyProvider.createKey(sessionAccountName) } /** @@ -203,18 +196,13 @@ class BtcAddressGenerationInitialization( addressType, time, nodeId - ) { saveWallet() } + ) } else { Result.of { Unit } } } } - // Safes wallet full of keys - private fun saveWallet() { - keysWallet.safeSave(btcAddressGenerationConfig.btcKeysWalletPath) - } - /** * Logger */ diff --git a/btc-address-generation/src/main/kotlin/com/d3/btc/generation/main.kt b/btc-address-generation/src/main/kotlin/com/d3/btc/generation/main.kt index 2dc0e1e6..707318e2 100644 --- a/btc-address-generation/src/main/kotlin/com/d3/btc/generation/main.kt +++ b/btc-address-generation/src/main/kotlin/com/d3/btc/generation/main.kt @@ -8,6 +8,7 @@ package com.d3.btc.generation import com.d3.btc.generation.init.BtcAddressGenerationInitialization +import com.d3.btc.keypair.getKeyProviderProfile import com.d3.commons.config.getProfile import com.github.kittinunf.result.Result import com.github.kittinunf.result.failure @@ -24,7 +25,9 @@ const val BTC_ADDRESS_GENERATION_SERVICE_NAME = "btc-add-gen" "com.d3.btc.healthcheck", "com.d3.btc.provider.generation", "com.d3.btc.provider.network", - "com.d3.btc.generation.trigger"] + "com.d3.btc.generation.trigger", + "com.d3.btc.keypair" + ] ) class BtcAddressGenerationApplication @@ -33,7 +36,7 @@ private val logger = KLogging().logger fun main(args: Array) { Result.of { val context = AnnotationConfigApplicationContext() - context.environment.setActiveProfiles(getProfile()) + context.environment.setActiveProfiles(getProfile(), getKeyProviderProfile()) context.register(BtcAddressGenerationApplication::class.java) context.refresh() context diff --git a/btc-address-generation/src/main/resources/address_generation_local.properties b/btc-address-generation/src/main/resources/address_generation_local.properties index 94f7a2d2..39b7fb03 100644 --- a/btc-address-generation/src/main/resources/address_generation_local.properties +++ b/btc-address-generation/src/main/resources/address_generation_local.properties @@ -23,5 +23,3 @@ btc-address-generation.mstRegistrationAccount.privkey=e457ce0afc8059e7a2e4d14339 btc-address-generation.iroha.hostname=d3-iroha # Iroha peer port btc-address-generation.iroha.port=50051 -# --------- Bitcoin --------- -btc-address-generation.btcKeysWalletPath=deploy/bitcoin/regtest/keys.d3.wallet diff --git a/btc-address-generation/src/main/resources/address_generation_mainnet.properties b/btc-address-generation/src/main/resources/address_generation_mainnet.properties index 201f4db0..bfbc44ea 100644 --- a/btc-address-generation/src/main/resources/address_generation_mainnet.properties +++ b/btc-address-generation/src/main/resources/address_generation_mainnet.properties @@ -22,5 +22,3 @@ btc-address-generation.mstRegistrationAccount.privkey=e457ce0afc8059e7a2e4d14339 btc-address-generation.iroha.hostname=d3-iroha # Iroha peer port btc-address-generation.iroha.port=50051 -# --------- Bitcoin --------- -btc-address-generation.btcKeysWalletPath=deploy/bitcoin/mainnet/keys.d3.wallet diff --git a/btc-address-generation/src/main/resources/address_generation_testnet.properties b/btc-address-generation/src/main/resources/address_generation_testnet.properties index b2689643..39b7fb03 100644 --- a/btc-address-generation/src/main/resources/address_generation_testnet.properties +++ b/btc-address-generation/src/main/resources/address_generation_testnet.properties @@ -23,5 +23,3 @@ btc-address-generation.mstRegistrationAccount.privkey=e457ce0afc8059e7a2e4d14339 btc-address-generation.iroha.hostname=d3-iroha # Iroha peer port btc-address-generation.iroha.port=50051 -# --------- Bitcoin --------- -btc-address-generation.btcKeysWalletPath=deploy/bitcoin/testnet/keys.d3.wallet diff --git a/btc-dw-bridge/src/main/kotlin/com/d3/btc/dwbridge/main.kt b/btc-dw-bridge/src/main/kotlin/com/d3/btc/dwbridge/main.kt index e2b20320..7d431225 100644 --- a/btc-dw-bridge/src/main/kotlin/com/d3/btc/dwbridge/main.kt +++ b/btc-dw-bridge/src/main/kotlin/com/d3/btc/dwbridge/main.kt @@ -9,6 +9,7 @@ package com.d3.btc.dwbridge import com.d3.btc.deposit.init.BtcNotaryInitialization import com.d3.btc.dwbridge.config.dwBridgeConfig +import com.d3.btc.keypair.getKeyProviderProfile import com.d3.btc.withdrawal.init.BtcWithdrawalInitialization import com.d3.commons.config.getProfile import com.d3.commons.util.createFolderIfDoesntExist @@ -43,7 +44,8 @@ const val BTC_DW_BRIDGE_SERVICE_NAME = "btc-dw-bridge" "com.d3.btc.deposit.expansion", "com.d3.btc.peer", "com.d3.btc.dwbridge", - "com.d3.btc.healthcheck"] + "com.d3.btc.healthcheck", + "com.d3.btc.keypair"] ) class BtcDWBridgeApplication @@ -58,7 +60,7 @@ fun main(args: Array) { createFolderIfDoesntExist(dwBridgeConfig.bitcoin.blockStoragePath) }.map { val context = AnnotationConfigApplicationContext() - context.environment.setActiveProfiles(getProfile()) + context.environment.setActiveProfiles(getProfile(), getKeyProviderProfile()) context.register(BtcDWBridgeApplication::class.java) context.refresh() context diff --git a/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/config/BtcWithdrawalConfig.kt b/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/config/BtcWithdrawalConfig.kt index 5ab3c4e5..797c946a 100644 --- a/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/config/BtcWithdrawalConfig.kt +++ b/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/config/BtcWithdrawalConfig.kt @@ -33,8 +33,6 @@ interface BtcWithdrawalConfig { val irohaBlockQueue: String // Path to wallet that stores transfers(UTXO) val btcTransfersWalletPath: String - // Path to wallet that stores keys - val btcKeysWalletPath: String // Account that is used to store created Bitcoin transactions val txStorageAccount: String // Account that is used to store used UTXO diff --git a/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/handler/NewTransactionCreatedHandler.kt b/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/handler/NewTransactionCreatedHandler.kt index 19053129..949e24f7 100644 --- a/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/handler/NewTransactionCreatedHandler.kt +++ b/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/handler/NewTransactionCreatedHandler.kt @@ -1,6 +1,5 @@ package com.d3.btc.withdrawal.handler -import com.d3.btc.withdrawal.config.BtcWithdrawalConfig import com.d3.btc.withdrawal.service.BtcRollbackService import com.d3.btc.withdrawal.transaction.SignCollector import com.d3.btc.withdrawal.transaction.TransactionsStorage @@ -14,7 +13,6 @@ import org.springframework.stereotype.Component class NewTransactionCreatedHandler( private val signCollector: SignCollector, private val transactionsStorage: TransactionsStorage, - private val btcWithdrawalConfig: BtcWithdrawalConfig, private val btcRollbackService: BtcRollbackService ) { @@ -28,7 +26,7 @@ class NewTransactionCreatedHandler( val txHash = createNewTxCommand.key transactionsStorage.get(createNewTxCommand.key).map { (withdrawalDetails, transaction) -> logger.info { "Tx to sign\n$transaction" } - signCollector.signAndSave(transaction, btcWithdrawalConfig.btcKeysWalletPath).fold({ + signCollector.signAndSave(transaction).fold({ logger.info { "Signatures for ${transaction.hashAsString} were successfully processed" } }, { ex -> logger.error("Cannot sign transaction $transaction", ex) diff --git a/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/transaction/SignCollector.kt b/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/transaction/SignCollector.kt index 68fac903..84ab31ba 100644 --- a/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/transaction/SignCollector.kt +++ b/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/transaction/SignCollector.kt @@ -79,10 +79,9 @@ class SignCollector( * 2) Create special account named after tx hash for signature storing * 3) Save signatures in recently created account details * @param tx - transaction to sign - * @param walletPath - path to current wallet. Used to get private keys */ - fun signAndSave(tx: Transaction, walletPath: String): Result { - return transactionSigner.sign(tx, walletPath).flatMap { signedInputs -> + fun signAndSave(tx: Transaction): Result { + return transactionSigner.sign(tx).flatMap { signedInputs -> if (signedInputs.isEmpty()) { logger.warn( "Cannot sign transaction ${tx.hashAsString}. " + diff --git a/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/transaction/TransactionSigner.kt b/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/transaction/TransactionSigner.kt index 12f2ee11..1a2cf959 100644 --- a/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/transaction/TransactionSigner.kt +++ b/btc-withdrawal/src/main/kotlin/com/d3/btc/withdrawal/transaction/TransactionSigner.kt @@ -9,15 +9,14 @@ import com.d3.btc.helper.address.createMsRedeemScript import com.d3.btc.helper.address.outPutToBase58Address import com.d3.btc.helper.address.toEcPubKey import com.d3.btc.helper.input.getConnectedOutput +import com.d3.btc.keypair.KeyPairService import com.d3.btc.provider.BtcChangeAddressProvider import com.d3.btc.provider.BtcRegisteredAddressesProvider -import com.d3.btc.wallet.safeLoad import com.d3.commons.util.hex import com.github.kittinunf.result.Result import com.github.kittinunf.result.fanout import com.github.kittinunf.result.map import mu.KLogging -import org.bitcoinj.core.ECKey import org.bitcoinj.core.Transaction import org.bitcoinj.wallet.Wallet import org.springframework.stereotype.Component @@ -29,17 +28,17 @@ import org.springframework.stereotype.Component class TransactionSigner( private val btcRegisteredAddressesProvider: BtcRegisteredAddressesProvider, private val btcChangeAddressesProvider: BtcChangeAddressProvider, - private val transfersWallet: Wallet + private val transfersWallet: Wallet, + private val keyPairService: KeyPairService ) { /** - * Signs transaction using available private keys from wallet + * Signs transaction using available private keys * * @param tx - transaction to sign - * @param keysWalletPath - path to wallet file. Used to take private keys * @return - result with list full of signatures in form "input index"->"signatureHex hex" */ - fun sign(tx: Transaction, keysWalletPath: String): Result, Exception> { - return Result.of { signUnsafe(tx, safeLoad(keysWalletPath)) } + fun sign(tx: Transaction): Result, Exception> { + return Result.of { signUnsafe(tx) } } /** @@ -59,26 +58,29 @@ class TransactionSigner( } } - // Main signing function - private fun signUnsafe(tx: Transaction, wallet: Wallet): List { + /** + * Signs given transaction inputs if it possible + * @return list of input signatures + */ + private fun signUnsafe(tx: Transaction): List { var inputIndex = 0 val signatures = ArrayList() tx.inputs.forEach { input -> val connectedOutput = input.getConnectedOutput(transfersWallet) getUsedPubKeys(outPutToBase58Address(connectedOutput)).fold({ pubKeys -> - val keyPair = getPrivPubKeyPair(pubKeys, wallet) - if (keyPair != null) { + val pubKeyHex = getAvailableKey(pubKeys) + if (pubKeyHex != null) { val redeem = createMsRedeemScript(pubKeys) logger.info("Redeem script for tx ${tx.hashAsString} input $inputIndex is $redeem") val hashOut = tx.hashForSignature(inputIndex, redeem, Transaction.SigHash.ALL, false) - val signature = keyPair.sign(hashOut) + signatures.add( InputSignature( inputIndex, SignaturePubKey( - String.hex(signature.encodeToDER()), - keyPair.publicKeyAsHex + String.hex(keyPairService.sign(hashOut.bytes, pubKeyHex)!!), + pubKeyHex ) ) ) @@ -94,16 +96,16 @@ class TransactionSigner( return signatures } - //Returns key pair related to one of given public keys. Returns null if no key pair was found - private fun getPrivPubKeyPair(pubKeys: List, wallet: Wallet): ECKey? { - pubKeys.forEach { pubKey -> + /** + * Returns public key hex which corresponding private key is controlled by the current node + * @param pubKeys - public keys to check + * @return public key hex or null if no keys are controlled by us + */ + private fun getAvailableKey(pubKeys: List): String? { + return pubKeys.find { pubKey -> val ecKey = toEcPubKey(pubKey) - val keyPair = wallet.findKeyFromPubHash(ecKey.pubKeyHash) - if (keyPair != null) { - return keyPair - } + keyPairService.exists(ecKey.publicKeyAsHex) } - return null } /** diff --git a/btc-withdrawal/src/main/resources/withdrawal_local.properties b/btc-withdrawal/src/main/resources/withdrawal_local.properties index 1f78a8e5..6b5a5b57 100644 --- a/btc-withdrawal/src/main/resources/withdrawal_local.properties +++ b/btc-withdrawal/src/main/resources/withdrawal_local.properties @@ -7,7 +7,6 @@ btc-withdrawal.notaryListSetterAccount=notary@notary btc-withdrawal.notaryListStorageAccount=notaries@notary btc-withdrawal.irohaBlockQueue=btc_withdrawal_blocks btc-withdrawal.btcTransfersWalletPath=deploy/bitcoin/regtest/transfers.d3.wallet -btc-withdrawal.btcKeysWalletPath=deploy/bitcoin/regtest/keys.d3.wallet # --------- Credentials ------- btc-withdrawal.withdrawalCredential.accountId=btc_withdrawal_service@notary btc-withdrawal.withdrawalCredential.pubkey=2ea1d2c3eb5b35a85b393622609ae116ddb2ea35e060fc74adb3b2caa324eacb diff --git a/btc-withdrawal/src/main/resources/withdrawal_mainnet.properties b/btc-withdrawal/src/main/resources/withdrawal_mainnet.properties index d49443df..e01151fb 100644 --- a/btc-withdrawal/src/main/resources/withdrawal_mainnet.properties +++ b/btc-withdrawal/src/main/resources/withdrawal_mainnet.properties @@ -7,7 +7,6 @@ btc-withdrawal.notaryListSetterAccount=notary@notary btc-withdrawal.notaryListStorageAccount=notaries@notary btc-withdrawal.irohaBlockQueue=btc_withdrawal_blocks btc-withdrawal.btcTransfersWalletPath=deploy/bitcoin/mainnet/transfers.d3.wallet -btc-withdrawal.btcKeysWalletPath=deploy/bitcoin/mainnet/keys.d3.wallet # --------- Credentials ------- btc-withdrawal.withdrawalCredential.accountId=btc_withdrawal_service@notary btc-withdrawal.withdrawalCredential.pubkey=2ea1d2c3eb5b35a85b393622609ae116ddb2ea35e060fc74adb3b2caa324eacb diff --git a/btc-withdrawal/src/main/resources/withdrawal_testnet.properties b/btc-withdrawal/src/main/resources/withdrawal_testnet.properties index 05d7b9dc..025fdb81 100644 --- a/btc-withdrawal/src/main/resources/withdrawal_testnet.properties +++ b/btc-withdrawal/src/main/resources/withdrawal_testnet.properties @@ -7,7 +7,6 @@ btc-withdrawal.notaryListSetterAccount=notary@notary btc-withdrawal.notaryListStorageAccount=notaries@notary btc-withdrawal.irohaBlockQueue=btc_withdrawal_blocks btc-withdrawal.btcTransfersWalletPath=deploy/bitcoin/testnet/transfers.d3.wallet -btc-withdrawal.btcKeysWalletPath=deploy/bitcoin/testnet/keys.d3.wallet # --------- Credentials ------- btc-withdrawal.withdrawalCredential.accountId=btc_withdrawal_service@notary btc-withdrawal.withdrawalCredential.pubkey=2ea1d2c3eb5b35a85b393622609ae116ddb2ea35e060fc74adb3b2caa324eacb diff --git a/btc/build.gradle b/btc/build.gradle index e1682d32..6c958a0f 100644 --- a/btc/build.gradle +++ b/btc/build.gradle @@ -8,6 +8,7 @@ buildscript { apply plugin: "kotlin-spring" // See https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-spring-compiler-plugin dependencies { + compile files('libs/primusX.jar') //TODO change version after D3 release compile "com.github.d3ledger.notary:notary-commons:$notary_version" //bitcoin @@ -68,14 +69,4 @@ task btcGenerateBlocks(type: JavaExec) { args getBtcGenerateBlocksArgs() classpath = sourceSets.main.runtimeClasspath setWorkingDir("$rootDir/") -} - -/** Recreates wallets in RegTest mode - * - * Usage ./gradlew btcRefreshWallets - */ -task btcRefreshWallets(type: JavaExec) { - main = 'com.d3.btc.cli.BtcRefreshWalletsMain' - classpath = sourceSets.main.runtimeClasspath - setWorkingDir("$rootDir/") -} +} \ No newline at end of file diff --git a/btc/libs/primusX.jar b/btc/libs/primusX.jar new file mode 100644 index 00000000..9fd1bcc3 Binary files /dev/null and b/btc/libs/primusX.jar differ diff --git a/btc/src/main/kotlin/com/d3/btc/cli/RefreshWallets.kt b/btc/src/main/kotlin/com/d3/btc/cli/RefreshWallets.kt deleted file mode 100644 index 2a28e2c7..00000000 --- a/btc/src/main/kotlin/com/d3/btc/cli/RefreshWallets.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright D3 Ledger, Inc. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -@file:JvmName("BtcRefreshWalletsMain") -package com.d3.btc.cli - -import org.bitcoinj.params.RegTestParams -import org.bitcoinj.wallet.Wallet -import java.io.File - -/** - * Recreates Regtest wallets. Good fo testing. - */ -fun main(args: Array) { - val networkParams = RegTestParams.get() - // Wallet for keys - val keysWallet = Wallet(networkParams) - // Wallet for transfers - val transfersWallet = Wallet(networkParams) - //Save files - keysWallet.saveToFile(File("deploy/bitcoin/regtest/keys.d3.wallet")) - transfersWallet.saveToFile(File("deploy/bitcoin/regtest/transfers.d3.wallet")) -} diff --git a/btc/src/main/kotlin/com/d3/btc/keypair/KeyPairProfile.kt b/btc/src/main/kotlin/com/d3/btc/keypair/KeyPairProfile.kt new file mode 100644 index 00000000..d57f65ee --- /dev/null +++ b/btc/src/main/kotlin/com/d3/btc/keypair/KeyPairProfile.kt @@ -0,0 +1,19 @@ +package com.d3.btc.keypair + +import mu.KLogging + +private val logger = KLogging().logger +private const val KEY_PROVIDER_ENV = "KEY_PROVIDER" +private const val DEFAULT_KEY_PROVIDER = "wallet" + +/** + * Returns key provider profile from env variables + */ +fun getKeyProviderProfile(): String { + var profile = System.getenv(KEY_PROVIDER_ENV) + if (profile == null) { + logger.warn { "No key provider profile set. Using default '$DEFAULT_KEY_PROVIDER' profile" } + profile = DEFAULT_KEY_PROVIDER + } + return profile +} \ No newline at end of file diff --git a/btc/src/main/kotlin/com/d3/btc/keypair/KeyPairService.kt b/btc/src/main/kotlin/com/d3/btc/keypair/KeyPairService.kt new file mode 100644 index 00000000..40759f28 --- /dev/null +++ b/btc/src/main/kotlin/com/d3/btc/keypair/KeyPairService.kt @@ -0,0 +1,27 @@ +package com.d3.btc.keypair + +import org.bitcoinj.core.ECKey + +interface KeyPairService { + + /** + * Signs given [message] with private key named [pubKeyHex] + * @param message - message to sign + * @param pubKeyHex - hex of public key, which corresponding private key will be used to sign [message] + * @return signature in byte array or null if private key associated with [pubKeyHex] doesn't exist + */ + fun sign(message: ByteArray, pubKeyHex: String): ByteArray? + + /** + * Creates key pair + * @return keypair + */ + fun createKeyPair(): ECKey + + /** + * Cheks if public key exists + * @param pubKeyHex - hex of public key that will checked + * @return true if exists + */ + fun exists(pubKeyHex: String): Boolean +} \ No newline at end of file diff --git a/btc/src/main/kotlin/com/d3/btc/keypair/securosys/SecuroSysAppConfiguration.kt b/btc/src/main/kotlin/com/d3/btc/keypair/securosys/SecuroSysAppConfiguration.kt new file mode 100644 index 00000000..1acb113c --- /dev/null +++ b/btc/src/main/kotlin/com/d3/btc/keypair/securosys/SecuroSysAppConfiguration.kt @@ -0,0 +1,17 @@ +package com.d3.btc.keypair.securosys + +import com.d3.commons.config.loadRawLocalConfigs +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Profile + + +@Profile("securosys") +@Configuration +class SecuroSysAppConfiguration { + + private val securoSysConfig = loadRawLocalConfigs("securosys", SecuroSysConfig::class.java, "securosys.properties") + + @Bean + fun securoSysConfig() = securoSysConfig +} \ No newline at end of file diff --git a/btc/src/main/kotlin/com/d3/btc/keypair/securosys/SecuroSysConfig.kt b/btc/src/main/kotlin/com/d3/btc/keypair/securosys/SecuroSysConfig.kt new file mode 100644 index 00000000..db5ec1cd --- /dev/null +++ b/btc/src/main/kotlin/com/d3/btc/keypair/securosys/SecuroSysConfig.kt @@ -0,0 +1,15 @@ +package com.d3.btc.keypair.securosys + +/** + * Configurations of SecuroSys HSM + */ +interface SecuroSysConfig { + // Host of SecuroSys + val host: String + // Port of SecuroSys + val port: Int + // SecuroSys username + val username: String + // SecuroSys password + val password: String +} \ No newline at end of file diff --git a/btc/src/main/kotlin/com/d3/btc/keypair/securosys/SecuroSysJCE.kt b/btc/src/main/kotlin/com/d3/btc/keypair/securosys/SecuroSysJCE.kt new file mode 100644 index 00000000..efbc4b1a --- /dev/null +++ b/btc/src/main/kotlin/com/d3/btc/keypair/securosys/SecuroSysJCE.kt @@ -0,0 +1,76 @@ +package com.d3.btc.keypair.securosys + +import com.securosys.primus.jce.PrimusCertificate +import com.securosys.primus.jce.PrimusProvider +import mu.KLogging +import java.security.* +import java.security.cert.Certificate +import java.security.spec.ECGenParameterSpec + +private const val SIGN_ALGORITHM = "NONEwithECDSA" +private const val CURVE_TYPE = "secp256k1" +private const val KEY_PAIR_TYPE = "EC" +private val KEY_STORE_PASSWORD = "".toCharArray() + +private val logger = KLogging().logger + +/** + * Signs message with given keypair + * @param message - message to sign + * @param keyPair - keypair that is used to sign data + * @return signature in byte array + */ +fun sign(message: ByteArray, keyPair: KeyPair): ByteArray { + val signature = Signature.getInstance(SIGN_ALGORITHM, PrimusProvider.getProviderName()) + signature.initSign(keyPair.private) + signature.update(message) + return signature.sign() +} + +/** + * Saves key + * @param keyName - name of key to store + * @param keyPair - key pair to store + */ +fun persistKeyPair(keyName: String, keyPair: KeyPair) { + logger.info("Persist key $keyName") + val keyStore = + KeyStore.getInstance(PrimusProvider.getKeyStoreTypeName(), PrimusProvider.getProviderName()) + keyStore.load(null) + keyStore.setKeyEntry( + keyName.toLowerCase(), + keyPair.private, + KEY_STORE_PASSWORD, + arrayOf(PrimusCertificate(keyPair.public)) + ) +} + +/** + * Loads key pair from storage + * @param keyName - name of key to load + * @return key pair associated with given [keyName] or null + */ +fun loadKeyPair(keyName: String): KeyPair? { + val lowerCaseKeyName=keyName.toLowerCase() + val keyStore = + KeyStore.getInstance(PrimusProvider.getKeyStoreTypeName(), PrimusProvider.getProviderName()) + keyStore.load(null) + if (!keyStore.containsAlias(lowerCaseKeyName)) { + logger.warn("Key $keyName doesn't exist") + return null + } + val privateKey = keyStore.getKey(lowerCaseKeyName, KEY_STORE_PASSWORD) as PrivateKey + val publicKey = keyStore.getCertificate(lowerCaseKeyName).publicKey + return KeyPair(publicKey, privateKey) +} + +/** + * Creates key generator + * @return key generator + */ +fun createGenerator(): KeyPairGenerator { + val keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_TYPE, PrimusProvider.getProviderName()) + val ecParam = ECGenParameterSpec(CURVE_TYPE) + keyPairGenerator.initialize(ecParam) + return keyPairGenerator +} \ No newline at end of file diff --git a/btc/src/main/kotlin/com/d3/btc/keypair/securosys/SecuroSysKeyPairService.kt b/btc/src/main/kotlin/com/d3/btc/keypair/securosys/SecuroSysKeyPairService.kt new file mode 100644 index 00000000..1a49c047 --- /dev/null +++ b/btc/src/main/kotlin/com/d3/btc/keypair/securosys/SecuroSysKeyPairService.kt @@ -0,0 +1,97 @@ +package com.d3.btc.keypair.securosys + +import com.d3.btc.keypair.KeyPairService +import com.securosys.primus.jce.PrimusConfiguration +import com.securosys.primus.jce.PrimusKeyAttributes +import com.securosys.primus.jce.PrimusLogin +import com.securosys.primus.jce.PrimusProvider +import jp.co.soramitsu.iroha.java.Utils +import mu.KLogging +import org.bitcoinj.core.ECKey +import org.springframework.context.annotation.Profile +import org.springframework.stereotype.Component +import sun.security.ec.ECPublicKeyImpl + + +/** + * Cloud HSM 'SecuroSys' key pair service + */ +@Component +@Profile("securosys") +class SecuroSysKeyPairService( + private val securoSysConfig: SecuroSysConfig +) : KeyPairService { + + init { + logger.info("Install 'Primus' provider") + PrimusProvider.installProvider() + setAttributes() + } + + override fun exists(pubKeyHex: String): Boolean { + return loginAndApply { loadKeyPair(pubKeyHex) != null } + } + + override fun sign(message: ByteArray, pubKeyHex: String): ByteArray? { + return loginAndApply { + logger.info("Start signing message ${Utils.toHex(message)} with public key $pubKeyHex") + val keyPair = loadKeyPair(pubKeyHex) + if (keyPair != null) { + sign(message, keyPair) + } else { + logger.warn("Cannot sign message ${Utils.toHex(message)} with public key $pubKeyHex. Public key is not found.") + null + } + } + } + + override fun createKeyPair(): ECKey { + return loginAndApply { + val keyPairGenerator = createGenerator() + val keyPair = keyPairGenerator.generateKeyPair() + val ecPublicKey = ECPublicKeyImpl(keyPair.public.encoded) + val pubKeyHex = Utils.toHex(ecPublicKey.encodedPublicValue) + logger.info("New key pair with public key $pubKeyHex has been created.") + persistKeyPair(pubKeyHex, keyPair) + logger.info("Key pair with public key $pubKeyHex has been saved.") + ECKey.fromPublicOnly(ecPublicKey.encodedPublicValue) + } + } + + /** + * Logs in cloud HSM, runs given function and then logs out + * @param apply - function to apply after successful log attempt + * @return value that returns [apply] function + */ + @Synchronized + private fun loginAndApply(apply: () -> T): T { + try { + PrimusConfiguration.setHsmHostAndPortAndUser( + securoSysConfig.host, + securoSysConfig.port, + securoSysConfig.username + ) + logger.info("HSM log in attempt") + PrimusLogin.login(securoSysConfig.username, securoSysConfig.password.toCharArray()) + logger.info("HSM log in success") + return apply() + } finally { + PrimusLogin.logout() + logger.info("HSM logout") + } + } + + /** + * Sets default attributes + */ + private fun setAttributes() { + // Private keys MUST NOT be extractable + PrimusKeyAttributes.setKeyAccessFlag(PrimusKeyAttributes.ACCESS_EXTRACTABLE, false) + // Sensitive data MUST NOT be accessible + PrimusKeyAttributes.setKeyAccessFlag(PrimusKeyAttributes.ACCESS_SENSITIVE, false) + // Keys MUST NOT be 'deletable' + PrimusKeyAttributes.setKeyAccessFlag(PrimusKeyAttributes.ACCESS_INDESTRUCTIBLE, true); + } + + companion object : KLogging() +} \ No newline at end of file diff --git a/btc/src/main/kotlin/com/d3/btc/keypair/wallet/WalletAppConfiguration.kt b/btc/src/main/kotlin/com/d3/btc/keypair/wallet/WalletAppConfiguration.kt new file mode 100644 index 00000000..703e26f5 --- /dev/null +++ b/btc/src/main/kotlin/com/d3/btc/keypair/wallet/WalletAppConfiguration.kt @@ -0,0 +1,21 @@ +package com.d3.btc.keypair.wallet + +import com.d3.btc.provider.network.BtcNetworkConfigProvider +import com.d3.btc.wallet.createWalletIfAbsent +import com.d3.commons.config.loadLocalConfigs +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Profile + +@Profile("wallet") +@Configuration +class WalletAppConfiguration { + + private val walletConfig = loadLocalConfigs("wallet", WalletConfig::class.java, "wallet.properties").get() + + @Bean + fun keysWalletPath(networkProvider: BtcNetworkConfigProvider): String { + createWalletIfAbsent(walletConfig.btcKeysWalletPath, networkProvider) + return walletConfig.btcKeysWalletPath + } +} \ No newline at end of file diff --git a/btc/src/main/kotlin/com/d3/btc/keypair/wallet/WalletConfig.kt b/btc/src/main/kotlin/com/d3/btc/keypair/wallet/WalletConfig.kt new file mode 100644 index 00000000..4855a684 --- /dev/null +++ b/btc/src/main/kotlin/com/d3/btc/keypair/wallet/WalletConfig.kt @@ -0,0 +1,9 @@ +package com.d3.btc.keypair.wallet + +/** + * Config of wallet with keys + */ +interface WalletConfig { + // Path to wallet file + val btcKeysWalletPath: String +} \ No newline at end of file diff --git a/btc/src/main/kotlin/com/d3/btc/keypair/wallet/WalletKeyPairService.kt b/btc/src/main/kotlin/com/d3/btc/keypair/wallet/WalletKeyPairService.kt new file mode 100644 index 00000000..4e70d2ff --- /dev/null +++ b/btc/src/main/kotlin/com/d3/btc/keypair/wallet/WalletKeyPairService.kt @@ -0,0 +1,70 @@ +package com.d3.btc.keypair.wallet + +import com.d3.btc.helper.address.toEcPubKey +import com.d3.btc.keypair.KeyPairService +import com.d3.btc.wallet.safeLoad +import com.d3.btc.wallet.safeSave +import org.bitcoinj.core.ECKey +import org.bitcoinj.core.Sha256Hash +import org.bitcoinj.crypto.DeterministicKey +import org.bitcoinj.wallet.Wallet +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.context.annotation.Profile +import org.springframework.stereotype.Component + +/** + * Key pair service base on '.wallet' files + */ +@Component +@Profile("wallet") +class WalletKeyPairService( + @Qualifier("keysWalletPath") + private val keysWalletPath: String +) : KeyPairService { + + @Synchronized + override fun exists(pubKeyHex: String): Boolean { + val wallet = safeLoad(keysWalletPath) + val result = wallet.issuedReceiveKeys.any { ecKey -> + ecKey.publicKeyAsHex == pubKeyHex + } + return result + } + + @Synchronized + override fun sign(message: ByteArray, pubKeyHex: String): ByteArray? { + val wallet = safeLoad(keysWalletPath) + val keyPair = getKeyPair(pubKeyHex, wallet) + if (keyPair != null) { + return keyPair.sign(Sha256Hash.wrap(message)).encodeToDER() + } + return null + } + + @Synchronized + override fun createKeyPair(): ECKey { + var key: DeterministicKey? = null + val wallet = safeLoad(keysWalletPath) + try { + return wallet.freshReceiveKey() + } finally { + wallet.safeSave(keysWalletPath) + } + } + + /** + * Returns key pair associated with [pubKeyHex] + * @param pubKeyHex - hex of public key which associated private key will be returned + * @param wallet - wallet that will be used as a source of keys + * @return key pair or null if key doesn't exist in given [wallet] + */ + private fun getKeyPair(pubKeyHex: String, wallet: Wallet): ECKey? { + val ecKey = toEcPubKey(pubKeyHex) + val keyPair = wallet.findKeyFromPubHash(ecKey.pubKeyHash) + if (keyPair != null) { + return keyPair + } + return null + } + +} \ No newline at end of file diff --git a/btc/src/main/kotlin/com/d3/btc/provider/generation/BtcPublicKeyProvider.kt b/btc/src/main/kotlin/com/d3/btc/provider/generation/BtcPublicKeyProvider.kt index db278dc8..7433fd80 100644 --- a/btc/src/main/kotlin/com/d3/btc/provider/generation/BtcPublicKeyProvider.kt +++ b/btc/src/main/kotlin/com/d3/btc/provider/generation/BtcPublicKeyProvider.kt @@ -6,6 +6,8 @@ package com.d3.btc.provider.generation import com.d3.btc.helper.address.createMsAddress +import com.d3.btc.helper.address.toEcPubKey +import com.d3.btc.keypair.KeyPairService import com.d3.btc.model.AddressInfo import com.d3.btc.model.BtcAddressType import com.d3.btc.provider.network.BtcNetworkConfigProvider @@ -16,14 +18,12 @@ import com.d3.commons.util.getRandomId import com.github.kittinunf.result.Result import com.github.kittinunf.result.map import mu.KLogging -import org.bitcoinj.wallet.Wallet -import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component +import java.util.concurrent.ConcurrentHashMap /** * Bitcoin keys provider - * @param keysWallet - bitcoin wallet * @param notaryPeerListProvider - provider to query all current notaries * @param notaryAccount - Iroha account of notary service. * Used to store free BTC addresses that can be registered by clients later @@ -31,35 +31,36 @@ import org.springframework.stereotype.Component * @param multiSigConsumer - consumer of multisignature Iroha account. Used to create multisignature transactions. * @param sessionConsumer - consumer of session Iroha account. Used to store session data. * @param btcNetworkConfigProvider - provider of network configuration + * @param keyPairService - service that is used to create keys */ @Component class BtcPublicKeyProvider( - @Autowired private val keysWallet: Wallet, - @Autowired private val notaryPeerListProvider: NotaryPeerListProvider, + private val notaryPeerListProvider: NotaryPeerListProvider, @Qualifier("notaryAccount") - @Autowired private val notaryAccount: String, + private val notaryAccount: String, @Qualifier("changeAddressStorageAccount") - @Autowired private val changeAddressStorageAccount: String, + private val changeAddressStorageAccount: String, @Qualifier("multiSigConsumer") - @Autowired private val multiSigConsumer: IrohaConsumer, + private val multiSigConsumer: IrohaConsumer, @Qualifier("sessionConsumer") - @Autowired private val sessionConsumer: IrohaConsumer, - @Autowired private val btcNetworkConfigProvider: BtcNetworkConfigProvider + private val sessionConsumer: IrohaConsumer, + private val btcNetworkConfigProvider: BtcNetworkConfigProvider, + private val keyPairService: KeyPairService ) { init { logger.info { "BtcPublicKeyProvider was successfully initialized" } } + private val createdAddresses = ConcurrentHashMap.newKeySet() + /** * Creates notary public key and sets it into session account details * @param sessionAccountName - name of session account - * @param onKeyCreated - function that will be called right after key creation * @return new public key created by notary */ - fun createKey(sessionAccountName: String, onKeyCreated: () -> Unit): Result { - // Generate new key from wallet - val key = keysWallet.freshReceiveKey() - onKeyCreated() + fun createKey(sessionAccountName: String): Result { + // Generate new key + val key = keyPairService.createKeyPair() val pubKey = key.publicKeyAsHex return ModelUtil.setAccountDetail( sessionConsumer, @@ -78,15 +79,13 @@ class BtcPublicKeyProvider( * @param addressType - type of address to create * @param generationTime - time of address generation. Used in Iroha multisig * @param nodeId - node id - * @param onMsAddressCreated - function that will be called right after MS address creation * @return Result of operation */ fun checkAndCreateMultiSigAddress( notaryKeys: List, addressType: BtcAddressType, generationTime: Long, - nodeId: String, - onMsAddressCreated: () -> Unit + nodeId: String ): Result { return multiSigConsumer.getConsumerQuorum().map { quorum -> val peers = notaryPeerListProvider.getPeerList().size @@ -103,14 +102,12 @@ class BtcPublicKeyProvider( return@map } val msAddress = createMsAddress(notaryKeys, btcNetworkConfigProvider.getConfig()) - if (keysWallet.isAddressWatched(msAddress)) { + if (createdAddresses.contains(msAddress.toBase58())) { logger.info("Address $msAddress has been already created") return@map - } else if (!keysWallet.addWatchedAddress(msAddress)) { - throw IllegalStateException("BTC address $msAddress was not added to wallet") } - onMsAddressCreated() - logger.info("Address $msAddress was added to wallet. Used keys are ${notaryKeys}") + createdAddresses.add(msAddress.toBase58()) + logger.info("Address $msAddress was added to wallet. Used keys are $notaryKeys") val addressStorage = createAddressStorage(addressType, notaryKeys, nodeId, generationTime) ModelUtil.setAccountDetail( @@ -131,10 +128,9 @@ class BtcPublicKeyProvider( * @param notaryKeys - public keys of notaries * @return true if at least one current notary key is among given notaryKeys */ - private fun hasMyKey(notaryKeys: Collection) = notaryKeys.find { key -> - keysWallet.issuedReceiveKeys.find { ecKey -> ecKey.publicKeyAsHex == key } != null - } != null - + private fun hasMyKey(notaryKeys: Collection) = notaryKeys.any { key -> + keyPairService.exists(toEcPubKey(key).publicKeyAsHex) + } /** * Creates address storage object that depends on generated address type @@ -154,7 +150,7 @@ class BtcPublicKeyProvider( logger.info { "Creating change address" } Pair( AddressInfo.createChangeAddressInfo( - ArrayList(notaryKeys), + ArrayList(notaryKeys), nodeId, generationTime ), @@ -165,7 +161,7 @@ class BtcPublicKeyProvider( logger.info { "Creating free address" } Pair( AddressInfo.createFreeAddressInfo( - ArrayList(notaryKeys), + ArrayList(notaryKeys), nodeId, generationTime ), diff --git a/btc/src/main/resources/securosys.properties b/btc/src/main/resources/securosys.properties new file mode 100644 index 00000000..1f412fed --- /dev/null +++ b/btc/src/main/resources/securosys.properties @@ -0,0 +1,4 @@ +securosys.host=grimsel.securosys.ch +securosys.port=2400 +securosys.username=user +securosys.password=password \ No newline at end of file diff --git a/btc/src/main/resources/wallet_local.properties b/btc/src/main/resources/wallet_local.properties new file mode 100644 index 00000000..e7899754 --- /dev/null +++ b/btc/src/main/resources/wallet_local.properties @@ -0,0 +1 @@ +wallet.btcKeysWalletPath=deploy/bitcoin/regtest/keys.d3.wallet \ No newline at end of file diff --git a/btc/src/main/resources/wallet_mainnet.properties b/btc/src/main/resources/wallet_mainnet.properties new file mode 100644 index 00000000..8fe29a24 --- /dev/null +++ b/btc/src/main/resources/wallet_mainnet.properties @@ -0,0 +1 @@ +wallet.btcKeysWalletPath=deploy/bitcoin/mainnet/keys.d3.wallet \ No newline at end of file diff --git a/btc/src/main/resources/wallet_testnet.properties b/btc/src/main/resources/wallet_testnet.properties new file mode 100644 index 00000000..3fd930a4 --- /dev/null +++ b/btc/src/main/resources/wallet_testnet.properties @@ -0,0 +1 @@ +wallet.btcKeysWalletPath=deploy/bitcoin/testnet/keys.d3.wallet \ No newline at end of file diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcAddressGenerationIntegrationTest.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcAddressGenerationIntegrationTest.kt index 16d9f47d..07e2dd1c 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcAddressGenerationIntegrationTest.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcAddressGenerationIntegrationTest.kt @@ -26,7 +26,7 @@ import java.io.File import java.util.* const val WAIT_PREGEN_PROCESS_MILLIS = 15_000L -const val WAIT_PREGEN_INIT_PROCESS_MILLIS = 30_000L +const val WAIT_PREGEN_INIT_PROCESS_MILLIS = 45_000L @TestInstance(TestInstance.Lifecycle.PER_CLASS) class BtcAddressGenerationIntegrationTest { @@ -82,8 +82,7 @@ class BtcAddressGenerationIntegrationTest { }.map { entry -> entry.value } val pubKey = notaryKeys.first() assertNotNull(pubKey) - val wallet = Wallet.loadFromFile(File(environment.btcGenerationConfig.btcKeysWalletPath)) - assertTrue(wallet.issuedReceiveKeys.any { ecKey -> ecKey.publicKeyAsHex == pubKey }) + assertTrue(environment.keyPairService.exists(pubKey)) val notaryAccountDetails = integrationHelper.getAccountDetails( environment.btcGenerationConfig.notaryAccount, @@ -91,7 +90,6 @@ class BtcAddressGenerationIntegrationTest { ) val expectedMsAddress = com.d3.btc.helper.address.createMsAddress(notaryKeys, RegTestParams.get()) - assertTrue(wallet.isAddressWatched(expectedMsAddress)) val generatedAddress = AddressInfo.fromJson(notaryAccountDetails[expectedMsAddress.toBase58()]!!)!! assertNull(generatedAddress.irohaClient) @@ -127,8 +125,7 @@ class BtcAddressGenerationIntegrationTest { }.map { entry -> entry.value } val pubKey = notaryKeys.first() assertNotNull(pubKey) - val wallet = Wallet.loadFromFile(File(environment.btcGenerationConfig.btcKeysWalletPath)) - assertTrue(wallet.issuedReceiveKeys.any { ecKey -> ecKey.publicKeyAsHex == pubKey }) + assertTrue(environment.keyPairService.exists(pubKey)) val changeAddressStorageAccountDetails = integrationHelper.getAccountDetails( environment.btcGenerationConfig.changeAddressesStorageAccount, diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcAddressGenerationWalletAutogenerationTest.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcAddressGenerationWalletAutogenerationTest.kt index 860f5891..43cdd33e 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcAddressGenerationWalletAutogenerationTest.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcAddressGenerationWalletAutogenerationTest.kt @@ -47,7 +47,7 @@ class BtcAddressGenerationWalletAutogenerationTest { containerHelper.irohaContainer.toriiAddress.port.toString() ) addressGenerationContainer.addEnv( - "BTC-ADDRESS-GENERATION_BTCKEYSWALLETPATH", + "WALLET_BTCKEYSWALLETPATH", "$containerWalletsFolder/$walletName" ) } diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcDepositFailResistanceIntegrationTest.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcDepositFailResistanceIntegrationTest.kt index c80003e8..874051e9 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcDepositFailResistanceIntegrationTest.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcDepositFailResistanceIntegrationTest.kt @@ -64,7 +64,7 @@ class BtcDepositFailResistanceIntegrationTest { Assertions.assertEquals(200, res.statusCode) val btcAddress = integrationHelper.registerBtcAddress( - environment.btcAddressGenerationConfig.btcKeysWalletPath, + environment.keyPairService, randomName, CLIENT_DOMAIN ) diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcMultiAddressGenerationIntegrationTest.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcMultiAddressGenerationIntegrationTest.kt index dae197b2..9e1479b5 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcMultiAddressGenerationIntegrationTest.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcMultiAddressGenerationIntegrationTest.kt @@ -5,6 +5,7 @@ package integration.btc +import com.d3.btc.helper.address.createMsAddress import com.d3.btc.model.AddressInfo import com.d3.btc.model.BtcAddressType import com.d3.btc.provider.generation.ADDRESS_GENERATION_NODE_ID_KEY @@ -44,13 +45,13 @@ class BtcMultiAddressGenerationIntegrationTest { init { var peerCount = 0 integrationHelper.accountHelper.mstRegistrationAccounts.forEach { mstRegistrationAccount -> - val walletPostfix = "test-multisig-generation-$peerCount" + val testName = "test-multisig-generation-$peerCount" integrationHelper.addBtcNotary("test_notary_${peerCount++}", "test_notary_address") val environment = BtcAddressGenerationTestEnvironment( integrationHelper, + testName = testName, btcGenerationConfig = integrationHelper.configHelper.createBtcAddressGenerationConfig( - 0, - walletPostfix + 0 ), mstRegistrationCredential = mstRegistrationAccount ) @@ -95,28 +96,22 @@ class BtcMultiAddressGenerationIntegrationTest { entry.key != ADDRESS_GENERATION_TIME_KEY && entry.key != ADDRESS_GENERATION_NODE_ID_KEY }.map { entry -> entry.value } - val expectedMsAddress = - com.d3.btc.helper.address.createMsAddress(notaryKeys, RegTestParams.get()) - val wallets = ArrayList() - environments.forEach { env -> - wallets.add(Wallet.loadFromFile(File(env.btcGenerationConfig.btcKeysWalletPath))) - } + val expectedMsAddress = createMsAddress(notaryKeys, RegTestParams.get()) - //Check that every wallet has generated address - wallets.forEach { wallet -> - assertTrue(wallet.isAddressWatched(expectedMsAddress)) - } //Check that every wallet has only one public key that was used in address generation val keysSavedInWallets = ArrayList() notaryKeys.forEach { pubKey -> - val walletWithKey = wallets.first { wallet -> - wallet.issuedReceiveKeys.any { ecKey -> ecKey.publicKeyAsHex == pubKey } + var addedKeys = 0 + environments.forEach { env -> + if (env.keyPairService.exists(pubKey)) { + keysSavedInWallets.add(pubKey) + addedKeys++ + } } - keysSavedInWallets.add(pubKey) - wallets.remove(walletWithKey) + assertEquals(1, addedKeys) } - assertEquals(keysSavedInWallets.size, notaryKeys.size) + assertEquals(keysSavedInWallets, notaryKeys) val notaryAccountDetails = integrationHelper.getAccountDetails( environment.btcGenerationConfig.notaryAccount, diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcMultiNotaryIntegrationTest.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcMultiNotaryIntegrationTest.kt index 693be699..bcd99ade 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcMultiNotaryIntegrationTest.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcMultiNotaryIntegrationTest.kt @@ -85,7 +85,7 @@ class BtcMultiNotaryIntegrationTest { assertEquals(200, res.statusCode) val btcAddress = integrationHelper.registerBtcAddress( - environments.first().notaryConfig.btcTransferWalletPath, + environments.first().keyPairService, randomName, CLIENT_DOMAIN ) diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcMultiWithdrawalIntegrationTest.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcMultiWithdrawalIntegrationTest.kt index 1f184c82..b2d39b1d 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcMultiWithdrawalIntegrationTest.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcMultiWithdrawalIntegrationTest.kt @@ -76,7 +76,7 @@ class BtcMultiWithdrawalIntegrationTest { ) environment.withdrawalTransferService.addNewBtcTransactionListener { tx -> environment.createdTransactions[tx.hashAsString] = - Pair(System.currentTimeMillis(), tx) + Pair(System.currentTimeMillis(), tx) } withdrawalEnvironments.add(environment) val blockStorageFolder = @@ -92,9 +92,9 @@ class BtcMultiWithdrawalIntegrationTest { val testName = testNames[peerCount++] val environment = BtcAddressGenerationTestEnvironment( integrationHelper, + testName = testName, btcGenerationConfig = integrationHelper.configHelper.createBtcAddressGenerationConfig( - 0, - testName + 0 ), mstRegistrationCredential = mstRegistrationAccount ) diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcNotaryIntegrationTest.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcNotaryIntegrationTest.kt index dbcc46da..82698c4b 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcNotaryIntegrationTest.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcNotaryIntegrationTest.kt @@ -64,7 +64,7 @@ class BtcNotaryIntegrationTest { assertEquals(200, res.statusCode) val btcAddress = integrationHelper.registerBtcAddress( - environment.btcAddressGenerationConfig.btcKeysWalletPath, + environment.keyPairService, randomName, CLIENT_DOMAIN ) @@ -104,7 +104,7 @@ class BtcNotaryIntegrationTest { assertEquals(200, res.statusCode) val btcAddress = integrationHelper.registerBtcAddress( - environment.btcAddressGenerationConfig.btcKeysWalletPath, + environment.keyPairService, randomName, CLIENT_DOMAIN ) @@ -148,7 +148,7 @@ class BtcNotaryIntegrationTest { assertEquals(200, res.statusCode) val btcAddress = integrationHelper.registerBtcAddress( - environment.btcAddressGenerationConfig.btcKeysWalletPath, + environment.keyPairService, randomName, CLIENT_DOMAIN ) @@ -198,7 +198,7 @@ class BtcNotaryIntegrationTest { assertEquals(200, res.statusCode) val btcAddress = integrationHelper.registerBtcAddress( - environment.btcAddressGenerationConfig.btcKeysWalletPath, + environment.keyPairService, randomName, CLIENT_DOMAIN ) @@ -239,7 +239,7 @@ class BtcNotaryIntegrationTest { assertEquals(200, res.statusCode) val btcAddress = integrationHelper.registerBtcAddress( - environment.btcAddressGenerationConfig.btcKeysWalletPath, + environment.keyPairService, randomName, CLIENT_DOMAIN ) diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcRegistrationIntegrationTest.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcRegistrationIntegrationTest.kt index 2bb20b17..8addfb4a 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcRegistrationIntegrationTest.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcRegistrationIntegrationTest.kt @@ -8,7 +8,8 @@ package integration.btc import com.d3.commons.sidechain.iroha.CLIENT_DOMAIN import com.d3.commons.util.getRandomString import com.d3.commons.util.toHexString -import com.squareup.moshi.Moshi +import com.google.gson.Gson +import com.google.gson.JsonObject import integration.btc.environment.BtcRegistrationTestEnvironment import integration.helper.BtcIntegrationHelperUtil import integration.registration.RegistrationServiceTestEnvironment @@ -32,10 +33,7 @@ class BtcRegistrationIntegrationTest { private val registrationServiceEnvironment = RegistrationServiceTestEnvironment(integrationHelper) - // Moshi adapter for response JSON deserialization - private val moshiAdapter = Moshi - .Builder() - .build()!!.adapter(Map::class.java)!! + private val gson = Gson() init { registrationServiceEnvironment.registrationInitialization.init() @@ -57,7 +55,7 @@ class BtcRegistrationIntegrationTest { */ @Test fun testRegistration() { - integrationHelper.genFreeBtcAddress(btcRegistrationEnvironment.btcAddressGenerationConfig.btcKeysWalletPath) + integrationHelper.genFreeBtcAddress(btcRegistrationEnvironment.keyPairService) val keypair = Ed25519Sha3().generateKeypair() val userName = String.getRandomString(9) var res = registrationServiceEnvironment.register(userName, keypair.public.toHexString()) @@ -65,8 +63,8 @@ class BtcRegistrationIntegrationTest { res = btcRegistrationEnvironment.register(userName, keypair.public.toHexString()) assertEquals(200, res.statusCode) - val response = moshiAdapter.fromJson(res.jsonObject.toString())!! - val registeredBtcAddress = response["clientId"] + val response = gson.fromJson(res.jsonObject.toString(), JsonObject::class.java)!! + val registeredBtcAddress = response["clientId"].asString btcRegistrationEnvironment.btcRegisteredAddressesProvider.getRegisteredAddresses() .fold({ addresses -> @@ -90,20 +88,18 @@ class BtcRegistrationIntegrationTest { */ @Test fun testDoubleRegistration() { - integrationHelper.genFreeBtcAddress(btcRegistrationEnvironment.btcAddressGenerationConfig.btcKeysWalletPath) + integrationHelper.genFreeBtcAddress(btcRegistrationEnvironment.keyPairService) val keypair = Ed25519Sha3().generateKeypair() val userName = String.getRandomString(9) var res = registrationServiceEnvironment.register(userName, keypair.public.toHexString()) assertEquals(200, res.statusCode) res = btcRegistrationEnvironment.register(userName, keypair.public.toHexString()) assertEquals(200, res.statusCode) - val response = moshiAdapter.fromJson(res.jsonObject.toString())!! - + val response = gson.fromJson(res.jsonObject.toString(), JsonObject::class.java)!! //Double registration res = btcRegistrationEnvironment.register(userName, keypair.public.toHexString()) assertEquals(500, res.statusCode) - - val registeredBtcAddress = response["clientId"] + val registeredBtcAddress = response["clientId"].asString btcRegistrationEnvironment.btcRegisteredAddressesProvider.getRegisteredAddresses() .fold({ addresses -> @@ -130,7 +126,7 @@ class BtcRegistrationIntegrationTest { btcRegistrationEnvironment.btcRegisteredAddressesProvider.getRegisteredAddresses().get() .size integrationHelper.genFreeBtcAddress( - btcRegistrationEnvironment.btcAddressGenerationConfig.btcKeysWalletPath, + btcRegistrationEnvironment.keyPairService, "different node id" ) val keypair = Ed25519Sha3().generateKeypair() @@ -157,7 +153,7 @@ class BtcRegistrationIntegrationTest { val takenAddresses = HashSet() val addressesToRegister = 3 integrationHelper.preGenFreeBtcAddresses( - btcRegistrationEnvironment.btcAddressGenerationConfig.btcKeysWalletPath, + btcRegistrationEnvironment.keyPairService, addressesToRegister ) for (i in 1..addressesToRegister) { @@ -175,8 +171,10 @@ class BtcRegistrationIntegrationTest { assertEquals(200, res.statusCode) res = btcRegistrationEnvironment.register(userName, keypair.public.toHexString()) assertEquals(200, res.statusCode) - val response = moshiAdapter.fromJson(res.jsonObject.toString())!! - val registeredBtcAddress = response["clientId"].toString() + + val response = gson.fromJson(res.jsonObject.toString(), JsonObject::class.java)!! + val registeredBtcAddress = response["clientId"].asString + assertEquals(newestAddress.address, registeredBtcAddress) assertFalse(takenAddresses.contains(registeredBtcAddress)) takenAddresses.add(registeredBtcAddress) @@ -238,7 +236,7 @@ class BtcRegistrationIntegrationTest { val clientsBeforeRegistration = btcRegistrationEnvironment.btcRegisteredAddressesProvider.getRegisteredAddresses().get() .size - integrationHelper.genChangeBtcAddress(btcRegistrationEnvironment.btcAddressGenerationConfig.btcKeysWalletPath) + integrationHelper.genChangeBtcAddress(btcRegistrationEnvironment.keyPairService) val num = khttp.get("http://127.0.0.1:${btcRegistrationEnvironment.btcRegistrationConfig.port}/free-addresses/number") diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcWithdrawalExpansionTest.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcWithdrawalExpansionTest.kt index d3cfbdab..9bc05aa9 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcWithdrawalExpansionTest.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcWithdrawalExpansionTest.kt @@ -44,7 +44,7 @@ class BtcWithdrawalExpansionTest { blockStorageFolder.mkdirs() integrationHelper.addBtcNotary("test", "test") integrationHelper.generateBtcInitialBlocks() - integrationHelper.genChangeBtcAddress(environment.btcWithdrawalConfig.btcKeysWalletPath) + integrationHelper.genChangeBtcAddress(environment.keyPairService) .failure { ex -> throw ex } environment.btcWithdrawalInitialization.init().failure { ex -> throw ex } } diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcWithdrawalFailResistanceIntegrationTest.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcWithdrawalFailResistanceIntegrationTest.kt index 0e18d80d..fd188cec 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcWithdrawalFailResistanceIntegrationTest.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcWithdrawalFailResistanceIntegrationTest.kt @@ -62,10 +62,10 @@ class BtcWithdrawalFailResistanceIntegrationTest { blockStorageFolder.mkdirs() integrationHelper.addBtcNotary("test", "test") integrationHelper.generateBtcInitialBlocks() - integrationHelper.genChangeBtcAddress(environment.btcWithdrawalConfig.btcKeysWalletPath) + integrationHelper.genChangeBtcAddress(environment.keyPairService) .fold({ address -> changeAddress = address }, { ex -> throw ex }) integrationHelper.preGenFreeBtcAddresses( - environment.btcWithdrawalConfig.btcKeysWalletPath, + environment.keyPairService, TOTAL_TESTS * 2 ) environment.withdrawalTransferService.addNewBtcTransactionListener { tx -> diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcWithdrawalIntegrationTest.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcWithdrawalIntegrationTest.kt index a0b9f7e7..94192881 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcWithdrawalIntegrationTest.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/BtcWithdrawalIntegrationTest.kt @@ -64,10 +64,10 @@ class BtcWithdrawalIntegrationTest { blockStorageFolder.mkdirs() integrationHelper.addBtcNotary("test", "test") integrationHelper.generateBtcInitialBlocks() - integrationHelper.genChangeBtcAddress(environment.btcWithdrawalConfig.btcKeysWalletPath) + integrationHelper.genChangeBtcAddress(environment.keyPairService) .fold({ address -> changeAddress = address }, { ex -> throw ex }) integrationHelper.preGenFreeBtcAddresses( - environment.btcWithdrawalConfig.btcKeysWalletPath, + environment.keyPairService, TOTAL_TESTS ) // This listener emulates a failure @@ -335,7 +335,7 @@ class BtcWithdrawalIntegrationTest { ) assertEquals(200, res.statusCode) val btcAddressSrc = integrationHelper.registerBtcAddress( - environment.btcWithdrawalConfig.btcKeysWalletPath, + environment.keyPairService, randomNameSrc, CLIENT_DOMAIN, testClientSrcKeypair diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcAddressGenerationTestEnvironment.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcAddressGenerationTestEnvironment.kt index 6ed23c94..3bafc099 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcAddressGenerationTestEnvironment.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcAddressGenerationTestEnvironment.kt @@ -10,6 +10,9 @@ import com.d3.btc.generation.config.BtcAddressGenerationConfig import com.d3.btc.generation.expansion.AddressGenerationServiceExpansion import com.d3.btc.generation.init.BtcAddressGenerationInitialization import com.d3.btc.generation.trigger.AddressGenerationTrigger +import com.d3.btc.keypair.securosys.SecuroSysConfig +import com.d3.btc.keypair.securosys.SecuroSysKeyPairService +import com.d3.btc.keypair.wallet.WalletKeyPairService import com.d3.btc.provider.BtcChangeAddressProvider import com.d3.btc.provider.BtcFreeAddressesProvider import com.d3.btc.provider.BtcRegisteredAddressesProvider @@ -31,9 +34,7 @@ import io.grpc.ManagedChannelBuilder import jp.co.soramitsu.bootstrap.changelog.ChangelogInterface import jp.co.soramitsu.iroha.java.IrohaAPI import jp.co.soramitsu.iroha.java.Utils -import org.bitcoinj.wallet.Wallet import java.io.Closeable -import java.io.File //How many addresses to generate at initial phase private const val INIT_ADDRESSES = 3 @@ -43,9 +44,9 @@ private const val INIT_ADDRESSES = 3 */ class BtcAddressGenerationTestEnvironment( private val integrationHelper: BtcIntegrationHelperUtil, - val testName: String = "test", + testName: String = "test", val btcGenerationConfig: BtcAddressGenerationConfig = - integrationHelper.configHelper.createBtcAddressGenerationConfig(INIT_ADDRESSES, testName), + integrationHelper.configHelper.createBtcAddressGenerationConfig(INIT_ADDRESSES), mstRegistrationCredential: IrohaCredential = IrohaCredential( btcGenerationConfig.mstRegistrationAccount.accountId, Utils.parseHexKeypair( @@ -55,7 +56,9 @@ class BtcAddressGenerationTestEnvironment( ) ) : Closeable { - private val keysWallet = Wallet.loadFromFile(File(btcGenerationConfig.btcKeysWalletPath)) + private val walletConfig = integrationHelper.configHelper.createWalletConfig(testName) + val keyPairService = WalletKeyPairService(walletConfig.btcKeysWalletPath) + /** * It's essential to handle blocks in this service one-by-one. * This is why we explicitly set single threaded executor. @@ -120,13 +123,13 @@ class BtcAddressGenerationTestEnvironment( btcGenerationConfig.notaryListSetterAccount ) return BtcPublicKeyProvider( - keysWallet, notaryPeerListProvider, btcGenerationConfig.notaryAccount, btcGenerationConfig.changeAddressesStorageAccount, multiSigConsumer, sessionConsumer, - btcNetworkConfigProvider + btcNetworkConfigProvider, + keyPairService ) } @@ -169,7 +172,6 @@ class BtcAddressGenerationTestEnvironment( ) val btcAddressGenerationInitialization = BtcAddressGenerationInitialization( - keysWallet, registrationQueryHelper, btcGenerationConfig, btcPublicKeyProvider(), diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcNotaryTestEnvironment.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcNotaryTestEnvironment.kt index 83a72492..b0b72d14 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcNotaryTestEnvironment.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcNotaryTestEnvironment.kt @@ -12,6 +12,9 @@ import com.d3.btc.deposit.expansion.DepositServiceExpansion import com.d3.btc.deposit.init.BtcNotaryInitialization import com.d3.btc.deposit.service.BtcWalletListenerRestartService import com.d3.btc.handler.NewBtcClientRegistrationHandler +import com.d3.btc.keypair.securosys.SecuroSysConfig +import com.d3.btc.keypair.securosys.SecuroSysKeyPairService +import com.d3.btc.keypair.wallet.WalletKeyPairService import com.d3.btc.listener.NewBtcClientRegistrationListener import com.d3.btc.peer.SharedPeerGroup import com.d3.btc.provider.BtcChangeAddressProvider @@ -56,6 +59,9 @@ class BtcNotaryTestEnvironment( ) ) : Closeable { + private val walletConfig = integrationHelper.configHelper.createWalletConfig(testName) + val keyPairService = WalletKeyPairService(walletConfig.btcKeysWalletPath) + private val irohaAPI = IrohaAPI(notaryConfig.iroha.hostname, notaryConfig.iroha.port) private val queryHelper = diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcRegistrationTestEnvironment.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcRegistrationTestEnvironment.kt index 3092b938..8d843d7b 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcRegistrationTestEnvironment.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcRegistrationTestEnvironment.kt @@ -5,6 +5,10 @@ package integration.btc.environment +import com.d3.btc.keypair.securosys.SecuroSysConfig +import com.d3.btc.keypair.securosys.SecuroSysKeyPairService +import com.d3.btc.keypair.wallet.WalletConfig +import com.d3.btc.keypair.wallet.WalletKeyPairService import com.d3.btc.provider.BtcFreeAddressesProvider import com.d3.btc.provider.BtcRegisteredAddressesProvider import com.d3.btc.provider.account.IrohaBtcAccountRegistrator @@ -29,8 +33,8 @@ class BtcRegistrationTestEnvironment(private val integrationHelper: BtcIntegrati val btcRegistrationConfig = integrationHelper.configHelper.createBtcRegistrationConfig() - val btcAddressGenerationConfig = - integrationHelper.configHelper.createBtcAddressGenerationConfig(0) + private val walletConfig = integrationHelper.configHelper.createWalletConfig("test_registration") + val keyPairService = WalletKeyPairService(walletConfig.btcKeysWalletPath) private val btcRegistrationCredential = IrohaCredential( diff --git a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcWithdrawalTestEnvironment.kt b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcWithdrawalTestEnvironment.kt index 3f62b8fd..96239243 100644 --- a/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcWithdrawalTestEnvironment.kt +++ b/notary-btc-integration-test/src/integration-test/kotlin/integration/btc/environment/BtcWithdrawalTestEnvironment.kt @@ -8,6 +8,9 @@ package integration.btc.environment import com.d3.btc.config.BitcoinConfig import com.d3.btc.handler.NewBtcClientRegistrationHandler import com.d3.btc.helper.address.outPutToBase58Address +import com.d3.btc.keypair.securosys.SecuroSysConfig +import com.d3.btc.keypair.securosys.SecuroSysKeyPairService +import com.d3.btc.keypair.wallet.WalletKeyPairService import com.d3.btc.peer.SharedPeerGroup import com.d3.btc.provider.BtcChangeAddressProvider import com.d3.btc.provider.BtcRegisteredAddressesProvider @@ -73,6 +76,9 @@ class BtcWithdrawalTestEnvironment( val createdTransactions = ConcurrentHashMap>() + private val walletConfig = integrationHelper.configHelper.createWalletConfig(testName) + val keyPairService = WalletKeyPairService(walletConfig.btcKeysWalletPath) + /** * It's essential to handle blocks in this service one-by-one. * This is why we explicitly set single threaded executor. @@ -201,7 +207,7 @@ class BtcWithdrawalTestEnvironment( private val transactionCreator = TransactionCreator(btcChangeAddressProvider, btcNetworkConfigProvider, utxoProvider, transactionsStorage) private val transactionSigner = - TransactionSigner(btcRegisteredAddressesProvider, btcChangeAddressProvider, transferWallet) + TransactionSigner(btcRegisteredAddressesProvider, btcChangeAddressProvider, transferWallet, keyPairService) val signCollector = SignCollector( signaturesCollectorCredential, @@ -257,7 +263,7 @@ class BtcWithdrawalTestEnvironment( private val newConsensusDataHandler = NewConsensusDataHandler(withdrawalTransferService) private val newTransactionCreatedHandler = - NewTransactionCreatedHandler(signCollector, transactionsStorage, btcWithdrawalConfig, btcRollbackService) + NewTransactionCreatedHandler(signCollector, transactionsStorage, btcRollbackService) val btcWithdrawalInitialization by lazy { BtcWithdrawalInitialization( diff --git a/notary-btc-integration-test/src/main/kotlin/integration/helper/BtcConfigHelper.kt b/notary-btc-integration-test/src/main/kotlin/integration/helper/BtcConfigHelper.kt index dd8b1e00..f42fea2e 100644 --- a/notary-btc-integration-test/src/main/kotlin/integration/helper/BtcConfigHelper.kt +++ b/notary-btc-integration-test/src/main/kotlin/integration/helper/BtcConfigHelper.kt @@ -9,6 +9,7 @@ import com.d3.btc.config.BitcoinConfig import com.d3.btc.deposit.config.BtcDepositConfig import com.d3.btc.dwbridge.config.BtcDWBridgeConfig import com.d3.btc.generation.config.BtcAddressGenerationConfig +import com.d3.btc.keypair.wallet.WalletConfig import com.d3.btc.registration.config.BtcRegistrationConfig import com.d3.btc.withdrawal.config.BtcWithdrawalConfig import com.d3.commons.config.loadLocalConfigs @@ -35,8 +36,7 @@ class BtcConfigHelper( * @return config * */ fun createBtcAddressGenerationConfig( - initAddresses: Int, - walletNamePostfix: String = "test" + initAddresses: Int ): BtcAddressGenerationConfig { val btcPkPreGenConfig = loadLocalConfigs( @@ -60,12 +60,22 @@ class BtcConfigHelper( override val expansionTriggerCreatorAccountId = accountHelper.superuserAccount.accountId override val notaryAccount = accountHelper.notaryAccount.accountId override val iroha = createIrohaConfig() - override val btcKeysWalletPath = createWalletFile("keys.$walletNamePostfix") override val registrationAccount = accountHelper.createCredentialRawConfig(accountHelper.registrationAccount) } } + /** + * Creates wallet file config + * @param walletNamePostfix - wallet file name postfix + * @return config + */ + fun createWalletConfig(walletNamePostfix: String = "test"): WalletConfig { + return object : WalletConfig { + override val btcKeysWalletPath = createWalletFile("keys.$walletNamePostfix") + } + } + /** * Creates config for Bitcoin withdrawal * @param testName - name of the test. used to create folder for block storage and queue name @@ -84,7 +94,6 @@ class BtcConfigHelper( override val btcConsensusCredential = accountHelper.createCredentialRawConfig(accountHelper.btcConsensusAccount) override val irohaBlockQueue = testName - override val btcKeysWalletPath = createWalletFile("keys.$testName") override val btcTransfersWalletPath = createWalletFile("transfers.$testName") override val notaryListStorageAccount = accountHelper.notaryListStorageAccount.accountId override val notaryListSetterAccount = accountHelper.notaryAccount.accountId diff --git a/notary-btc-integration-test/src/main/kotlin/integration/helper/BtcIntegrationHelperUtil.kt b/notary-btc-integration-test/src/main/kotlin/integration/helper/BtcIntegrationHelperUtil.kt index e53c232e..96ff0997 100644 --- a/notary-btc-integration-test/src/main/kotlin/integration/helper/BtcIntegrationHelperUtil.kt +++ b/notary-btc-integration-test/src/main/kotlin/integration/helper/BtcIntegrationHelperUtil.kt @@ -8,6 +8,7 @@ package integration.helper import com.d3.btc.config.BitcoinConfig import com.d3.btc.helper.address.createMsAddress import com.d3.btc.helper.currency.satToBtc +import com.d3.btc.keypair.KeyPairService import com.d3.btc.model.AddressInfo import com.d3.btc.peer.SharedPeerGroup import com.d3.btc.provider.BtcFreeAddressesProvider @@ -32,12 +33,11 @@ import jp.co.soramitsu.bootstrap.changelog.ExpansionDetails import jp.co.soramitsu.bootstrap.changelog.ExpansionUtils import mu.KLogging import org.bitcoinj.core.Address -import org.bitcoinj.crypto.DeterministicKey import org.bitcoinj.params.RegTestParams import org.bitcoinj.wallet.Wallet -import java.io.File import java.math.BigDecimal import java.security.KeyPair +import kotlin.math.ceil // Btc asset id const val BTC_ASSET = "btc#bitcoin" @@ -102,36 +102,36 @@ class BtcIntegrationHelperUtil(peers: Int = 1) : IrohaIntegrationHelperUtil(peer /** * Pregenerates multiple BTC addresses that can be registered later - * @param walletFilePath - path to wallet file + * @param keyPairService - key pair service * @param addressesToGenerate - number of addresses to generate */ - fun preGenFreeBtcAddresses(walletFilePath: String, addressesToGenerate: Int) { + fun preGenFreeBtcAddresses(keyPairService: KeyPairService, addressesToGenerate: Int) { val totalBatches = - Math.ceil(addressesToGenerate.div(GENERATED_ADDRESSES_PER_BATCH.toDouble())).toInt() + ceil(addressesToGenerate.div(GENERATED_ADDRESSES_PER_BATCH.toDouble())).toInt() /* Iroha dies if it sees too much of transactions in a batch. */ for (batch in 1..totalBatches) { if (batch == totalBatches) { preGenFreeBtcAddressesBatch( - walletFilePath, + keyPairService, addressesToGenerate - (totalBatches - 1) * GENERATED_ADDRESSES_PER_BATCH ) } else { - preGenFreeBtcAddressesBatch(walletFilePath, GENERATED_ADDRESSES_PER_BATCH) + preGenFreeBtcAddressesBatch(keyPairService, GENERATED_ADDRESSES_PER_BATCH) } } } /** * Creates and executes a batch full of generated BTC addresses - * @param walletFilePath - path to wallet file + * @param keyPairService - key pair service * @param addressesToGenerate - number of addresses to generate */ - private fun preGenFreeBtcAddressesBatch(walletFilePath: String, addressesToGenerate: Int) { + private fun preGenFreeBtcAddressesBatch(keyPairService: KeyPairService, addressesToGenerate: Int) { val irohaTxList = ArrayList() for (i in 1..addressesToGenerate) { - val (key, address) = generateKeyAndAddress(walletFilePath) + val (key, address) = generateKeyAndAddress(keyPairService) val irohaTx = IrohaTransaction( mstRegistrationIrohaConsumer.creator, ModelUtil.getCurrentTime(), @@ -141,7 +141,7 @@ class BtcIntegrationHelperUtil(peers: Int = 1) : IrohaIntegrationHelperUtil(peer accountHelper.notaryAccount.accountId, address.toBase58(), AddressInfo.createFreeAddressInfo( - listOf(key.publicKeyAsHex), + listOf(key), NODE_ID, System.currentTimeMillis() ).toJson() @@ -181,16 +181,16 @@ class BtcIntegrationHelperUtil(peers: Int = 1) : IrohaIntegrationHelperUtil(peer * @return randomly generated BTC address */ fun genFreeBtcAddress( - walletFilePath: String, + keyPairService: KeyPairService, nodeId: String = NODE_ID ): Result { - val (key, address) = generateKeyAndAddress(walletFilePath) + val (key, address) = generateKeyAndAddress(keyPairService) return ModelUtil.setAccountDetail( mstRegistrationIrohaConsumer, accountHelper.notaryAccount.accountId, address.toBase58(), AddressInfo.createFreeAddressInfo( - listOf(key.publicKeyAsHex), + listOf(key), nodeId, System.currentTimeMillis() ).toJson() @@ -199,17 +199,17 @@ class BtcIntegrationHelperUtil(peers: Int = 1) : IrohaIntegrationHelperUtil(peer /** * Generates one BTC address that can be registered later - * @param walletFilePath - path to wallet file + * @param keyPairService - key pair service * @return randomly generated BTC address */ - fun genChangeBtcAddress(walletFilePath: String): Result { - val (key, address) = generateKeyAndAddress(walletFilePath) + fun genChangeBtcAddress(keyPairService: KeyPairService): Result { + val (key, address) = generateKeyAndAddress(keyPairService) return ModelUtil.setAccountDetail( mstRegistrationIrohaConsumer, accountHelper.changeAddressesStorageAccount.accountId, address.toBase58(), AddressInfo.createChangeAddressInfo( - listOf(key.publicKeyAsHex), + listOf(key), NODE_ID, System.currentTimeMillis() ).toJson() @@ -217,31 +217,28 @@ class BtcIntegrationHelperUtil(peers: Int = 1) : IrohaIntegrationHelperUtil(peer } // Generates key and key based address - private fun generateKeyAndAddress(walletFilePath: String): Pair { - val walletFile = File(walletFilePath) - val wallet = Wallet.loadFromFile(walletFile) - val key = wallet.freshReceiveKey() - val address = createMsAddress(listOf(key.publicKeyAsHex), RegTestParams.get()) - wallet.addWatchedAddress(address) - wallet.saveToFile(walletFile) + private fun generateKeyAndAddress(keyPairService: KeyPairService): Pair { + val keyPair = keyPairService.createKeyPair() + val address = createMsAddress(listOf(keyPair.publicKeyAsHex), RegTestParams.get()) + logger.info { "generated address $address" } - return Pair(key, address) + return Pair(keyPair.publicKeyAsHex, address) } /** * Registers BTC client - * @param walletFilePath - path to wallet file + * @param keyPairService - key pair service * @param irohaAccountName - client account in Iroha * @param keypair - key pair for new client in Iroha * @return btc address related to client */ fun registerBtcAddress( - walletFilePath: String, + keyPairService: KeyPairService, irohaAccountName: String, domain: String, keypair: KeyPair = ModelUtil.generateKeypair() ): String { - genFreeBtcAddress(walletFilePath).fold({ + genFreeBtcAddress(keyPairService).fold({ return registerBtcAddressNoPreGen(irohaAccountName, domain, keypair) }, { ex -> throw ex }) }